Errors
Failures arrive on two different channels, and the difference matters: one is a broken request, the other is something the model is meant to read and react to.
Tool errors
Anything the caller can act on — validation, not found, insufficient scope, insufficient permission, an endpoint error — comes back as a successful JSON-RPC response whose result is flagged isError, carrying the API's own error envelope as text:
{ "jsonrpc": "2.0", "id": 2, "result": {
"isError": true,
"content": [{ "type": "text",
"text": "{ \"error\": { \"code\": \"NOT_FOUND\", \"message\": \"Portal user not found\" } }" }]
} }
The code vocabulary is the REST API's, unchanged. The ones you will meet most:
code | When |
|---|---|
VALIDATION_ERROR | The arguments failed the endpoint's validation; the details name the fields. |
NOT_FOUND | No such record, or it belongs to another organization. |
CONFLICT / DUPLICATE_ERROR | external_id already in use, or a duplicated business key. |
BAD_REQUEST | Business rule violated — for example, resending the invitation of a portal user who is already active. |
FORBIDDEN | The operation is not allowed on this resource in the state it is in. |
EXTERNAL_SERVICE_ERROR | An external service the operation depends on refused or did not answer. |
USER_DECLINED | On the 2026-07-28 era, the user declined or cancelled the confirmation of a destructive tool. Nothing was changed. |
confirmation_required | The tool is destructive and the client cannot confirm: it is on the 2025 era or did not declare elicitation forms. Use a client on revision 2026-07-28 with elicitation. Nothing was executed. |
confirmation_replayed | The confirmation sent had already been used — each one runs a call once. Call the tool again to be asked again. Nothing was executed. |
confirmation_unavailable | The server could not record the confirmation right now, so it refused the tool. Nothing was executed; try again later. |
And the four MCP adds of its own, because they are about authorization, not about the resource:
code | Who resolves it |
|---|---|
insufficient_scope | The token scope does not reach the tool: the resource is not in the token, or write access to it is missing. Use a token that reaches the resource with the access requested — through the OAuth flow access is read-only today; a personal token can carry write access. |
insufficient_permission | An organization admin, by granting the permission the error names. |
membership_inactive | Reinstating the person who authorized the client — no permission fixes a dead membership. |
key_owner_not_member | Authorizing the client again with an account that is a member of the organization. |
Those four are separate on purpose: they are different conversations, with different people. A single error would say "you may not" without saying whom to ask. See Authentication.
input_required is not an error
On the 2026-07-28 era, the first tools/call to a destructive tool may come back with resultType: "input_required" and a confirmation request for the user. That is the normal flow, not a failure: the client shows the question and re-sends the same call with the answer. See Confirming destructive tools.
Protocol errors
A malformed message gets a JSON-RPC error object instead of a result:
| Code | Meaning |
|---|---|
-32700 | Parse error — the body is not valid JSON |
-32600 | Invalid request — not a JSON-RPC object, or an array (batching is not supported) |
-32601 | Method not found |
-32602 | Invalid params — unknown tool, prompt or argument, name missing; on the 2026-07-28 era, also resource not found |
-32002 | Resource not found — 2025 era only (2026-07-28 uses -32602) |
-32603 | Internal error — an unexpected failure while running the tool |
{ "jsonrpc": "2.0", "id": 3,
"error": { "code": -32601, "message": "Method not found: tools/describe" } }
Transport errors
Rejections that happen before the JSON-RPC message is read are plain HTTP responses with the API's error envelope: missing or invalid token, unsupported protocol version, disallowed Origin, rate limit, a body over 1 MB (413, with JSON-RPC error -32600 Request body too large). They are listed in Authentication → Failure modes.
Why isError and not a JSON-RPC error
A 404 on a portal user is not a defect in the MCP client — it is information about the world, and the model on the other side needs it to correct itself. Burying it in a protocol error would make the client treat it as a transport failure, hide the text and, at best, retry identically. Hence the rule: if the caller can act on it, it is a result; if the request is broken, it is an error.
Observability
Every tools/call writes a structured line with the tool, the organization, the token, the status and the duration. Writes also appear in the organization's audit trail, written by the dispatched endpoint itself and attributed to the person who authorized the client — what an agent did shows up next to what a person did, on the same screen.