Skip to content

Errors and retries

REST errors use a stable envelope:

{
"error": {
"code": "insufficient_scope",
"status": 403,
"message": "The caller cannot perform this operation.",
"request_id": "req_…",
"retryable": false,
"details": {}
}
}

Branch on code, status, and retryable, never on message. Log request_id for operator correlation. Honor retry_after_seconds when present.

Common classes include:

Status Typical codes Handling
400 invalid_request, invalid_json Fix the request; do not retry unchanged
401 invalid_token, session_expired Refresh or replace credentials
403 insufficient_scope, origin_not_allowed Change authorization or browser origin
404 not_found, route_not_found Re-discover opaque IDs; verify the route
409 idempotency_conflict, draft_conflict Reconcile state; do not invent a new retry body
413 body or upload too large Reduce content before retrying
422 unknown_scope, cardinality or provider constraint Correct semantic input
429 rate or waiter limit Wait for the supplied retry interval
502–504 provider or upstream failure Retry only when retryable is true

MCP reports protocol failures as JSON-RPC errors and operation failures in the tool result. Use the structured error fields returned by the tool. A timed-out wait is normally a successful result with timed_out: true, not an error.

For mutating calls, retry with the same idempotency key and identical body. Reusing a key for a different operation produces a conflict by design.