MCP Python SDK v2.0.0b2

v2.0.0b2Pre-release
Added 3
  • Add client-side subscriptions/listen with context manager, async iteration, and typed events
  • Request cancellation now works on 2026 transports by closing POST/SSE streams or sending notifications/cancelled over stdio
  • Resolver dependency injection now supports Sample and ListRoots requests in addition to Elicit
Changed 4
  • Replace httpx and httpx-sse with httpx2 (>=2.5.0) as the HTTP stack
  • TLS verification now uses the operating system trust store via truststore instead of certifi's bundle
  • Logger names changed from httpx to httpx2 and httpcore.* to httpcore2.*
  • SSE GET streams now send Accept header with application/json, text/event-stream instead of exactly text/event-stream
Fixed 1
  • Tool-name validation now rejects names with a trailing newline

Second v2 beta. Pre-releases are opt-in only; pip install mcp still resolves to the stable 1.x line.

pip install mcp==2.0.0b2
# or
uv add "mcp==2.0.0b2"

The documentation has the full tutorial and API reference, and the migration guide covers coming from v1. Stable v2 is still targeted for 2026-07-28 alongside the spec release - keep pinning an exact version.

Highlights
httpx is replaced by httpx2 (#2972)

The SDK's HTTP stack now runs on httpx2 (>=2.5.0), the next-generation httpx fork with SSE support built in, replacing httpx + httpx-sse. Most code needs no changes; if you pass your own http_client into a transport, change the import to httpx2. Runtime behavior that changes:

  • TLS verification uses the operating system trust store (via truststore) instead of certifi's bundle. SSL_CERT_FILE / SSL_CERT_DIR are honored first.
  • Loggers are renamed: httpx -> httpx2, httpcore.* -> httpcore2.* - update logging filters that match on those names.
  • SSE GET streams send Accept: application/json, text/event-stream (previously exactly text/event-stream).
Client-side subscriptions/listen (#3047)

The client half of subscriptions/listen (SEP-2575), promised in the b1 notes: one context manager, async for consumption, typed events.

async with client.listen(tools_list_changed=True, resource_subscriptions=["note://todo"]) as sub:
    print(sub.honored)  # the subset the server agreed to deliver
    async for event in sub:
        match event:
            case ToolsListChanged():
                tools = await client.list_tools()
            case ResourceUpdated(uri=uri):
                body = await client.read_resource(uri)

Entering waits for the server's acknowledgment, so sub.honored is always populated and pre-ack failures raise instead of degrading silently.

Request cancellation works on the 2026 transports (#3046)

Cancelling or timing out a client request now actually stops it: over streamable HTTP the request's own POST/SSE stream is closed (the spec's cancellation signal), and over stdio the client sends notifications/cancelled. Callers can also supply the request id for a call - the seam the listen driver builds on.

Resolvers can sample and list roots (#3049)

Resolver dependency injection now covers all three multi-round-trip request kinds (SEP-2322): a dependency can return Sample(...) or ListRoots() in addition to Elicit(...), so a tool can ask the client's LLM or fetch its roots mid-call, on both protocol eras.

Notes
  • Tool-name validation now rejects names with a trailing newline (#3076).
  • The tasks extension is still in review and will ship in a later pre-release.
  • If you install under uv's exclude-newer cooldown: mcp pins mcp-types to the exact same version, so exempt both packages - exclude-newer-package = { mcp = false, mcp-types = false }.
What's Changed
New Contributors

Full Changelog: https://github.com/modelcontextprotocol/python-sdk/compare/v2.0.0b1...v2.0.0b2

View original

Upgraded? How did it go?

Discussion