aicert.study
Study Track/A tool error is also a response

A tool error is also a response

75 min

We recommend seeing first: MCP decouples capability from host

Lesson objectives

  • Return structured, retryable errors
  • Expose catalogs and schemas as resources instead of repeated calls
  • Design progressive discovery for large tool catalogs

The problem

An internal MCP server scales from 6 to 40 tools over three months. Every new tool is added using the same initial pattern: a one-line description exposed directly in the global tool catalog injected into Claude at the start of every session. Token consumption spikes, tool selection accuracy degrades (the model frequently confuses update_invoice with update_invoice_line_item), and when a tool execution fails, the returned payload is an unformatted raw Python traceback. The agent retries blindly. It fails again. It retries a third time. Three round trips later, the failure persists — because the root cause was an expired API credential, not transient network jitter, and no volume of retries could ever resolve it.

Two distinct architectural challenges are conflated here: how the tool catalog is exposed and how execution errors are communicated back to the model. Solving only one leaves the system vulnerable to the other.

Errors are structured responses, not unstructured obstacles

A poorly architected tool error returns free-form text — a string written for a human reading log streams, not structured metadata for an agent making autonomous control-flow decisions. A resilient error contract returns structured payloads with at least three core fields: error category, retryability boolean, and actionable remediation guidance.

{
  "error_type": "rate_limited",
  "retryable": true,
  "guidance": "Wait and retry with exponential backoff."
}

versus

{
  "error_type": "invalid_credentials",
  "retryable": false,
  "guidance": "Escalate to a human operator — configured credentials are invalid."
}

The fundamental difference is not phrasing; it is the deterministic next action. rate_limited is a transient system condition — the agent loop should apply backoff and retry. invalid_credentials is a terminal condition until an operator rotates the secret — retrying burns tokens and latency while masking an unrecoverable failure. The classic scenario distractor is prescribing "add more retries" as the universal fix for tool failures — a pattern that helps transient hiccups while disastrously masking terminal faults.

Generalize this architectural taxonomy: failures that resolve automatically over time (rate limits, network timeouts, temporary 503s) versus failures requiring intervention (auth failures, permission denials, business constraint violations). A production-ready agent harness routes them through distinctly different state machine branches.

Progressive discovery: stop dumping monolithic catalogs

The second failure mode — 40 tools competing for attention in every prompt turn — requires an architectural solution rather than prompt engineering. Instead of listing exhaustive tool schemas in every turn, expose a discovery endpoint (such as search_tools(query)) or categorized catalog resources, allowing Claude to dynamically fetch complete schemas only for tools relevant to the active subtask. This is progressive discovery: capabilities remain accessible without forcing the entire context window to ingest them upfront.

The same architectural principle governs large database schemas and API specifications: they belong in retrievable MCP resources, not embedded in every tool definition. If a SQL generation tool requires schemas for 30 relational tables, expose the schema as an on-demand resource fetched when needed — not as a 2,000-token payload repeated in every system message.

The guiding architectural question: what must live in immediate context now, and what merely needs to be discoverable on demand? Tool catalogs belong on demand. Immediate execution errors belong in immediate context — formatted as structured, actionable contracts.

Put it into practice

In this lesson's lab, you will ingest raw backend exceptions from a simulated external service, transform them into structured error contracts (error_type, retryable, guidance), and route execution deterministically between exponential backoff retries and immediate human escalation.

Hands-on lab

Clone the repository and run it locally:

git clone https://github.com/aicertstudy/labs
cd labs/ccar-f/lessons/18-tool-contracts-errors-and-progressive-discovery
View folder on GitHub

Ready to test it for real?

Take the full CCAR-F mock exam, in the same format as the official test.

See mock exams

Lesson checkpoint

Loading quiz...