Skip to content

feat: migrate to the mcp 2.0 SDK, release 0.5.0 - #6

Merged
shossain786 merged 1 commit into
masterfrom
feat/mcp-2.0-migration
Aug 23, 2026
Merged

shossain786 merged 1 commit into
masterfrom
feat/mcp-2.0-migration

Conversation

@shossain786

Copy link
Copy Markdown
Contributor

Closes the loop on #2. 0.4.2 stopped the bleeding by pinning mcp<2.0.0; this does the migration that pin was holding the door open for.

The change

mcp 2.0.0 removed the @app.list_tools() / @app.call_tool() decorators the server registered all 85 tools with. They're replaced by on_list_tools / on_call_tool callbacks on the Server constructor — handlers now take a ServerRequestContext plus typed request params and return ListToolsResult / CallToolResult rather than bare content lists.

The surface really was as small as the gate predicted. mcp 2.0 keeps camelCase aliases on its models (populate_by_name + validate_by_alias), so Tool(..., inputSchema=...) still validates — none of the 85 tool definitions across the four tools/*.py files needed a single edit. Only server.py changed.

The pin inverts to mcp>=2.0.0. The 0.4.2 ceiling was load-bearing because the code spoke 1.x; the floor is load-bearing now because the code speaks 2.x.

No wire change, on purpose

Tool names, input schemas, response content and error strings are byte-for-byte what 0.4.x emitted. A migration that also changes behaviour can't be verified as a migration. Returning is_error: true on the exception path is the semantically correct thing and is deliberately left as a follow-up.

smoke.yml had to change — and it caught itself

The smoke test called server.list_tools() with no arguments, so this migration breaks it. That signature belongs to the SDK, not to us. It now asserts against server.ALL_TOOLS — the registry we own — so the test measures the package rather than the SDK's calling convention.

Verification

Against the built wheel installed into a clean venv, never src/:

Check Result
Registry 85 tools, 85 handlers, no orphans either direction
Entry point exits 0 on EOF
Handshake initialize still negotiates protocolVersion 2025-03-26
Wire schema inputSchema still camelCase in tools/list
selenium-mcp-test Java suite 68/68 pass over real stdio JSON-RPC (same count as the 0.4.2 baseline)
New floor is real forced onto mcp 1.29.0 the import fails loudly at ServerRequestContext; pip refuses the combination outright

Suite run under xvfb with the clean venv first on PATH, so python -m selenium_mcp.server resolved to the installed artifact.

⚠️ Merge after #5

The CHANGELOG's Infrastructure section describes Trusted Publishing and Dependabot, which land in #5. More importantly: do not tag 0.5.0 until #5 is merged and the PyPI publisher is enrolled, or the release will fail at the 403 that has been failing since ~July 1 and 0.5.0 will need publishing by hand like the three before it.

Completes the work 0.4.2 deferred. 2.0.0 removed the @app.list_tools() /
@app.call_tool() decorators the server registered all 85 tools with (#2);
they are replaced by on_list_tools / on_call_tool callbacks on the Server
constructor, which take a ServerRequestContext plus typed request params
and return ListToolsResult / CallToolResult instead of bare content lists.

The pin inverts: mcp>=2.0.0. The 0.4.2 ceiling was load-bearing because
the code spoke 1.x; now the floor is, because the code speaks 2.x. An
upper bound returns when 3.0 is on the horizon.

The wire output is deliberately byte-identical to 0.4.x — same tool
names, same schemas, same response content, same error strings. A
migration that also changes behaviour cannot be verified as a migration.
Returning is_error=True on the exception path is the semantically
correct thing and is left as a follow-up.

Also: the server now reports its version in the handshake, read from the
installed distribution rather than duplicated in source.

smoke.yml asserted by calling server.list_tools() with no arguments,
which this change breaks — the handler's signature belongs to the SDK.
It now asserts against server.ALL_TOOLS, the registry we actually own,
so the test measures the package and not the SDK's calling convention.

Verified against the built wheel installed in a clean venv (never src/):
  - 85 tools, 85 handlers, no orphans either direction
  - entry point exits 0 on EOF
  - initialize still negotiates protocolVersion 2025-03-26, and
    inputSchema is still camelCase on the wire (mcp 2.0 keeps the
    camelCase aliases, so none of the 85 tool definitions changed)
  - selenium-mcp-test Java suite: 68/68 pass over real stdio JSON-RPC
  - the new floor is real: forced onto mcp 1.29.0 the import fails
    loudly at ServerRequestContext, and pip refuses the combination

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shossain786
shossain786 merged commit 29bac68 into master Aug 23, 2026
3 checks passed
@shossain786
shossain786 deleted the feat/mcp-2.0-migration branch August 23, 2026 06:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant