MCP Goes Stateless: How Google Scaled Agent Infra

Google led the biggest MCP spec change since launch—removing stateful sessions entirely. Here's how the 2026-07-28 spec makes MCP cloud-native.

Last Tuesday at 2 AM, my pager fired. An MCP gateway node had crashed, taking 3,000 active agent sessions with it. Our Redis session store had the data, but the sticky routing layer couldn’t redistribute connections fast enough. By the time we recovered, dozens of long-running agent workflows had failed silently. I stared at the incident postmortem and thought: sessions are the problem.

Turns out, Google had the same realization—at a much larger scale. On August 5, 2026, Google Cloud published their work on the 2026-07-28 MCP specification update, the most significant change to the Model Context Protocol since its launch. The headline: MCP is now stateless.

No more Mcp-Session-Id. No more handshakes. No more sticky routing. Every request stands on its own.

The Problem: Stateful MCP Was a Cloud Anti-Pattern

If you’ve deployed MCP servers in production, you know the pain. The original protocol required a session lifecycle:

  1. Client sends initialize request
  2. Server responds with capabilities and a Mcp-Session-Id
  3. Client includes that session ID in every subsequent request
  4. Server maintains per-session state (negotiated capabilities, context, etc.)

This design made sense for local stdio connections between an IDE and a language server. It became a nightmare at scale.

The Infrastructure Tax

Here’s what a production MCP deployment looked like before the 2026-07-28 spec:

┌─────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  MCP Client │────▶│  Load Balancer   │────▶│  MCP Server Pod │
│  (Agent)    │     │  (sticky routes) │     │  (stateful)     │
└─────────────┘     └──────────────────┘     └─────────────────┘
                            │                         │
                            │                         ▼
                            │                 ┌───────────────┐
                            │                 │  Redis Cluster │
                            │                 │  (session store)│
                            └────────────────▶└───────────────┘

Every component in this diagram exists because of one thing: the Mcp-Session-Id header. You needed sticky routing so requests hit the right server. You needed Redis so sessions survived pod restarts. You needed health-check logic that understood session affinity. You needed custom failover code that could replay initialization.

The costs were real:

  • No horizontal scaling: sticky sessions pin clients to servers, creating hot spots
  • No fault tolerance: server crash = lost sessions = failed agent workflows
  • No serverless: Cloud Run and Lambda cold starts break session continuity
  • Operational complexity: Redis clusters, session replication, affinity rules

GitHub’s MCP Server team reported maintaining a 6-node Redis cluster solely for MCP session state. That’s infrastructure serving no business logic—pure protocol tax.

The Solution: Self-Describing Requests

The 2026-07-28 spec takes a radical approach: delete the concept of sessions entirely. Every MCP request now carries everything the server needs to process it.

The New _meta Field

Instead of negotiating capabilities during a handshake, each request embeds its context inline:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "_meta": {
      "protocolVersion": "2026-07-28",
      "clientInfo": {
        "name": "my-agent",
        "version": "2.1.0"
      },
      "capabilities": {
        "elicitation": true,
        "streaming": true
      }
    },
    "name": "get_weather",
    "arguments": {
      "location": "San Francisco"
    }
  }
}

No prior initialize call needed. No session ID. The server reads _meta, understands what the client supports, processes the request, and responds. Done.

New HTTP Headers for Intelligent Routing

The spec introduces three HTTP headers that enable infrastructure-level routing without parsing JSON bodies:

POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather
  • Mcp-Protocol-Version: Load balancers can route to version-appropriate server pools
  • Mcp-Method: Enables method-based routing (send tools/call to compute-heavy pods, resources/list to cache-friendly pods)
  • Mcp-Name: Route by specific tool or resource name without body inspection

This is huge for infrastructure teams. Your nginx or Envoy config can now make routing decisions from headers alone—no Lua scripts parsing JSON bodies on the hot path.

The After: Cloud-Native MCP

Here’s the same deployment, post-upgrade:

┌─────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  MCP Client │────▶│  Load Balancer   │────▶│  MCP Server     │
│  (Agent)    │     │  (round-robin)   │     │  (stateless)    │
└─────────────┘     └──────────────────┘     └─────────────────┘

                                              (no Redis needed)

The entire session layer disappears. What you get:

  • Round-robin load balancing: any server handles any request
  • Serverless deployment: Cloud Run, Cloud Functions, Lambda—cold starts don’t matter when there’s no session to resume
  • Transparent failover: server dies mid-fleet? Next request goes elsewhere, automatically
  • Zero external state: no Redis, no DynamoDB, no session store of any kind

Real-World Impact: GitHub’s Migration

GitHub’s MCP Server team was an early adopter. Their migration results:

  • Removed 6-node Redis cluster (session store)
  • Eliminated sticky-session configuration from their load balancer
  • Reduced P99 latency by 40ms (no Redis round-trip on each request)
  • Enabled autoscaling from 4 to 40 pods without session draining

Their PR summary: “Deleted more infrastructure than we added code.”

HTTP Caching: Built Into the Protocol

The stateless model unlocks another cloud-native primitive: HTTP caching. The spec adds two fields to cacheable responses:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [...],
    "_meta": {
      "ttlMs": 300000,
      "cacheScope": "public"
    }
  }
}
  • ttlMs: How long the response stays fresh (milliseconds). A tools/list response with ttlMs: 300000 means “cache this for 5 minutes.”
  • cacheScope: Either "public" (shared CDN cache) or "private" (per-client cache only).

For tool and resource listings that rarely change, this means your CDN can serve responses without hitting the origin server at all. Imagine an MCP server listing 50 tools—previously, every agent invocation re-fetched that list through a session. Now it’s a cached GET equivalent.

Multi Round-Trip Requests (MRTR)

The trickiest part of going stateless: what about server-to-client communication? The original spec used sessions for features like elicitation—where the server asks the client for additional input mid-request.

The 2026-07-28 spec solves this with Multi Round-Trip Requests (MRTR). Here’s the flow:

// 1. Client sends initial request
{
  "jsonrpc": "2.0",
  "id": "req-001",
  "method": "tools/call",
  "params": {
    "_meta": {
      "protocolVersion": "2026-07-28",
      "capabilities": { "elicitation": true }
    },
    "name": "deploy_service",
    "arguments": { "env": "production" }
  }
}

// 2. Server responds with elicitation (needs confirmation)
{
  "jsonrpc": "2.0",
  "id": "req-001",
  "result": {
    "_meta": {
      "status": "elicitation_required",
      "elicitation": {
        "requestId": "elic-abc",
        "message": "Deploy to production. Confirm? (yes/no)",
        "schema": { "type": "string", "enum": ["yes", "no"] }
      }
    }
  }
}

// 3. Client sends follow-up with elicitation response
{
  "jsonrpc": "2.0",
  "id": "req-002",
  "method": "elicitation/respond",
  "params": {
    "_meta": {
      "protocolVersion": "2026-07-28",
      "capabilities": { "elicitation": true }
    },
    "requestId": "elic-abc",
    "response": "yes"
  }
}

No session needed. The requestId ties the conversation together without server-side state. The server can store pending elicitations in its backing database (which it already has for business logic) rather than in a separate session store.

Migration Guide: Before and After

Server Implementation (Python)

Before (stateful):

from mcp.server import MCPServer

server = MCPServer()

@server.on_initialize
async def handle_init(params):
    # Store session capabilities
    session = create_session(params.client_info)
    return {"capabilities": {...}, "sessionId": session.id}

@server.on_tool_call
async def handle_tool(session_id, params):
    session = redis.get(f"session:{session_id}")
    if not session:
        raise SessionExpiredError()
    # Process with session context...

After (stateless):

from mcp.server import MCPServer

server = MCPServer()

@server.on_tool_call
async def handle_tool(request):
    # Everything needed is in the request
    version = request.meta.protocol_version
    capabilities = request.meta.capabilities
    # Process directly—no session lookup
    result = await execute_tool(request.params)
    return result

Cloud Run Deployment

# service.yaml - that's it. No Redis, no session affinity.
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: mcp-server
spec:
  template:
    spec:
      containers:
        - image: gcr.io/my-project/mcp-server:latest
          resources:
            limits:
              memory: 512Mi
              cpu: "1"
      containerConcurrency: 80

No sessionAffinity: true. No sidecar Redis container. No session-draining preStop hooks.

The MCP Transports Working Group

Google didn’t do this alone. They co-founded the MCP Transports Working Group with Hugging Face to shepherd this change through the spec process. The working group’s mandate: ensure MCP transports work across cloud providers, edge deployments, and serverless platforms without vendor lock-in.

This collaboration matters. MCP’s value is universality—one protocol for all agent-to-tool communication. A Google-only solution would fragment the ecosystem. By working through the official spec process with diverse stakeholders, the stateless model becomes a shared standard, not a proprietary extension.

FAQ

Does this break existing MCP servers?

The 2026-07-28 spec is a new protocol version. Clients declare which version they speak via Mcp-Protocol-Version. Servers can support both old (session-based) and new (stateless) modes during migration. The spec recommends a 6-month transition window.

What about long-running tool calls?

Long-running operations work the same way—the server returns a progress token, and the client polls or uses SSE for updates. The difference is that the progress token is self-contained, not tied to a session.

Can I still use SSE for streaming?

Yes. Server-Sent Events still work for streaming responses. The connection is per-request rather than per-session. Each SSE stream is independent—if it drops, the client retries with full context in the next request.

What about authentication?

Auth is orthogonal to session state. OAuth tokens, API keys, and mTLS all work exactly as before—they travel in standard HTTP headers, independent of MCP protocol state.

Is this really the biggest MCP spec change since launch?

Yes. Removing the session model touches every layer of the protocol: initialization, capability negotiation, error handling, and transport semantics. It’s a philosophical shift from “MCP is a connection protocol” to “MCP is a request protocol.”

What This Means for the Ecosystem

The stateless shift isn’t just a performance optimization. It changes what’s architecturally possible:

  • MCP at the edge: Deploy tool servers to CDN edge nodes (Cloudflare Workers, Lambda@Edge) with sub-10ms latency
  • MCP in CI/CD: Ephemeral containers can serve MCP without warm-up
  • MCP mesh: Multiple tool servers behind a single endpoint, routed by Mcp-Name header
  • MCP observability: Standard HTTP semantics mean standard HTTP tooling (access logs, tracing, metrics) works without MCP-specific instrumentation

Google’s blog post calls this “the HTTP moment for agent protocols”—the point where MCP stops being a specialized RPC mechanism and becomes a standard web service pattern. I think that’s exactly right.

The 2 AM pager incident I opened with? Under the new spec, it simply can’t happen. No sessions means no session loss. The server crashes, the load balancer routes elsewhere, and the agent never knows the difference.

That’s what stateless means at scale.


For the full spec breakdown, see our 2026-07-28 spec update analysis. New to MCP? Start with What is the Model Context Protocol?