Skip to main content

MCP's Stateless Core Just Shipped: What a Deploy-From-Chat MCP Server Gets to Delete

9 min readDora NodaDora Noda
Share
On this page

On July 28, 2026 — three days ago — the Model Context Protocol's largest spec revision since launch went from release candidate to final. The headline change: MCP is no longer a stateful, session-pinned protocol. The initialize/initialized handshake is gone. The Mcp-Session-Id header is gone. Any request can now land on any server instance, answered by a plain round-robin load balancer instead of the sticky-routing setup a remote MCP server used to need.

For most MCP servers — a docs search tool, a read-only API wrapper — that's a nice ops simplification. For a server whose job is to deploy and roll back running services from a chat message, it's closer to a rewrite of the load-bearing wall. Here's the concrete before/after: what infrastructure a deploy/rollback MCP server needed under the old stateful model, what replaces it under 2026-07-28, and what a platform building one now — bex's own included — gets to delete versus what it still has to keep.

What Actually Shipped

The spec's core change is architectural: MCP moves from a bidirectional, session-oriented protocol to a stateless request/response model. Each request now self-describes its protocol version, client identity, and capabilities instead of relying on a handshake that pinned a connection to one server process. Two new headers, Mcp-Method and Mcp-Name, let a load balancer route traffic by inspecting headers instead of deep-packet-inspecting message bodies — and, notably, neither should ever carry a secret or PII, since both are visible to any gateway or log sitting in front of the server.

The piece that matters most for an operations tool is the Tasks extension (io.modelcontextprotocol/tasks), which formalizes how long-running work — a build, a deploy, anything that doesn't finish inside one request/response cycle — gets tracked without a session. A tools/call that starts something slow now returns a task handle instead of blocking or relying on server-side session state; the client polls tasks/get(handle) until it's done, or cancels it with tasks/cancel(handle). The old tasks/list — "show me every task in this session" — is gone outright, because there's no session left to scope it to.

Two more pieces round out the release: MCP Apps (SEP-1865), the first official extension, lets a server ship a sandboxed-iframe UI a host can render inline — a progressive enhancement, since a host that doesn't support it just gets the text fallback. And a formal deprecation policy gives Roots, Sampling, Logging, and the legacy HTTP+SSE transport a 12-month minimum runway before removal, so today's breaking changes (sessions, tasks/list) aren't the pattern for every future one. All four Tier-1 SDKs — TypeScript, Python, Go, C# — shipped 2026-07-28 support the day the spec went final.

The Before/After for a Deploy/Rollback MCP Server

Picture the MCP server bex has roadmapped: an agent sends deploy_service({serviceId}) in a chat thread and later checks whether it finished, or sends rollback_service({serviceId, revision}) to undo it. Under the pre-2026-07-28 stateful model, building that tool honestly required infrastructure most teams would rather not run:

Before. The client opens a session via the initialize handshake and gets back an Mcp-Session-Id. The deploy tool call — and every follow-up "is it done yet" call — has to reach the same server process that started tracking the deploy, because that's where the in-memory state lives. That means either sticky-session affinity at the load balancer (route by session ID, every request from this client to this one instance) or a shared session store — a Redis map from session ID to deploy status — so any instance can answer, at the cost of running and operating that store. If the pinned instance dies mid-deploy, the session's view of "which deploy is this and how far along is it" dies with it, unless that Redis layer was already doing the real bookkeeping.

After. tools/call("deploy_service", {serviceId}) returns a task handle immediately — not tied to a session, not tied to the instance that issued it. The client polls tasks/get(handle) on any instance behind a plain round-robin load balancer, because the answer comes from a durable store keyed by the handle, not by connection. rollback_service takes the deploy's handle (or the service's revision history) as an explicit tool argument rather than reading it out of session state. No instance is special; none needs to remember anything about who called it or when.

What that deletes: the load balancer's sticky-session affinity rules, the session-keyed Redis layer purpose-built to survive an instance restart, and the initialize handshake bootstrap code on both ends. For a platform like bex, built on a Cluster API fleet where any node in the pool should be able to answer any request, that's not a hypothetical convenience — session affinity is exactly the kind of per-connection state a multi-node control plane exists to avoid needing in the first place.

What it doesn't delete: a durable task-state store. tasks/get(handle) still has to read from somewhere — the protocol didn't make deploy tracking free, it moved where that tracking lives. The difference is that the lookup is now a plain per-request read by handle, the same shape as any other database row, instead of a piece of transport-layer session state a load balancer has to route around. In bex's case that store already exists: it's the same deploy record a git push already creates. The Tasks extension doesn't add a new system to run — it gives the MCP server a standard shape for exposing a record bex's control plane was keeping anyway.

Pin to 2026-07-28 Now, or Wait?

The case for pinning a new deploy/rollback MCP server to 2026-07-28 today, rather than building against the older stateful shape and migrating later:

  • Extensions version independently of the core spec. Tasks and MCP Apps live in their own ext-* repositories, identified by reverse-DNS IDs and negotiated through an extensions capability map. A future Tasks revision doesn't force a core-protocol bump, so pinning to 2026-07-28 today isn't pinning to a spec that stops moving underneath the extensions.
  • Tier-1 SDKs already ship it. TypeScript, Python, Go, and C# all support 2026-07-28 as of publication day — there's no beta-SDK tax to pay for building against it now.
  • The deprecation runway is real, not a cliff. Twelve months minimum on Roots, Sampling, Logging, and legacy HTTP+SSE means a server built today isn't racing a surprise removal next quarter.

The honest counterweight: this is still a breaking change, not an additive one. tasks/list is gone, so any UI that enumerated "all running deploys for this session" needs a different data source — in bex's case, a query against its own deploy-history table instead of the protocol. And MCP Apps' sandboxed iframe is a new UI surface with its own threat model, worth building deliberately rather than turning on by default. Neither is a reason to wait; both are reasons to scope the first version narrowly — deploy and rollback as task handles, no bundled UI — rather than shipping every new extension in one pass. For a server that doesn't exist yet, "pin to the spec that just went final" is a cheaper decision than "build against the old shape and migrate in six months," and it's the one bex is making.

The Security Bar Is Higher for a Server That Can Deploy

A docs-search MCP server getting its task-handling wrong is an inconvenience. A deploy/rollback server getting it wrong touches production, which raises the bar on a few specifics the spec makes explicit but doesn't enforce for you:

  • Randomize every task and handle ID. A predictable deploy-task handle is a hijacking vector — if an attacker can guess or enumerate handles, they can poll or cancel someone else's deploy.
  • Budget and expire abandoned tasks. A client that starts a deploy and disconnects shouldn't leave compute running indefinitely; an unbounded task queue on a tool that provisions real infrastructure is a self-inflicted denial-of-service surface.
  • Treat Mcp-Method and Mcp-Name as visible, not private. They're routing headers, which means they're visible to load balancers and show up in logs — never carry a service ID's associated secret or any PII in them, only routing metadata.
  • Threat-model any MCP App before shipping it. A deploy-status card rendered inline in a chat thread is exactly the kind of interactive surface worth reviewing for what it can trigger before turning it on, even though the fallback-to-text design makes it optional.

None of this is unique to MCP — it's the same discipline any request-scoped, credential-adjacent API needs — but a spec change that removes the session as an implicit trust boundary means a server author has to be explicit about handle randomness and task lifecycle instead of getting some of it for free from "this session is who it says it is."

What This Changes

The stateless core doesn't make a deploy/rollback MCP server simpler to build — the Tasks extension replaces implicit session bookkeeping with an explicit handle-and-poll pattern that a server author still has to implement correctly. What it removes is the infrastructure tax around that server: the sticky routing, the session-affinity load balancer config, the Redis layer that existed only to survive an instance restart. For a self-hosted platform running on a real multi-node fleet rather than one long-lived process, that's the part of "deploy from chat" that was never supposed to need special-casing in the first place — and as of three days ago, it doesn't.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Its MCP server already lets an agent read and mutate a service's configuration; deploy-from-chat and rollback are next, built against the 2026-07-28 spec from day one instead of migrating into it later. Star the repo on GitHub or deploy your first app today.

Related articles

Give your agents a chain backend

Autonomous agents hit RPC endpoints very differently than people do. See what bex router handles on their behalf.

Read the agents guide