MCP Error Handling Extension: Structured Failures and Retry Strategy
Every MCP tool failure should return a structured response the agent can act on — not an opaque error that forces the agent to guess.
Why Structured Error Handling Matters
An MCP tool that fails with an unstructured error forces the calling agent to guess what went wrong. The agent may retry indefinitely, report a nonsensical error to the user, or silently drop the failed action. None of these is acceptable in a production enterprise deployment.
Structured error handling means every MCP tool failure returns a response the agent can act on: a machine-readable error code, a human-readable description, and enough context to decide what to do next.
The Standard Error Response Format
Every MCP tool should return a consistent response object whether it succeeds or fails:
success: boolean— did the tool call succeed?data: object— the result data (present on success, null on failure)error_code: string— machine-readable error category (e.g., NOT_FOUND, PERMISSION_DENIED, SYSTEM_UNAVAILABLE, VALIDATION_ERROR)error_message: string— human-readable description of what went wrongretry_recommended: boolean— should the agent try again?retry_after_seconds: integer— if retrying, how long to wait
Error Categories and Agent Behavior
| Error Code | Meaning | Agent Should |
|---|---|---|
| NOT_FOUND | The requested resource doesn't exist | Inform user, stop retrying |
| PERMISSION_DENIED | Agent lacks authorization for this action | Escalate to human, stop retrying |
| VALIDATION_ERROR | Input parameters are invalid | Report validation details, allow correction |
| SYSTEM_UNAVAILABLE | Target system is temporarily down | Retry with backoff after retry_after_seconds |
| RATE_LIMITED | Too many calls in the time window | Pause and retry after retry_after_seconds |
Retry Strategy
Agents should implement exponential backoff with jitter for retryable errors. Never retry PERMISSION_DENIED or NOT_FOUND — these won't resolve with retries. Always retry SYSTEM_UNAVAILABLE and RATE_LIMITED with the specified delay.