Skip to main content

MCP Goes Stateless on July 28: Why Model Context Protocol Servers Can Finally Run Behind a Plain Kubernetes Load Balancer

9 min readDora NodaDora Noda
Share
On this page

An MCP server that can deploy, roll back, and read logs for your production apps is, today, usually pinned to a single pod. Not because anyone wants it that way — because the protocol makes it hard to do otherwise. Every client connection carries an Mcp-Session-Id that a specific server process negotiated during an initialize handshake, and if a load balancer routes the next request to a different pod, that pod has no idea what session abc123 means. So teams either pin the server to one instance (a single point of failure for something with deploy authority) or bolt on sticky-session routing and a Redis-backed session store to fake statelessness across a fleet.

On July 28, 2026, that constraint goes away at the protocol level. The Model Context Protocol's next specification release removes Mcp-Session-Id and the initialize handshake entirely — two changes tracked as SEP-2567 — so that, in the spec's own words, any request can land on any server instance. A stateful protocol that needed sticky routing and shared session stores to scale horizontally becomes one that doesn't need either. Here's exactly what breaks, what a "before" and "after" Kubernetes deployment actually look like, and what it unlocks for an MCP server whose job is deploying and operating your infrastructure, not just answering chat questions.

The Stateful Tax: What Running an MCP Server at Scale Cost You Before

Before July 28, teams running an MCP server behind more than one replica had exactly three options, and each has a specific failure mode worth naming rather than waving off.

Sticky sessions (load balancer affinity). The simplest fix: route every request from a given session to the same pod, using the session ID as the effective routing key. It works until the pod restarts — a routine deploy, an OOM kill, a node drain — at which point every session pinned to it is gone, along with whatever multi-step tool-call sequence was mid-flight. IP-based affinity is worse: NAT gateways and mobile carrier proxies mean two requests from the "same" client can arrive from different source IPs, breaking affinity that was never really tied to the client in the first place.

Redis-backed distributed session state. The more robust fix: on session creation, serialize the negotiated state and store it in Redis under the session ID, so any pod can rehydrate it on the next request. This actually survives pod restarts — but it adds a hard dependency (Redis, its own HA story, its own failure mode) to what should be a stateless HTTP service, plus a network round-trip on every tool call just to answer "whose session is this."

Deep packet inspection at the gateway. The heaviest fix, used where the gateway itself needs to make routing or policy decisions per tool call: parse the JSON-RPC body to extract the method and session before the request even reaches a server pod. This works, but it means your load balancer needs to understand MCP's wire format, not just terminate TLS and round-robin — infrastructure coupling that a plain HTTP load balancer was never supposed to need.

All three solve the same underlying problem: the protocol tied a request to the specific process that first accepted it, and every workaround exists to fake statelessness the protocol didn't actually provide.

What Actually Changes on July 28: The Breaking-Change List

The MCP specification's 2026-07-28 release candidate — reviewed by SDK maintainers and client implementers over a ten-week validation window before it finalizes — makes five concrete changes. Each maps to a specific problem above:

ChangeSEPWhat it does
Session removedSEP-2567Mcp-Session-Id and the initialize handshake are gone. No setup phase, no identifier tying one request to the next — any instance can serve any request.
Routing headers mandatedSEP-2243Every Streamable HTTP request must carry Mcp-Method (e.g. tools/call) and Mcp-Name (the tool/resource name), mirroring the JSON-RPC body. Infrastructure can now route and observe on headers alone — no body parsing, no DPI. Servers must reject requests where header and body disagree.
Error code alignedSEP-2164The MCP-custom -32002 error code for a missing resource becomes the standard JSON-RPC -32602 Invalid Params. Any client matching the literal -32002 needs updating.
Caching metadata addedSEP-2549tools/list, prompts/list, resources/list, resources/read, and resources/templates/list responses now carry a CacheableResult with a ttlMs freshness hint, so clients can cache instead of re-polling every call.
Three features deprecatedRoots (replaced by tool parameters or config), Sampling (call the LLM provider directly), and Logging (use stderr or OpenTelemetry) enter a formal 12-month deprecation window — nothing breaks on July 28, but plan the migration.

The headline change is SEP-2567 and SEP-2243 together: remove the thing that tied a request to one process, and give infrastructure a header-level way to route and observe without needing to understand the protocol's body format. That combination is what makes "plain load balancer" true rather than aspirational.

The After: What a Stateless MCP Deployment Actually Looks Like

Removing the protocol-level session does not mean the application has to be stateless — it means the protocol stops mandating that servers fake statefulness to scale. The pattern the spec itself recommends: if a tool call needs to reference something from a prior call, mint an explicit handle — a deploy_id, a job_id — and have the model pass that handle back as an ordinary argument on the next call, exactly the way any REST API has always done pagination cursors or resource IDs.

Concretely, here's what changes in a Kubernetes manifest for an MCP server going from before to after:

Before: a Service with sessionAffinity: ClientIP, a StatefulSet (not a Deployment) so pods keep stable identities for session pinning, a Redis dependency in the same namespace just to survive a pod restart mid-session, and an ingress or gateway rule that inspects request bodies to extract session IDs for routing.

After: a plain Deployment behind a standard Service with default round-robin balancing, a HorizontalPodAutoscaler scaling on CPU/memory like any other stateless workload, routing decisions made on the now-mandatory Mcp-Method/Mcp-Name headers instead of body inspection, and zero session store — because there's no session to store. Any pod that's up can answer any request. A pod dying mid-tool-call loses nothing but that one in-flight request, which the client retries against whichever pod is next.

That's the concrete unlock: an MCP server stops needing special-cased infrastructure and becomes just another autoscaled service.

What This Unlocks for a Deploy-From-Chat MCP Server

This matters most for MCP servers that don't just answer questions — they hold deploy, rollback, and scale authority over real infrastructure, the shape bex's own MCP server takes on a Cluster-API-managed fleet. A deploy-wait-verify-rollback sequence is inherently multi-step: call deploy, poll status until healthy, call rollback if it isn't. Before July 28, keeping that sequence coherent across calls meant either pinning the whole MCP server to one pod (an availability risk for something with production write access) or standing up the Redis-backed session store above just to let the sequence survive a scale-out event.

After July 28, that sequence becomes: deploy returns a deploy_id as an ordinary tool result; the model passes that deploy_id back on status and rollback calls; any pod in the fleet can answer any of those calls, because the handle — not a protocol session — carries the continuity. The MCP server serving deploy authority can now run as a horizontally-scaled Deployment on the same Cluster-API fleet it's managing, autoscaled by the same HPA machinery as any other tenant workload, with no special pinning and no shared session store to keep available.

For a team building or auditing an MCP server today, the concrete migration checklist ahead of July 28:

  1. Audit for Mcp-Session-Id reliance — any code path assuming a session persists state across calls needs an explicit-handle rewrite (the deploy_id pattern above) before the session ID disappears.
  2. Check for literal -32002 matches — update to -32602 per SEP-2164.
  3. Add Mcp-Method/Mcp-Name headers on every Streamable HTTP request, and make sure the server rejects mismatches between header and body per SEP-2243.
  4. Emit ttlMs on list/read responses per SEP-2549 so clients stop re-polling unnecessarily.
  5. Plan the Roots/Sampling/Logging migration within the 12-month deprecation window rather than waiting for a forced cutover.

None of this is optional infrastructure archaeology — it's the difference between an MCP server with deploy authority running as a fragile pinned singleton and running as a boring, horizontally-scaled service like everything else on the fleet.

What's Next: Enterprise Readiness and Server Cards

Transport statelessness is the 2026 roadmap's first priority, not its only one. Enterprise readiness — audit trails, SSO-integrated auth, well-defined gateway behavior — is landing as extensions rather than core spec changes, and MCP Server Cards (a .well-known manifest exposing a server's capabilities without a client having to connect first) are aimed at making deploy-authority servers discoverable the way a REST API's OpenAPI spec already is. Both build directly on top of the stateless foundation shipping July 28: an audit trail is far easier to reconstruct when every request already carries an explicit method, name, and handle instead of an opaque session ID, and a Server Card can't describe a server's capabilities honestly if answering that description still requires pinning a session to find out.

The practical takeaway for anyone running — or building — an MCP server with real infrastructure authority: July 28 is the date your deployment topology gets simpler, not the date your application logic does. Treat the session removal as the forcing function to replace implicit session state with explicit handles now, ahead of the mandatory migration window closing.


Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with an MCP server exposing deploy, rollback, logs, and scale as first-class tools for the agents operating your infrastructure. Star the repo on GitHub or deploy your first app today.

Sources

Related articles

Give your agents a chain backend

Autonomous agents hit RPC endpoints very differently than people do. See what bex router handles on their behalf.

Read the agents guide