AnthropicClaude Certified Architect – Foundations2026-102.2 Implement structured error responses for MCP tools
Distinguish no matches from inaccessible data
Completed by the knowledge check
Learning objective
Distinguish successful no-match responses from access failures requiring a recovery decision.
Core idea
“No matching records” is a result of a completed search. “Could not access the records” is a failure to obtain that result. An agent needs this distinction to avoid telling a customer that an order, document, or account does not exist when the source was unavailable or inaccessible.
The difference is not the size of the returned collection. Both paths might contain no records, but only one provides evidence that the authorized query completed. Use MCP isError to preserve success or failure, then use the tool’s result contract to identify the searched scope or the missing access condition. The recovery decision follows the cause, not the absence of rows.
How it works
Define what a successful empty result proves
A successful search result should identify the query scope and its completion state through the tool-defined payload. For example, matches, searchedScope, and complete can describe a search that completed over the customer’s authorized order history. These names are application fields inside MCP structuredContent, not reserved protocol keys.
When that query completes and finds nothing, return isError: false, matches: [], and the scope that was actually searched. The agent can report no matches in that scope. It cannot expand that statement into “no orders exist anywhere” or “the customer never purchased anything” unless the tool’s documented scope supports those claims.
A successful empty result is meaningful data, so it still deserves a clear explanation. Apply the same specificity Anthropic asks of error responses: a no-match explanation can identify the searched date range or suggest checking the order identifier. That is query refinement after success, not recovery from a failed operation.
See 2.2.2 for the output schema, compatibility text, and Agent SDK delivery boundary. Whichever representation carries this tool’s data, keep it clear about successful completion rather than printing an ambiguous “nothing returned.”
Preserve access failures as failures
If a recognized tool cannot retrieve records because its dependency is unavailable or denies access, use isError: true and a specific failure explanation. MCP explicitly includes API failures in tool execution errors. See 2.2.1 for failures at the protocol layer, such as an unknown tool, that should not be represented as completed searches either.
Use the metadata contract from 2.2.2 to distinguish errorCategory: "transient" from errorCategory: "permission". A temporary dependency outage can be eligible for a bounded retry. A denied request needs an authorized access change or a clear report of the limitation. Retrying unchanged access repeatedly does not establish that the customer has no matching records.
A failure explanation should state what remains unknown. “Order history could not be read; matching orders were not determined” preserves the evidence boundary. “No orders found” falsely converts the missing evidence into an observation. A generic empty array is equally misleading if the adapter silently discards the original access failure.
Keep completed and incomplete scope separate
A tool might search more than one source. If the authorized order store completes but an archive cannot be read, preserve the successful records and name the unsearched source. For this example contract, partialResults and unresolvedSources can carry those distinctions within an error result. Their exact shape belongs in the tool’s output schema.
Do not return a globally successful empty result merely because the completed source returned no matches. The failed archive leaves the requested search incomplete. Conversely, do not throw away records from the completed source just because another source failed. See 2.2.5 for carrying partial results and attempted recovery steps to a coordinator.
The agent’s statement must follow the declared completeness. It can say the accessible source had no matches and the archive could not be checked. That gives the customer useful evidence without pretending that all requested sources were searched. A collection alone cannot express this distinction; completion and scope are load-bearing parts of the response.
Choose recovery from the failed precondition
For a transient failure, use the local retry budget assigned to the operation. For a permission failure, identify the approved access recovery step if the application has one. If access cannot be restored within the allowed workflow, propagate the limitation instead of inventing a result. This lesson does not prescribe a universal login or authorization API because that mechanism belongs to the connected business service.
MCP requires server access controls and output sanitization. A recovery suggestion must remain within that authorized scope. Searching a different customer’s account or a broader private store is not a correction for denied access. State what can be checked within the caller’s authorization and what cannot be concluded from the failed query.
Key distinctions and trade-offs
No match versus no access: A completed query can support a no-match conclusion. A failed read cannot support any conclusion about the missing records.
Query refinement versus error recovery: A different date range can refine a completed search. Repairing credentials or waiting for a dependency addresses a failed precondition. These actions have different reasons and different evidence.
Partial success versus full completion: Useful records from one source do not establish completion across all requested sources. Preserve both the retrieved evidence and the remaining gap.
Misreading in either direction does damage:
| What the tool returned | What happens downstream |
|---|---|
| A completed no-match flagged as an error | The agent retries or escalates a query that already succeeded |
| An access failure as an empty success | The agent tells the customer the order does not exist |
| An empty collection with no scope data | The agent cannot tell which sources the zero covers |
isError plus scope and completeness | The agent reports the finding or makes a cause-specific choice |
Architecture / decision scenario
A customer support agent investigates whether an order exists for a supplied identifier. The authorized order store completes the lookup and returns isError: false, matches: [], and the searched scope. The agent reports that the identifier had no match in that store and asks the customer to verify it. No failed-call retry is necessary.
For another customer, the store denies the lookup. The handler returns isError: true, errorCategory: "permission", isRetryable: false, and an explanation that order existence was not determined. The agent follows the application’s approved verification step or reports the access limitation. It does not convert the denial into “you have no order.”
For a third lookup, the store is temporarily unavailable. The handler identifies a transient failure; local bounded recovery can retry if eligible. If the task also searches an archive and only the store completes, the result preserves the completed search and marks the archive unresolved. The coordinator can choose a targeted follow-up rather than repeating all completed work or presenting an unsupported global no-match answer.
Common exam traps
- Inferring successful completion from an empty collection alone.
- Mapping permission denials or timeouts into no-match responses.
- Treating every access failure as eligible for the same retry.
- Claiming no records exist outside the declared search scope.
- Hiding an unsearched source inside an otherwise successful result.
Where the exam guide differs
The guide distinguishes valid empty results from access failures needing recovery. It also names errorCategory and isRetryable as structured metadata. Those names are application payload fields inside the MCP result, not protocol fields. This lesson uses the shared contract from 2.2.2 to choose between transient recovery and authorized access recovery.
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 report execution failures as isError: true tool results, and the object payload this lesson places in structuredContent is valid under either.
What to remember
A no-match response is successful evidence about a defined, completed query. An access failure is missing evidence that needs a cause-specific recovery decision. Preserve isError, scope, completeness, and any partial results so the agent can distinguish what the tool learned from what it could not inspect.
Knowledge check
search_orders completes over the customer’s orders from the last 12 months and returns isError: false, matches: [] and searchedScope: "orders, last 12 months". The customer asks whether they have ever ordered from the store. What can the agent state?
An adapter in front of an order store catches every exception and returns isError: false with matches: []. When the store denies a lookup for an account outside the agent’s authorization, the agent tells the customer the order does not exist. What should the tool return for the denial?
isError: false , matches: [] , and a searchedScope naming the requested customer accountisError: true , errorCategory: "transient" , and isRetryable: true for an unchanged retryisError: true , errorCategory: "permission" , and a note that existence is undeterminedisError: false , matches: [] , and a nextAction to search the full order store insteadisError: true , the permission cause, and an explanation of what remains unknown. An empty success, with or without a scope, turns missing access into a no-match finding. A denial is not transient, and widening the search beyond the caller’s authorization is not a correction for it.A lookup tool searches two sources for an order: the live order store and an archive. The order store completes with no matches; the archive cannot be read. Which result preserves what the tool learned?
isError: false with matches: [] and the order store named as the searched scopeisError: true with the store search in partialResults and the archive in unresolvedSourcesisError: true with an archive failure and a nextAction to check archive accessisError: true with both sources in unresolvedSources and a nextAction to repeat the searchA shipment tracker’s find_parcel tool queries the carrier database, which responds without trouble: no parcel carries the tracking number the user typed. The tool reports isError: true with “Nothing returned”, and the agent tries the same lookup three more times before escalating. What is the best correction?
isError: true with isRetryable: false and the text “Nothing returned”isError: true with errorCategory: "validation" naming the tracking numberisError: true with errorCategory: "transient" and a bounded retry budgetisError: false with matches: [] and the scope that was searchedReferences
- Model Context Protocol, Tools
- Anthropic, Writing effective tools for agents
- Anthropic, Claude Certified Architect – Foundations Exam Guide
- Model Context Protocol, Key Changes, protocol revision 2026-07-28