MCP Python SDK v2: Migrate FastMCP to MCPServer Now The MCP Python SDK v2, released stable on July 27, removes the FastMCP class, renaming it to MCPServer, and introduces breaking changes including snake_case field names and context injection. The official migration guide from the Model Context Protocol team details the changes, and most migrations take five minutes. Teams unable to migrate immediately can pin to mcp>=1.28.1,<2, as IBM's mcp-context-forge team did, while v1.x continues to receive critical fixes. 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 https://py.sdk.modelcontextprotocol.io/migration/ covers the full list — but the rename is the one that breaks your server at startup, before anything else runs. python Before — MCP Python SDK v1 from mcp.server.fastmcp import FastMCP mcp = FastMCP "my-server" python 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.inputSchema → tool.input schema result.isError → result.is error listing.nextCursor → listing.next cursor content.mimeType → content.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: php Before @mcp.tool async def search query: str - str: ctx = mcp.get context await ctx.report progress 0, 100 return f"Results for: {query}" php 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 https://github.com/IBM/mcp-context-forge/issues/5839 . 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 https://blog.modelcontextprotocol.io/posts/sdk-betas-2026-07-28/ 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 - Update package: pip install "mcp =2.0" - Replace all FastMCP imports → MCPServer from mcp.server.mcpserver - Update any mcp.server.fastmcp. submodule paths - Replace ctx = mcp.get context with ctx: Context parameter in handler signatures - Search codebase for inputSchema , isError , nextCursor , mimeType — rename each - Move constructor transport params to run - If using HTTP transport directly: swap httpx for httpx2 If you built a v1 server from our MCP Server in Python guide https://byteiota.com/build-mcp-server-python-tutorial/ , the structure still holds — apply these changes on top. For anything beyond the mechanical renames, the full v2 changelog https://py.sdk.modelcontextprotocol.io/whats-new/ covers the low-level server API, union type adapter changes, and the new multi-round-trip request pattern.