On July 28, 2026, the Model Context Protocol ships its biggest spec revision since launch — the handshake is gone, sessions are gone, and the stateful backbone MCP has run on since day one gets torn out. Here's the full architecture breakdown: what MCP looks like today, why it broke at scale, and exactly what replaces it.
If you've deployed an MCP server behind a load balancer, you've probably already felt the pain this release fixes. Ten weeks from the release candidate locking, MCP 2026-07-28 becomes final — and the MCP maintainers themselves are calling it the largest revision of the protocol since launch. Six Specification Enhancement Proposals (SEPs) came together just to deliver the headline change: a fully stateless protocol core.
The Deadline
Mark the calendar: the release candidate for MCP 2026-07-28 locked on May 21, 2026, kicking off a ten-week validation window for SDK maintainers and client implementers to test against real workloads. Tier 1 SDKs are expected to ship support inside that window. The final spec publishes July 28, 2026.
The good news buried in all this churn: going forward, every deprecated feature gets a minimum twelve-month runway before it can be removed, under a new formal feature lifecycle policy. This kind of breaking change is meant to be the last one of its size.
The Basics: Host, Client, Server
MCP standardizes how LLM applications plug into external tools and data — conceptually similar to how the Language Server Protocol standardized language tooling across editors. Three roles make up the topology:
- Host — the LLM application that initiates connections (an IDE, a chat client, an agent runtime).
- Client — a connector living inside the host, maintaining a strict one-to-one relationship with a server.
- Server — the service exposing tools, data, and prompt templates back to the model.
All three talk over JSON-RPC 2.0. A single host isn't limited to one server — it can spin up many isolated client↔server sessions in parallel, one per connected server, each fully sandboxed from the others.
The Payload: What a Server Offers
Once connected, a server can expose three capability types to the client, negotiated at connection time:
- Resources — context and data for the model or user to read.
- Prompts — templated messages and workflows.
- Tools — functions the model can actually execute.
A real tools/call request looks like this:
{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search","arguments":{"q":"otters"}}}
Clients can offer capabilities back to servers too — historically, sampling, roots, and elicitation. Two of those three are being deprecated in this release, which we'll get to.
Before: The Stateful Handshake
Under the outgoing 2025-11-25 spec, calling a tool over Streamable HTTP means establishing a session first via an initialize handshake:
POST /mcp HTTP/1.1
Content-Type: application/json
{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-11-25","capabilities":{},
"clientInfo":{"name":"my-app","version":"1.0"}}}
The server responds with an Mcp-Session-Id that every subsequent request must carry — pinning the client to whichever server instance issued it:
POST /mcp HTTP/1.1
Mcp-Session-Id: 1868a90c-3a3f-4f5b
Content-Type: application/json
{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"search","arguments":{"q":"otters"}}}
The Problem: Sticky Sessions Don't Scale Quietly
That single pinned session creates three concrete operational costs for anyone running MCP servers at any real scale:
| Cost | What it means |
|---|---|
| Sticky routing | The load balancer must pin every client to one instance — no plain round-robin. |
| Shared session store | Every server instance needs access to the same session state to stay consistent, usually meaning new infrastructure (Redis, a database) just for protocol bookkeeping. |
| Deep packet inspection | Gateways and rate-limiters must read into the message body just to figure out what operation is even happening. |
None of that is what anyone signs up for when standing up a tool server. This is exactly the pain the 2026 rewrite targets.
After: The Stateless Core
In the new spec, the initialize/initialized handshake is removed entirely (SEP-2575), and the Mcp-Session-Id header and protocol-level session go with it (SEP-2567). Client info, protocol version, and capabilities now travel inside _meta on every single request instead of being negotiated once up front:
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
Content-Type: application/json
{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search","arguments":{"q":"otters"},
"_meta":{"io.modelcontextprotocol/clientInfo":{"name":"my-app","version":"1.0"}}}}
Because nothing is pinned to a session anymore, that request can land on any server instance — plain round-robin, no sticky routing, no shared session store. The Streamable HTTP transport now requires Mcp-Method and Mcp-Name headers (SEP-2243), so load balancers and gateways can route on the operation without inspecting the body at all. There's also a new server/discover method for clients that want to fetch server capabilities on demand, plus ttlMs/cacheScope fields on list and resource results (SEP-2549) so clients know exactly how long a tools/list response stays fresh and whether it's safe to share across users.
The Handle Pattern: State Without Sessions
A stateless protocol doesn't mean a stateless application. Servers that need to carry state across calls do what HTTP APIs have always done: mint an explicit handle and have the model pass it back as an ordinary argument on later calls.
Model -> create_basket()
Server -> { "basket_id": "b_9x2" }
Model -> add_item(basket_id: "b_9x2", sku: "...")
Server -> { "ok": true, "total": 2 }
In practice this turns out to be more powerful than hidden session state ever was — the model can compose handles across tools, reason about them explicitly, and hand them off between steps in ways that transport-level metadata never allowed.
Server-initiated requests (like an elicitation prompt) still needed a rework for a world with no persistent connection. They may now only be issued while the server is actively processing a client request (SEP-2260), and Multi Round-Trip Requests (SEP-2322) replace a held-open SSE stream with an explicit InputRequiredResult that any server instance can pick back up on retry.
New Capabilities: MCP Apps & Tasks
New capabilities no longer get bolted directly onto the core spec — they ship as Extensions: reverse-DNS IDs, their own repositories and maintainers, versioned independently (SEP-2133). Two official extensions ship with this release.
- MCP Apps — servers ship interactive HTML interfaces that hosts render in a sandboxed iframe. Tools declare their UI templates ahead of time so hosts can prefetch and security-review before anything runs — every UI action still routes through the same JSON-RPC audit path as a direct tool call.
- Tasks — a
tools/callcan now return a task handle instead of an immediate result. The client drives it forward withtasks/get,tasks/update, andtasks/cancel— task creation is server-directed.tasks/listis gone, since it can't be scoped safely without sessions.
Security: Authorization Gets Hardened
Six SEPs harden MCP's authorization spec to align more closely with how OAuth 2.0 and OpenID Connect actually get deployed in practice:
- Clients must validate the
issparameter on authorization responses per RFC 9207 — closing off a mix-up attack class especially relevant to MCP's single-client, many-server pattern. - Clients declare their OpenID Connect
application_typeduring Dynamic Client Registration, fixing the common bug where a desktop or CLI client defaults to"web"and gets its localhost redirect URI rejected. - Registered credentials bind to the issuing authorization server's issuer, with re-registration required when a resource migrates between auth servers.
- The spec now documents requesting refresh tokens from OpenID-Connect-style servers, and clarifies scope accumulation during step-up auth.
What's Being Deprecated
Three core features are formally deprecated under the new lifecycle policy (SEP-2577) — annotation-only for now, guaranteed to keep working for at least twelve months:
| Deprecated | Replacement |
|---|---|
| Roots | Tool parameters, resource URIs, or server configuration |
| Sampling | Direct integration with LLM provider APIs |
| Logging | stderr for stdio transports / OpenTelemetry for structured observability |
There's also a smaller but very real breaking change: the error code for a missing resource moves from the MCP-custom -32002 to the standard JSON-RPC -32602 Invalid Params. If your client matches on the literal -32002 value anywhere, update it before July 28.
The Rollout Timeline
RC locked May 21, 2026 → ten-week SDK validation window → final spec July 28, 2026. Across the release: six SEPs delivered the stateless core, two official extensions shipped alongside it, another six SEPs hardened authorization, and every future deprecation now carries a twelve-month-minimum runway. That last number is arguably the real point of this release — not just this one breaking change, but making sure it's the last time MCP has to break this hard.
Three Pillars to Remember
- Stateless Core — no handshake, no session — any instance can handle any request.
- Extensions — MCP Apps and Tasks ship and evolve independently of the core spec.
- Hardened Auth — OAuth/OIDC-aligned, resistant to mix-up attacks.
If you're building or operating MCP servers, don't wait for July 28 — the release candidate is available now. Test against it.