DEV Community

Jonathan Trippett
Jonathan Trippett

Posted on

MCP dropped sessions. Here's the pattern that replaces them.

The Model Context Protocol's 2026-07-28 revision removed protocol-level
sessions entirely. No initialize handshake, no Mcp-Session-Id header,
no held-open bidirectional stream. Every request is now self-describing
and can land on any server instance behind a plain load balancer.

That's a real win for scaling. It's also a real problem if your server
needs to remember anything between calls, which most useful ones do.

The pattern: explicit state handles

Instead of a hidden session living in the transport layer, a tool mints
a handle and hands it back to the model:

create_cart()  →  "cart_7f3a9c2e5b1d"
add_item(cart="cart_7f3a9c2e5b1d", sku="MUG-01", quantity=2)
view_cart(cart="cart_7f3a9c2e5b1d")
Enter fullscreen mode Exit fullscreen mode

Four HTTP requests. Four separate server instances, potentially. The
only thread connecting them is a twelve-character string the model can
see, hold onto, and pass around.

Why a visible handle actually beats a hidden session

  • The model can hold more than one at once. Two carts isn't a protocol problem anymore, it's just two strings.
  • It shows up in the transcript. When something breaks, you can read the handle and go look at exactly the state that caused it.
  • Scope is explicit. A tool that wasn't handed a handle can't touch that cart. There's no ambient "current cart" to reach for by accident.
  • Any instance can serve any request. No sticky routing, no shared session table, no session affinity to configure.

The cost: handles are now part of your tool's contract, so getting their
error cases right matters. Expired, malformed, and unknown all need to
be distinct, readable messages, not one generic 500.

I wrote a generator for this pattern

I kept rebuilding the same scaffolding, a pluggable state store, handle
minting and validation, a working multi-turn example, so I turned it
into a CLI:

npm create stateforge@latest my-server
Enter fullscreen mode Exit fullscreen mode

It generates a TypeScript + Express server with:

  • A swappable StateStore (in-memory for dev, Redis for production/serverless)
  • A working shopping-cart example built entirely on explicit handles
  • A visual inspector, live tool list, call forms, editable state browser
  • Deploy configs for Vercel and Docker

MIT licensed, zero runtime dependencies in the CLI itself.

Repo: https://github.com/JRTrippett/mcp-stateforge

Would genuinely like to hear if anyone's solving this differently, the
2026-07-28 spec is new enough that I don't think there's a "standard"
answer yet.

Top comments (0)