claudio.cool
CCAR-FLessons

CCAR-F · Tool Design & MCP

Tool errors the agent can act on

⏱ 3 min readDraft

“Operation failed” is the worst message an agent can receive. It doesn’t say whether to wait and retry, fix the input, tell the customer or ask for help. With that response, the agent retries what will never work or gives up on what could have been solved.

The three fields that guide recovery

In MCP, a tool flags its failure with isError: isError: true tells the agent the call failed. On top of that, add structured metadata:

  • errorCategory: what kind of failure it is;
  • isRetryable: whether repeating the same call can work;
  • description: what failed and what to do, in plain language.

The four categories

Category Example What the agent does
Transient The payment gateway didn’t respond within 30 seconds Retry with backoff and an attempt limit
Validation order-abc instead of #12345 Fix the input and make a new call
Business A 750 refund against a 500 automatic limit Explain the policy and escalate, without changing what the customer asked for
Permission The key has no access to that resource Escalate or request access

Watch out with validation: isRetryable is false because resending the same input always fails, but it isn’t a dead end. The description has to name the field, the expected format and an example (“Expected YYYY-MM-DD, e.g. 2026-10-20; resolve relative dates”). “Invalid input.” gives the model nothing to correct with.

For business errors, the description should also carry a customer-friendly explanation, so the agent can tell the customer what happened.

A query that worked and had no matches is a valid empty result: isError: false and an empty list. A database outage is a transient error. If the tool returns an empty array in both cases, the agent retries a success or, worse, tells the customer their account doesn’t exist when it actually couldn’t search. The reverse is also bad: returning the exception text with isError: false makes the agent quote it as if it were data.

Partial failures in subagents

A subagent that searches five sources and times out on two shouldn’t hide the failures or throw everything away. It applies local recovery: it retries the transient failures itself and, if that doesn’t work, returns to the coordinator the partial results, what it attempted and what failed. With that, the coordinator decides whether to retry only those sources, continue with what it has or record the gap.

The usual traps

  • Retrying a business error with backoff: the policy doesn’t change between attempts.
  • Quietly “fixing” the request: switching to a partial refund or a cancellation with a fee without the customer’s agreement.
  • Escalating a mistyped format: disproportionate when the model can fix it given the right information.
  • Detecting errors by searching the text for “Error”: fragile, and it doesn’t say whether to retry.
  • Per-tool retry rules in the prompt: they don’t generalize; metadata does.

In the exam

Read the error in the scenario and classify it: temporary, malformed input, business rule or permissions? The right option is the one that handles that type correctly and gives the agent the metadata to decide.

Quick question

A practice exam question on this domain. It counts towards your progress.

A furniture retailer's support agent has two tools for account questions: get_customer for profile data and lookup_order for orders. During a design review, the team looks at the draft description for lookup_order: "Queries the orders database. Accepts order_id (string). Returns JSON with status, items and total. Rate limit: 100 requests/min." The description was copied from the internal API documentation written by the backend team.

In staging, the agent sometimes calls lookup_order for customer-profile questions such as "what email do you have on file for me?", which belong to get_customer. The staging environment uses the same model and system prompt that will go to production next month.

Which addition to the draft would most improve tool selection?

Practise this domain in a practice exam →