# Stateless MCP for Beginners

> Source: <https://dev.to/blackgirlbytes/stateless-mcp-for-beginners-23dg>
> Published: 2026-07-31 18:34:13+00:00

I've been seeing news everywhere that MCP just went stateless, but I had no clue what it means. So I decided to dig into it and write a blog post about it.

The Model Context Protocol (MCP) connects AI assistants to tools, databases, and external applications. In the `2026-07-28`

specification revision, MCP removed protocol-level sessions and became stateless.

That change makes remote MCP servers easier to operate. They can scale behind ordinary load balancers without sticky routing or a shared MCP session store. Clients can safely cache tool definitions, and agents get more control over which application resources they share.

But stateless does not mean MCP servers can no longer remember anything. A browser can still have open tabs, a database transaction can still have uncommitted changes, and a shopping cart can still hold items. The difference is how the client refers to that state.

State is information a system remembers between requests. Imagine an MCP server that controls a web browser. An agent might call `open_browser`

, followed by `navigate`

, `click`

, and `take_screenshot`

. The server needs to know that all four actions refer to the same browser.

In earlier MCP versions, the connection could provide that context. The client began with an `initialize`

request. Under Streamable HTTP, the server could respond with an `Mcp-Session-Id`

, which the client attached to later requests. The server could then use that ID to recover information associated with the session.

This worked naturally when one client talked to one server process. It became more complicated when an MCP service ran across several machines behind a load balancer. If Server A created a session and the next request reached Server B, Server B needed some way to recover that session. Infrastructure teams typically solved this with sticky routing, which kept the client tied to Server A, or a shared database that every server could use for session lookup.

Sessions also meant different things in different clients. A session could last for one tool call, one conversation, one page load, or the lifetime of an application. Server authors could store a browser or shopping cart inside a session, but they could not reliably predict how long that state would survive or which conversations might share it.

Under the `2026-07-28`

revision, the `initialize`

and `notifications/initialized`

handshake is gone. Servers no longer issue MCP session IDs, and clients no longer store or resend them.

Instead, every request carries the protocol information needed to understand it, including the protocol version and client capabilities. A client can also call `server/discover`

to learn which versions and features a server supports without opening a session.

This means any compatible server instance can understand an incoming MCP request without recovering information from an earlier handshake. If a tool manages application state, such as a running browser, the service still needs a way to locate that resource. Stateless MCP removes protocol session state, not application state.

When a tool needs state across calls, the server can return an explicit identifier, often called a handle. A handle is not a special MCP data type. It is an ordinary value returned by one tool and passed to another.

For example, a browser server might work like this:

```
// Open a browser and receive its handle
open_browser()
// Returns: { "browser_id": "browser_abc123" }

// Pass the handle into later calls
navigate({
  "browser_id": "browser_abc123",
  "url": "https://example.com"
})
```

The browser still lives on the server and keeps its tabs, cookies, and history. The relationship between calls is now visible in the tool arguments instead of hiding inside the connection.

Explicit handles also give orchestrators more control over shared state. If three agents are shopping together, they can share one `cart_id`

while each receives a separate `browser_id`

. A single MCP session could not express those two state boundaries cleanly.

Some tools need more information before they can finish. A deployment tool might ask for confirmation before publishing to production. Under the Multi Round-Trip Requests (MRTR) pattern, the tool returns an `input_required`

result describing what it needs. The result may include an opaque `requestState`

value, which the client returns with the requested answers when it retries the original call. The information needed to continue travels with the retried request instead of remaining tied to an open connection.

For longer-running or durable work, servers can use task handles through the Tasks extension. The client can check or update the task later without keeping a network connection open.

In previous MCP versions, the tools returned by `tools/list`

could vary by session. A server might expose a `connect_database`

tool first, then add `query_database`

after the connection was established. Because the list could depend on session history, clients could not safely reuse it elsewhere.

Tool lists can still change when a server is updated or a user's permissions change, but they no longer vary by MCP connection. Servers return `ttlMs`

and `cacheScope`

values that tell clients how long a result should remain fresh and whether it can be shared. This allows an orchestrator to reuse tool definitions across subagents, reducing redundant requests and improving prompt-cache reuse.

If you build or maintain an MCP server:

`2026-07-28`

and enable the new revision if your framework requires an explicit opt-in.`browser_id`

or `connection_id`

and require them in later calls.MCP began with a connection-oriented model that worked naturally for local processes running on a single machine. As the ecosystem expanded into cloud services, hosted gateways, and multi-agent systems, connection-level state became a scaling bottleneck.

The `2026-07-28`

specification separates these concerns. Protocol details travel with the request, application state uses explicit handles, interactive workflows pass continuation state, and tool definitions are cached cleanly. MCP servers still remember everything they need to remember. They just name that state directly inside the request.
