What You Need to Know
A structured error response is the result an MCP tool returns when a call fails. Its metadata tells the agent the error's category, whether a retry can work, and how to recover. The MCP protocol provides the isError flag to report the failure to the agent. When the tool sets isError, the model knows that the execution failed. The model reasons about recovery, instead of reading the error text as a normal successful result. This response decides whether the agent recovers intelligently or fails without knowing what went wrong. A generic message such as "Operation failed" is useless to an LLM. It says nothing about what went wrong, whether to retry, or what to try instead.
This lesson uses one made-up example throughout: a picture framer whose agent handles orders through three MCP tools. They are a stock tool for a moulding supplier's catalogue, a jobs tool for job references, and a refund tool.
Two Error Layers
The MCP specification reports tool failures through two separate kinds of response. To design recovery, first learn which kind of response a failure belongs to.
Protocol errors are standard JSON-RPC error responses. The server sends one when the request itself is malformed. This happens when the tool name does not exist, when the arguments fail the input schema, or when the server has an internal fault. The response has no result object, only an error with a code and a message. The host application handles protocol errors. The model never sees a tool result, because no tool ran. If the framer's agent misspelt a tool name, the call would fail at this layer. Below is a generic example.
{
"jsonrpc": "2.0",
"id": 3,
"error": { "code": -32602, "message": "Unknown tool: invalid_tool_name" }
}Tool execution errors are results. The tool was found, the arguments were valid and the tool ran. Then an error occurred inside the tool: an upstream API failed, the input data was wrong, or a business rule rejected the request. The server returns a normal result with isError: true and the detail in content. The model reads the result and decides what to do next. A failed stock check at the framer would be a tool execution error. Below is a generic example.
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"content": [{ "type": "text", "text": "Failed to fetch weather data: API rate limit exceeded" }],
"isError": true
}
}The four categories, isRetryable and the recovery guidance all describe execution errors, because the agent reasons about that layer. A protocol error means that the call was built incorrectly. Fix it in the tool schema or the client, not in the agent's recovery loop.
The Four Error Categories
Every tool failure belongs to one of four categories. Each category needs a different recovery strategy. The agent needs structured metadata to distinguish the categories.
The fields errorCategory, isRetryable and description are an application-level convention, not part of the MCP envelope. The envelope is the protocol's CallToolResult, which defines only content, structuredContent and isError. The examples below put the metadata in structuredContent, which is where structured data belongs.
1. Transient Errors Timeouts, service unavailability, rate limits. The underlying system is briefly unreachable, but the request is valid. Recovery: retry after a short delay.
{
"isError": true,
"content": [{
"type": "text",
"text": "Service temporarily unavailable"
}],
"structuredContent": {
"errorCategory": "transient",
"isRetryable": true,
"description": "The order database is experiencing high load. The request is valid and should succeed on retry."
}
}At the framer, a supplier catalogue that times out under load causes a transient error.
2. Validation Errors Invalid input format, missing required fields, out-of-range values. The request itself is malformed. Recovery: fix the input, then send a corrected call.
{
"isError": true,
"content": [{
"type": "text",
"text": "Invalid order ID format"
}],
"structuredContent": {
"errorCategory": "validation",
"isRetryable": false,
"description": "Order ID must be in format #NNNNN (e.g. #12345). Received: 'order-abc'. Reformat the ID and call again."
}
}Here isRetryable: false does not mean "give up". It means that resending this call is pointless, because order-abc fails the same format check every time. The agent still recovers by correcting the input first, and the description tells the agent how. The boolean says whether to resend. errorCategory says what to do instead. At the framer, a job reference in the wrong format is a validation error, which the agent fixes and resends.
3. Business Errors Policy violations, limit exceedances, business rule conflicts. The request is technically valid but breaks a business constraint. Recovery: do not retry. The agent needs an alternative workflow.
{
"isError": true,
"content": [{
"type": "text",
"text": "Refund exceeds policy limit"
}],
"structuredContent": {
"errorCategory": "business",
"isRetryable": false,
"description": "Refund amount of £750 exceeds the £500 automatic refund limit. This requires manager approval. Please escalate to a human agent with the refund details."
}
}Business errors have isRetryable: false because the same policy violation applies every time. So a retry never resolves a business error. The agent has to take a different path, which is usually escalation. A customer-friendly explanation in the description lets the agent tell the customer why. At the framer, a refund above the automatic limit is a business error, so the agent escalates the refund to a person.
4. Permission Errors Access denied, insufficient credentials, authorisation failures. The tool cannot run because the caller lacks the required permissions. Recovery: escalate or use different credentials.
{
"isError": true,
"content": [{
"type": "text",
"text": "Access denied"
}],
"structuredContent": {
"errorCategory": "permission",
"isRetryable": false,
"description": "The current service account does not have permission to access financial records. Escalate to a senior agent with financial system access."
}
}At the framer, a request for records that the agent has no rights to read raises a permission error.
What isRetryable Signals
isRetryable answers one narrow question: will resending this exact request work? Only transient errors get true, because the call was valid and the system was briefly unavailable. Every other category gets false, because something has to change first: the input (validation), the request itself (business) or the caller (permission).
Read isRetryable to decide whether to resend the call without changes. Then read errorCategory to decide what to do when you cannot resend it.
| Category | isRetryable | Recovery |
|---|---|---|
transient | true | Resend the same call after a delay |
validation | false | Correct the input, send a new call |
business | false | Take an alternative path or escalate |
permission | false | Retry as a principal with the right access |
The most important distinction is between the three false rows. The agent alone can recover from a validation error. Business and permission errors are not recoverable by the agent alone. A policy limit applies however the agent words the request. A permission error needs a different account, not a better call. So false means "not this call again", not "stop".
Current state: where this table comes from
Exam guide v1.0 states retriable: false for business rule violations and never assigns a value to validation. The false for validation above is the wider ecosystem's convention: gRPC treats INVALID_ARGUMENT as non-retryable, and AWS-style retry metadata does the same. The table applies that convention where the guide gives no value. (Verified against the exam guide, August 2026.)
Access Failure vs Valid Empty Result
An access failure means the tool could not reach the data source. A timeout occurred, authentication failed, or the service was unavailable. The data might exist, but the tool could not check.
A valid empty result means the tool queried the data source successfully and found no matches. The query ran correctly, and no data matches the criteria. The agent should not retry. The answer is "no results found".
A tool should distinguish the two. An access failure needs a retry decision. A valid empty result is a successful query with no matches. Confusing the two breaks recovery logic.
Say the framer's agent asks the stock tool for a moulding the supplier has never made. The query runs and finds nothing. The tool's response does not separate "I could not reach the catalogue" from "I reached it and found nothing". So the agent treats the empty answer as a failure, retries three times and passes the request to a person. The tool succeeded.
To fix this, structure tool responses so that a successful query with no results is clearly different from a failed query. Below is a generic pair of responses.
// Valid empty result — NOT an error
{
"isError": false,
"content": [{
"type": "text",
"text": "No customer found matching email 'john@example.com'. The query executed successfully but returned no matches."
}],
"structuredContent": {
"resultCount": 0
}
}
// Access failure — IS an error
{
"isError": true,
"content": [{
"type": "text",
"text": "Could not reach customer database"
}],
"structuredContent": {
"errorCategory": "transient",
"isRetryable": true,
"description": "Connection to the customer database timed out after 5 seconds. The query did not execute."
}
}Error Propagation in Multi-Agent Systems
In multi-agent systems, error handling follows one principle: recover locally, and propagate errors selectively. Say the framer's coordinator sends a subagent to compare moulding prices from five suppliers.
- Subagents implement local recovery for transient failures. If one supplier's price list times out, the subagent retries before it involves the coordinator.
- Only propagate errors that cannot be resolved locally. If all retries fail, the subagent reports the failure to the coordinator.
- Include partial results and what was attempted. The coordinator needs context: "I checked 3 of 5 suppliers successfully. Suppliers 4 and 5 timed out. Here are partial results from the 3 that answered."
This principle prevents two anti-patterns: silently suppressing errors by returning empty results as success, and ending an entire workflow on a single failure. Both make the coordinator decide with missing information.
In the exam
The key distinction to learn in this domain is between an access failure and a valid empty result. The exam tests it directly.
The exam guide names the four categories and the isRetryable boolean. So know them by name, even though the MCP specification does not define them. Expect questions on which category a failure belongs to and what recovery it needs. The guide specifies both. If a question depends on the isRetryable value for validation, ask whether resending this exact call would work. Your answer will be false.
Key Concept
Access failures and valid empty results need different handling. Confusing the two causes wasted retries and incorrect escalations.
Exam Traps
Retrying when a tool returns an empty result from a successful query
An empty result from a successful query means 'no data matches your criteria.' Retrying will produce the same empty result. The agent should accept the result and respond accordingly.
Using generic error messages like 'Operation failed' without structured metadata
Without errorCategory, isRetryable, and a description, the agent cannot distinguish transient failures from business rule violations. It cannot make appropriate recovery decisions.
Treating business errors as retryable
Business errors (e.g. refund exceeds policy limit) will never resolve through retry. The same policy violation applies every time. The agent must take an alternative path such as escalation.
Marking a validation error isRetryable: true because the agent can recover from it
isRetryable asks whether resending this exact call can work. A malformed order ID fails the same check every time, so validation is isRetryable: false. The agent recovers by correcting the input and issuing a new call, which errorCategory conveys.
Reading isRetryable: false as 'abandon the task'
Validation is false because the input must change first, and the agent fixes it unaided. Business and permission errors still continue, through an alternative path, escalation or a different principal. None of the three non-retryable categories means abandon the task.
Silently suppressing subagent errors by returning empty results as success
Returning empty results as success hides the failure, so the coordinator cannot tell 'found nothing' from 'could not search'. Return structured error context instead, with the failure type, the attempted query and any partial results.
Practice Scenario
A tool returns an empty array after a customer lookup. The agent retries 3 times, then escalates to a human agent. Analysis shows the customer's account simply does not exist. What is the root cause of this wasted effort?
Build Exercise
Build Structured Error Responses for All Four Categories
What you'll learn
- Implement structured error responses with errorCategory, isRetryable, and description metadata
- Distinguish between access failures (isError: true) and valid empty results (isError: false)
- Categorise tool failures into transient, validation, business, and permission types
- Build agent recovery logic that takes different actions based on error metadata
- Create an MCP tool that queries a mock customer database with simulated failure modes
Why: Simulating failure modes in a controlled environment lets you observe how agents behave when errors lack structure. The exam tests your understanding of how poor error responses cause wasted retries and incorrect escalations.
You should see: An MCP server running with a customer_lookup tool that accepts a customer identifier and a failure_mode parameter to trigger specific error conditions on demand.
- Implement four error response types: transient (simulated timeout), validation (invalid input format), business (refund exceeds policy limit), and permission (access denied)
Why: Each error category demands a different recovery strategy. The exam tests whether you can identify which category an error belongs to and what recovery action is appropriate. Transient errors are retryable; business errors never are.
You should see: Four distinct error responses, each with isError: true, a specific errorCategory value, the correct isRetryable boolean, and a descriptive message explaining what went wrong and what to do next.
- Include structured metadata in each error: errorCategory, isRetryable boolean, and a human-readable description
Why: Structured metadata is what enables intelligent recovery. Without these fields, the agent cannot distinguish a transient timeout from a permanent policy violation. The exam specifically tests whether you know that isRetryable: false means the agent must take an alternative path, not retry.
You should see: Each error response parses to a JSON object containing exactly three fields: errorCategory (one of transient, validation, business, permission), isRetryable (boolean), and description (a sentence explaining the error and suggesting recovery).
- Implement a valid empty result response (isError: false, resultCount: 0) clearly distinguished from an access failure
Why: This is one of the most critical distinctions in Domain 2. Confusing access failures with valid empty results causes wasted retries and incorrect escalations. The exam tests this directly — an agent retrying a successful empty query is the canonical anti-pattern.
You should see: Two structurally different responses: a valid empty result with isError: false and resultCount: 0 (indicating the query ran successfully but found nothing), and an access failure with isError: true, errorCategory: transient, and isRetryable: true.
- Write an agent loop that reads the error metadata and takes appropriate action: retry for transient, fix input for validation, escalate for business, and request credentials for permission
Why: The agent loop demonstrates the practical outcome of structured error metadata. Each error category maps to a specific recovery action, and the loop must branch correctly. This is exactly the kind of decision logic the exam expects you to design.
You should see: An agent loop that parses the error metadata, branches on errorCategory, retries transient errors up to 3 times with backoff (a longer delay before each new retry), reformats input for validation errors, escalates business errors to a human, and requests elevated credentials for permission errors.
Sources
- Claude Certified Architect Foundations Exam Guide — Domain 2, Task Statement 2.2 — Anthropic
- MCP Specification — Tool Results — Model Context Protocol
- MCP Specification — Tools, Error Handling — Model Context Protocol
- Building Effective Agents — Anthropic — Anthropic
- CCAR-F Exam Guide v1.0: Task Statement 2.2 — Anthropic