66[ ![ PHP Version] ( https://img.shields.io/packagist/php-v/code-wheel/mcp-error-codes.svg )] ( https://packagist.org/packages/code-wheel/mcp-error-codes )
77[ ![ License] ( https://poser.pugx.org/code-wheel/mcp-error-codes/license )] ( https://packagist.org/packages/code-wheel/mcp-error-codes )
88
9- Standardized error codes for MCP (Model Context Protocol) servers in PHP.
9+ Standardized error codes and fluent error builders for MCP (Model Context Protocol) servers in PHP.
1010
1111** Zero dependencies** - pure PHP 8.1+.
1212
@@ -16,7 +16,71 @@ Standardized error codes for MCP (Model Context Protocol) servers in PHP.
1616composer require code-wheel/mcp-error-codes
1717```
1818
19- ## Usage
19+ ## Quick Start
20+
21+ ### Fluent Error Builder
22+
23+ ``` php
24+ use CodeWheel\McpErrorCodes\McpError;
25+
26+ // Simple errors with factory methods
27+ $error = McpError::notFound('user', 'user-123');
28+ $error = McpError::accessDenied('delete', 'admin permission required');
29+ $error = McpError::validation('email', 'Invalid format');
30+ $error = McpError::rateLimited('tool_calls');
31+
32+ // Add context and suggestions
33+ $error = McpError::notFound('user', 'user-123')
34+ ->withSuggestion('Check if user ID is correct')
35+ ->withContext(['searched_in' => 'active_users']);
36+
37+ // Convert to different formats
38+ $array = $error->toArray(); // ['success' => false, 'error' => '...', 'code' => '...']
39+ $result = $error->toToolResult(); // ToolResult with success=false
40+ $rpcError = $error->toJsonRpcError(); // JSON-RPC 2.0 Error object
41+
42+ // Rate limiting with retry hint
43+ $error = McpError::rateLimited('api_calls')
44+ ->retryAfter(60);
45+ ```
46+
47+ ### ErrorBag for Multiple Errors
48+
49+ ``` php
50+ use CodeWheel\McpErrorCodes\ErrorBag;
51+ use CodeWheel\McpErrorCodes\McpError;
52+
53+ $errors = new ErrorBag();
54+
55+ // Collect validation errors
56+ if (empty($input['email'])) {
57+ $errors->addValidation('email', 'Email is required');
58+ }
59+ if (!filter_var($input['email'] ?? '', FILTER_VALIDATE_EMAIL)) {
60+ $errors->addValidation('email', 'Invalid email format');
61+ }
62+ if (strlen($input['name'] ?? '') < 2) {
63+ $errors->addValidation('name', 'Name must be at least 2 characters');
64+ }
65+
66+ // Check and return
67+ if ($errors->hasErrors()) {
68+ return $errors->toToolResult();
69+ }
70+
71+ // Filter errors by field
72+ $emailErrors = $errors->forField('email');
73+
74+ // Merge error bags
75+ $errors->merge($otherErrors);
76+
77+ // Iterate over errors
78+ foreach ($errors as $error) {
79+ echo $error->getMessage();
80+ }
81+ ```
82+
83+ ### Error Code Constants
2084
2185``` php
2286use CodeWheel\McpErrorCodes\ErrorCode;
@@ -37,12 +101,46 @@ $shouldRetry = ErrorCode::isRecoverable(ErrorCode::RATE_LIMIT_EXCEEDED); // true
37101// Map to HTTP status
38102$httpStatus = ErrorCode::getHttpStatus(ErrorCode::NOT_FOUND); // 404
39103
40- // Validate error codes
41- if ( ErrorCode::isValid($code)) {
42- // Known error code
43- }
104+ // Map to JSON-RPC 2.0 error codes
105+ $rpcCode = ErrorCode::getJsonRpcCode(ErrorCode::VALIDATION_ERROR); // -32602
106+ $rpcCode = ErrorCode::getJsonRpcCode(ErrorCode::NOT_FOUND); // -32002
107+ $rpcCode = ErrorCode::getJsonRpcCode(ErrorCode::INTERNAL_ERROR); // -32603
44108```
45109
110+ ## Available Factory Methods
111+
112+ | Method | Description | Error Code |
113+ | --------| -------------| ------------|
114+ | ` McpError::notFound($type, $id) ` | Entity not found | NOT_FOUND |
115+ | ` McpError::accessDenied($action, $reason) ` | Permission denied | ACCESS_DENIED |
116+ | ` McpError::validation($field, $message) ` | Input validation error | VALIDATION_ERROR |
117+ | ` McpError::rateLimited($resource) ` | Rate limit exceeded | RATE_LIMIT_EXCEEDED |
118+ | ` McpError::alreadyExists($type, $id) ` | Duplicate entity | ALREADY_EXISTS |
119+ | ` McpError::insufficientScope($required) ` | Missing scope | INSUFFICIENT_SCOPE |
120+ | ` McpError::internalError($message) ` | Server error | INTERNAL_ERROR |
121+ | ` McpError::timeout($operation) ` | Operation timed out | TIMEOUT |
122+ | ` McpError::invalidInput($field, $message) ` | Invalid input | VALIDATION_ERROR |
123+ | ` McpError::missingRequired($field) ` | Required field missing | MISSING_REQUIRED |
124+ | ` McpError::operationFailed($message) ` | Operation failed | OPERATION_FAILED |
125+ | ` McpError::serviceUnavailable($service) ` | External service down | SERVICE_UNAVAILABLE |
126+ | ` McpError::entityProtected($type, $id) ` | Cannot modify protected | ENTITY_PROTECTED |
127+ | ` McpError::entityInUse($type, $id) ` | Cannot delete in-use | ENTITY_IN_USE |
128+ | ` McpError::confirmationRequired($action) ` | Needs confirmation | CONFIRMATION_REQUIRED |
129+
130+ ## JSON-RPC 2.0 Error Code Mapping
131+
132+ MCP uses JSON-RPC 2.0. This package maps semantic error codes to standard JSON-RPC codes:
133+
134+ | Error Code | JSON-RPC Code | Description |
135+ | ------------| ---------------| -------------|
136+ | VALIDATION_ERROR | -32602 | Invalid params |
137+ | INVALID_TOOL | -32601 | Method not found |
138+ | NOT_FOUND | -32002 | Resource not found |
139+ | ACCESS_DENIED | -32003 | Access denied |
140+ | RATE_LIMIT_EXCEEDED | -32004 | Rate limited |
141+ | INTERNAL_ERROR | -32603 | Internal error |
142+ | TIMEOUT | -32001 | Timeout |
143+
46144## Error Categories
47145
48146| Category | Codes | Description |
@@ -53,56 +151,6 @@ if (ErrorCode::isValid($code)) {
53151| ` operation ` | INTERNAL_ERROR, OPERATION_FAILED, TIMEOUT, CONFIRMATION_REQUIRED | Operation execution errors |
54152| ` domain ` | TEMPLATE_NOT_FOUND, CRON_FAILED, MIGRATION_FAILED, etc. | Domain-specific errors |
55153
56- ## All Error Codes
57-
58- ### Access Control
59- - ` INSUFFICIENT_SCOPE ` - Write operations not allowed
60- - ` ADMIN_REQUIRED ` - Operation requires admin scope
61- - ` ACCESS_DENIED ` - Generic access denied
62- - ` RATE_LIMIT_EXCEEDED ` - Rate limit exceeded
63-
64- ### Resource
65- - ` NOT_FOUND ` - Entity/resource not found
66- - ` ALREADY_EXISTS ` - Duplicate entity
67- - ` ENTITY_IN_USE ` - Cannot delete/modify entity in use
68- - ` ENTITY_PROTECTED ` - Protected entity
69-
70- ### Validation
71- - ` VALIDATION_ERROR ` - Input validation failed
72- - ` INVALID_NAME ` - Invalid machine name format
73- - ` INVALID_FILE_TYPE ` - Invalid file type
74- - ` PAYLOAD_TOO_LARGE ` - Size limit exceeded
75- - ` MISSING_REQUIRED ` - Required parameter missing
76-
77- ### Operation
78- - ` INTERNAL_ERROR ` - Internal server error
79- - ` OPERATION_FAILED ` - Operation failed
80- - ` TIMEOUT ` - Operation timed out
81- - ` CONFIRMATION_REQUIRED ` - Confirmation needed
82-
83- ### Domain-Specific
84- - ` TEMPLATE_NOT_FOUND ` - Template not found
85- - ` CRON_FAILED ` - Cron job failed
86- - ` MIGRATION_FAILED ` - Migration failed
87- - ` RECIPE_FAILED ` - Recipe application failed
88- - ` CONFIG_ERROR ` - Configuration error
89- - ` MEDIA_ERROR ` - Media processing failed
90- - ` SERVICE_UNAVAILABLE ` - External service unavailable
91-
92- ## HTTP Status Mapping
93-
94- | Error Code | HTTP Status |
95- | ------------| -------------|
96- | ACCESS_DENIED, INSUFFICIENT_SCOPE, ADMIN_REQUIRED | 403 |
97- | RATE_LIMIT_EXCEEDED | 429 |
98- | NOT_FOUND, TEMPLATE_NOT_FOUND | 404 |
99- | ALREADY_EXISTS, ENTITY_IN_USE, ENTITY_PROTECTED | 409 |
100- | VALIDATION_ERROR, INVALID_NAME, INVALID_FILE_TYPE, MISSING_REQUIRED | 400 |
101- | PAYLOAD_TOO_LARGE | 413 |
102- | TIMEOUT | 408 |
103- | SERVICE_UNAVAILABLE | 503 |
104- | All others | 500 |
105-
106154## Recoverable Errors
107155
108156These errors may resolve on retry:
0 commit comments