Developer ToolsProgrammingPython

MCP Python SDK v2: Migrate FastMCP to MCPServer Now

Python code comparison showing FastMCP renamed to MCPServer in MCP SDK v2

MCP Python SDK v2 shipped stable on July 27. If you have a Python MCP server — including one built last week following a tutorial — you have breaking changes waiting. FastMCP is gone, import paths moved, and every field flipped to snake_case. The good news: most migrations take five minutes. Here’s exactly what to change.

The Rename That Breaks Everything First

The most immediate change is the class rename: FastMCP is now MCPServer. There is no deprecation shim. There is no backward-compatible alias. The old import path simply does not exist in v2. The official migration guide covers the full list — but the rename is the one that breaks your server at startup, before anything else runs.

# Before — MCP Python SDK v1
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-server")
# After — MCP Python SDK v2
from mcp.server.mcpserver import MCPServer, Context
mcp = MCPServer("my-server")

Everything under mcp.server.fastmcp.* moved to mcp.server.mcpserver.*. The ctx.fastmcp property is now ctx.mcp_server. One more detail worth catching: the default server name string changes from "FastMCP" to "mcp-server" — pass an explicit name if you rely on serverInfo.name in your client.

snake_case Is Now Everywhere

All Pydantic model fields switched from camelCase to snake_case for Python access. The JSON wire format is unchanged — but the Python attributes are not. This one hides well: your server may start fine and only fail at runtime when code reads a tool or resource field.

  • tool.inputSchematool.input_schema
  • result.isErrorresult.is_error
  • listing.nextCursorlisting.next_cursor
  • content.mimeTypecontent.mime_type

If you serialize models for wire format, pass by_alias=True: tool.model_dump(by_alias=True, mode="json") still produces the camelCase JSON that clients expect.

Context Injection Replaces get_context()

Handler context is now injected as an explicit parameter. mcp.get_context() is removed. The fix is a one-line signature change — but it’s pervasive if your tools use progress reporting or logging:

# Before
@mcp.tool()
async def search(query: str) -> str:
    ctx = mcp.get_context()
    await ctx.report_progress(0, 100)
    return f"Results for: {query}"
# After
@mcp.tool()
async def search(query: str, ctx: Context) -> str:
    await ctx.report_progress(0, 100)
    return f"Results for: {query}"

The @mcp.tool() decorator stays. Only the context acquisition changes.

Transport Parameters Move to run()

Constructor-level transport arguments no longer exist. Move them to the run() call:

# Before
mcp = FastMCP("Demo", json_response=True, stateless_http=True)
mcp.run(transport="streamable-http")

# After
mcp = MCPServer("Demo")
mcp.run(transport="streamable-http", json_response=True, stateless_http=True)

Not Ready Yet? Pin Your Version

If your team cannot migrate immediately, pin before an unpinned install auto-upgrades:

# requirements.txt
mcp>=1.28.1,<2

This is exactly what IBM’s mcp-context-forge team did. SDK v1.x continues to receive critical bug fixes and security patches. The deprecated features — sampling, roots, logging — have a one-year grace period, and a v2 server falls back to legacy behavior for older clients. Pinning is not a cop-out; it’s responsible dependency management while your team plans the migration.

Why FastMCP Had to Go

The rename reflects a deeper protocol shift. The MCP 2026-07-28 specification eliminates the initialize handshake and session IDs entirely — any server instance can handle any request. Round-robin load balancers work without sticky sessions. Serverless deployments become straightforward. “FastMCP” made sense as a high-level layer on top of session-based MCP. Once sessions disappear from the protocol, all MCP servers are stateless by design — the name stops meaning anything, and MCPServer is simply what it is.

Migration Checklist

  1. Update package: pip install "mcp>=2.0"
  2. Replace all FastMCP imports → MCPServer from mcp.server.mcpserver
  3. Update any mcp.server.fastmcp.* submodule paths
  4. Replace ctx = mcp.get_context() with ctx: Context parameter in handler signatures
  5. Search codebase for inputSchema, isError, nextCursor, mimeType — rename each
  6. Move constructor transport params to run()
  7. If using HTTP transport directly: swap httpx for httpx2

If you built a v1 server from our MCP Server in Python guide, the structure still holds — apply these changes on top. For anything beyond the mechanical renames, the full v2 changelog covers the low-level server API, union type adapter changes, and the new multi-round-trip request pattern.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *