Should an MCP tool failure be a protocol error or a failed result?
A tool that ran and failed should come back as a normal result marked isError: true, with the reason in the content; a protocol error is reserved for the request itself being invalid, an unknown tool name or a malformed call the server never even attempted to run. The distinction decides whether the model ever sees the failure. A failed-result error rides back through the normal response, so the model reads it and can retry with different arguments, ask for clarification, or give up gracefully. A protocol error fails the request at the transport level and the client’s SDK typically raises an exception; the spec lets a client forward that error to the model anyway, but says doing so is less likely to end in a successful retry than a failed result would.
Servers mix the two up often, reporting a tool’s own failure as a protocol error, which leaves the agent with no way to recover. Reliable tool calling depends on the model seeing what went wrong, not just on the call technically succeeding at the transport level.