
TL;DR
MCP just dropped sessions entirely. Every request is now one self-contained POST. Here is what changed in the 2026-07-28 spec and a Bun + Hono pattern for hosting many MCP servers on a single process.
The Model Context Protocol just went through its biggest revision since launch. The 2026-07-28 spec - informally "MCP 2.0" - removes protocol-level sessions entirely. No more initialize handshake, no more Mcp-Session-Id header, no more GET stream endpoint. Every request is now a single, fully self-contained HTTP POST.
Simon Willison has an excellent writeup on why this matters in Stateless MCP, along with a set of small tools he built against the new spec (a uvx-runnable MCP explorer, a Datasette plugin, and an LLM client integration). His framing is the right one: statelessness "greatly decreases the complexity of implementing both clients and servers." This post covers what actually changed on the wire, and a server pattern the new spec unlocks - hosting a whole fleet of MCP servers on one Bun process.
Under the old Streamable HTTP transport (2025-03-26 through 2025-11-25), a client had to initialize first, hold on to a server-minted session ID, and echo it on every request. Servers had to route requests back to session state, which made horizontal scaling and serverless deployment awkward. That tradeoff is part of why we compared CLIs and MCPs as complementary interfaces rather than interchangeable ones.
Under 2026-07-28, one tools/call is one POST:
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "location": "Seattle, WA" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
The interesting details:
params._meta under io.modelcontextprotocol/* keys. There is no handshake to carry them anymore.MCP-Protocol-Version, Mcp-Method, and Mcp-Name duplicate body values so load balancers and gateways can route on them without parsing JSON. Servers must validate that headers match the body and reject mismatches with a 400 and JSON-RPC error -32020 (HeaderMismatch) - otherwise an intermediary routing on a header and a server executing on the body could disagree, which is a security hole.x-mcp-header, and conforming clients mirror that value into an Mcp-Param-{Name} header. That means a gateway can rate-limit or route by tenant without ever reading a request body.InputRequiredResult, and the client retrying the original call with the answers attached (the spec calls this MRTR - multi round-trip requests). Long-lived notifications moved to an explicit subscriptions/listen SSE stream.If you have deployed MCP servers behind a load balancer, you already know why this is a big deal: session affinity is gone as a requirement. Any replica can answer any request. This is the same property that made plain REST APIs easy to scale, applied to the agent tool ecosystem.
From the archive
Aug 1, 2026 • 11 min read
Aug 1, 2026 • 5 min read
Aug 1, 2026 • 10 min read
Jul 31, 2026 • 8 min read
Once a server is a pure function of the request, hosting many MCP servers stops being an infrastructure problem and becomes a routing problem. We built this out as a small Bun + Hono + Commander repo, and the core of it is genuinely tiny. It fits the same practical “choose the right server for the job” workflow behind our MCP server guide.
An MCP server is just data - a name and a list of tools:
import { defineMcp } from "../mcp/types.ts";
export const mathMcp = defineMcp({
name: "math",
version: "0.1.0",
description: "Arithmetic tools - add, multiply, power",
tools: [
{
name: "add",
description: "Add two numbers",
inputSchema: {
type: "object",
properties: { a: { type: "number" }, b: { type: "number" } },
required: ["a", "b"],
},
handler: (args) => [{ type: "text", text: String(Number(args.a) + Number(args.b)) }],
},
],
});
A registry maps mount paths to servers - nested paths included:
export const registry: Record<string, McpServerDef> = {
time: timeMcp,
math: mathMcp,
"labs/math": mathMcp,
};
And one Hono app serves the whole fleet:
const app = new Hono();
for (const [path, mcp] of Object.entries(registry)) {
app.all(`/${path}`, (c) => {
const toolsParam = c.req.query("tools");
const allowedTools = toolsParam ? toolsParam.split(",") : undefined;
return handleMcpRequest(mcp, c.req.raw, { allowedTools });
});
}
export default { port: 3100, fetch: app.fetch };
handleMcpRequest is the only part with real spec surface area: it validates the three mirrored headers against the body, answers tools/list and tools/call, returns 404 with -32601 for unknown methods, and 405 for the legacy GET/DELETE verbs. It is around a hundred lines total, with zero session bookkeeping. That is the whole point.
The ?tools= parameter in that route is the detail we like most. Because every request is self-contained, the URL itself can carry policy:
/math exposes add, multiply, and power/math?tools=add exposes only add - it disappears from tools/list and calling anything else failsYou can hand different agents different URLs to the same server and get different capability surfaces, with no auth framework and no per-client configuration. Under the stateful spec this would have been fragile - the filter would have had to live in session state. Statelessly, it is just a query string. That kind of deliberately scoped tool surface pairs well with the UI patterns in our Apps SDK and MCP UI guide.
The repo ships a Commander CLI that speaks the new wire format (correct headers, _meta block, base64 sentinel encoding for non-ASCII tool names):
bun run cli list http://localhost:3100/math
bun run cli call http://localhost:3100/math add -a '{"a":2,"b":3}'
bun run cli call "http://localhost:3100/math?tools=add" power -a '{"a":2,"b":8}'
# -> error: Unknown tool: power
And the header-validation rule in action - send an Mcp-Name that does not match the body and the server must refuse:
curl -s -X POST localhost:3100/math \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/call' \
-H 'Mcp-Name: wrong' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"add","arguments":{"a":1,"b":1}}}'
# -> {"error":{"code":-32020,"message":"Header mismatch: Mcp-Name 'wrong' does not match body value 'add'"}}
Deployment is equally boring, in the best way: one small Dockerfile on the oven/bun image, one container, any number of MCP endpoints. Adding a new experiment is scaffolding a file and adding one registry line.
If you maintain an MCP server today: yes, start now. The spec has a defined backward-compatibility story - modern clients probe with a stateless request first and fall back to initialize on a legacy error - so you can support both eras during the transition. The old HTTP+SSE transport is formally deprecated and eligible for removal. For the production edge, pair the migration with the auth considerations in our zero-touch OAuth guide.
If you are building new agent infrastructure, the calculus is simpler. Stateless MCP servers deploy like ordinary web handlers: they scale horizontally, they work on serverless platforms, and a whole catalog of them can share one process until traffic says otherwise. The protocol finally matches how the rest of the web is built.
Worth reading alongside this: Simon's original post, the 2026-07-28 Streamable HTTP transport spec, and the changelog for the full delta.
Read next
The MCP 2026-07-28 final spec is here - sessions are gone, the protocol is stateless. Here is what changed, what broke, and how to finish migrating your MCP servers.
9 min readThe 2026-07-28 Model Context Protocol spec is the largest revision since launch: a stateless core, deprecated Roots/Sampling/Logging, MCP Apps, Tasks, and tougher OAuth. Here is what breaks, what to adopt, and a migration checklist for server authors and client integrators before the July 28 deadline.
11 min readVercel MCP now serves both the stateless 2026-07-28 protocol and the 2025 protocol from one endpoint, with mcp-handler 2.x handling the negotiation. The first major hosted MCP server has crossed over - here is what it means for server authors and clients.
7 min readTechnical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.
Visual testing tool for Model Context Protocol servers. Like Postman for MCP - call tools, browse resources, and view...
View ToolCentralized manager for MCP servers. Connect once to localhost:37373 and access all your servers through a single endpoi...
View ToolRegistry and hosting platform for MCP servers. 6,000+ servers indexed. One-command install and configuration via CLI. Su...
View ToolA hosted infinite canvas your headless AI agents drive over MCP. Any MCP-speaking agent - Claude Code, Codex, Cursor, or...
View ToolRun any MCP server without running infra. Private endpoints, no DevOps.
View AppSpec out AI agents, run them overnight, wake up to a verified GitHub repo.
View AppFind an MCP server, copy the install line, you're done.
View AppWhat MCP servers are, how they work, and how to build your own in 5 minutes.
AI AgentsRoute specific MCP servers only to specific subagents.
Claude CodeConfigure Claude Code for maximum productivity -- CLAUDE.md, sub-agents, MCP servers, and autonomous workflows.
AI Agents
The MCP 2026-07-28 final spec is here - sessions are gone, the protocol is stateless. Here is what changed, what broke,...

MCP lets AI agents connect to databases, APIs, and tools. Here is what it is and how to use it in your TypeScript projec...

Vercel MCP now serves both the stateless 2026-07-28 protocol and the 2025 protocol from one endpoint, with mcp-handler 2...

MCP Apps shipped with the 2026-07-28 final spec - sandboxed interactive UIs for MCP servers. How they compare to standar...

A practical comparison of the four authentication platforms developers reach for when connecting AI agents to third-part...

The DataFlow-Harness paper is a useful reminder that coding agents should not just emit scripts. For data work, the dura...

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.