AI Skill Certs
Tool Design & MCP Integration·Task 2.2·Bloom: remember·Difficulty 1/5·7 min read·Updated 2026-06-07

MCP isError Flag: Signalling Tool Failures to Claude

Implement structured error responses for MCP tools

SUBy Solomon UdohReviewed by Solomon UdohAI-assisted · human-reviewed
In short
The MCP isError flag is a boolean on a tool's result object that signals the tool executed but failed. When it is true, the accompanying content carries a human-readable error message; when it is false or absent, the content is a successful result. The flag is what lets the agent tell a failure apart from a real answer.

What the MCP isError flag is

The MCP isError flag is a single boolean that travels on every tool result a Model Context Protocol server returns. When a tool finishes its work and everything went well, the result carries its content with isError left false or omitted. When the tool ran but could not complete the requested work, the server sets isError: true and puts a description of the failure in the same content field. That one boolean is the whole signalling mechanism, and getting it right is the foundation of every other error-handling pattern in Domain 2.

The reason it matters is subtle. From the protocol's point of view, a tool that times out and a tool that returns a perfect answer look almost identical: both come back as a normal tools/call response with a content array. The only thing that distinguishes a broken result from a good one is the MCP isError flag. Strip the flag away and the model has no reliable way to know whether the text it just received is an answer to trust or an apology to recover from.

MCP isError flag
A boolean field on a tool's CallToolResult. true means the tool executed but failed and the content describes the error; false or absent means the content is a valid result. It is the envelope, not the recovery logic.

Two kinds of failure: protocol errors versus tool errors

The MCP specification is explicit that tools use two error-reporting mechanisms, and conflating them is a classic exam trap. The first is protocol errors, standard JSON-RPC errors with a numeric code, raised for things like an unknown tool name or invalid arguments that never reach your tool's body. The second is tool execution errors, failures that happen inside a tool that did run, such as an upstream API returning a 500, a malformed record, or a business rule rejecting the request. These are reported inside the result with isError: true.

The distinction is not academic. A protocol error means the request was structurally wrong and the call never really happened; the framework usually surfaces it before the model ever acts. A tool execution error means the call happened, the tool tried, and it failed in a way the model is expected to read and respond to. The model reasons about the second category, not the first, which is exactly why the isError envelope has to be present and correct.

Why a flag, and not an exception

Newcomers often expect a failed tool to throw, the way a function in their own code would. MCP deliberately does not work that way for execution failures. A thrown transport exception would tear down the structured round trip and leave the model with nothing to interpret. Instead the failure is returned as data: a normal response whose isError boolean is true and whose content is a sentence the model can read. The agent stays in its loop, sees the error in context, and decides what to do next.

That design choice is what makes Claude agents resilient. Because the error comes back as ordinary content rather than a crash, the model can apologise to a user, try a different tool, or fix its input and retry, all without the surrounding application having to catch and re-inject anything. The flag keeps the conversation intact while still telling the truth about what happened.

How isError routes a tool result
Loading diagram...
Both paths return a normal result; only the isError boolean tells them apart.

How MCP isError maps to the Claude API is_error

When an MCP server is wired into Claude, the MCP isError boolean is surfaced to the model through the Claude Messages API as the is_error field on a tool_result content block. Anthropic's documentation shows the same idea from the API side: if a tool throws during execution, you return the error message in the result content along with "is_error": true, and Claude incorporates that into its reply rather than acting on a missing value. The two names, MCP's isError and the API's is_error, describe the same contract at two layers of the stack.

Knowing both names protects you on the exam. A question may describe an MCP tool or a hand-written Claude tool loop, but the correct behaviour is identical: failures are returned as content with the error boolean set, never disguised as a successful payload. Anthropic even advises writing instructive error text, "Rate limit exceeded. Retry after 60 seconds." beats a bare "failed", because the message is what Claude reads to decide its next move.

isError
the MCP server-side field
is_error
the Claude API tool_result field
boolean
true = failed, false/absent = ok

Where the flag surfaces: the MCP connector

You do not always wire MCP tools by hand. Claude's MCP connector lets the Messages API reach a remote MCP server directly, without a separate MCP client in your application. You declare the server in an mcp_servers array on the request. Each entry carries a type: "url", a name, the server url, and, for an authenticated server, an optional authorization_token. Claude then calls that server's tools as part of its normal turn.

What matters for this knowledge point is that the connector preserves the same failure contract end to end. When a tool on the remote server fails, the connector represents that failure to the model by setting is_error to true on the resulting tool-result content block. The boolean you set inside the MCP server is the very boolean the model reads back through the connector; nothing in the hosted path changes the rule that a failure is returned as flagged data rather than thrown as a transport error.

This is why the discipline is worth getting right at the server itself. The same tool may be reached through a hand-written loop or through the managed connector, and both paths depend on the flag to tell a real answer from a failure. A server that forgets to set it produces phantom answers in either integration, because the one signal the model would have used to notice the failure was never sent.

Writing the error content the flag carries

The flag alone is not enough; it is the envelope around a message. A result with isError: true and content that just says "error" technically signals failure but tells the model nothing it can act on. The content should name what failed and, where possible, hint at what to do, whether the operation is worth retrying, what input was wrong, or that the request simply cannot be honoured. Later knowledge points turn that hint into a structured, machine-readable shape, but even at this foundational level the habit is to pair the boolean with a description, not a shrug.

This is why the exam frames isError as the first step in a chain, not the whole answer. You set the flag so the model knows there is a problem; you write the content so the model knows which problem. Domain 2's later task statements then add categories and metadata on top of this base.

Worked example

A customer-support agent calls an MCP billing tool, get_invoice, which depends on a payments API that is currently timing out.

The tool's job is to fetch an invoice for a stated month. On this call the upstream payments API does not respond within the timeout. You now have a choice, and only one option is correct under the MCP contract.

The wrong move is to catch the timeout and return a normal result whose content reads "No invoice found." That looks like a successful empty answer. The model has no flag to inspect, so it reports to the customer that there is no invoice for May, a confident, wrong statement built on a swallowed failure.

The correct move is to return the result with isError: true and content such as "Timed out reaching the billing service after 5s; the invoice could not be retrieved." Now the model sees an explicit failure. It can tell the customer it is having trouble reaching billing, retry the call, or escalate, none of which were possible when the failure masqueraded as data. Notice that the tool still returned; it did not throw. The agentic loop stayed alive, and the flag did its one job: distinguishing a failure from an answer.

Common misreadings to avoid

Misconception

If a tool fails, it should throw an exception so the agent stops.

What's actually true

For ordinary execution failures, MCP tools return a normal result with isError set to true, not a thrown transport error. The agent is meant to stay in its loop, read the error content, and recover. Exceptions are reserved for protocol-level problems like an unknown tool or invalid arguments.

Misconception

Returning the error text in the content is enough; the flag is optional.

What's actually true

Without isError: true, an error message is indistinguishable from a successful result. The model may quote your failure text back to the user as if it were the answer. The flag is what changes how the content is interpreted, so it is never optional for a failed call.

What the result object carries besides the flag

It helps to picture the whole result object the boolean lives on. An MCP tool result is not just a flag; it is a structured envelope with a content array of blocks, usually text, sometimes images or embedded resources, and, when the tool declares an output schema, a structuredContent object as well. The isError boolean sits alongside all of that and governs how every other field is read. The same content array means "here is your answer" when the flag is false and "here is what went wrong" when the flag is true.

That framing keeps you from a common confusion: the flag does not replace the content, it reframes it. A failed result still carries content, and that content is where the explanation lives. So a correct error result is always two things working together, the boolean that classifies the outcome and the content that describes it. Neither alone is sufficient. The flag with no content tells the model nothing actionable; rich content with no flag is read as a successful answer.

Why a swallowed failure is worse inside an agentic loop

In a single, one-shot tool call, a failure disguised as success produces one wrong answer, which is bad but bounded. Inside an agentic loop the same mistake compounds. The model takes the phantom answer, reasons one step further, calls another tool based on it, and builds an entire chain of decisions on a foundation that was never real. By the time the damage surfaces, several turns have passed and the original failure is buried deep in the transcript.

This is why the isError discipline is treated as foundational rather than cosmetic. An agent is, by definition, a system that acts on tool results across many turns. If even one tool quietly returns failure as success, the loop has no way to notice, because the signal it would have used to notice was never sent. Honest error signalling at every tool is what lets the loop self-correct early instead of confidently marching off a cliff.

A short checklist for tool authors

When you write or review an MCP tool, three quick questions catch most mistakes. First, does every failure path set the error flag, or are some failures falling through as empty or default success results? Second, does the content on a failed result describe the problem in plain, instructive language rather than a bare label or a raw stack trace? Third, are protocol-level problems (unknown tool, bad arguments) left to the JSON-RPC error channel rather than being smuggled into a tool-execution result?

Run those three checks and you have covered the substance of this knowledge point. They map directly onto how the exam probes it: a tool that forgets the flag, a tool whose error text is useless, or an author who conflates the two error channels. Each is a small omission with outsized consequences for an agent that trusts what its tools return.

How this shows up on the exam

Domain 2 is worth 18% of the exam, and Task Statement 2.2, structured error responses for MCP tools, opens with exactly this concept. Questions rarely ask you to recite the field name. Instead they describe a tool that returns "no results" when it actually crashed, or an agent that keeps acting on phantom answers, and ask you to name the root cause. The answer traces back to a missing or misused isError flag: a failure was returned as a success, so the model could not tell the difference. Get this base right and the categories, metadata, and propagation patterns built on top of it have somewhere solid to stand.

Watch, too, for items that test the protocol-versus-execution boundary directly. A stem may describe a request that names a tool the server does not expose, and ask whether that should come back as isError: true. It should not, an unknown tool is a protocol error, not an execution failure, and recognising that line is part of demonstrating you understand what the flag is actually for.

Check your understanding

An MCP-connected support agent calls a refund-lookup tool. When the backend database is unreachable, the tool catches the exception and returns a normal result whose content is the empty string. Users start seeing the agent confidently say 'there are no refunds on this account.' What is the root cause?

People also ask

What does the isError flag do in MCP?
It marks a tool result as a failure rather than a success. The tool still returns normally, but isError: true tells the client and the model the operation did not complete, so the model can recover instead of acting on bad data.
How does an MCP tool report a failure?
It returns a normal result object with isError set to true and a content block describing what went wrong in plain language. It does not throw a transport exception for ordinary execution failures.
Is an MCP protocol error the same as a tool execution error?
No. Protocol errors are JSON-RPC errors for unknown tools or bad arguments at the transport layer. Tool execution errors are normal results carrying isError: true, and only those are surfaced to the model to reason about.

Watch and learn

Official Anthropic Academy lessons first, then hand-picked walkthroughs. Videos load only when you press play.

AI Engineer

Building Agents with Model Context Protocol - Full Workshop with Mahesh Murag of Anthropic

Why watch: Anthropic's own workshop walks through how MCP tools return results to the agent, including how tool-call outcomes (success vs failure) are surfaced so the model can reason about them.

More videos for this concept

References & primary sources

Adaptive study

Master this concept with Archie

Practice it inside an adaptive study session. Archie, your Socratic AI tutor, tracks your mastery with Bayesian Knowledge Tracing and schedules the perfect next review.

Start studying