diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6614444..0a26281 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,6 +133,8 @@ jobs: uv venv /tmp/uxarray-mcp-wheel --python 3.12 uv pip install --python /tmp/uxarray-mcp-wheel/bin/python dist/uxarray_mcp-*.whl /tmp/uxarray-mcp-wheel/bin/uxarray-mcp --help + /tmp/uxarray-mcp-wheel/bin/python scripts/check_mcp_handshake.py \ + --command /tmp/uxarray-mcp-wheel/bin/uxarray-mcp test-hpc: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a8ba02f..d1baf94 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,6 +44,8 @@ jobs: uv venv /tmp/uxarray-mcp-wheel --python 3.12 uv pip install --python /tmp/uxarray-mcp-wheel/bin/python dist/uxarray_mcp-*.whl /tmp/uxarray-mcp-wheel/bin/uxarray-mcp --help + /tmp/uxarray-mcp-wheel/bin/python scripts/check_mcp_handshake.py \ + --command /tmp/uxarray-mcp-wheel/bin/uxarray-mcp - name: Upload distributions uses: actions/upload-artifact@v4 @@ -109,6 +111,11 @@ jobs: fi /tmp/uxarray-mcp-pypi/bin/uxarray-mcp --help /tmp/uxarray-mcp-pypi/bin/python -c "import uxarray_mcp; print(uxarray_mcp.__version__)" + curl -fsSL \ + https://raw.githubusercontent.com/UXARRAY/uxarray-mcp-server/${REF_NAME}/scripts/check_mcp_handshake.py \ + -o /tmp/check_mcp_handshake.py + /tmp/uxarray-mcp-pypi/bin/python /tmp/check_mcp_handshake.py \ + --command /tmp/uxarray-mcp-pypi/bin/uxarray-mcp update-conda-feedstock: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b53e8..05626ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ uses Semantic Versioning for public releases. ## Unreleased +### Fixed +- Pin the MCP Python SDK to `<2` until toolregistry-server supports the renamed + `MCPError` exception in SDK 2.x. Fresh installs previously resolved MCP 2.0, + installed successfully, then failed when starting the stdio server. +- CI and release verification now perform a real clean-wheel MCP handshake: + initialize the server, list tools, and call `get_capabilities` over stdio. +- Package metadata now enforces the documented UXarray 2026.7.0 minimum used by + the vector-calculus fixes and scientific contracts. + ### Breaking - `gradient` and `curl` now default `scale_by_radius=True`, matching UXarray's public API. Pass `scale_by_radius=False` explicitly to preserve the previous diff --git a/conda/recipe/meta.yaml b/conda/recipe/meta.yaml index 166085b..e5e3373 100644 --- a/conda/recipe/meta.yaml +++ b/conda/recipe/meta.yaml @@ -28,10 +28,11 @@ requirements: # behavior is validated on conda-forge. - python >={{ python_min }} - toolregistry-server >=0.4.0 + - mcp >=1.20,<2 - holoviews >=1.19.0 - matplotlib-base >=3.9.0 - pyyaml >=6.0 - - uxarray >=2026.6.0 + - uxarray >=2026.7.0 test: requires: diff --git a/pyproject.toml b/pyproject.toml index 94c367a..f444d1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,10 +26,12 @@ license = { file = "LICENSE" } requires-python = ">=3.12,<3.13" dependencies = [ "toolregistry-server[mcp]>=0.4.0", + # toolregistry-server 0.4.x imports McpError, renamed to MCPError in mcp 2. + "mcp>=1.20,<2", "holoviews>=1.19.0", "matplotlib>=3.9.0", "pyyaml>=6.0", - "uxarray>=2026.6.0", + "uxarray>=2026.7.0", ] [project.optional-dependencies] diff --git a/scripts/check_mcp_handshake.py b/scripts/check_mcp_handshake.py new file mode 100644 index 0000000..8e1d900 --- /dev/null +++ b/scripts/check_mcp_handshake.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +"""Verify a clean uxarray-mcp install over the real stdio MCP transport.""" + +from __future__ import annotations + +import argparse +import asyncio + +from mcp import ClientSession, StdioServerParameters +from mcp.client.stdio import stdio_client + + +async def _check(command: str) -> None: + server = StdioServerParameters(command=command, args=["serve", "--profile", "core"]) + async with stdio_client(server) as (read, write): + async with ClientSession(read, write) as session: + initialized = await session.initialize() + listed = await session.list_tools() + names = {tool.name for tool in listed.tools} + required = {"get_capabilities", "run_analysis"} + if not required.issubset(names): + raise RuntimeError( + f"Missing required tools: {sorted(required - names)}" + ) + result = await session.call_tool( + "get_capabilities", {"grid_path": "healpix:1"} + ) + if result.isError: + raise RuntimeError(f"get_capabilities failed: {result.content}") + print( + f"MCP handshake passed: {initialized.serverInfo.name} " + f"with {len(listed.tools)} tools" + ) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--command", default="uxarray-mcp") + args = parser.parse_args() + asyncio.run(_check(args.command)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/uv.lock b/uv.lock index 10afc2b..64e592a 100644 --- a/uv.lock +++ b/uv.lock @@ -2437,11 +2437,12 @@ wheels = [ [[package]] name = "uxarray-mcp" -version = "0.1.2" +version = "0.2.0" source = { editable = "." } dependencies = [ { name = "holoviews" }, { name = "matplotlib" }, + { name = "mcp" }, { name = "pyyaml" }, { name = "toolregistry-server", extra = ["mcp"] }, { name = "uxarray" }, @@ -2476,13 +2477,14 @@ requires-dist = [ { name = "globus-compute-sdk", marker = "extra == 'hpc'", specifier = ">=4.5.0" }, { name = "holoviews", specifier = ">=1.19.0" }, { name = "matplotlib", specifier = ">=3.9.0" }, + { name = "mcp", specifier = ">=1.20,<2" }, { name = "myst-parser", marker = "extra == 'docs'", specifier = ">=3.0" }, { name = "pyyaml", specifier = ">=6.0" }, { name = "sphinx", marker = "extra == 'docs'", specifier = ">=7.0" }, { name = "sphinx-book-theme", marker = "extra == 'docs'", specifier = ">=1.1.0" }, { name = "toolregistry-server", extras = ["mcp"], specifier = ">=0.4.0" }, { name = "toolregistry-server", extras = ["openapi"], marker = "extra == 'openapi'", specifier = ">=0.4.0" }, - { name = "uxarray", specifier = ">=2026.6.0" }, + { name = "uxarray", specifier = ">=2026.7.0" }, ] provides-extras = ["openapi", "hpc", "docs"]