What changed in MCP Python SDK from 1 to 2
4 releases numbered after v1.29.1 up to and including v2.1.1, stable releases only. v1.29.1 and v2.1.1 are the newest stable releases of 1 and 2 we track; this page follows them as new ones ship.
- 2 mention breaking changes
- 1 removes or deprecates something
36 changes across 4 releases · 1 landed on more than one version
- Client accepts StdioServerParameters directly
- Prompt messages accept Image and Audio
- Prompt functions may return bare content blocks
- Message, UserMessage, and AssistantMessage are exported from mcp.server.mcpserver
- SseServerTransport and MCPServer.sse_app() take max_request_body_size parameter
- Support for the 2026-07-28 revision of the Model Context Protocol with stateless requests, no handshake, server/discover, subscriptions/listen, and multi-round-trip requests
- First-class Client object that negotiates protocol version automatically and connects to URLs, stdio subprocesses, custom transports, or server objects in memory
- Resolve parameter for multi-round-trip requests allowing tools to return questions instead of answers in 2026-07-28 era
- Pluggable extension APIs for composing protocol extensions with MCP Apps built in
- OpenTelemetry tracing shipped by default
- Standalone types package mcp-types (imported as mcp_types) published in lock-step with mcp
- OAuth support for RFC 9207 issuer validation, SEP-990 identity-assertion flow, and client-credentials extension
- Handler exceptions from tool, resource or prompt handlers are logged once at ERROR with traceback, and client sees only Error executing message instead of exception text
- Content-block return annotations no longer advertise outputSchema or return structuredContent for tools returning TextContent, EmbeddedResource, Image, Audio, or lists/unions of them
- The 4 MiB request body limit now covers the SSE transport and OAuth endpoints
- MCPServer now speaks both 2026-07-28 and 2025-era protocol revisions from the same server over Streamable HTTP and stdio with automatic version negotiation
- FastMCP renamed to MCPServer with decorator API unchanged but low-level Server rebuilt around a shared dispatcher engine
- Client replaces v1's transport-plus-ClientSession-plus-initialize() layering with a single unified object
- Per-version wire packages are now private (mcp_types._v*) with mcp.types as permanent alias for mcp_types
- Client cache parameter changed from Client(cache=False) to cache=None with CacheConfig() as default
- FileResource is_binary parameter renamed to encoding
- Streamable HTTP servers now reject bodies over 4 MiB with HTTP 413
- stdio servers keep handler subprocesses and stray prints off the wire with stdout diverted to stderr while serving
- TypedDict tool results with NotRequired keys are omitted instead of serialized as null
- TypedDict tool registration no longer fails on Python 3.10
- Recursive tool return types get an object-rooted outputSchema that pre-2026 clients accept
- POSTed notifications such as notifications/cancelled are acknowledged with 202 instead of 400 on 2026-07-28 HTTP entry
- Pre-2026 sessions ignore cache-hint fields from later revisions instead of failing list_tools()
- Pre-2026 sessions accept boolean sub-schemas in tool schema properties
- mcp install reads and preserves Claude Desktop config containing non-ASCII text on any Windows code page
- SSE message endpoint answers 405 to non-POST requests
- Cancelled requests are no longer answered
- Context.client_id, RFC7523OAuthClientProvider, and OAuthClientProvider(timeout=) removed
- MCP_* environment variables removed with pydantic-settings
- v1.x line moved to maintenance mode and will only receive security fixes
Original release notes, newest first
The list above is our reading of these notes; the originals from Anthropic are here, one fold per release.
v2.0.1
One off backport of the FastMCP import warning for 2.0.x, this is due to a lot of people running into this error and making issues on other repos about it. Ideally either pin mcp<2 or upgrade to 2.
What's Changed
- [v2.0.x] Point imports of mcp.server.fastmcp at the migration guide by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3393
Full Changelog: https://github.com/modelcontextprotocol/python-sdk/compare/v2.0.0...v2.0.1
v2.1.1
What's Changed
- Point imports of mcp.server.fastmcp at the migration guide by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3388
Full Changelog: https://github.com/modelcontextprotocol/python-sdk/compare/v2.1.0...v2.1.1
v2.1.0
Highlights
ClientacceptsStdioServerParametersdirectly:Client(StdioServerParameters(command="uv", args=["run", "server.py"]))(#3321).- Prompt messages accept
ImageandAudio, prompt functions may return bare content blocks, andMessage/UserMessage/AssistantMessageare exported frommcp.server.mcpserver(#3320). - The 4 MiB request body limit now also covers the SSE transport and the OAuth endpoints;
SseServerTransportandMCPServer.sse_app()takemax_request_body_size, and the SSE message endpoint answers 405 to non-POST requests (#3336).
Behaviour changes to be aware of
- Handler exceptions (#3314): an unexpected exception from a tool, resource or prompt handler is logged once at ERROR with its traceback, and the client now sees only
Error executing tool <name>(or the resource/prompt equivalent) rather than the exception text. RaiseToolError/ResourceErrorwhen the message is meant for the model; those still reach the client and are logged at INFO without a traceback. - Content-block return annotations (#3320): a tool annotated to return
TextContent,EmbeddedResource,Image,Audio, or lists/unions of them no longer advertisesoutputSchemaor returnsstructuredContent; itscontentis unchanged. Passstructured_output=Trueto keep the previous shape.
Fixes
- TypedDict tool results:
NotRequiredkeys are omitted instead of serialized asnull, and registration no longer fails on Python 3.10 (#3224, #3227); recursive return types get an object-rootedoutputSchemathat pre-2026 clients accept (#3337). - 2026-07-28 over HTTP: a POSTed notification such as
notifications/cancelledis acknowledged with 202 instead of rejected with 400 (#3324). - Pre-2026 sessions ignore cache-hint fields from later revisions instead of failing
list_tools()(#3223), and accept boolean sub-schemas in tool schemaproperties(#3353). mcp installreads and preserves a Claude Desktop config containing non-ASCII text on any Windows code page (#3296).
What's Changed
- Retire wording tied to pre-2.0 milestones by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3211
- Describe the maintenance line without hardcoding 1.28 by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3212
- Ask which release line a bug report is on by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3213
- Link the released 2026-07-28 spec and point migrators at /v1/ by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3214
- Bump conformance harness to 0.2.0-alpha.11 by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3282
- Read UTF-8 test fixtures with explicit encoding by @ShuQingDollarVoyager in https://github.com/modelcontextprotocol/python-sdk/pull/3245
- Pin each conformance leg to a spec-revision wire by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3304
- docs: publish translated docs in twelve languages and the tool that maintains them by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3280
- Pin text I/O to UTF-8 and fail CI on locale-dependent reads/writes by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3296
- docs: lead the README client example with a URL, not the server object by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3315
- Publish versioning, roadmap, and dependency policies for v2 by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3215
- Drop later-revision cache-hint fields on pre-2026 sessions by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3223
- Stop framing breaking changes as a workflow in AGENTS.md by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3286
- MCPServer: content-block returns are unstructured, prompt messages take Image/Audio by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3320
- Let Client take StdioServerParameters directly by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3321
- Gate external PRs on an assigned, linked issue by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3291
- docs: cover the remaining Tier 1 audit items by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3325
- Acknowledge notification POSTs with 202 on the 2026-07-28 HTTP entry by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3326
- Shorten stdio test comments by @Kludex in https://github.com/modelcontextprotocol/python-sdk/pull/3329
- Hand TypedDict tool results to pydantic natively by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3331
- Apply the request body limit to the SSE and OAuth endpoints by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3336
- Accept boolean sub-schemas in 2025-11-25 tool schema properties by @pja-ant in https://github.com/modelcontextprotocol/python-sdk/pull/3354
- Log MCPServer handler exceptions by kind and keep crash details off the wire by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3314
- Give recursive tool return types an object-rooted output schema by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3376
- docs: refresh translations for recent English changes by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3379
- Build releases with the pinned hatchling and a publish action that accepts Metadata 2.5 by @maxisbey in https://github.com/modelcontextprotocol/python-sdk/pull/3380
New Contributors
- @ShuQingDollarVoyager made their first contribution in https://github.com/modelcontextprotocol/python-sdk/pull/3245
Full Changelog: https://github.com/modelcontextprotocol/python-sdk/compare/v2.0.0...v2.1.0
v2.0.0
MCP Python SDK v2 Stable Release
This is v2.0.0, the stable v2 release of the MCP Python SDK. It supports the 2026-07-28 revision of the Model Context Protocol and serves every earlier revision from the same server. pip install mcp now installs 2.x.
pip install "mcp[cli]"
# or
uv add "mcp[cli]"
Documentation Rewrite
The documentation has the full tutorial and API reference. Coming from v1? What's new in v2 is the tour of what changed and why, and the migration guide lists every breaking change with before-and-after code.
V1 Maintenance mode
v1.x is in maintenance mode and will only receive security fixes from now on The 1.x line lives on the v1.x branch, continues to receive critical bug fixes and security patches, and is documented at https://py.sdk.modelcontextprotocol.io/v1/. If your project is not ready to migrate, keep a <2 upper bound on your requirement (for example mcp>=1.28,<2).
Highlights
One SDK, both protocol eras
v2 speaks the 2026-07-28 revision (stateless requests with no handshake, server/discover, subscriptions/listen, multi-round-trip requests) and still serves every 2025-era client from the same MCPServer, over Streamable HTTP and stdio, with nothing to configure. Client(target) negotiates the version automatically.
FastMCP is now MCPServer, and there is a first-class Client
The decorator API is unchanged; the low-level Server is rebuilt around a shared dispatcher engine, and one Client object replaces v1's transport-plus-ClientSession-plus-initialize() layering. It connects to a URL, a stdio subprocess, a custom transport, or straight to a server object in memory for tests.
Multi-round-trip requests and resolver dependency injection
At 2026-07-28 the server can no longer call the client, so tools return the question instead. A Resolve(fn) parameter is filled by your function invisibly to the model and can put a question to the user; one tool body serves both eras.
Extension APIs, OpenTelemetry, and a standalone types package
Servers and clients compose protocol extensions through pluggable extension APIs (MCP Apps built in); OpenTelemetry tracing ships on by default; every protocol type is its own package, mcp-types (imported as mcp_types), published in lock-step with mcp.
Hardened stdio and auth
stdio servers keep handler subprocesses and stray prints off the wire, and stdout is diverted to stderr while serving. OAuth adds RFC 9207 issuer validation, the SEP-990 identity-assertion flow, and the client-credentials extension.
Coming from a v2 pre-release
Since the last release candidate: the per-version wire packages are private (mcp_types._v*), mcp.types is a permanent alias for mcp_types, the auth registration request model is split from the registered-client record, cancelled requests are no longer answered, and log notifications are gated on the per-request log-level opt-in at 2026-07-28. Since the betas: Client(cache=False) is now cache=None with CacheConfig() the default; Context.client_id, RFC7523OAuthClientProvider, and OAuthClientProvider(timeout=) are removed; the client-credentials providers take scope=; message_handler receives notifications and exceptions only; FileResource(is_binary=) becomes encoding; MCP_* env vars are gone with pydantic-settings; Streamable HTTP servers reject bodies over 4 MiB with HTTP 413. The migration guide covers all of it.
Known gaps
The tasks extension (SEP-2663) is not part of this release. On the client, the DPoP proof binding (SEP-1932) and the workload-identity jwt-bearer grant are not implemented; both are additive and can land in 2.x.
Feedback
Something rough, confusing, or broken? Open an issue or find us in #python-sdk-dev on the MCP Contributors Discord.
Full Changelog: https://github.com/modelcontextprotocol/python-sdk/compare/v2.0.0rc1...v2.0.0