MCP 2026-07-28 goes stateless: what you need to know
TL;DR
The MCP 2026-07-28 spec drops the initialize handshake and the Mcp-Session-Id header: every request carries its own version and capabilities. Servers scale more easily, but session-based logic, sampling and resumable SSE need redesigning.
If you've deployed a remote MCP server, you've probably wrestled with sessions: the Mcp-Session-Id header, sticky sessions behind a load balancer, hanging SSE connections, an initialize handshake on every reconnect. The MCP 2026-07-28 spec fixes this at the root: the protocol becomes stateless. It's the biggest change since MCP launched, and it directly affects how you write, deploy and scale servers.
The major changes
| Before (2025-xx) | From 2026-07-28 |
|---|---|
initialize / notifications/initialized handshake | No handshake. Every request carries its protocol version and client capabilities in _meta |
Sessions via the Mcp-Session-Id header | No protocol-level sessions. Servers that need state across calls mint their own "handles" and pass them as ordinary tool arguments |
| Server capabilities learned from the initialize result | New server/discover RPC (required on servers) to advertise versions, capabilities and identity |
GET endpoint opening SSE + resources/subscribe | A single subscriptions/listen stream; clients opt in to the notification types they want |
| Server-initiated requests (sampling, elicitation, roots) | Multi Round-Trip Requests: the server returns input_required, the client retries the request with the extra information |
Resuming SSE streams with Last-Event-ID | Resumability removed. If a stream breaks, the client re-issues a new request |
Notable minor changes
- Every result has a required
resultTypefield:"complete"or"input_required". - Results of
tools/list,resources/listand friends carryttlMsandcacheScopefor client caching; servers should return tools in a deterministic order, which improves LLM prompt cache hit rates. - Streamable HTTP POSTs must include
Mcp-MethodandMcp-Nameheaders, handy for gateway routing and logging. - Log level is set per request via
_meta;pingandlogging/setLevelare removed. - Tasks (long-running work) move into an official extension using
tasks/getpolling. - OpenTelemetry trace propagation via
_metais supported.
Deprecated
- Roots, Sampling, Logging: still work during the transition window (at least 12 months under the new policy), but new implementations shouldn't use them. Suggested replacements: pass directories via tool parameters, call LLM APIs directly instead of sampling, log to stderr or OpenTelemetry.
- The old HTTP+SSE transport: move to Streamable HTTP.
- OAuth Dynamic Client Registration: replaced by Client ID Metadata Documents.
Why stateless is good news
- Easy horizontal scaling: any instance can handle any request, no sticky sessions. Serverless or a plain load balancer both work.
- Less hanging state: no more mysterious expired sessions or silently dead SSE streams.
- Easier caching and observability: standard headers and TTLs help gateways and proxies do their job.
Upgrade risks
- Two "eras" coexist: older clients still use the handshake. Servers should support both during the transition; MCP Inspector has
--protocol-era legacyandmodernmodes to test both. - Session-based logic must be rewritten: carts, login state, conversation context… move them to explicit handles.
- Lost stream = lost request: long-running work should use the tasks extension rather than one long SSE stream.
How to apply it
- Dev: Upgrade to an SDK that supports 2026-07-28, run Inspector in both eras, and audit every use of sessions or sampling.
- Tech Lead: Use statelessness to drop sticky sessions and move MCP servers to serverless; add OpenTelemetry tracing from the start.
- PM: Plan the migration within the deprecation window, prioritising public servers with many external clients.
Sources & references
- Key Changes (2026-07-28) — Model Context Protocol
- MCP Inspector — Model Context Protocol