documentation / published note
MCP 2026-07-28: from sessionful integrations to stateless protocol infrastructure
Created 2026-08-31 · Updated 2026-08-31
Local review is browser-only; canonical flags are display-only.
Summary
The 2026-07-28 MCP specification changes the protocol's operational model more than its basic purpose. MCP still uses JSON-RPC to connect hosts, clients, and servers that expose tools, resources, and prompts, but its core is now stateless and self-describing. The release removes protocol-level sessions and the initialize/initialized handshake, moves protocol version and client capabilities into per-request metadata, replaces server-initiated mid-call requests with Multi Round-Trip Requests (MRTR), adds header-based routing and cache hints, hardens authorization, and moves Tasks into an official extension.
Why it matters
Before this revision, a typical remote MCP integration was organized around a protocol session: establish a connection, negotiate capabilities once, retain the session identity, and perform subsequent operations through that connection. The 2026-07-28 design instead treats each request as independently routable web traffic. This removes session affinity and shared session storage from the protocol layer, making ordinary load balancing and horizontally scaled deployments much simpler.
The important distinction is not “MCP can no longer have state.” Application state can still exist, but the server must mint an explicit handle and the client/model must pass that handle on later requests. State becomes visible application data rather than hidden transport context.
Key ideas
Before versus after
| Concern | How MCP was commonly implemented before 2026-07-28 | What the new revision changes |
|---|---|---|
| Lifecycle | Client sent initialize; server returned capabilities and implementation information; client sent notifications/initialized; normal work followed. | No protocol handshake. Each request carries its protocol version and client capabilities in _meta; server/discover is available for up-front discovery or compatibility probing. |
| HTTP identity | Streamable HTTP used the Mcp-Session-Id header to identify the protocol session. | The protocol session and session header are removed. A request can land on any server instance behind a normal round-robin load balancer. |
| State | Servers could infer context from prior messages on the same connection/session. | Servers must process requests independently. Cross-call state uses an explicit server-minted handle passed as an ordinary argument. |
| Server-to-client interaction | Elicitation, sampling, and roots could be server-initiated requests that depended on a held-open bidirectional stream. | MRTR returns an input_required result and the client retries the original request with inputResponses. The interaction is modeled as request/response turns rather than hidden stream state. |
| Routing and policy | An HTTP gateway generally had to inspect JSON-RPC bodies to route by method or tool name. | Streamable HTTP requests carry Mcp-Method and Mcp-Name headers, so gateways, WAFs, and rate limiters can route and meter without parsing the body. |
| Discovery results | Tool, prompt, and resource lists had no standard TTL/cache scope contract. | List results carry deterministic ordering plus ttlMs and cacheScope, allowing clients to cache catalogs safely and keep upstream prompt caches stable across reconnects. |
| Notifications | Resource subscriptions and server change notifications used the older HTTP GET and subscribe/unsubscribe shape. | Clients opt into notification types through one subscriptions/listen stream, with request-scoped progress and messages remaining on the response stream for the request they belong to. |
| Long-running work | Tasks were experimental functionality in the core, with session-based access control and result retrieval patterns such as tasks/result. | Tasks move to io.modelcontextprotocol/tasks, use polling through tasks/get, accept client input through tasks/update, and can expose durable handles without per-request task opt-in. |
| Authorization | Dynamic Client Registration was the common interoperability answer for an unbounded client ecosystem, despite proxy and registration friction. | Client ID Metadata Documents become the preferred direction; issuer validation and issuer-bound credentials harden the OAuth flow, while DCR remains only for backward compatibility and is formally deprecated. |
The old lifecycle is documented in the 2025-11-25 MCP lifecycle specification. The release's normative comparison is in the 2026-07-28 key changes, with the announcement in the official release post.
What did not change
- MCP remains a JSON-RPC protocol for connecting AI applications to external tools and context.
- Servers still expose resources, prompts, and tools; the release changes the lifecycle and transport assumptions around them.
- A long-lived stream can still exist, but its state is scoped to the subscription or request, not inferred from the underlying connection.
- Extensions remain opt-in. Tasks, MCP Apps, and other specialized capabilities are not silently imposed on every implementation.
- Legacy handshake-based implementations are a recognized compatibility era. A dual-era client or server can support both legacy and modern revisions while migrating.
Practical applications
- When upgrading a server, first decide whether it will support only the modern stateless revision or operate as a dual-era implementation during migration.
- Remove assumptions that one connection equals one conversation, task, or user. Put durable workflow identity in explicit handles and validate their authorization on every call.
- Make every request carry the protocol version and required client capabilities; reject unsupported versions clearly rather than inferring them from an earlier handshake.
- Update gateways to use
Mcp-MethodandMcp-Namefor routing, authorization, rate limiting, and observability. - Treat list responses as cacheable data with explicit expiry and scope. Revalidate when
ttlMsexpires or when a subscription indicates a relevant change. - Rewrite elicitation and sampling flows as resumable request/retry state machines using MRTR instead of expecting a server-initiated message to arrive on a permanently held stream.
- Use the official SDK migration notes and the full specification before changing a production client or server; the breaking changes are concentrated in lifecycle, transport, tasks, and deprecated client features.
Open questions
- How much operational complexity moves into application-level handle design, expiry, storage, and authorization once protocol sessions disappear?
- What migration patterns will work best for clients that must talk to both handshake-based and stateless servers at large scale?
- How should observability systems correlate a multi-request workflow without accidentally recreating hidden connection-scoped session semantics?
- Will the deprecation of roots, sampling, logging, and legacy HTTP+SSE converge implementations on a smaller, more composable core, or push important capabilities into a fragmented extension ecosystem?