Cruxly

Cruxly › AI engineering › Agentic Systems

Frameworks, Protocols and Durable Execution: MCP, A2A and Long-Running Agents

build or adopt, what the 2026-07-28 MCP revision changes for your server, and how a 2-hour run survives a crash

Open the interactive lesson

Prompt: "Our team wants to build agents that run for up to two hours, call our internal tools, and sometimes wait for a manager's approval. Do we use LangGraph, a vendor SDK, or our own loop? A worker dies at step 87 of 120: what happens? Also, our MCP server was written last year. Does anything in the protocol's latest revision affect us?"

40 minutes first. Price one crash two ways (restart from scratch versus replay), and write down the three MCP changes that touch a server author. The trap is a framework logo comparison with no mention of state, side effects, or credentials.

Build or adopt: what each layer gives you and what it costs

Choose the layer by the property you need to keep when something fails, not by popularity. There are four common layers.

:::key Verified October 2026 Agent SDK facts from the "Agent SDK overview" and "How the agent loop works" pages; LangGraph facts from its persistence page (it does not describe checkpointing mechanics in detail, so check the durability guarantees yourself before relying on them for money-moving flows); Temporal facts from docs.temporal.io. All read October 2026. :::

A decision rubric that survives an interview. Ask four questions.

@@ 1 | How long can a run last, and what does a crash cost? Under a minute with no side effects: a plain loop. Minutes to hours or any money movement: you need persisted state and replay.

@@ 2 | Do you need human approval or timers inside the run? A pause that lasts days cannot be a blocked process. It needs checkpointed state (graph) or a durable timer and signal (workflow engine).

@@ 3 | How much of the framework will you actually use? If you use only the loop, a vendor SDK or 100 lines is lighter. If you use state, branching, retries and tracing together, the framework saves a rebuild.

@@ 4 | What is the exit cost? Keep tools, prompts and state schemas in your own modules behind a thin interface, so replacing the orchestration layer is a week, not a rewrite.

MCP after the 2026-07-28 revision: what changed and what it means for a server

The July 2026 revision of the Model Context Protocol makes servers stateless at the protocol level, and that changes how you write them. MCP Servers, Prompt Injection, and Tamper-Evident Audit covers the security and audit side and is already updated for this revision; this section is the server author's checklist.

:::key Verified October 2026 From the MCP 2026-07-28 changelog (modelcontextprotocol.io/specification/2026-07-28/changelog), read October 2026:

:::

What each change means for a server you wrote last year.

No session means no hidden state. If your tool add_to_cart relied on the connection to remember the cart, that breaks: two requests may land on two replicas, and nothing ties them together. Return a cart handle from the first call and require it as an argument to the next. This is more work and more honest: the model sees the handle, the state lives in your database, and any replica can serve any request. It is also the property that lets you scale an MCP server like any other stateless HTTP service.

Discovery replaces the handshake. A client that wants to know what you support calls server/discover instead of negotiating in initialize. Implement it first; a client built for the new revision will start there.

Long jobs use the tasks extension. A 20-minute report generation should return a task the client polls with tasks/get instead of holding a connection open. Because tasks are now an extension, check that your client library supports it.

Questions in the middle of a call use the input-required result. If a tool needs a missing parameter or a confirmation, it returns input_required with the requests; the client gathers the answers and retries the call with inputResponses. Design the tool so the retry is idempotent, since the whole call is sent again. This is the protocol-level home for the human-approval step that Guardrails for an Agent That Takes Real Actions describes.

Deprecated is a schedule, not an emergency. Sampling (the server asking the client's model to generate text), Roots and Logging are deprecated with at least twelve months of overlap. If you use sampling, plan the migration; do not rip it out this quarter. Removed items such as ping are different and need action now.

Stable ordering helps your bill. Return tools/list in a deterministic order and keep descriptions byte-stable, so the tool block stays a cacheable prefix (Prompt Caching: Paying for the Same Tokens Once).

A2A versus MCP: two different seams

MCP connects an agent to tools and data; A2A connects an agent to another agent. That is the common way to frame the pair, and it is a useful first answer, but give the mechanism behind it.

With MCP the model is the client and the server exposes functions with schemas that the model calls: the callee is passive, deterministic code or data. With the Agent2Agent protocol (A2A) the callee is itself an agent that plans, may take many steps, may ask questions, and may take minutes or hours. The protocol therefore centres on a task with a lifecycle rather than on a function call.

:::key Verified October 2026 From the A2A site and specification (a2a-protocol.org), read October 2026: A2A is an open standard that lets agents built with different frameworks discover each other's abilities and collaborate, donated by Google to the Linux Foundation. An Agent Card is a JSON document published by an A2A server describing its identity, capabilities, skills, service endpoint and authentication requirements. Task states in the spec are submitted, working, input-required, auth-required, completed, failed, canceled and rejected (completed, failed, canceled and rejected are terminal; input-required and auth-required are interrupted states that wait for the caller). The latest released version listed was 1.0.0, with the version sent in an A2A-Version header (Major.Minor, e.g. 1.0). A2A's own "A2A and MCP" page uses the same split: MCP deepens a single agent with tools and resources, A2A links agents across team or organisation boundaries, and the two are complementary. The "function call versus delegated task" mechanism that follows is this lesson's own explanation, not the spec's wording. :::

What A2A standardises is discovery (read the Agent Card to learn what a remote agent claims it can do), the shape of a task and its states, and how messages and artifacts move. Notice the state auth-required: an agent partway through a task can say it needs the user to authenticate to some other system, which is the same kind of interruption as MCP's input-required result.

What it leaves to you is everything that makes delegation safe.

When not to use it. If both agents live in one codebase and one team, an in-process call or a sub-agent is simpler, faster and easier to trace. A2A earns its place across team or vendor boundaries, where you cannot share code or deploy together. The honest interview answer is often "we do not need A2A yet, and here is the trigger that would change that."

Durable execution: event history, deterministic replay and idempotent side effects

Durable execution turns a crash from a restart into a resume. The idea, as Temporal documents it, is that a workflow keeps a complete, ordered event history of everything that has happened, and that history is the source of truth for its state. It does not snapshot memory. When a worker dies and another picks the workflow up, the engine re-runs the workflow code from the start and uses the recorded events to bring it back to where it was, so completed work is not done again.

The consequences shape how you write an agent.

Orchestration code must be deterministic; the world goes in activities. On replay the code has to make the same decisions given the same history. Anything that can differ between runs (the current time, random numbers, a network response) must not be read directly in that code. Calls to the outside world, including every LLM call and every tool call, run as activities: once one completes, its result is stored in the history, and on replay the stored result is returned without running it again. (An activity that was interrupted before completing is retried, which is why idempotency below still matters.) Timers are also recorded as events, so a replay does not wait again.

For an agent this means: each model call is an activity whose recorded output is the assistant message; each tool call is an activity whose recorded output is the tool result; the loop itself, which decides what to do with those, is the deterministic orchestration. Replay then reconstructs the transcript exactly, with no model calls and no tool calls for the steps already done, and the first step with no recorded result is where real work resumes.

Human approval and long waits are cheap. A workflow waiting three days for a manager's approval holds no process and no tokens; the wait is a timer and an incoming event (in Temporal's vocabulary a signal) recorded in the history, and a worker is only needed when something happens. That is what makes "pause until approved" honest at scale; a blocked thread per pending approval is not.

Idempotency still matters. Replay protects completed steps. The step that was running when the worker died has no recorded result, so the engine will run it again, and if it was "issue refund" the first attempt may or may not have reached the payment system. The activity must carry an idempotency key (derived from the workflow id and step number, not from the clock) so the second attempt is recognised and does nothing. This is the same key described in Guardrails for an Agent That Takes Real Actions; durable execution makes it necessary and gives you a stable value to build it from.

Retries with budgets. Activities retry on transient failure with backoff and a maximum attempt count. Put the token and spend budget from The Agent Loop in Depth in the workflow state, so a retry storm cannot silently spend what a loop cap would have stopped.

:::warn A framework checkpoint is not the same guarantee A graph checkpointer that saves state after each node resumes you at a node boundary. It does not by itself protect a half-finished side effect inside a node, or guarantee exactly-once execution. Read what your tool promises and add the idempotency key anyway. :::

The crash at step 87: restart versus resume, in tokens, dollars and side effects

Put numbers on the crash so the engineering effort has a price. A 45-minute agent run makes 120 tool-using steps and the worker dies while executing step 87. Assume each step re-sends about 6,000 input tokens (a simplification, since real context grows) at $2 per million tokens.

@@ 1 | Restart from scratch Steps 1 to 86 are redone: 86 x 6,000 = 516,000 input tokens, which is 516,000 / 1,000,000 x $2 = $1.03. Wall-clock time: the run was 86 of 120 steps done, so about 45 x 86 / 120 = 32 minutes of work repeated, and the user waits for it.

@@ 2 | The side effect The redone steps include any write: the email sent at step 40, the ticket opened at step 55, and perhaps the refund at step 70. Running them again sends a second email and opens a second ticket. This is the real cost, and it does not show up on the token bill.

@@ 3 | Durable replay Steps 1 to 86 are served from the event history: zero model calls and zero tool calls for them. The orchestration resumes at step 87 and pays for that one step plus the single model call that carries the rebuilt transcript, which you would have paid anyway. The extra spend is close to zero, the time lost is the replay itself (milliseconds to seconds), and the one in-flight step is guarded by its idempotency key.

The dollar figure is small. Do not oversell it: $1.03 per crash is not why you adopt durable execution. You adopt it for the repeated side effects, for the 32 minutes of user time, and for the case where steps cost much more than $0.012 each, for example a research agent whose steps call a large model on a long context, where the same arithmetic gives dollars per crash, not cents. Multiply by how often workers die (deploys, preemptible nodes, out-of-memory kills) and you have the case for or against. At one crash a week the engine is not worth it for a read-only agent; at one deploy a day with money-moving steps it is.

What to put in the history, and what not to. Record the model's response and the tool results, because replay needs them. Do not put a 2 MB tool output in the event payload; store it in object storage and record the pointer, since histories have size limits and every replay reads them. And store only the data the agent needs: a history is a permanent record, so it falls under the same retention and erasure rules as agent memory.

Where tools run, where credentials live, and what to trace

An agent that holds secrets will eventually leak them, so design so that it never holds them. The model's context is not a vault: anything in it can be echoed in an output, written into a log, or extracted by an injected instruction. The pattern that holds up is to keep credentials outside the model's reach, in two ways.

Where tools execute decides your blast radius. Tools running in the agent's process share its permissions; tools in a separate service can be given narrow identities, rate limits and audit logs of their own. For anything with side effects, prefer a separate service with its own identity.

What to trace. A long-running agent is debugged from traces. Emit one trace per run with a span per model call and per tool call, carrying the run id, the step number, token counts, latency and the exit reason. The MCP revision above carries W3C trace context in _meta, so a trace can continue across an MCP call into your server. OpenTelemetry has a set of generative-AI semantic conventions for naming such spans and attributes. As of October 2026 the official spec pages say they have moved to a dedicated GenAI conventions repository, and the sources I found still describe them as Development (not Stable); I could not confirm a stable release on the official pages, so pin the version and expect attribute renames before you build dashboards on them. Observability and Cost Governance for LLM Systems covers what to chart; here the point is the join key, a run id present on every span, every activity and every log line.

Accounting across hours. A run that lasts two hours spans many cache lifetimes and may cross model-price changes. Record tokens and the price version per step in the event history, so cost per run is a sum of recorded facts rather than an estimate rebuilt later.

How to say it in the interview

"I would start from what must survive: the run's state, its side effects, and its credentials. A hand-rolled loop is fine for a short run, a framework graph or vendor SDK earns its place when I need checkpointing, human approval and tracing that I would otherwise rebuild, and for a two-hour run I want durable execution underneath, meaning an event history and deterministic replay, so a crash at step 87 resumes at 87 instead of re-spending 86 steps and repeating a refund. Every side effect carries an idempotency key. For MCP, the 2026-07-28 revision removes protocol sessions and the initialize handshake, so my server must not depend on session state, must answer server/discover, and should use the tasks extension for long jobs and the input-required result for mid-call questions. Roots, sampling and logging are deprecated, not removed, so I plan a migration rather than an emergency. A2A is for agent-to-agent delegation across teams; it standardises discovery and task state, not trust."

Checklist

Practice this interactively
Share this lessonWhatsAppLinkedInX

Related lessons