Skip to main content

Your Deploy Agent's Sandbox Will Die Mid-Rollout — Here's How Its MCP Server Should Survive That

8 min readDora NodaDora Noda
Share
On this page

An agent calls your platform's rollout_fleet tool over MCP: roll a new image out across forty tenant nodes, ten at a time, health-check each batch before moving on. Four batches in, the agent's sandbox gets recycled — an idle timeout, a host reschedule, a chat session the user closed and forgot about. The tool call that started the rollout is gone. The question that matters isn't whether that happens. It's what your MCP server does about it: does the rollout resume at batch five, or does the platform now have twenty nodes on the new image and twenty on the old one, with nothing left that remembers which is which?

This piece is about building the second answer, not the first one — a durable checkpoint layer that keeps the deploy's state alive even when the sandbox, the chat session, and the process that issued the tool call are all gone. The Model Context Protocol's own spec just shifted responsibility for this problem, and there's already a production-tested pattern for solving it.

Why "keep the connection open" was never going to work

Long-running agent tasks fail differently than short ones, and the difference isn't linear. Research on long-horizon task success tracked how agent reliability degrades as a task's human-time-equivalent length grows: performance holds up well on tasks a skilled human could finish in minutes, then drops off sharply as that estimate crosses roughly the half-hour mark — and past that point, doubling the task's expected duration doesn't just double the failure rate, it roughly quadruples it. A fleet rollout that takes twenty minutes end-to-end isn't a mildly-riskier version of a two-minute health check. It's operating in a different reliability regime entirely.

Infrastructure compounds this instead of absorbing it. The serverless and gateway layers a lot of tool-calling infrastructure runs on top of were never built for a request to stay open for the duration of a rollout:

LayerHard timeout
Typical API gateway (synchronous)~29 seconds
Serverless HTTP trigger (e.g. Azure Functions)~230 seconds
Serverless function execution (e.g. AWS Lambda)900 seconds

None of those numbers is close to "however long it takes to roll forty nodes." A tool call that tries to hold a live connection open for the length of a real deploy is going to hit a wall that has nothing to do with the deploy itself — it'll get killed by infrastructure the agent never even knew was there. The conversation being open, or the sandbox still running, was never a guarantee that the work underneath it would survive. It was an accident of timing.

MCP went stateless on purpose — and that's exactly the point

If you've built or operated an MCP server recently, you've likely run into the spec dated 2026-07-28: it rewrites the protocol's core from a stateful, session-oriented model to a stateless request/response one, specifically so servers can run on ordinary HTTP infrastructure — load balancers, serverless functions, edge workers — without pinning a client to one session.

That change came bundled with a new Tasks extension, built for exactly the workload a stateless core can't otherwise handle: work that outlives a single request. Instead of a tool call blocking until the rollout finishes, tools/call returns immediately with a task handle. The client then drives progress independently:

  • tasks/get — poll current status and progress
  • tasks/update — receive or push incremental updates
  • tasks/cancel — cancel a task in flight

That's the mechanism a rollout_fleet call should actually use: return a handle the instant the rollout is accepted, let the agent (or a human, or a monitoring loop) poll it whenever it reconnects.

Here's the part worth sitting with, though: a stateless protocol is not the same thing as a stateless server. The spec stopped requiring a persistent session as the thing that carries a task's state. It did not — and cannot — make the task's state disappear. It just moved the obligation to hold that state somewhere durable off the protocol layer and onto whatever implements the Tasks extension. If your MCP server keeps task progress in a process-local dictionary, you haven't adopted the new spec's model — you've just relabeled "the connection has to stay open" as "the process has to stay up," which is the same fragility with a different name.

What ephemeral sandboxes guarantee — and the layer above that they don't

It's tempting to assume the sandbox running your agent already handles this. It doesn't, and it isn't supposed to. Current-generation agent sandbox platforms — Modal, E2B, Daytona, Blaxel, and similar — are explicit about what they persist: a live filesystem, installed dependencies, shell history, sometimes a warm process, all scoped to that sandbox's lifetime or a session tied to it. That's a real and useful guarantee. It is not the same guarantee as "the rollout job this sandbox kicked off is still tracked, correctly, if the sandbox never comes back."

A sandbox that persists its own state solves continuity for the agent's environment. It does nothing for continuity of the operation once that environment is gone for good — recycled, evicted, or simply never reconnected to. That's a layer above the sandbox: it belongs to whatever system actually executes the rollout, which for a deploy-from-chat platform is the MCP server sitting between the agent and the fleet. Naming that gap plainly: no sandbox vendor's persistence story extends to "and if the sandbox is gone permanently, the multi-step operation it started is still correct and resumable." That has to be built into the tool implementation itself.

Borrow LangGraph's checkpoint playbook, not its runtime

You don't have to invent this from scratch. LangGraph's Postgres-backed checkpointer — the reference architecture the underlying research points to — already solves durable resumption for long-running graphs, and its shape ports directly onto an MCP Tasks implementation. LangGraph's PostgresSaver writes a state snapshot at every super-step boundary, with per-node writes recorded separately so that if one branch fails, the sibling branches that already succeeded aren't recomputed on retry. LangGraph 1.2 (May 2026) pushed this further, treating an agent run as a durable graph execution rather than a Python function call that either finishes or doesn't.

A rollout task backing the Tasks extension needs the same shape, scoped to deploy operations instead of graph nodes:

text
checkpoint (
  task_id           uuid primary key,
  step              int,              -- which batch (1..N)
  target            text,             -- node/tenant ids in this batch
  status            text,             -- pending | applied | failed
  idempotency_key   text unique,      -- see below
  updated_at        timestamptz
)

Two things matter about that table beyond its columns existing:

It's the source of truth tasks/get reads from, not a cache in front of one. If the MCP server process restarts, it reloads every task with status != 'done', resumes each at its last completed step, and answers tasks/get correctly for a client that reconnects five minutes or five hours later — a chat session and its answer to "where's my rollout" are decoupled by design.

Every side-effecting step carries an idempotency key. This is the detail that's easy to skip and expensive to skip badly. A rollout step that restarts pods on ten nodes is not a pure computation — if the checkpoint marks it pending, the server crashes mid-batch, and it comes back and reapplies the same batch, you need the fleet's own API (or your wrapper around it) to recognize "I've already done this exact restart" and no-op the retry, rather than double-restarting nodes that already came back healthy. Durable execution research on agentic workflows is consistent on this point: checkpointing without idempotent side effects just changes what gets duplicated on replay, not whether something does.

What this actually buys a deploy-from-chat platform

Put together, the pattern answers the scenario this post opened with concretely: rollout_fleet returns a task handle the moment it's accepted; the checkpoint table is the durable record of which batches are applied, which are pending, and which failed; tasks/get reads straight from that table so it's correct whether the caller reconnects in ten seconds or after a full server restart; and idempotency keys on each batch mean a resumed task retries safely instead of doubly applying an already-completed step.

None of that requires the original sandbox to still exist, the original chat session to still be open, or the MCP server process to have stayed up the whole time. That's the actual guarantee "the sandbox died, but the deploy state didn't" is asking for — and it's a guarantee the checkpoint table provides, not one the sandbox or the protocol's statelessness provides on their own.

As MCP's Tasks extension matures past its introduction in the 2026-07-28 spec, expect it to become the default way any deploy platform exposes operations that take longer than a request — not just for rollouts, but migrations, fleet-wide upgrades, anything with more than one step and a nonzero chance of an interruption in between. A Postgres checkpoint table isn't optional infrastructure bolted onto that story. It's the thing that makes "AI agents as first-class operators" actually true once the operation they're kicking off takes longer than the conversation they started it in.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with an MCP server built for agents that need to kick off deploys and trust that the platform, not the chat session, is the one keeping track of them. 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