Structured Error Codes Specification
This document defines the structured error code system for MCP-AQL protocol responses. Structured error codes enable machine-readable error handling, consistent error categorization, and reliable error mapping across ada
Source: spec/docs/error-codes.md
On this page
Jump to a section
Use the outline to move through longer pages without losing your place.
Version: 1.0.0-draft Status: Draft (MVP) Last Updated: 2026-04-15
Abstract
This document defines the structured error code system for MCP-AQL protocol responses. Structured error codes enable machine-readable error handling, consistent error categorization, and reliable error mapping across adapter implementations.
1. Overview
1.1 Purpose
Structured error codes address several challenges with string-based error messages:
- Machine-readable - Programs can take action based on error type
- Consistent categorization - Monitoring systems can categorize and alert
- Adapter mapping - Errors map reliably to target protocol codes
- Localization - Clients can provide localized error messages
1.2 Design Principles
- Category-based - Codes follow
CATEGORY_SPECIFICnaming pattern - Self-documenting - Code names describe the error condition
- Deterministic - Each error code maps to a specific recovery strategy
- Extensible - New codes can be added without breaking existing clients
1.3 MVP Scope
This specification covers the Minimum Viable Product error codes:
Included:
- 8 essential error codes (MVP)
- 7 Phase 1 robustness error codes
- Basic error response structure
- HTTP status code mapping
- Generator error code category reference
Deferred to future specifications:
- Full error code taxonomy
- Conflict error codes
- Detailed error context schemas
- Per-adapter error overrides
- Error code extension mechanism
1.4 Error Format
This specification defines the canonical error response format for MCP-AQL:
{
"success": false,
"error": {
"code": "VALIDATION_MISSING_PARAM",
"message": "Missing required parameter 'owner'"
}
}Implementations MUST use structured error objects with code and message fields. The optional details field MAY provide additional context.
2. Error Response Structure
2.1 Structured Error Format
interface ErrorResponse {
success: false;
error: ErrorDetail;
}
interface ErrorDetail {
/**
* Machine-readable error code
* Format: CATEGORY_SPECIFIC_ERROR
*/
code: string;
/**
* Human-readable error message
*/
message: string;
/**
* Optional contextual details
*/
details?: Record<string, unknown>;
}2.2 Example Responses
Minimal error:
{
"success": false,
"error": {
"code": "VALIDATION_MISSING_PARAM",
"message": "Missing required parameter 'owner'"
}
}Error with details:
{
"success": false,
"error": {
"code": "NOT_FOUND_RESOURCE",
"message": "Repository 'octocat/nonexistent' not found",
"details": {
"resource_type": "repository",
"resource_id": "octocat/nonexistent"
}
}
}3. Error Code Format
3.1 Naming Convention
Error codes follow the pattern:
CATEGORY_SPECIFIC_CONDITION
Rules:
- All uppercase with underscores
- Category prefix identifies error class
- Specific suffix describes the condition
- 2-4 word components typical
Examples:
VALIDATION_MISSING_PARAMNOT_FOUND_OPERATIONPERMISSION_DENIEDINTERNAL_ERROR
3.2 Category Prefixes
| Category | Description | HTTP Range |
|---|---|---|
VALIDATION_ |
Input validation errors | 400, 422 |
NOT_FOUND_ |
Resource not found | 404 |
PERMISSION_ |
Authentication/authorization | 401, 403 |
CONFLICT_ |
Resource conflicts | 409 |
RATE_LIMIT_ |
Rate limiting | 429 |
TOKEN_ |
Confirmation token errors | 400, 403 |
SCHEMA_ |
Schema validation errors (generators) | N/A |
INTERNAL_ |
Server errors | 500+ |
Note on
SCHEMA_category: Unlike other error categories which occur at runtime,SCHEMA_errors are produced by adapter generators during schema validation. These errors do not map to HTTP status codes because they occur during code generation, not API requests. See Adapter Generator Specification Section 2.2 for the complete list of schema validation error codes.
4. MVP Error Codes
4.1 Error Code Registry
The MVP includes 8 essential error codes:
| Code | Category | Description |
|---|---|---|
VALIDATION_MISSING_PARAM |
Validation | Required parameter not provided |
VALIDATION_INVALID_TYPE |
Validation | Parameter has wrong type |
VALIDATION_UNKNOWN_PARAM |
Validation | Request contains parameter not defined in operation schema |
VALIDATION_INVALID_ENCODING |
Validation | Request contains invalid character encoding |
VALIDATION_PAYLOAD_TOO_LARGE |
Validation | Request or response exceeds size limits |
NOT_FOUND_OPERATION |
Not Found | Requested operation does not exist |
NOT_FOUND_RESOURCE |
Not Found | Target resource not found (HTTP 404) |
PERMISSION_DENIED |
Permission | Access denied (HTTP 401/403) |
INTERNAL_ERROR |
Internal | Server error or unexpected failure |
4.2 Message Template Conventions
All error codes define a message format template that implementations SHOULD follow for consistency. Templates use the following conventions:
- Variable placeholders use
{variable_name}syntax matching keys in thedetailsobject - Dynamic values MUST be wrapped in single quotes within the message (e.g.,
'{param_name}') - The message prefix MUST match the error category (e.g.,
VALIDATION_codes start with the validation context,NOT_FOUND_codes reference what was not found) - Implementations MAY substitute the target API's error message when it provides more specific context, but SHOULD prefer the template format for consistency
4.3 VALIDATION_MISSING_PARAM
When used: A required parameter was not provided in the request.
Message format: Missing required parameter '{param_name}'
Details:
{
/** Name of the missing parameter */
param_name: string;
/** Operation that requires this parameter */
operation?: string;
}Example:
{
"success": false,
"error": {
"code": "VALIDATION_MISSING_PARAM",
"message": "Missing required parameter 'owner'",
"details": {
"param_name": "owner",
"operation": "get_repo"
}
}
}Reference: This specification (MVP error code)
4.4 VALIDATION_INVALID_TYPE
When used: A parameter was provided with an incorrect type.
Message format: Parameter '{param_name}' expected '{expected_type}', got '{actual_type}'
Details:
{
/** Name of the invalid parameter */
param_name: string;
/** Expected type (string, integer, etc.) */
expected_type: string;
/** Type that was received */
actual_type: string;
/** The invalid value (if safe to include) */
value?: unknown;
}Example:
{
"success": false,
"error": {
"code": "VALIDATION_INVALID_TYPE",
"message": "Parameter 'per_page' expected 'integer', got 'string'",
"details": {
"param_name": "per_page",
"expected_type": "integer",
"actual_type": "string",
"value": "fifty"
}
}
}Reference: This specification (MVP error code)
4.5 VALIDATION_UNKNOWN_PARAM
When used: A request contains one or more parameters not defined in the operation schema at the params level.
Note: This code applies to unknown parameters in the
paramsobject. For unknown fields within the nestedinputobject (used in UPDATE operations per Section 4.5 of the normative spec), useVALIDATION_UNKNOWN_FIELDinstead. The distinction enables precise error handling:VALIDATION_UNKNOWN_PARAMindicates a top-level parameter error, whileVALIDATION_UNKNOWN_FIELDindicates an error within the update payload.
Message format: Unknown parameter(s) for operation '{operation}': {param_list}
When multiple unknown parameters are detected, adapters SHOULD either:
- List all unknown parameters in a comma-separated format:
Unknown parameter(s) for operation 'create_user': force_create, admin_override - Report the first unknown parameter with a count:
Unknown parameter 'force_create' for operation 'create_user' (and 1 other)
Details:
{
/** The operation being called */
operation: string;
/** List of unknown parameter names */
unknown_params: string[];
/** List of valid parameter names for this operation */
valid_params: string[];
}Example (multiple unknown parameters):
{
"success": false,
"error": {
"code": "VALIDATION_UNKNOWN_PARAM",
"message": "Unknown parameter(s) for operation 'create_user': force_create, admin_override",
"details": {
"operation": "create_user",
"unknown_params": ["force_create", "admin_override"],
"valid_params": ["user_name", "password", "email"]
}
}
}Example (single unknown parameter):
{
"success": false,
"error": {
"code": "VALIDATION_UNKNOWN_PARAM",
"message": "Unknown parameter(s) for operation 'create_user': force_create",
"details": {
"operation": "create_user",
"unknown_params": ["force_create"],
"valid_params": ["user_name", "password", "email"]
}
}
}Note: The
parameter(s)format and array structure work for both singular and plural cases. Implementers do not need special-case logic based on the count.
HTTP Status Mapping: This error SHOULD map to HTTP 400 (Bad Request) or 422 (Unprocessable Entity).
Reference: MCP-AQL Specification Section 4.6
4.6 VALIDATION_INVALID_ENCODING
When used: A request contains invalid character encoding (non-UTF-8 sequences).
Message format: Invalid character encoding in request
Details:
{
/** Location where invalid encoding was detected */
location?: string;
/** Byte offset of the invalid sequence (if available) */
byte_offset?: number;
}Example:
{
"success": false,
"error": {
"code": "VALIDATION_INVALID_ENCODING",
"message": "Invalid character encoding in request",
"details": {
"location": "params.description",
"byte_offset": 42
}
}
}Reference: MCP-AQL Specification Section 4.7.1
4.7 VALIDATION_PAYLOAD_TOO_LARGE
When used: A request or response exceeds configured size limits.
Message format: Payload exceeds {limit_type} limit of {limit_value}
Details:
{
/** Type of limit exceeded */
limit_type: 'request_size' | 'response_size' | 'string_length' | 'array_elements' | 'nesting_depth';
/** The configured limit */
limit_value: number;
/** The actual size/count */
actual_value: number;
/** Unit of measurement */
unit: 'bytes' | 'elements' | 'levels';
}Example:
{
"success": false,
"error": {
"code": "VALIDATION_PAYLOAD_TOO_LARGE",
"message": "Payload exceeds request_size limit of 1048576",
"details": {
"limit_type": "request_size",
"limit_value": 1048576,
"actual_value": 2500000,
"unit": "bytes"
}
}
}Reference: MCP-AQL Specification Section 4.7.5
4.8 NOT_FOUND_OPERATION
When used: The requested operation does not exist in the adapter schema.
Design note: This code uses the
NOT_FOUND_category rather thanVALIDATION_because the error signals a fundamentally different recovery strategy. AVALIDATION_error tells the client to fix its input and retry the same operation. ANOT_FOUND_OPERATIONerror tells the client that the operation itself does not exist and it should discover valid operations via introspection. This distinction is especially important for LLM clients, which use the error category to determine whether to adjust parameters or switch to a different operation entirely.
Message format: Unknown operation: '{operation_name}'
Details:
{
/** The operation name that was requested */
operation: string;
/** Valid operation names the client can use instead */
available?: string[];
}Example:
{
"success": false,
"error": {
"code": "NOT_FOUND_OPERATION",
"message": "Unknown operation: 'get_users'",
"details": {
"operation": "get_users"
}
}
}Reference: This specification (MVP error code)
4.9 NOT_FOUND_RESOURCE
When used: The target API returned HTTP 404 - the requested resource does not exist.
Message format: Resource '{resource_type}' not found: '{resource_id}'
Details:
{
/** Type of resource (e.g., "repository", "user", "issue") */
resource_type?: string;
/** Identifier that was not found */
resource_id?: string;
/** HTTP status code from the target API */
http_status?: number;
}Example:
{
"success": false,
"error": {
"code": "NOT_FOUND_RESOURCE",
"message": "Repository 'octocat/nonexistent' not found",
"details": {
"resource_type": "repository",
"resource_id": "octocat/nonexistent",
"http_status": 404
}
}
}Reference: This specification (MVP error code); RFC 9110 Section 15.5.5 (HTTP 404)
4.10 PERMISSION_DENIED
When used: The target API returned HTTP 401 (unauthorized) or 403 (forbidden).
Message format: Permission denied: '{reason}'
Details:
{
/** Human-readable explanation of why permission was denied */
reason?: string;
/** HTTP status code from the target API (401 or 403) */
http_status?: number;
/** OAuth scope required for this operation, if known */
required_scope?: string;
}Example:
{
"success": false,
"error": {
"code": "PERMISSION_DENIED",
"message": "Permission denied: requires 'repo' scope",
"details": {
"http_status": 403,
"required_scope": "repo"
}
}
}Reference: This specification (MVP error code); RFC 9110 Section 15.5.2 (HTTP 401), Section 15.5.4 (HTTP 403)
4.11 INTERNAL_ERROR
When used: Server error from target API (HTTP 500+) or unexpected error in the runtime.
Message format: Internal error: '{description}'
Details:
{
/** HTTP status code from the target API */
http_status?: number;
/** Error message returned by the target API */
upstream_error?: string;
}Example:
{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal error: GitHub API unavailable",
"details": {
"http_status": 503,
"upstream_error": "Service temporarily unavailable"
}
}
}Reference: This specification (MVP error code); RFC 9110 Section 15.6 (HTTP 5xx)
5. Phase 1: Robustness Error Codes
Phase 1 of MCP-AQL adds robustness features including trust levels, dangerous operation classification, rate limiting, and confirmation tokens. These features introduce 11 additional error codes.
5.1 Phase 1 Error Code Registry
| Code | Category | Description |
|---|---|---|
PERMISSION_TRUST_LEVEL_INSUFFICIENT |
Permission | Adapter trust level too low for operation |
PERMISSION_DANGER_LEVEL_DENIED |
Permission | Operation danger level exceeds trust allowance |
CONFIRMATION_REQUIRED |
Permission | Dangerous operation requires user confirmation |
RATE_LIMIT_EXCEEDED |
Rate Limit | Target API rate limit reached |
RATE_LIMIT_QUOTA_PAUSE |
Rate Limit | User quota pause threshold reached |
RATE_LIMIT_QUOTA_EXHAUSTED |
Rate Limit | User quota hard stop reached |
RATE_LIMIT_QUOTA_WARNING |
Rate Limit | Approaching quota limit (warning) |
TOKEN_INVALID |
Token | Confirmation token not found or malformed |
TOKEN_EXPIRED |
Token | Confirmation token has expired |
TOKEN_ALREADY_USED |
Token | Confirmation token has already been redeemed |
TOKEN_SCOPE_MISMATCH |
Token | Token issued for different operation or parameters |
Note on
CONFIRMATION_REQUIREDcategorization: This code is categorized under "Permission" rather than having its own category because it functions as part of the permission gating flow. The operation is denied pending user confirmation—conceptually similar to other permission denials, but with a recovery path (providing a confirmation token). Clients can treat it as a permission error that includes instructions for resolution.
5.2 PERMISSION_TRUST_LEVEL_INSUFFICIENT
When used: An operation is denied because the adapter's trust level is below the minimum required for the operation's danger level.
Message format: Operation '{operation}' requires trust level '{required_trust}', adapter has '{actual_trust}'
Details:
{
/** The operation that was attempted */
operation: string;
/** Trust level required for this operation */
required_trust: 'untested' | 'generated' | 'validated' | 'community_reviewed' | 'certified';
/** Adapter's current trust level */
actual_trust: string;
/** The danger level of the operation */
danger_level?: number;
}Example:
{
"success": false,
"error": {
"code": "PERMISSION_TRUST_LEVEL_INSUFFICIENT",
"message": "Operation 'delete_user' requires trust level 'community_reviewed', adapter has 'validated'",
"details": {
"operation": "delete_user",
"required_trust": "community_reviewed",
"actual_trust": "validated",
"danger_level": 2
}
}
}Reference: Trust Levels Specification
5.3 PERMISSION_DANGER_LEVEL_DENIED
When used: An operation is denied because its danger level is too high for the adapter's trust level.
Message format: Operation '{operation}' (danger: {danger_level}) denied for adapter trust level '{adapter_trust}'
Details:
{
/** The operation that was attempted */
operation: string;
/** The danger level of the operation */
danger_level: 'safe' | 'reversible' | 'destructive' | 'dangerous' | 'forbidden';
/** Adapter's current trust level */
adapter_trust: string;
/** Minimum trust level required */
minimum_trust_required: string;
/** Reasons why this operation is dangerous */
reasons?: string[];
}Example:
{
"success": false,
"error": {
"code": "PERMISSION_DANGER_LEVEL_DENIED",
"message": "Operation 'bulk_delete' (danger: dangerous) denied for adapter trust level 'validated'",
"details": {
"operation": "bulk_delete",
"danger_level": "dangerous",
"adapter_trust": "validated",
"minimum_trust_required": "community_reviewed",
"reasons": [
"Affects multiple resources",
"Cannot be undone"
]
}
}
}Reference: Dangerous Operation Classification
5.4 CONFIRMATION_REQUIRED
When used: A dangerous operation requires explicit user confirmation before execution.
Design note: This code is categorized under "Permission" in the registry table because it functions as a conditional permission denial—the operation is blocked until the user provides explicit confirmation. Unlike a hard permission denial (
PERMISSION_DENIED), this error includes aconfirmation_tokenthat enables the client to retry the operation once user consent is obtained. This pattern aligns with the gatekeeper security model where dangerous operations require explicit user approval.
Message format: This operation requires confirmation
Details:
{
/** The operation that requires confirmation */
operation: string;
/** The danger level of the operation */
danger_level: string;
/** Human-readable reasons for the confirmation requirement */
reasons?: string[];
/** Custom confirmation message to display */
confirmation_message?: string;
/** Token to include in retry request */
confirmation_token: string;
/** When the confirmation token expires */
expires_at: string;
}Example:
{
"success": false,
"error": {
"code": "CONFIRMATION_REQUIRED",
"message": "This operation requires confirmation",
"details": {
"operation": "delete_repo",
"danger_level": "destructive",
"reasons": [
"Permanently removes repository and all contents",
"Cannot be recovered after grace period"
],
"confirmation_message": "Delete repository 'acme/widgets'? This cannot be undone.",
"confirmation_token": "conf_abc123xyz",
"expires_at": "2026-01-28T12:05:00Z"
}
}
}Reference: Dangerous Operation Classification
5.5 RATE_LIMIT_EXCEEDED
When used: The target API rate limit has been reached and requests are blocked until reset.
Message format: API rate limit exceeded
Details:
{
/** The rate limit that was exceeded */
limit: number;
/** Remaining requests (usually 0) */
remaining: number;
/** Time window of the limit */
window: 'second' | 'minute' | 'hour' | 'day';
/** When the rate limit resets */
resets_at: string;
/** Seconds until retry is allowed */
retry_after_seconds: number;
}Example:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "API rate limit exceeded",
"details": {
"limit": 5000,
"remaining": 0,
"window": "hour",
"resets_at": "2026-01-28T13:00:00Z",
"retry_after_seconds": 1847
}
}
}Reference: Rate Limiting Specification
5.6 RATE_LIMIT_QUOTA_PAUSE
When used: A user-configured quota pause threshold has been reached. The user can confirm to continue.
Message format: Quota pause threshold reached
Details:
{
/** The metric that triggered the pause */
metric: string;
/** Current usage */
current: number;
/** The pause threshold */
pause_threshold: number;
/** The hard stop threshold (if configured) */
hard_stop_threshold?: number;
/** Token to continue past the pause */
confirmation_token: string;
/** When the confirmation token expires */
expires_at: string;
}Example:
{
"success": false,
"error": {
"code": "RATE_LIMIT_QUOTA_PAUSE",
"message": "Quota pause threshold reached",
"details": {
"metric": "requests_per_hour",
"current": 4850,
"pause_threshold": 4800,
"hard_stop_threshold": 5000,
"confirmation_token": "quota_continue_abc123",
"expires_at": "2026-01-28T12:05:00Z"
}
}
}Reference: Rate Limiting Specification
5.7 RATE_LIMIT_QUOTA_EXHAUSTED
When used: A user-configured quota hard stop threshold has been reached. All requests are blocked until reset.
Message format: Quota exhausted
Details:
{
/** The metric that triggered the hard stop */
metric: string;
/** Current usage */
current: number;
/** The hard stop threshold */
hard_stop_threshold: number;
/** When the quota resets */
resets_at: string;
}Example:
{
"success": false,
"error": {
"code": "RATE_LIMIT_QUOTA_EXHAUSTED",
"message": "Quota exhausted",
"details": {
"metric": "requests_per_hour",
"current": 5000,
"hard_stop_threshold": 5000,
"resets_at": "2026-01-28T13:00:00Z"
}
}
}Reference: Rate Limiting Specification
5.8 RATE_LIMIT_QUOTA_WARNING
When used: Included in the warnings array of successful responses when approaching a quota limit.
⚠️ IMPORTANT: This is a WARNING code, not an error code.
Unlike all other codes in this section,
RATE_LIMIT_QUOTA_WARNINGappears in thewarningsarray of successful responses (success: true), not in theerrorobject. The operation completes normally; this code signals an informational warning about approaching limits.See Warnings Specification for details on warning handling.
Message format: Approaching quota limit
Details:
{
/** The metric approaching the limit */
metric: string;
/** Current usage */
current: number;
/** The warning threshold */
warn_threshold: number;
/** The pause threshold (next level) */
pause_threshold?: number;
}Example (in successful response):
{
"success": true,
"data": { "...": "..." },
"warnings": [
{
"code": "RATE_LIMIT_QUOTA_WARNING",
"message": "Approaching quota limit",
"details": {
"metric": "requests_per_hour",
"current": 4100,
"warn_threshold": 4000,
"pause_threshold": 4800
}
}
]
}Reference: Rate Limiting Specification
5.9 TOKEN_INVALID
When used: A confirmation token was provided but could not be found in the token store or is malformed.
Message format: Invalid confirmation token
Details:
{
/** The token that was provided */
token: string;
}Example:
{
"success": false,
"error": {
"code": "TOKEN_INVALID",
"message": "Invalid confirmation token",
"details": {
"token": "conf_nonexistent123"
}
}
}Reference: Confirmation Token Specification
5.10 TOKEN_EXPIRED
When used: A confirmation token was provided but has passed its expiration time.
Message format: Confirmation token has expired
Details:
{
/** The token that expired */
token: string;
/** When the token expired */
expired_at: string;
/** Current server time */
current_time: string;
}Example:
{
"success": false,
"error": {
"code": "TOKEN_EXPIRED",
"message": "Confirmation token has expired",
"details": {
"token": "conf_abc123xyz",
"expired_at": "2026-01-28T12:05:00Z",
"current_time": "2026-01-28T12:07:30Z"
}
}
}Reference: Confirmation Token Specification
5.11 TOKEN_ALREADY_USED
When used: A confirmation token was provided but has already been redeemed for a previous operation.
Message format: Confirmation token has already been used
Details:
{
/** The token that was already used */
token: string;
/** When the token was consumed */
consumed_at?: string;
}Example:
{
"success": false,
"error": {
"code": "TOKEN_ALREADY_USED",
"message": "Confirmation token has already been used",
"details": {
"token": "conf_abc123xyz",
"consumed_at": "2026-01-28T12:04:15Z"
}
}
}Reference: Confirmation Token Specification
5.12 TOKEN_SCOPE_MISMATCH
When used: A confirmation token was provided but was issued for a different operation or with different parameters.
Message format: Confirmation token scope mismatch
Details:
{
/** The token that was provided */
token: string;
/** Operation the token was issued for */
token_operation: string;
/** Operation the client is attempting */
requested_operation: string;
}Example:
{
"success": false,
"error": {
"code": "TOKEN_SCOPE_MISMATCH",
"message": "Confirmation token scope mismatch",
"details": {
"token": "conf_abc123xyz",
"token_operation": "delete_repo",
"requested_operation": "force_push"
}
}
}Reference: Confirmation Token Specification
6. HTTP Status Mapping
6.1 Default Mapping
The runtime maps HTTP status codes to MCP-AQL error codes:
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | VALIDATION_INVALID_TYPE |
Bad request (default for validation errors) |
| 400 | VALIDATION_MISSING_PARAM |
Bad request (missing required parameter) |
| 400 | VALIDATION_UNKNOWN_PARAM |
Bad request (unknown parameter) |
| 401 | PERMISSION_DENIED |
Authentication required |
| 403 | PERMISSION_DENIED |
Forbidden |
| 404 | NOT_FOUND_RESOURCE |
Not found |
| 422 | VALIDATION_INVALID_TYPE |
Unprocessable entity |
| 500 | INTERNAL_ERROR |
Internal server error |
| 502 | INTERNAL_ERROR |
Bad gateway |
| 503 | INTERNAL_ERROR |
Service unavailable |
| 504 | INTERNAL_ERROR |
Gateway timeout |
6.2 Mapping Algorithm
function mapHttpStatusToErrorCode(status: number): string {
if (status === 400 || status === 422) {
return 'VALIDATION_INVALID_TYPE';
}
if (status === 401 || status === 403) {
return 'PERMISSION_DENIED';
}
if (status === 404) {
return 'NOT_FOUND_RESOURCE';
}
if (status >= 500) {
return 'INTERNAL_ERROR';
}
// Default for other 4xx errors
return 'VALIDATION_INVALID_TYPE';
}Note: HTTP status codes alone cannot distinguish between
VALIDATION_MISSING_PARAMandVALIDATION_INVALID_TYPE(both typically return 400 or 422). Adapters SHOULD examine the target API's response body to determine the specific validation error and set the appropriate code. The mapping algorithm above provides a default when response body inspection is not feasible.
7. Implementation Requirements
7.1 Error Generation
Implementations MUST:
- Return structured errors for all failure cases
- Include
codeandmessagefields - Use codes from the MVP registry
- Provide human-readable messages
Implementations SHOULD:
- Include
detailswith contextual information - Preserve upstream error messages
- Log full error context for debugging
7.2 Error Handling
Client implementations SHOULD:
- Check
successfield first - Parse the
errorobject to extractcodeandmessage - Use
codefield for programmatic error handling and recovery decisions - Display
messagefield to users
7.3 Message Localization
The code field enables localization:
const ERROR_MESSAGES = {
en: {
VALIDATION_MISSING_PARAM: "Missing required parameter: '{param_name}'",
NOT_FOUND_RESOURCE: 'Resource not found',
},
es: {
VALIDATION_MISSING_PARAM: "Falta el parámetro requerido: '{param_name}'",
NOT_FOUND_RESOURCE: 'Recurso no encontrado',
}
};
function localizeError(error: ErrorDetail, locale: string): string {
const template = ERROR_MESSAGES[locale]?.[error.code];
if (template && error.details) {
return interpolate(template, error.details);
}
return error.message;
}8. Future Extensions
8.1 Additional Error Codes
Future specifications may add:
Conflict Handling:
CONFLICT_ALREADY_EXISTS- Resource already existsCONFLICT_VERSION_MISMATCH- Optimistic locking failure (see Request Concurrency)
Enhanced Validation:
VALIDATION_INVALID_ENUM- Value not in allowed enumVALIDATION_OUT_OF_RANGE- Value outside allowed rangeVALIDATION_PATTERN_MISMATCH- String doesn't match pattern
8.2 Error Code Extension Mechanism
Future versions will define how adapters can register custom error codes:
# In adapter schema
error_codes:
GITHUB_ABUSE_DETECTED:
category: RATE_LIMIT
message_template: "Abuse detection triggered: {reason}"
maps_from_http: [403]
condition: "response.body.message contains 'abuse'"8.3 Per-Adapter Error Overrides
Future versions will allow adapters to customize HTTP error mapping:
# In adapter schema
error_mapping:
404:
code: NOT_FOUND_REPOSITORY
message_template: "Repository '{owner}/{repo}' not found"
403:
condition: "response.body.message contains 'rate limit'"
code: RATE_LIMIT_EXCEEDED8.4 Error Aggregation
For batch operations, errors may be aggregated:
{
"success": false,
"error": {
"code": "BATCH_PARTIAL_FAILURE",
"message": "3 of 5 operations failed",
"details": {
"total": 5,
"succeeded": 2,
"failed": 3,
"errors": [
{ "index": 1, "code": "NOT_FOUND_RESOURCE", "message": "..." },
{ "index": 3, "code": "PERMISSION_DENIED", "message": "..." },
{ "index": 4, "code": "VALIDATION_MISSING_PARAM", "message": "..." }
]
}
}
}References
- MCP-AQL Specification
- Dangerous Operation Classification
- Trust Levels Specification
- Rate Limiting Specification
- Universal Adapter Runtime (in mcpaql-adapter repo)
- DollhouseMCP Implementation
- GitHub Issue: #35