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
Metadata
Release files for mcp-error-codes 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mcp_error_codes-1.0.0.tar.gz | 15.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_error_codes-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.7 kB
Release files / mcp_error_codes-1.0.0.tar.gz
| Download URL | mcp_error_codes-1.0.0.tar.gz |
|---|---|
| Size | 15.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6af1e4ffe15b2747c7214da973ed036dc8512c75574d760ed246ded480bf29cc
|
|
BLAKE2b-256 checksum How to use checksums |
1cd77011dce2dcb3ce38355bed2c1c5a5a5a1af79083f9404b35d3f9c813c13b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / mcp_error_codes-1.0.0-py3-none-any.whl
| Download URL | mcp_error_codes-1.0.0-py3-none-any.whl |
|---|---|
| Size | 13.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
64bef2a16f51cc3da84bcc551e64bccf059cb86cd8cfe9d3f27b0b702b9a5600
|
|
BLAKE2b-256 checksum How to use checksums |
5107c4cbf3f785d25071c5ec66d1696cc1a6e0d1169f556e764c17275982104e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Security for mcp-error-codes 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.