Skip to content

AB#3134 Migrate to the mcp 2.0 SDK (FastMCP -> MCPServer) - #3

Merged
vosesoftware merged 1 commit into
mainfrom
feature/3134-mcp-2.0
Aug 12, 2026
Merged

vosesoftware merged 1 commit into
mainfrom
feature/3134-mcp-2.0

Conversation

@vosesoftware

Copy link
Copy Markdown
Owner

Lifts the mcp<2 cap added alongside AB#3132.

mcp 2.0 removed mcp.server.fastmcp outright and renamed the high-level server class FastMCP → MCPServer, now exported from mcp.server. That rename is essentially the whole migration: the @mcp.tool / @mcp.resource / @mcp.prompt decorators keep their signatures and still return the plain undecorated function, so the 25 tool bodies, their descriptions and their generated schemas are untouched — and the tests that call tools directly keep working.

Two real API changes

1.x 2.0
Server class from mcp.server.fastmcp import FastMCP from mcp.server import MCPServer
HTTP host/port mutate mcp.settings before run() run(transport=..., host=..., port=...)

MCPServer also accepts version, which FastMCP had no equivalent for, so the server now reports its own version in serverInfo instead of leaving it blank. CLI flags (--transport, --host, --port) are unchanged.

Verification

pytest here runs against a fake bridge and never exercises the protocol layer, so the suite passing is necessary but nowhere near sufficient. Also checked:

  • Registration compared name-for-name against the 1.x baseline, in a detached worktree at origin/main: 25 tools, 4 resources, 2 prompts — identical names, descriptions and schemas, including the AB#3123 generator output schema. (25/4/2 matches the decorator count exactly; an earlier 27/5/4 grep was counting docstring mentions.)
  • Live MCP initialize handshake over stdio — the same check release.yml runs against the packed .exe:
    {"jsonrpc":"2.0","id":1,"result":{"capabilities":{...},"protocolVersion":"2025-06-18","serverInfo":...
    serverInfo: YES   identity: YES   version 0.0.31: YES
    
  • streamable-http boots and honours a custom --host/--port (Uvicorn running on http://127.0.0.1:8931) — the one code path that changed and that neither pytest nor the stdio check touches.
  • ruff + mypy + pytest green (79 passed, 2 skipped).

uv.lock re-locked to mcp 2.0.0; CI's --locked sync keeps it honest.

Note

The major-version cap stays, now as mcp>=2,<3. mcp 2.0 arriving unannounced is exactly what broke main in the first place.

Lifts the mcp<2 cap added alongside AB#3132.

mcp 2.0 removed `mcp.server.fastmcp` outright and renamed the high-level server
class FastMCP -> MCPServer, now exported from `mcp.server`. That rename is
essentially the whole migration: the @mcp.tool / @mcp.resource / @mcp.prompt
decorators keep their signatures AND still return the plain undecorated function,
so the 25 tool bodies, their descriptions and their generated schemas are
untouched, and the tests that call tools directly keep working.

Two real API changes:

- HTTP transports take host/port as run() keyword arguments, forwarded to
  run_streamable_http_async / run_sse_async. Under 1.x you mutated mcp.settings
  before calling run(). __main__.py updated; the CLI flags are unchanged.

- MCPServer accepts `version`, which FastMCP had no equivalent for, so the
  server now reports its own version in serverInfo instead of leaving it blank.

Verified beyond the test suite, because pytest here runs against a fake bridge
and never exercises the protocol layer:

- Registration compared name-for-name against the 1.x baseline in a detached
  worktree at origin/main: 25 tools, 4 resources, 2 prompts, identical names,
  descriptions and schemas (including the AB#3123 `generator` output schema).
- Live MCP initialize handshake over stdio - the same check release.yml runs
  against the packed .exe - returns a serverInfo block identifying
  modelchoice-mcp 0.0.31.
- streamable-http boots and honours a custom --host/--port, covering the one
  code path that changed and that neither pytest nor the stdio check touches.
- ruff + mypy + pytest green (79 passed, 2 skipped).

uv.lock re-locked to mcp 2.0.0; CI's --locked sync keeps it honest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vosesoftware
vosesoftware merged commit db30cdd into main Aug 12, 2026
2 checks passed
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.

2 participants