Standardized MCP error codes with semantic categories, HTTP/JSON-RPC mapping, and fluent builders
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_error_codes-1.0.0.tar.gz.
File metadata
- Download URL: mcp_error_codes-1.0.0.tar.gz
- Upload date:
- Size: 15.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6af1e4ffe15b2747c7214da973ed036dc8512c75574d760ed246ded480bf29cc
|
|
| MD5 |
ad972a222d1a61441841912ff479f3cf
|
|
| BLAKE2b-256 |
1cd77011dce2dcb3ce38355bed2c1c5a5a5a1af79083f9404b35d3f9c813c13b
|
File details
Details for the file mcp_error_codes-1.0.0-py3-none-any.whl.
File metadata
- Download URL: mcp_error_codes-1.0.0-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64bef2a16f51cc3da84bcc551e64bccf059cb86cd8cfe9d3f27b0b702b9a5600
|
|
| MD5 |
6dbba6ada778dc8882676d9af651732d
|
|
| BLAKE2b-256 |
5107c4cbf3f785d25071c5ec66d1696cc1a6e0d1169f556e764c17275982104e
|