C Claude Cert Prep All Claude Certifications

Error Handling and Tool Distribution Choices

How to design structured tool error responses and how to choose between a built-in tool, an MCP server, and a skill.

Tools & MCP·Lesson 6 of 6·8 min

This lesson covers two related decisions that show up together on the exam: how a tool should report failure, and which mechanism — built-in tool, MCP server, or skill/slash command — should carry a given piece of functionality in the first place.

Structured error responses

When a tool call fails for any reason — invalid input that passed schema validation but failed at runtime, a downstream service being unavailable, a permission denial, a not-found condition — the response sent back to the model should always be a tool_result with is_error: true and a message describing what went wrong in plain, actionable language. This is what lets the model self-correct on the next turn: it can see that the call failed, understand roughly why, and either retry with adjusted input, try a different tool, or surface the problem to the user instead of confabulating a fake success.

What that error message should never contain is a raw stack trace, a database error code with no explanation, or an internal exception string. Those are meaningless to the model as guidance and often leak implementation details (table names, internal paths, library versions) that shouldn't be exposed. The fix is to catch the underlying error in your tool implementation and translate it into a short, human-readable sentence describing what went wrong and, where possible, what a valid retry would look like — for example, "no customer found with id cus_004, check the id format" rather than "KeyError: 'cus_004' at db/lookup.py:52."

Exam trap A question shows a tool implementation that, on failure, returns the full exception text (including file paths and a stack trace) inside a tool_result with is_error:true correctly set. Test-takers sometimes mark this fully correct because the is_error flag is present. But returning a raw stack trace as the error content is itself the flaw being tested — is_error:true is necessary but not sufficient; the content also has to be a clear, actionable message the model can act on. Both conditions must hold.

Choosing how to expose a capability

Given some piece of functionality you want an agent to have, there are three common ways to expose it, and the exam expects you to pick the right one for a given scenario rather than defaulting to MCP for everything:

Exam trap A scenario describes wanting to automate a purely local, repo-specific code review checklist with no external system involved, and offers "build an MCP server for it" as an answer choice. This is the over-engineering trap: MCP is for external-system integration, and a purely local, project-specific workflow with nothing external to talk to belongs in a skill or slash command, not a server. Don't reach for MCP just because the exam domain is about MCP — the correct answer is sometimes explicitly not MCP.
Scenario: a team wants their agent to (1) run repo-local lint-and-format checks before committing, (2) query their production Postgres database, and (3) fetch arbitrary web pages for research. The right distribution is: (1) a skill or slash command, since it's a local workflow with no external system; (2) an MCP server, since Postgres is an external system that multiple team members and projects will want to query the same way; (3) the built-in web fetch tool, since Claude already ships one and there's no reason to rebuild it.

Try it

Take a tool you've built or are considering building. Write out its failure modes (bad input, downstream timeout, not-found, permission denied) and draft the exact is_error:true message text for each — not a category, the literal sentence the model would receive. Then separately classify the tool itself: should it actually be a custom tool at all, or does it duplicate a built-in, belong in an MCP server, or belong in a skill instead?

← Transport Choice: stdio vs. Streamable HTTP CLAUDE.md and the Memory Hierarchy →