Skip to content

Proof of Concept - Python MCP SDK 2 Migration - #10427

Open
gsmith-alvarez wants to merge 8 commits into
marimo-team:mainfrom
gsmith-alvarez:feat/mcp-sdk-2-proof-of-concept
Open

Proof of Concept - Python MCP SDK 2 Migration#10427
gsmith-alvarez wants to merge 8 commits into
marimo-team:mainfrom
gsmith-alvarez:feat/mcp-sdk-2-proof-of-concept

Conversation

@gsmith-alvarez

@gsmith-alvarez gsmith-alvarez commented Aug 1, 2026

Copy link
Copy Markdown
Contributor
  • feat(mcp): migrate server from FastMCP to MCPServer for MCP SDK 2.0
  • feat(mcp): migrate client and tools to snake_case fields for MCP SDK 2.0
  • fix(mcp): update tests for MCP SDK 2.0 compatibility
  • feat(mcp): deps updated, httpx2 adopted and MCP 1.0 dropped for 2.0 Support

#10388
#10373
#10433

📝 Summary

Seeing that my orginal pr was only part of the migration I wanted to see if I could do the rest of it for a small project.

I do not expect this to be merged as 2.0 largely breaks compatibility with 1.0.

I hope this pr serves more to assist when the migration eventually occurs.

Key changes:

FastMCP was renamed to MCPServer

The MCPServer object no longer take stateless_http, streamable_http_path, transport_security and these now must be passed into mcp.streamable_http_app().

The SDK has transitioned from preferring CamalCase to preferring snake_case.

The tests were mostly just updated to use snake_case for when calling the server and I updated the Tool type to use the snake_case preferred from the SDK.

Finally, I dropped the try/except for support for streamablehttp_client and adopted the httpx2 as advised from their docs.

Resources

Here is a picture to show that the server is responding.

image

NOTE:

I had to hardcore the exclude-newer tag for this to work.

Also, don't know how to fix the ruff formatting so that it doesn't clog up the git change.

📋 Pre-Review Checklist

  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • Video or media evidence is provided for any visual changes (optional).

✅ Merge Checklist

  • I have read the contributor guidelines.
  • Documentation has been updated where applicable, including docstrings for API changes.
  • Tests have been added for the changes made.

In MCP SDK 2.0, FastMCP was renamed to MCPServer and the import path
changed from mcp.server.fastmcp to mcp.server.mcpserver.

Transport-specific parameters (stateless_http, streamable_http_path,
transport_security) were also moved off the MCPServer constructor and
onto streamable_http_app(), as the constructor no longer accepts them.

Changes:
- Replace  with
   in both
  code_server/main.py and server/main.py
- Move stateless_http, streamable_http_path, and transport_security
  from MCPServer() constructor to streamable_http_app() calls
- Remove redundant constructor arguments (stateless_http was a
  duplicate since it was also set at app creation time in v1)
MCP SDK 2.0 renamed all Pydantic model fields from camelCase to
snake_case. The JSON wire format is unchanged (Pydantic aliases handle
serialization), but Python attribute access now uses snake_case names.

Key renames per the migration guide:
- CallToolResult.isError -> is_error
- Tool.inputSchema -> input_schema

Changes in client.py:
- _create_error_result(): use is_error=True (was isError=True)
- is_error_result(): check both is_error and isError via getattr for
  cross-version compatibility
- extract_text_content(): use self.is_error_result() helper instead of
  inline hasattr(result, "isError") check (eliminates duplication)
- _add_server_tools(): read tool.input_schema with fallback to
  tool.inputSchema for cross-version compat; pass inputSchema to Tool()
  constructor which accepts both spellings via Pydantic populate_by_name

Changes in tool_manager.py:
- _convert_mcp_tool(): use mcp_tool.input_schema (was inputSchema)
MCP SDK 2.0 removed the deprecated streamablehttp_client function
(renamed to streamable_http_client in v1.x). The legacy fallback test
that patches streamablehttp_client now fails at import time because the
attribute no longer exists on mcp.client.streamable_http.

Changes:
- test_http_connector_connect_legacy_fallback: remove @patch decorator
  for streamablehttp_client and instead check hasattr() at runtime,
  calling pytest.skip() when the legacy function is absent. This keeps
  the test working on MCP 1.x (where streamablehttp_client exists) while
  gracefully skipping on MCP 2.0+ where it was removed.
Copilot AI review requested due to automatic review settings August 1, 2026 04:00
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview Aug 1, 2026 4:32am

Request Review

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

mcp==2.0.0 was published 2026-07-28. The previous "7 days" window
excluded it from dependency resolution, causing Vercel deploy failures.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Proof-of-concept migration of marimo’s MCP integration to the Python MCP SDK 2.x API surface (server/client/tool schema naming and transport wiring), along with dependency constraint updates to target MCP 2.x.

Changes:

  • Migrate MCP server setup from FastMCP to MCPServer, moving HTTP transport config into streamable_http_app(...).
  • Update MCP client/tool handling to prefer snake_case fields (e.g. is_error, input_schema) with selective backward-compat fallbacks.
  • Update dependency constraints to require mcp>=2 and adjust tests accordingly (including removing legacy fallback coverage).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/_server/ai/test_mcp.py Removes legacy streamable HTTP fallback test aligned with dropping older MCP SDK behavior.
pyproject.toml Updates MCP optional dependency constraints to MCP 2.x and adjusts formatting.
marimo/_server/ai/tools/tool_manager.py Updates MCP tool schema field access to snake_case.
marimo/_server/ai/mcp/transport.py Updates streamable HTTP connector to use MCP SDK 2 client + httpx2.
marimo/_server/ai/mcp/client.py Updates error/tool schema handling for MCP SDK 2 with compatibility fallbacks.
marimo/_mcp/server/main.py Migrates the main MCP server from FastMCP to MCPServer and updates HTTP app wiring.
marimo/_mcp/code_server/main.py Migrates the code-mode MCP server from FastMCP to MCPServer and updates HTTP app wiring.

timeout=server_def.timeout,
)
# Establish streamable HTTP connection
read, write = await exit_stack.enter_async_context(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new streamable_http_client is a 2-tuple of read and write. So *_ is no longer needed.

Comment on lines 176 to 180
return ToolDefinition(
name=namespaced_name or mcp_tool.name,
description=mcp_tool.description or "No description available",
parameters=mcp_tool.inputSchema,
parameters=mcp_tool.input_schema,
source="mcp",
Comment thread pyproject.toml
Comment on lines 116 to 119
mcp = [
"mcp>=1.0.0,<2", # MCP 2.0 is a major rework, unsupported for now.
"mcp>=2", # MCP 2.0 is a major rework, unsupported for now.
"pydantic>2",
]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

httpx2 is a transitive dependency of mcp>=2

Comment on lines 458 to 460
return CallToolResult(
isError=True,
is_error=True,
content=[TextContent(type="text", text=error_message)],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.

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