mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

AI Agents

Stateless MCP: How the 2026-07-28 Spec Removes Sessions and Simplifies Agent Tool Servers

The MCP 2.0 spec drops session state, reducing tool calls from two HTTP requests to one. Here's what changed and why it matters for scale and security.

Source: simonwillison.net
Stateless MCP: How the 2026-07-28 Spec Removes Sessions and Simplifies Agent Tool Servers

The Model Context Protocol (MCP) just got simpler. The 2026-07-28 specification removes stateful sessions entirely, cutting the request flow from two round trips to one. This is not a minor tweak. It changes how you deploy MCP servers, how you reason about horizontal scaling, and how you audit tool boundaries for security.

Simon Willison built three new MCP implementations in a week after the spec dropped. That velocity tells you something about the friction the old design imposed.

What Changed: Before and After

Legacy MCP (the 2025-11-25 spec) required two HTTP requests for every tool call:

  1. Initialize a session to get a Mcp-Session-Id
  2. Call the tool with that session ID in the header
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" }
  }
}

Then:

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 new stateless MCP collapses this into a single request:

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"
      }
    }
  }
}

Client info moves into _meta. The session ID disappears. The protocol version and method move to headers.

Deployment Implications

Removing session state changes the deployment shape:

  • No session affinity. You don’t need sticky routing or consistent hashing to ensure the same backend handles both the initialize and the call.
  • Horizontal scale is trivial. Any replica can handle any request. Load balancers can round-robin without coordination.
  • No session store. You don’t need Redis, Memcached, or in-memory maps to track session IDs.
  • Simpler failure modes. A crashed replica doesn’t orphan sessions. Clients don’t need retry logic for “session expired” errors.

If you’re running MCP servers behind a cloud load balancer or in a Kubernetes cluster, this is a meaningful simplification. The old design forced you to either accept session loss on replica churn or build session persistence into your infrastructure.

Security Boundary Shift

Willison argues that MCP is “a safer way to build with agents” compared to giving an agent shell access with curl. The reasoning:

  • Explicit tool boundaries. Each tool declares its inputs and outputs via JSON schema. You can audit what data flows in and out.
  • No arbitrary command execution. The agent can’t run rm -rf / or exfiltrate data via a hidden curl to an attacker-controlled endpoint.
  • Smaller models can drive it. The protocol is simple enough that a laptop-sized model can call tools reliably, reducing dependency on frontier models that might be harder to control.

The stateless change amplifies this. Because there’s no session to hijack or replay, the attack surface shrinks. An attacker who intercepts a request can’t reuse a session ID to impersonate the client across multiple calls.

That said, MCP doesn’t solve prompt injection. If an attacker can manipulate the agent’s context, they can still trick it into calling tools with malicious arguments. The protocol just makes it easier to see what happened after the fact.

Three Implementations in a Week

Willison built:

  1. mcp-explorer: A CLI tool for probing MCP servers. You can list tools, inspect schemas, and call tools directly from the command line.
  2. datasette-mcp: A Datasette plugin that exposes a /-/mcp endpoint with three tools: list_databases(), get_database_schema(database_name), and execute_sql(database_name, sql).
  3. llm-mcp-client: An alpha plugin for his LLM CLI tool that lets you invoke MCP tools from the command line.

Example of mcp-explorer:

uvx mcp-explorer list https://agentic-mermaid.dev/mcp
uvx mcp-explorer call \
  https://agentic-mermaid.dev/mcp \
  render_svg \
  -a source 'graph TD; A-->B' \
  -a options '{"padding":24}'

The datasette-mcp plugin is particularly interesting. It turns any Datasette instance into an MCP server. An agent can query your database by calling execute_sql() with natural language translated to SQL. Willison ran a Claude session that executed 7 separate SQL queries to answer “what has Simon said recently about MCP?”

Observability and Debugging

Stateless MCP makes tracing easier:

  • Single request per tool call. You don’t need to correlate two requests with a session ID to understand what happened.
  • Headers carry metadata. Mcp-Method and Mcp-Name are visible in HTTP logs without parsing the JSON body.
  • No session lifecycle to track. You don’t need to log session creation, expiration, or cleanup.

If you’re using OpenTelemetry or a similar tracing system, you can instrument the MCP endpoint once and get full visibility into tool calls without custom session tracking.

Trade-offs and Failure Modes

AspectStateless MCPLegacy MCP
Request count1 per tool call2 per tool call (initialize + call)
Session managementNoneMust track session IDs server-side
Horizontal scalingTrivial (any replica handles any request)Requires sticky routing or shared session store
Replay attack surfaceLower (no session ID to steal)Higher (session ID can be reused)
Client complexityLower (no session lifecycle)Higher (must initialize, track, and clean up sessions)
ObservabilitySimpler (one request per trace)More complex (correlate two requests)

The main trade-off: if you need server-side state across multiple tool calls (e.g., a transaction or a multi-step workflow), you now have to manage that yourself. The protocol won’t do it for you.

Likely failure modes:

  • Client sends wrong protocol version. Server must reject with a clear error. Check the MCP-Protocol-Version header.
  • Missing required headers. Mcp-Method and Mcp-Name are mandatory. If they’re absent, the server can’t route the request.
  • Tool arguments don’t match schema. Validation happens on every request. No session state means no cached schema validation.

Technical Verdict

Use stateless MCP when:

  • You’re building a new MCP server and want the simplest possible implementation.
  • You need to scale horizontally without session affinity.
  • You want to audit tool calls without correlating multiple requests.
  • You’re deploying in serverless environments (AWS Lambda, Cloud Run) where session state is expensive or impossible.

Avoid (or reconsider) when:

  • You need server-side state across multiple tool calls (e.g., a transaction that spans several agent actions). You’ll have to build your own session layer on top.
  • You’re maintaining a legacy MCP server and can’t justify the migration cost. The old spec still works.
  • You need backward compatibility with clients that only speak the 2025-11-25 protocol.

The stateless shift makes MCP a more attractive alternative to giving agents unrestricted shell access. It’s easier to build, easier to deploy, and easier to secure. If you’ve been on the fence about MCP, this is the version to bet on.