AnthropicClaude Certified Architect – Foundations2026-102.2 Implement structured error responses for MCP tools
Bound retries and preserve unresolved evidence
Completed by the knowledge check
Learning objective
Retry transient failures locally within bounded limits and propagate unresolved errors with attempted steps and partial results.
Core idea
A transient tool failure should first be handled by the component that owns the failed operation and its recovery budget. A temporary lookup outage does not require the coordinator to rediscover the whole task. Local recovery can repeat an eligible read, retain successful work, and return either the recovered result or a precise account of what remains unresolved.
Local retries are also cheap for the coordinator. A subagent’s intermediate tool calls and results stay inside its own conversation, and only its final message returns to the parent (see 1.2.1), so three attempts at an archive read add nothing to the coordinator’s context. Anthropic’s account of its multi-agent research system gives the other half: restarts are expensive and frustrating for users, so it resumes from where the agent was and pairs the model’s adaptability with deterministic safeguards such as retry logic and regular checkpoints.
MCP defines error results and request timeout behavior. Your tool handler or client-side recovery controller implements the bounded attempt policy, and the subagent’s assignment defines what it must report to its coordinator.
How it works
Assign one local recovery owner
Use the error metadata from 2.2.2 to identify eligible transient failures. A valid read that encounters temporary service unavailability can qualify. A validation error needs changed input, a permission error needs authorized access, and a business-rule rejection needs explanation. Do not put all isError: true results into a blanket retry loop.
Place deterministic dependency retries in the MCP handler or a client-side recovery controller that can enforce the budget. If a subagent directs the recovery, give it an explicit assignment describing allowed retries and the required handoff. In the Python Agent SDK, AgentDefinition.prompt holds that subagent instruction; in TypeScript, the corresponding agent definition’s prompt serves that role. See 1.3.1 for defining specialists and 1.3.4 for evidence-bearing handoffs.
A prompt communicates the policy; the recovery controller enforces the limits, which is the deterministic half of that pairing. Account for retries in the Anthropic Python client too: use max_retries=0 when another layer deliberately owns those retries; see 0.4. A handler, subagent, and coordinator must not each restart independent budgets.
Bound attempts and elapsed time separately
For a concrete example, assign three total dependency attempts and a ten-second local deadline. These are scenario settings, not MCP or Anthropic defaults. Three total attempts means one initial attempt and at most two retries. The recovery controller records an application attemptCount and stops when either the attempt limit or deadline is exhausted.
A count limit does not bound a hung request. MCP revision 2026-07-28 recommends request timeouts, per-request configuration, and a maximum timeout despite progress notifications. On timeout, cancel and stop waiting. For Streamable HTTP, closing the SSE response stream signals cancellation; no notifications/cancelled message is required or expected. For stdio, the client must send notifications/cancelled referencing the original requestId.
In Claude Code, set MCP_TOOL_TIMEOUT or a per-server timeout in milliseconds in .mcp.json. The per-server value overrides the environment variable and enforces a hard wall-clock limit that progress cannot extend. Values below 1000 milliseconds fall through to MCP_TOOL_TIMEOUT, whose unset default is about 28 hours. In the TypeScript Agent SDK, pass timeout to createSdkMcpServer() to bound a single in-process server’s tool calls.
Claude Code also has an idle window controlled by CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT: five minutes for HTTP/SSE/WebSocket and 30 minutes for stdio, excluding IDE and SDK in-process servers. For Claude Code v2.1.203 or later, a per-server timeout of at least 1000 milliseconds is also a floor on that idle window.
Tool-call timeouts bound caller waiting; the handler’s dependency deadline bounds upstream work, and both fit within the assignment’s deadline. The cited MCP pages prescribe no retry count or backoff schedule; those are application settings.
Preserve the difference between eligibility and exhaustion
A transient cause can remain transient after the permitted recovery budget is gone. Return the cause along with the exhausted state. In this example contract, errorCategory: "transient", isRetryable: false, and budgetExhausted: true mean the local owner cannot repeat the unchanged call within its assignment. The fields inside structuredContent are application-defined.
The coordinator can then decide whether a separate approved recovery action is warranted. It should not silently reset the same budget just because a different agent received the error. Preserve attemptCount, elapsed evidence, and the failed operation’s scope so any follow-up decision can account for work already performed.
A timeout during a state-changing operation also needs outcome clarity. In this example workflow, only read-only lookups are eligible for automatic repetition. If a refund request times out after dispatch and its outcome is unknown, the result reports that uncertainty and requests a status check through the merchant’s approved mechanism. It does not infer that no refund happened or repeat payment execution as if it were a harmless read.
Propagate a useful unresolved result
When local recovery succeeds, return the valid success result. When it fails, use an isError: true result with an actionable explanation. See 2.2.2 for structured metadata delivery, output schemas, and the Python in-process support boundary.
The unresolved payload should identify the failed operation, the category, whether local recovery is exhausted, what was attempted, and what evidence is already available. This example uses attemptedSteps, partialResults, and unresolvedSources as schema keys. They are not MCP-reserved identifiers, but they make the exam’s reporting requirement concrete.
Record which source was queried, how many attempts occurred, and what each produced, and keep successful evidence with its source and scope. “Could not finish” is insufficient when only an archive lookup remains missing; the coordinator needs the gap, not a transcript.
Only an eligible transient failure loops back for another attempt, and the loop ends when either the attempt limit or the deadline is exhausted.
Key distinctions and trade-offs
Local recovery versus coordinator recovery: Local recovery handles eligible failures inside the assigned operation. The coordinator chooses among unresolved alternatives using the resulting evidence and remaining constraints.
Transient cause versus remaining budget: A temporary outage can persist after retries are exhausted. Classification describes the cause; exhaustion describes the permitted work remaining.
Partial evidence versus completion: Retained records are useful, but they do not prove that unresolved sources were checked. Report both the results and the gaps.
A bounded local policy caps latency and dependency traffic, and gives the coordinator a defined terminal outcome instead of an indefinite wait.
Architecture / decision scenario
A research subagent must check two authorized customer-history sources. Its MCP lookup controller has the scenario’s three-total-attempt limit and ten-second local deadline. The primary source succeeds. The archive returns a transient availability failure, so the controller retries only that eligible read within the remaining budget.
If the archive recovers, the subagent returns both sources’ evidence. If it remains unavailable, the controller returns isError: true with the transient category, budgetExhausted: true, attemptCount: 3, attempted archive steps, primary-source partial results, and the archive as unresolved. The subagent carries those fields into its coordinator handoff rather than discarding the primary evidence.
The coordinator can accept a qualified answer or authorize a targeted later archive check. It does not rerun the primary search or restart the same exhausted budget invisibly. A permission denial would have bypassed the transient retry path, and an empty successful archive query would have ended normally; neither is equivalent to the unresolved availability failure.
Common exam traps
- Retrying every error regardless of category or side effects.
- Counting three total attempts as three retries plus the initial call.
- Using an attempt cap without request timeouts and a deadline.
- Resetting an exhausted budget at each delegation boundary.
- Escalating a generic failure without attempted steps or partial evidence.
Where the exam guide differs
The guide asks for “local error recovery within subagents” with attempted steps and partial results. This is an assignment and recovery policy you implement, not an automatic retry contract in MCP or the Agent SDK. The application payload fields here implement that handoff; see 2.2.2 for the metadata vocabulary. MCP request timeouts and Anthropic tool-call settings bound execution, while the retry count remains application policy.
The exam guide (version 1.0, effective July 2026, first drafted in February 2026) names no MCP revision; it was written while revision 2025-11-25 was the published specification. This lesson cites revision 2026-07-28, a later revision, and the differences between the two do not change what it teaches for the exam. Both revisions recommend request timeouts and cancelling a request that times out. Revision 2025-11-25 cancels by sending a notifications/cancelled notification; revision 2026-07-28 makes closing the SSE response stream the signal on Streamable HTTP and keeps the notification for stdio.
What to remember
Keep eligible transient recovery local, finite, and owned by one controller. Use MCP timeout behavior to bound waiting and application limits to bound attempts. When recovery remains unresolved, preserve the cause, exhausted work, successful partial results, and missing scope so the coordinator can make a targeted decision.
Knowledge check
A literature-review subagent has gathered five papers when a read-only citation lookup reports temporary service unavailability. Its local recovery budget still permits another attempt. The subagent at once returns only “citation lookup down”, and the lead agent throws away its five papers and starts the whole review again. Which change addresses this at the right layer?
A lookup controller allows three total attempts for an archive read. During an incident, the first attempt never returns, and the subagent waits 40 minutes without retrying or reporting anything. Which change bounds this failure?
A subagent completes its primary-source search, but its archive lookup fails. The handler allows three total archive attempts per tool call, the subagent allows three total tool calls per assignment, and the coordinator allows three total assignments, producing 27 archive attempts. Which design bounds archive recovery while retaining completed work?
budgetExhausted and attemptCount upwardAn MCP client implementing revision 2026-07-28 sends tools/call to a local server over stdio. The client’s request timeout expires before any response arrives. How does the client cancel the request?
notifications/cancelled with the request ID, then stop waitingerror response for that request ID, then stop waitingnotifications/cancelled referencing the request ID; closing the SSE response stream is the signal on Streamable HTTP. A JSON-RPC error answers a request rather than cancelling one, and waiting on is exactly the hung connection a timeout prevents.References
- Model Context Protocol, Tools
- Model Context Protocol, Cancellation
- Anthropic, Subagents in the SDK
- Anthropic, How we built our multi-agent research system
- Anthropic, Claude Certified Architect – Foundations Exam Guide
- Anthropic, Connect Claude Code to tools via MCP
- Anthropic, MCP in the SDK
- Anthropic, Python SDK
- Model Context Protocol, Key Changes, protocol revision 2026-07-28
- Model Context Protocol, Lifecycle, protocol revision 2025-11-25