Standardized MCP error codes with semantic categories, HTTP/JSON-RPC mapping, and fluent builders (TypeScript)
@codewheel/mcp-error-codes
Standardized MCP error codes with semantic categories, HTTP/JSON-RPC mapping, and fluent builders for TypeScript/JavaScript.
Installation
npm install @codewheel/mcp-error-codes
Features
- 20+ 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 TypeScript support with strict types
- Zero runtime dependencies
- Tree-shakeable ESM and CommonJS builds
Quick Start
Using Error Codes Directly
import { ErrorCode, NOT_FOUND, getHttpStatus } from '@codewheel/mcp-error-codes';
// Use constants
if (!user) {
return {
success: false,
code: NOT_FOUND,
message: 'User not found',
};
}
// Use helper functions
ErrorCode.isValid('NOT_FOUND'); // true
ErrorCode.getCategory(NOT_FOUND); // 'resource'
ErrorCode.getHttpStatus(NOT_FOUND); // 404
ErrorCode.getJsonRpcCode(NOT_FOUND); // -32002
ErrorCode.isRecoverable(NOT_FOUND); // false
Using Fluent Error Builder
import { McpError } from '@codewheel/mcp-error-codes';
// Simple errors
const error = McpError.notFound('User', 123);
console.log(error.getMessage()); // "User '123' not found."
console.log(error.getHttpStatus()); // 404
// With suggestions and context
const detailed = McpError.validation('email', 'Invalid format')
.withSuggestion('Use a valid email like user@example.com')
.withContext({ provided: 'not-an-email' });
// Convert to different formats
detailed.toArray(); // { success: false, error: '...', code: '...', ... }
detailed.toJsonRpcError(); // { code: -32602, message: '...', data: {...} }
Collecting Multiple Errors
import { ErrorBag, McpError } from '@codewheel/mcp-error-codes';
const errors = new ErrorBag();
if (!input.email) {
errors.addValidation('email', 'Required');
}
if (!input.name) {
errors.addValidation('name', 'Required');
}
if (input.age < 0) {
errors.add(McpError.validation('age', 'Must be positive'));
}
if (errors.hasErrors()) {
return errors.toArray();
// {
// 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 |
Domain-Specific
| Code | Description | HTTP | JSON-RPC |
|------|-------------|------|----------|
| TEMPLATE_NOT_FOUND | Template not found | 404 | -32002 |
| CRON_FAILED | Cron job failed | 500 | -32011 |
| MIGRATION_FAILED | Migration failed | 500 | -32011 |
| SERVICE_UNAVAILABLE | External service down | 503 | -32008 |
API Reference
ErrorCode
// All error code constants
ErrorCode.NOT_FOUND
ErrorCode.VALIDATION_ERROR
// ... etc
// Helper functions
ErrorCode.all(): Record<string, string>
ErrorCode.isValid(code: string): boolean
ErrorCode.getCategory(code: string): 'access' | 'resource' | 'validation' | 'operation' | 'domain'
ErrorCode.isRecoverable(code: string): boolean
ErrorCode.getHttpStatus(code: string): number
ErrorCode.getJsonRpcCode(code: string): number
McpError
// Factory methods
McpError.notFound(entityType: string, identifier?: string | number): McpError
McpError.accessDenied(resource?: string): McpError
McpError.validation(field: string, reason: string): McpError
McpError.rateLimited(retryAfter?: number): McpError
McpError.internal(message: string): McpError
// ... and more
// Builder methods
error.withSuggestion(suggestion: string): McpError
error.withContext(context: Record<string, unknown>): McpError
error.withDetail(key: string, value: unknown): McpError
error.retryAfter(seconds: number): McpError
// Getters
error.getCode(): string
error.getMessage(): string
error.getCategory(): string
error.getHttpStatus(): number
error.getJsonRpcCode(): number
// Conversion
error.toArray(): ErrorArray
error.toJsonRpcError(): JsonRpcError
error.toCallToolResult(): CallToolResult // requires @modelcontextprotocol/sdk
ErrorBag
// Construction
new ErrorBag()
ErrorBag.fromArray(errors: McpError[]): ErrorBag
// Adding errors
bag.add(error: McpError): ErrorBag
bag.addValidation(field: string, reason: string): ErrorBag
bag.merge(other: ErrorBag): ErrorBag
// Querying
bag.hasErrors(): boolean
bag.isEmpty(): boolean
bag.count(): number
bag.all(): McpError[]
bag.first(): McpError | undefined
bag.forField(field: string): McpError[]
bag.byCategory(category: string): McpError[]
// Conversion
bag.toArray(): ErrorBagArray
bag.toJsonRpcError(): JsonRpcError
bag.toCallToolResult(): CallToolResult // requires @modelcontextprotocol/sdk
Cross-Language Support
This package is part of the MCP error codes ecosystem:
| Language | Package |
|----------|---------|
| TypeScript | @codewheel/mcp-error-codes |
| PHP | code-wheel/mcp-error-codes |
| Python | mcp-error-codes (coming soon) |
All packages maintain API parity for consistent error handling across your stack.
License
MIT