Skip to content

feat(mcp): adopt FastMCP 4 beta - #1198

Merged
phernandez merged 1 commit into
mainfrom
codex/fastmcp-4-beta
Aug 5, 2026
Merged

feat(mcp): adopt FastMCP 4 beta#1198
phernandez merged 1 commit into
mainfrom
codex/fastmcp-4-beta

Conversation

@phernandez

Copy link
Copy Markdown
Member

Why

FastMCP 4 moves its runtime and Python model surface onto MCP SDK v2. Basic Memory still depended on FastMCP 3, imported ToolError from the legacy MCP SDK compatibility path, and read SDK model fields through camelCase Python attributes.

This PR delivers the Core Phase 1 compatibility work from #1181 and fixes the production exception-class mismatch from #1197. It deliberately leaves hosted Cloud MCP App callbacks and optional FastMCP 4 capabilities for the follow-up phase described in #1181.

What changed

  • Pin fastmcp and its fastmcp-slim runtime exactly to the latest verified beta, 4.0.0b1.
  • Move the direct MCP SDK requirement to mcp>=2,<3 and refresh the UV lockfile.
  • Import the runtime ToolError from fastmcp.exceptions throughout Core and its tests.
  • Preserve HTTPStatusError as the cause of translated tool failures.
  • Read negotiated client identity from the current FastMCP request before consulting legacy session state.
  • Update SDK v2 Python model access to snake_case while preserving camelCase MCP wire schemas.
  • Add modern and legacy client identity coverage with FastMCP's real in-memory client.

Implementation details

Current-request identity is authoritative. is_openai_mcp_client() reads context.request_context.session.client_params.client_info first; stored initialize state is used only when a request does not expose negotiated identity. This prevents a non-OpenAI request from inheriting stale OpenAI identity while retaining the legacy-session fallback.

UV's constraint pins fastmcp-slim==4.0.0b1 alongside the public fastmcp==4.0.0b1 dependency so the runtime cannot drift independently. The resulting lock resolves MCP SDK and MCP types to 2.0.0.

Testing

  • just fast-check
  • uv lock --check
  • just test-smoke — 1 passed
  • just doctor — passed end to end
  • Focused FastMCP 4 compatibility suite with FASTMCP_MCP_CAMELCASE_COMPAT=false — 83 passed, 1 skipped
  • Complete MCP unit/integration surface with FASTMCP_MCP_CAMELCASE_COMPAT=false — 1,115 passed, 1 skipped
  • Focused Postgres MCP suite with BASIC_MEMORY_TEST_POSTGRES=1 and the camelCase bridge disabled — 84 passed, 1 skipped
  • Broad impacted suite — 5,100 passed, 35 skipped; one stale FastMCP 3 error-envelope assertion was updated and passed in isolation
  • Non-live impacted gate with the provider key disabled — passed

The live OpenAI semantic-quality benchmark could not complete because the provider returned 429 insufficient_quota. Deterministic local and Postgres coverage passed.

Risks and follow-ups

  • FastMCP remains beta software, so both the public package and slim runtime are intentionally exact-pinned for deliberate upgrades.
  • Existing FastMCP logging deprecation and Pydantic alias-metadata warnings remain visible, but the public schemas and behavior pass with the temporary camelCase compatibility bridge disabled.
  • Hosted MCP App acceptance and optional FastMCP 4 capabilities remain follow-up work under feat(mcp): adopt FastMCP 4 beta and validate hosted MCP Apps #1181.

Refs #1181
Closes #1197

Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez
phernandez merged commit 2c62db7 into main Aug 5, 2026
25 checks passed
@phernandez
phernandez deleted the codex/fastmcp-4-beta branch August 5, 2026 23:01
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.

fix(mcp): raise the FastMCP runtime ToolError instead of the legacy MCP SDK class

1 participant