Update the v2 status banner and pin spawned environments to the running SDK version (#2834)
Some checks failed
CI / checks (push) Has been cancelled
CI / all-green (push) Has been cancelled

This commit is contained in:
Max 2026-06-11 09:41:19 +01:00 • committed by GitHub
commit 1e21814ed5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 107 additions and 16 deletions

View file

@ -1,24 +1,68 @@
"""Tests for mcp.cli.claude — Claude Desktop config file generation."""
import importlib.metadata
import json
from pathlib import Path
from typing import Any
import pytest
from mcp.cli.claude import get_uv_path, update_claude_config
from mcp.cli.claude import get_uv_path, mcp_requirement, update_claude_config
def _set_mcp_version(monkeypatch: pytest.MonkeyPatch, version: str) -> None:
real_version = importlib.metadata.version
def fake_version(distribution_name: str) -> str:
return version if distribution_name == "mcp" else real_version(distribution_name)
monkeypatch.setattr(importlib.metadata, "version", fake_version)
@pytest.fixture
def config_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
"""Temp Claude config dir with get_claude_config_path and get_uv_path mocked."""
"""Temp Claude config dir with the config path, uv path, and SDK version mocked."""
claude_dir = tmp_path / "Claude"
claude_dir.mkdir()
monkeypatch.setattr("mcp.cli.claude.get_claude_config_path", lambda: claude_dir)
monkeypatch.setattr("mcp.cli.claude.get_uv_path", lambda: "/fake/bin/uv")
# The ambient version is a dev build in the repo venv but varies by
# environment; pin it so the generated --with requirement is stable.
_set_mcp_version(monkeypatch, "1.2.3")
return claude_dir
def test_mcp_requirement_pins_release_versions(monkeypatch: pytest.MonkeyPatch):
"""Release versions produce an exact pin so spawned environments run the installed SDK version."""
_set_mcp_version(monkeypatch, "2.0.0a1")
assert mcp_requirement() == "mcp==2.0.0a1"
assert mcp_requirement("mcp[cli]") == "mcp[cli]==2.0.0a1"
def test_mcp_requirement_leaves_dev_versions_unpinned(monkeypatch: pytest.MonkeyPatch):
"""Dev versions are not published to PyPI, so the requirement falls back to the unpinned package."""
_set_mcp_version(monkeypatch, "2.0.0a2.dev3")
assert mcp_requirement() == "mcp"
assert mcp_requirement("mcp[cli]") == "mcp[cli]"
def test_mcp_requirement_leaves_local_versions_unpinned(monkeypatch: pytest.MonkeyPatch):
"""Local version segments (source builds) are not published to PyPI, so no pin is emitted."""
_set_mcp_version(monkeypatch, "1.2.3+g0123abc")
assert mcp_requirement() == "mcp"
def test_mcp_requirement_falls_back_when_mcp_is_not_installed(monkeypatch: pytest.MonkeyPatch):
"""Without distribution metadata there is no version to pin, so the requirement stays unpinned."""
def raise_not_found(distribution_name: str) -> str:
raise importlib.metadata.PackageNotFoundError(distribution_name)
monkeypatch.setattr(importlib.metadata, "version", raise_not_found)
assert mcp_requirement() == "mcp"
assert mcp_requirement("mcp[cli]") == "mcp[cli]"
def _read_server(config_dir: Path, name: str) -> dict[str, Any]:
config = json.loads((config_dir / "claude_desktop_config.json").read_text())
return config["mcpServers"][name]
@ -31,7 +75,7 @@ def test_generates_uv_run_command(config_dir: Path):
resolved = Path("server.py").resolve()
assert _read_server(config_dir, "my_server") == {
"command": "/fake/bin/uv",
"args": ["run", "--frozen", "--with", "mcp[cli]", "mcp", "run", f"{resolved}:app"],
"args": ["run", "--frozen", "--with", "mcp[cli]==1.2.3", "mcp", "run", f"{resolved}:app"],
}
@ -43,11 +87,19 @@ def test_file_spec_without_object_suffix(config_dir: Path):
def test_with_packages_sorted_and_deduplicated(config_dir: Path):
"""Extra packages should appear as --with flags, sorted and deduplicated with mcp[cli]."""
"""Extra packages should appear as sorted --with flags with duplicates removed."""
assert update_claude_config(file_spec="s.py:app", server_name="s", with_packages=["zebra", "aardvark", "zebra"])
args = _read_server(config_dir, "s")["args"]
assert args[:8] == ["run", "--frozen", "--with", "aardvark", "--with", "mcp[cli]", "--with", "zebra"]
assert args[:8] == ["run", "--frozen", "--with", "aardvark", "--with", "mcp[cli]==1.2.3", "--with", "zebra"]
def test_explicit_mcp_cli_kept_alongside_pinned_requirement(config_dir: Path):
"""A user-supplied mcp[cli] no longer collapses into the pinned requirement; uv resolves both to the pin."""
assert update_claude_config(file_spec="s.py:app", server_name="s", with_packages=["mcp[cli]"])
args = _read_server(config_dir, "s")["args"]
assert args[:6] == ["run", "--frozen", "--with", "mcp[cli]", "--with", "mcp[cli]==1.2.3"]
def test_with_editable_adds_flag(config_dir: Path, tmp_path: Path):

View file

@ -1,3 +1,4 @@
import importlib.metadata
import subprocess
import sys
from pathlib import Path
@ -8,6 +9,15 @@ import pytest
from mcp.cli.cli import _build_uv_command, _get_npx_command, _parse_file_path # type: ignore[reportPrivateUsage]
def _set_mcp_version(monkeypatch: pytest.MonkeyPatch, version: str) -> None:
real_version = importlib.metadata.version
def fake_version(distribution_name: str) -> str:
return version if distribution_name == "mcp" else real_version(distribution_name)
monkeypatch.setattr(importlib.metadata, "version", fake_version)
@pytest.mark.parametrize(
"spec, expected_obj",
[
@ -38,14 +48,23 @@ def test_parse_file_exit_on_dir(tmp_path: Path):
_parse_file_path(str(dir_path))
def test_build_uv_command_minimal():
"""Should emit core command when no extras specified."""
def test_build_uv_command_pins_the_running_mcp_version(monkeypatch: pytest.MonkeyPatch):
"""The spawned environment installs the same SDK version that is running, not the latest stable."""
_set_mcp_version(monkeypatch, "1.2.3")
cmd = _build_uv_command("foo.py")
assert cmd == ["uv", "run", "--with", "mcp==1.2.3", "mcp", "run", "foo.py"]
def test_build_uv_command_leaves_source_builds_unpinned(monkeypatch: pytest.MonkeyPatch):
"""Source-build versions are not on PyPI, so the requirement stays unpinned."""
_set_mcp_version(monkeypatch, "2.0.0a2.dev3+g0123abc")
cmd = _build_uv_command("foo.py")
assert cmd == ["uv", "run", "--with", "mcp", "mcp", "run", "foo.py"]
def test_build_uv_command_adds_editable_and_packages():
def test_build_uv_command_adds_editable_and_packages(monkeypatch: pytest.MonkeyPatch):
"""Should include --with-editable and every --with pkg in correct order."""
_set_mcp_version(monkeypatch, "1.2.3")
test_path = Path("/pkg")
cmd = _build_uv_command(
"foo.py",
@ -56,7 +75,7 @@ def test_build_uv_command_adds_editable_and_packages():
"uv",
"run",
"--with",
"mcp",
"mcp==1.2.3",
"--with-editable",
str(test_path), # Use str() to match what the function does
"--with",