Skip to content

Build1 publisher2 min readPublished

MCP's stateless core moves a 30-minute approval pause into your database

A dev.to post says the 2026-07-28 specification dropped the initialize flow and Mcp-Session-Id, so MCP requests can land on any instance. The refund agent it walks through still breaks on the second pod.

The Engineer · Build desk

Illustration accompanying MCP's stateless core moves a 30-minute approval pause into your database

What happened

  • The 2026-07-28 Model Context Protocol specification removed the session-oriented initialize flow and the Mcp-Session-Id header, according to a dev.to post, leaving requests self-describing.
  • A request can now hit any of three MCP server instances behind a load balancer without the balancer pinning a client back to the instance that served its first call.
  • In the version the post calls wrong, the paused run sits in a pending_runs dict in Server A's memory, so the approve request that the balancer sends to Server B returns KeyError.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • capability Once workflow state lives in Postgres, Redis or Temporal, any pod can pick up a run that paused on another one, and the agent process becomes disposable.
  • decision Adopting the stateless transport forces a choice of durable store before the first workflow that waits on a human, not after the first lost approval.
  • exposure A resumed run with no record of what it already called is free to hit the payment API twice, so the side-effect layer is what keeps a retry from moving money again.
  • constraint Workflow status can no longer ride inside the model's message history, because a second process has to be able to read where execution stopped.

Statelessness at the transport layer buys one thing: the balancer stops caring which instance served the last call. According to the dev.to post, requests now carry enough information to be handled independently, with no Mcp-Session-Id to match and no session-oriented initialize flow to replay [2][3]. Three MCP server instances behind one balancer become interchangeable [4]. Session affinity comes out of the config [3].

The pause is where that stops helping. The post's worked example is a refund agent: it investigates the order, checks the refund policy, calculates the amount, requires human approval, and waits 30 minutes [6]. In that window the process might restart, a deployment might land, the request might reach another Kubernetes pod, or the machine might disappear, and the approval itself might arrive hours later [7].

The failing implementation is short. A module-level `pending_runs` dict, one write when the result comes back with `requires_approval`, one read in `approve(run_id)` [8]. The entry exists in Server A's memory, so the approve call that the balancer sends to Server B raises `KeyError` [9]. With two pods and even routing, half the approvals land on the pod that never held the run [15]. A deployment during the 30-minute wait makes it all of them, because the dict lives in the process that just exited [16]. An in-memory dict passes every test you run on one pod.

The post's fix is to persist workflow state outside the runtime, naming Postgres, Redis, Temporal and a durable runtime, so that any server can reconstruct the current workflow and the agent runtime becomes replaceable [10]. It then splits state three ways. Conversation state is messages, summary, user preferences and retrieved context, and it controls what the model knows [11]. Workflow state is `workflow_id: refund_39281`, `status: WAITING_FOR_APPROVAL`, `current_step: refund_confirmation`, `order_id: ORD_8821`, `refund_amount: 149.99`, and the author calls it distributed-system state, not prompt context [12]. Side-effect state is the flags for what already happened: `email_sent: true`, `refund_created: false`, `crm_updated: true`, and the post says that without it, retries become dangerous [13].

"MCP should not need to remember your connection," the author wrote. "Your agent absolutely needs to remember its work." [14]

One caveat on the record: this is a single post, and it describes the specification change in its own prose without reproducing the specification's wording [18].

The three-layer split costs a schema, a migration, and a read on every resume. It pays when a run can pause and when the resume can arrive at a different process [7]. An agent whose runs finish inside one request, calling tools that are safe to repeat, pays that cost and gets nothing back for it.

What to watch

  • Whether the specification text itself matches the post's account that the initialize flow and Mcp-Session-Id are gone rather than deprecated.
  • Whether MCP client SDKs keep session handling for compatibility with servers built against the older flow.
  • Whether durable runtimes such as Temporal ship resume primitives shaped around the post's workflow and side-effect layers.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories