Skip to main content

MCP Just Went Stateless: What Breaks and What Gets Much Easier

· 4 min read
TheMCPGuy
MCP Developer & Educator

A client sending many requests through a load balancer to three stateless server instances, with the Mcp-Session-Id header crossed out

If you have ever tried to run a remote MCP server behind a load balancer and discovered that request #2 has no idea what request #1 did, this post is for you. One of the largest changes to the protocol since launch is aimed squarely at that pain, and it does it by removing things.

Version disclosure (as of July 2026)

Everything below describes the 2026-07-28 MCP specification, which was ratified on 28 July 2026 and is now the current stable revision. The session-removal work is SEP-2567 and SEP-2575. One practical caveat: SDKs are still catching up. The Java MCP SDK's latest release, 2.0.0 from 11 June 2026, predates ratification and still implements 2025-11-25, so the stateless protocol described here is not yet something you can adopt from Java without the SDK shipping support. Check your SDK's release notes before planning a migration.

The session problem

Today's remote MCP relies on a session: the client and server do an initialization handshake, the server issues an Mcp-Session-Id, and subsequent requests carry it. That works beautifully on one process and miserably across many. The moment you want to scale horizontally, that session id becomes a sticky leash, because every request for a session has to land on the one instance that holds its state, so you reach for sticky load balancing, shared session stores, and a lot of operational duct tape.

What changed

The 2026-07-28 revision removes session management: the Mcp-Session-Id header is gone, and so is the initialize/notifications/initialized handshake. Each request now carries its protocol version, client identity, and client capabilities in _meta instead. Servers gain a new server/discover RPC that clients can call up front to negotiate versions and capabilities. The protocol becomes effectively stateless at the transport layer: any request can be served by any instance, because no instance is special.

This is one of the largest revisions since MCP launched, and it lines up with the 2026 roadmap's stated priorities of Transport Evolution and Scalability and Enterprise Readiness. Notably, it does this without introducing a new transport. Streamable HTTP remains the one remote transport; the change is about removing session coupling, not adding plumbing.

What breaks

Be honest with yourself about what leaned on the session:

  • Server-held per-session state has nowhere to live implicitly anymore. If your server stashed "what we're doing" in memory keyed by session id, that assumption is gone.
  • Code that reads or asserts Mcp-Session-Id needs to stop.
  • Init-handshake-dependent flows must tolerate a world where there is no handshake to hang setup on.

What gets much easier

This is the trade you are being offered, and it's a good one:

  • Horizontal scaling becomes boring: spin up N identical instances behind a plain round-robin balancer, no stickiness, no shared session store required for the protocol's sake.
  • Resilience improves: an instance dying no longer orphans a session's worth of in-memory state.
  • Deploys get simpler: rolling restarts stop being a session-eviction event.

State doesn't vanish; it just has to become explicit. Anything durable moves to your data layer and is referenced by handle in requests, rather than living implicitly in a session on one box.

Migrating, roughly

The migration shape is:

  1. Inventory everything that depends on the session or the handshake.
  2. Move per-session memory into an external store, keyed by an explicit handle you pass in requests.
  3. Stop emitting and requiring Mcp-Session-Id.
  4. Put your instances behind a stateless balancer and delete the sticky-session config you no longer need.

The bottom line

MCP is trading a convenience (implicit session state) for the thing enterprises actually need (trivial horizontal scaling). It's the right trade, and the ink is now dry. The remaining constraint is your SDK rather than the spec: make your state explicit now, because that part runs on today's SDKs, and pick up the protocol-level changes as your SDK ships them.

This is the spine of our MCP at Scale course, which goes deeper on stateless transport, explicit state handles, routing, and horizontal scaling.