Skip to content

Commit 6420265

Browse files
mowens3claude
andcommitted
Update README with fluent builder and ErrorBag docs
Document new v1.2.0 features: - McpError fluent builder with factory methods - ErrorBag for collecting multiple errors - JSON-RPC 2.0 error code mapping - Integration examples Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b26f3b3 commit 6420265

File tree

1 file changed

+104
-56
lines changed

1 file changed

+104
-56
lines changed

README.md

Lines changed: 104 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
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.
1616
composer 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
2286
use 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

108156
These errors may resolve on retry:

0 commit comments

Comments
 (0)