Stateless MCP has recaptured my interest
Rediscovering the Appeal of Stateless MCP
By Simon Willison
The arrival of Stateless MCP has completely renewed my interest in the protocol, sparking the creation of two new projects: mcp-explorer and datasette-mcp.
The Evolution of the Protocol
Tuesday marked a pivotal moment: the release of MCP 2.0 (formally known as the 2026-07-28 Model Context Protocol specification). This represents the most substantial update since the protocol's inception and has personally reignited my enthusiasm for its potential.
What exactly is MCP?
The Model Context Protocol (MCP) provides a standardized framework for offering new tools to agentic frameworks powered by Large Language Models (LLMs).
The timeline of its adoption looks roughly like this:
- November 2024: Introduced by Anthropic.
- 2025: Experienced a massive surge in popularity.
- Late 2025/2026:
Became secondary to "Skills(another Anthropic project).
The shift toward "Skills" happened because developers realized that giving an agent a terminal and curl access offered more flexibility than MCP. However, there is a significant trade-off:
Giving an AI agent a full shell environment with internet access is inherently risky. It requires an exceptionally powerful model to navigate that environment safely and effectively.
In contrast, MCP tools are:
- Easier to audit and restrict.
- Accessible to smaller models (e.g., those running locally on a laptop).
The Shift: Stateful Stateless
The core improvement in the new specification is the move to a stateless architecture, which drastically simplifies the implementation for both the server and the client.
Comparison of Request Flows
In the "Legacy" (stateful) version, a tool call required a two-step handshake. In the new version, it is a single atomic operation.
Request Comparison Table
| Feature | Legacy MCP (Stateful) | New MCP (Stateless) |
|---|---|---|
| Request Count | Two (Init Call) | One (Direct Call) |
| Session Tracking | Requires Mcp-Session-Id | No session ID needed |
| Server State | Must maintain session memory | No server-side state required |
| Scalability | Requires sticky sessions/routing | Highly scalable web-native approach |
The Legacy Workflow (Stateful)
# Request 1: Initialize
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" }
}
}
# Request 2: Call Tool
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 Modern Workflow (Stateless)
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" }
}
}
}
Project 1: mcp-explorer
Since I couldn't find a satisfactory CLI tool for probing MCP servers, I used Codex to build one. It is a stateless Python utility that can be run instantly via uvx.
Trying it out
To list tools on a server (using Ade Oshineye’s demo):
uvx mcp-explorer list https://agentic-mermaid.dev/mcp
Available Tools discovered:
execute: Runs JavaScript in a sandbox.describe_sdk: Returns mutation operations for a diagram family.render_svg: Converts Mermaid source to SVG.render_ascii: Converts Mermaid source to text.render_png: Rasterizes Mermaid source to PNG.
Inspecting and Calling
To see the JSON schema for a specific tool:
uvx mcp-explorer inspect render_svg
To actually execute a tool:
uvx mcp-explorer call \
https://agentic-mermaid.dev/mcp \
render_svg \
-a source 'graph TD; A-- B' \
-a options '{"padding":24}'
Pro tip: Pipe the output to jq .svg -r to extract the raw SVG code.
Resulting Image:
Project 2: datasette-mcp
My second project is a plugin for Datasette that exposes a /-/mcp endpoint. After several failed attempts in the past, the stateless spec finally made this feel "right" to release.
Capabilities
The plugin provides a specific set of tools for agents:
-
list_databases(): List all available databases. -
get_database_schema(database_name): Retrieve the schema for a specific DB. -
execute_sql(database_name, sql): Run a query (currently read-only).
By connecting these to Claude or ChatGPT, the AI can perform live SQL queries against a hosted Datasette instance. I currently have this active on my blog's mirror: datasette.simonwillison.net/-/mcp.
I've already successfully used this in a Claude session to ask:
- "list tables in simonwillison.net"
- "what has Simon said recently about MCP"