Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion tests/test_v1_harbor_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
terminus_2_agent_script,
)
from verifiers.v1.packages.tasksets.harbor import harbor_reward
from verifiers.v1.utils.mcp_proxy_utils import MCP_PROXY_PYTHON_PATH
from verifiers.v1.utils.program_utils import merge_task_program, merge_task_sandbox


Expand Down Expand Up @@ -304,7 +305,10 @@ def test_pi_harness_writes_intercepted_model_and_mcp_config() -> None:
assert provider["api"] == "openai-completions"
assert provider["apiKey"] == "secret"
assert provider["models"] == [{"id": "model", "name": "openai/gpt-5.4-mini"}]
assert mcp["mcpServers"]["verifiers-tools"]["command"] == "python3"
server = mcp["mcpServers"]["verifiers-tools"]
assert server["command"] == "/bin/sh"
assert server["args"][0] == "-lc"
assert MCP_PROXY_PYTHON_PATH in server["args"][1]


def test_terminus_2_harness_builds_sandbox_program() -> None:
Expand Down
41 changes: 38 additions & 3 deletions tests/test_v1_runtime_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from verifiers.v1.utils.endpoint_utils import endpoint_api_key
from verifiers.v1.utils import mcp_utils
from verifiers.v1.utils.mcp_proxy_utils import MCP_PROXY_CONFIG_PATH, MCP_PROXY_PATH
from verifiers.v1.utils.mcp_proxy_utils import MCP_PROXY_PYTHON_PATH
from verifiers.v1.utils.mcp_proxy_utils import proxy_command, proxy_source
from verifiers.v1.utils.program_utils import command_env
from verifiers.v1.utils.sandbox_program_utils import (
Expand All @@ -38,6 +39,7 @@
from verifiers.v1.utils.sandbox_utils import (
VF_STATE_INPUT_PATH_KEY,
collect_sandbox_artifacts,
python_package_install_command,
run_sandbox_command,
)

Expand Down Expand Up @@ -1019,6 +1021,30 @@ def test_sandbox_fn_program_installs_local_package(
assert command[2].endswith(" /tmp/vf_program_runner.py fn local_program:run")


def test_python_package_install_command_ignores_image_pip_config() -> None:
command = python_package_install_command("'mcp>=1.14.1' requests")

assert "export PIP_CONFIG_FILE=/dev/null" in command
assert (
"unset PIP_INDEX_URL PIP_EXTRA_INDEX_URL PIP_FIND_LINKS PIP_NO_INDEX "
"PIP_REQUIRE_VIRTUALENV"
) in command
assert "UV_TOOL_DIR=/tmp/vf-tools" in command
assert "UV_DEFAULT_INDEX=https://pypi.org/simple" in command
assert "uv --no-config tool install" in command
assert "--python 3.11 --with requests 'mcp>=1.14.1'" in command
assert "$UV_TOOL_DIR/mcp/bin/python" in command
assert MCP_PROXY_PYTHON_PATH in command
assert (
"pip install --disable-pip-version-check --break-system-packages requests"
in command
)
assert (
"pip install --disable-pip-version-check --break-system-packages 'mcp>=1.14.1'"
not in command
)


def test_sandbox_fn_program_resolves_local_module_package(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
Expand Down Expand Up @@ -1208,7 +1234,11 @@ def test_program_channels_mcp_injects_proxy_into_sandbox_program() -> None:
"tool_base_url": "http://127.0.0.1:1/rollout/test/vf/tools",
"tool_api_key": harness.endpoint.secret,
}
assert proxy_command() == ["python3", MCP_PROXY_PATH, MCP_PROXY_CONFIG_PATH]
command = proxy_command()
assert command[:2] == ["/bin/sh", "-lc"]
assert MCP_PROXY_PYTHON_PATH in command[2]
assert MCP_PROXY_PATH in command[2]
assert MCP_PROXY_CONFIG_PATH in command[2]
packages = sandbox["packages"]
assert isinstance(packages, list)
assert "mcp>=1.14.1" in packages
Expand Down Expand Up @@ -1417,14 +1447,15 @@ async def write_real_sandbox_file(text: str, sandbox, state) -> str:
REAL_MCP_PROXY_SCRIPT = r"""
import asyncio
import json
import sys

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


async def main():
server = StdioServerParameters(
command="python3",
command=sys.executable,
args=["/tmp/vf_mcp_tools.py", "/tmp/vf_mcp_tools.json"],
)
async with stdio_client(server) as (read_stream, write_stream):
Expand Down Expand Up @@ -1505,7 +1536,11 @@ async def test_real_sandbox_command_program_uses_mcp_tool_proxy() -> None:
harness = make_harness(
program={
"sandbox": True,
"command": ["python", "/tmp/call_mcp.py"],
"command": [
"/bin/sh",
"-lc",
f'exec "$(cat {MCP_PROXY_PYTHON_PATH})" /tmp/call_mcp.py',
],
"channels": "mcp",
"files": {"/tmp/call_mcp.py": REAL_MCP_PROXY_SCRIPT},
},
Expand Down
9 changes: 8 additions & 1 deletion verifiers/v1/utils/mcp_proxy_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

MCP_PROXY_PATH = "/tmp/vf_mcp_tools.py"
MCP_PROXY_CONFIG_PATH = "/tmp/vf_mcp_tools.json"
MCP_PROXY_PYTHON_PATH = "/tmp/vf_mcp_python"
MCP_PACKAGE = "mcp>=1.14.1"
REQUESTS_PACKAGE = "requests"

Expand Down Expand Up @@ -69,7 +70,13 @@ def proxy_program(


def proxy_command() -> list[str]:
return ["python3", MCP_PROXY_PATH, MCP_PROXY_CONFIG_PATH]
command = (
f"PYTHON=$(cat {shlex.quote(MCP_PROXY_PYTHON_PATH)} 2>/dev/null || "
"command -v python3); "
f'exec "$PYTHON" {shlex.quote(MCP_PROXY_PATH)} '
f"{shlex.quote(MCP_PROXY_CONFIG_PATH)}"
)
return ["/bin/sh", "-lc", command]


def proxy_sandbox(sandbox_config: ConfigMap) -> ConfigData:
Expand Down
44 changes: 40 additions & 4 deletions verifiers/v1/utils/sandbox_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from .artifact_utils import artifact_format, artifact_key, artifact_optional
from .artifact_utils import artifact_path
from .mcp_proxy_utils import MCP_PROXY_PYTHON_PATH
from .program_utils import command_argv, command_env, float_config, int_config
from .program_utils import program_option_mapping, program_channel_setup
from .program_utils import resolve_program_value
Expand Down Expand Up @@ -511,8 +512,45 @@ def sandbox_scope(sandbox_config: ConfigMap) -> str:


def python_package_install_command(package_args: str) -> str:
packages = shlex.split(package_args)
pip_packages = [package for package in packages if not package.startswith("mcp")]
pip_package_args = " ".join(shlex.quote(package) for package in pip_packages)
mcp_python_setup = ""
if any(package.startswith("mcp") for package in packages):
mcp_packages = [package for package in packages if package.startswith("mcp")]
mcp_package_args = " ".join(shlex.quote(package) for package in mcp_packages)
requests_packages = [
package for package in packages if package.startswith("requests")
]
requests_package = requests_packages[0] if requests_packages else "requests"
mcp_python_setup = (
"VF_UV_SITE_PACKAGES=/tmp/vf-uv-site-packages\n"
"export UV_TOOL_DIR=/tmp/vf-tools\n"
"export UV_PYTHON_INSTALL_DIR=/tmp/vf-python\n"
"export UV_CACHE_DIR=/tmp/vf-uv-cache\n"
"export UV_DEFAULT_INDEX=https://pypi.org/simple\n"
"unset UV_INDEX UV_INDEX_URL UV_EXTRA_INDEX_URL UV_FIND_LINKS UV_NO_INDEX UV_CONFIG_FILE\n"
'mkdir -p "$VF_UV_SITE_PACKAGES" "$UV_TOOL_DIR" "$UV_PYTHON_INSTALL_DIR" "$UV_CACHE_DIR"\n'
'"$PYTHON" -m pip install --disable-pip-version-check --break-system-packages '
' --target "$VF_UV_SITE_PACKAGES" uv==0.11.7 || '
'"$PYTHON" -m pip install --disable-pip-version-check '
' --target "$VF_UV_SITE_PACKAGES" uv==0.11.7\n'
'env PYTHONPATH="$VF_UV_SITE_PACKAGES" "$PYTHON" -m uv --no-config tool install '
f"--python 3.11 --with {shlex.quote(requests_package)} {mcp_package_args}\n"
f'printf "%s\\n" "$UV_TOOL_DIR/mcp/bin/python" > {shlex.quote(MCP_PROXY_PYTHON_PATH)}\n'
Comment on lines +538 to +540
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass a single tool package to uv tool install

This builds uv ... tool install ... {mcp_package_args} from every sandbox.packages entry starting with mcp, but uv tool install --help shows Usage: uv tool install [OPTIONS] <PACKAGE> (exactly one positional package). If a sandbox includes more than one mcp* requirement (for example the default mcp>=... plus mcp-agent), setup will fail with unexpected argument ... before installation completes, which breaks MCP-enabled rollouts that previously accepted multiple packages via pip install.

Useful? React with 👍 / 👎.

)
pip_install = ""
if pip_package_args:
pip_install = (
"$PYTHON -m pip install --disable-pip-version-check --break-system-packages "
f"{pip_package_args} || "
"$PYTHON -m pip install --disable-pip-version-check "
f"{pip_package_args}"
)
return (
"set -e\n"
"export PIP_CONFIG_FILE=/dev/null\n"
"unset PIP_INDEX_URL PIP_EXTRA_INDEX_URL PIP_FIND_LINKS PIP_NO_INDEX PIP_REQUIRE_VIRTUALENV\n"
"if command -v python3 >/dev/null 2>&1; then PYTHON=python3; "
"elif command -v python >/dev/null 2>&1; then PYTHON=python; "
"elif command -v apt-get >/dev/null 2>&1; then "
Expand All @@ -525,10 +563,8 @@ def python_package_install_command(package_args: str) -> str:
"(command -v apt-get >/dev/null 2>&1 && "
"apt-get -o Acquire::Retries=3 update && "
"apt-get -o Acquire::Retries=3 install -y python3-pip)\n"
"$PYTHON -m pip install --disable-pip-version-check --break-system-packages "
f"{package_args} || "
"$PYTHON -m pip install --disable-pip-version-check "
f"{package_args}"
f"{mcp_python_setup}"
f"{pip_install}"
)


Expand Down
Loading