Domain 2 · Lesson 2 · Tool Design & MCP (18%)

Structured Error Responses for MCP Tools

Task Statement 2.2 — an error is data the agent reasons over, not a dead end.

Course progress: Domain 2 ▸ lesson 2 of ~4

A generic "Operation failed" tells the agent nothing. It can't decide whether to retry, rephrase, escalate, or explain. Structured errors turn failures into decisions.

The isError flag + structured metadata

MCP uses an isError flag to signal a tool failure back to the agent. But the flag alone isn't enough — attach metadata:

The error taxonomy (know all four)

CategoryExampleRetryable?Agent should…
TransientTimeout, service unavailableYesRetry (ideally recover locally)
ValidationMalformed inputAfter fixing inputCorrect the input, then retry
BusinessPolicy violation (refund too large)NoExplain to the user; don't retry
PermissionNot authorizedNoEscalate / request access
Why it matters Returning isRetryable: false on a business error prevents wasted retry loops and lets the agent give a customer-friendly explanation instead of hammering the tool.

Two distinctions the exam tests

Access failure ≠ empty result A timeout (access failure) needs a retry decision. A valid empty result (query succeeded, zero matches) is a success — the agent should treat "no orders found" differently from "couldn't reach the order service." Collapsing them is a classic bug.

Local recovery before propagation: a subagent should handle transient failures itself (retry locally) and only propagate up errors it can't resolve — and when it does, include what it attempted and any partial results (this bridges into Domain 5's error propagation).

Check yourself

A refund exceeds policy. The MCP tool should return an error that is categorized as:
Correct: option 2. A policy violation is a business error, non-retryable; the agent should explain, not retry. Marking it transient/validation would trigger pointless retries; permission is a different failure class.
An order query returns zero rows because the customer genuinely has no orders. The tool should signal this as:
Correct: option 3. A valid empty result is a successful query with no matches — distinct from an access failure. Flagging it as an error causes needless retries and can misreport "no data" as "system down."
Decision rules Failure → return category + isRetryable + readable message. Business/permission → not retryable, explain/escalate. Transient → retry, recover locally first. Zero matches → success with empty set, never an error.
Ask your teacher. Want the exact MCP error payload shape, or how local recovery interacts with coordinator propagation (Domain 5)? Ask.