# MCP Python SDK v2: Migrate FastMCP to MCPServer Now

> Source: <https://byteiota.com/mcp-python-sdk-v2-migrate-fastmcp-mcpserver/>
> Published: 2026-08-04 10:09:30+00:00

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.
