Standardized MCP error codes with semantic categories, HTTP/JSON-RPC mapping, and fluent builders (Python)
mcp-error-codes
Standardized MCP error codes with semantic categories, HTTP/JSON-RPC mapping, and fluent builders for Python.
Installation
pip install mcp-error-codes
Features
- 28 predefined error codes covering access, resource, validation, operation, and domain errors
- Semantic categories for error classification
- HTTP status code mapping for REST APIs
- JSON-RPC 2.0 code mapping for MCP protocol compliance
- Fluent error builder (
McpError) for creating rich error responses - Error collection (
ErrorBag) for aggregating multiple validation errors - Full type hints with strict mypy compliance
- Zero runtime dependencies
Quick Start
Using Error Codes Directly
from mcp_error_codes import ErrorCode, NOT_FOUND
# Use constants
if user is None:
return {"success": False, "code": NOT_FOUND}
# Use helper methods
ErrorCode.is_valid("NOT_FOUND") # True
ErrorCode.get_category(NOT_FOUND) # "resource"
ErrorCode.get_http_status(NOT_FOUND) # 404
ErrorCode.get_json_rpc_code(NOT_FOUND) # -32002
ErrorCode.is_recoverable(NOT_FOUND) # False
Using Fluent Error Builder
from mcp_error_codes import McpError
# Simple errors
error = McpError.not_found("User", 123)
print(error.get_message()) # "User '123' not found."
print(error.get_http_status()) # 404
# With suggestions and context
detailed = (
McpError.validation("email", "Invalid format")
.with_suggestion("Use a valid email like user@example.com")
.with_context({"provided": "not-an-email"})
)
# Convert to different formats
detailed.to_dict() # {"success": False, "error": "...", ...}
detailed.to_json_rpc_error() # {"code": -32602, "message": "...", ...}
Collecting Multiple Errors
from mcp_error_codes import ErrorBag, McpError
errors = ErrorBag()
if not data.get("email"):
errors.add_validation("email", "Required")
if not data.get("name"):
errors.add_validation("name", "Required")
if data.get("age", 0) < 0:
errors.add(McpError.validation("age", "Must be positive"))
if errors.has_errors():
return errors.to_dict()
# {
# "success": False,
# "error": "3 validation errors occurred.",
# "code": "VALIDATION_ERROR",
# "error_count": 3,
# "errors": [...]
# }
Error Codes
Access Control
| Code | Description | HTTP | JSON-RPC |
|------|-------------|------|----------|
| INSUFFICIENT_SCOPE | Write operations not allowed | 403 | -32001 |
| ADMIN_REQUIRED | Admin privileges required | 403 | -32001 |
| ACCESS_DENIED | Generic access denied | 403 | -32001 |
| RATE_LIMIT_EXCEEDED | Rate limit exceeded | 429 | -32003 |
| READ_ONLY_MODE | System in read-only mode | 403 | -32004 |
Resource
| Code | Description | HTTP | JSON-RPC |
|------|-------------|------|----------|
| NOT_FOUND | Resource not found | 404 | -32002 |
| ALREADY_EXISTS | Resource already exists | 409 | -32005 |
| ENTITY_IN_USE | Cannot delete, entity in use | 409 | -32005 |
| ENTITY_PROTECTED | Entity is protected | 409 | -32005 |
| MISSING_DEPENDENCY | Required dependency missing | 500 | -32006 |
Validation
| Code | Description | HTTP | JSON-RPC |
|------|-------------|------|----------|
| VALIDATION_ERROR | Input validation failed | 400 | -32602 |
| INVALID_NAME | Invalid machine name | 400 | -32602 |
| INVALID_FILE_TYPE | Invalid file type | 400 | -32602 |
| PAYLOAD_TOO_LARGE | Payload exceeds limit | 413 | -32009 |
| MISSING_REQUIRED | Required parameter missing | 400 | -32602 |
Operation
| Code | Description | HTTP | JSON-RPC |
|------|-------------|------|----------|
| INTERNAL_ERROR | Internal server error | 500 | -32603 |
| OPERATION_FAILED | Operation failed | 500 | -32011 |
| TIMEOUT | Operation timed out | 408 | -32007 |
| CONFIRMATION_REQUIRED | Needs user confirmation | 500 | -32010 |
| INVALID_TOOL | Tool not found/invalid | 400 | -32601 |
| EXECUTION_FAILED | Tool execution failed | 500 | -32603 |
| INSTANTIATION_FAILED | Tool instantiation failed | 500 | -32603 |
API Reference
ErrorCode
# All error code constants
ErrorCode.NOT_FOUND
ErrorCode.VALIDATION_ERROR
# ... etc
# Helper methods
ErrorCode.all() -> dict[str, str]
ErrorCode.is_valid(code: str) -> bool
ErrorCode.get_category(code: str) -> Literal["access", "resource", "validation", "operation", "domain"]
ErrorCode.is_recoverable(code: str) -> bool
ErrorCode.get_http_status(code: str) -> int
ErrorCode.get_json_rpc_code(code: str) -> int
McpError
# Factory methods
McpError.not_found(entity_type: str, identifier: str | int | None = None) -> McpError
McpError.access_denied(resource: str | None = None) -> McpError
McpError.validation(field: str, reason: str) -> McpError
McpError.rate_limited(retry_after: int | None = None) -> McpError
McpError.internal(message: str) -> McpError
# ... and more
# Builder methods
error.with_suggestion(suggestion: str) -> McpError
error.with_context(context: dict[str, Any]) -> McpError
error.with_detail(key: str, value: Any) -> McpError
error.retry_after(seconds: int) -> McpError
# Getters
error.get_code() -> str
error.get_message() -> str
error.get_category() -> str
error.get_http_status() -> int
error.get_json_rpc_code() -> int
# Conversion
error.to_dict() -> ErrorDict
error.to_json_rpc_error() -> JsonRpcError
error.to_call_tool_result() -> CallToolResult # requires mcp package
ErrorBag
# Construction
ErrorBag()
ErrorBag.from_list(errors: list[McpError]) -> ErrorBag
# Adding errors
bag.add(error: McpError) -> ErrorBag
bag.add_validation(field: str, reason: str) -> ErrorBag
bag.merge(other: ErrorBag) -> ErrorBag
# Querying
bag.has_errors() -> bool
bag.is_empty() -> bool
bag.count() -> int
bag.all() -> list[McpError]
bag.first() -> McpError | None
bag.for_field(field: str) -> list[McpError]
bag.by_category(category: str) -> list[McpError]
# Conversion
bag.to_dict() -> ErrorBagDict
bag.to_json_rpc_error() -> dict
bag.to_call_tool_result() -> CallToolResult # requires mcp package
Cross-Language Support
This package is part of the MCP error codes ecosystem:
| Language | Package |
|----------|---------|
| Python | mcp-error-codes |
| TypeScript | @codewheel/mcp-error-codes |
| PHP | code-wheel/mcp-error-codes |
All packages maintain API parity for consistent error handling across your stack.
License
MIT