Errores y límites de peticiones
Formas de error JSON-RPC mapeadas desde el contrato v1, la tabla completa de códigos y throttling por token / por plan con Retry-After.
El servidor MCP habla JSON-RPC 2.0 estricto. Los fallos vuelven como un
objeto error, nunca como un cuerpo de error HTTP al estilo de la API REST —
pero la semántica es idéntica: la misma violación de regla de negocio que
devuelve 422 sobre REST devuelve aquí el error JSON-RPC equivalente, con el
code y el http_status de v1 conservados en data.
Esta página cubre el mapeo JSON-RPC específico de MCP y los buckets de throttling
de MCP. Para el contrato REST canónico — el envoltorio de error por code y las
cuotas por tier — consulta Errores y
Límites de peticiones.
Forma del error
{
"jsonrpc": "2.0",
"id": "<request id>",
"error": {
"code": -32008,
"message": "invoice_cannot_be_modified",
"data": {
"http_status": 422,
"code": "invoice_cannot_be_modified",
"hint": "La factura ya emitida no puede modificarse.",
"param": "status"
}
}
}error.code— el código numérico JSON-RPC (siempre en el rango-32099..-32000definido por la implementación, o-32603para errores internos).error.message— un identificador de cadena estable (p. ej.insufficient_scope,invoice_cannot_be_modified).error.data.code— el mismocodecanónico de v1 que devuelve la API REST, para que puedas ramificar según un único valor en ambas superficies.error.data.http_status— el estado HTTP que devolvería la llamada REST equivalente (422 / 404 / 409 / …), para clientes que prefieren razonar en términos HTTP.error.data.hint— un mensaje legible para personas (en español, acorde con el idioma de la app). Otros campos (param,subcode,required_scope, …) aparecen cuando son relevantes.
Tabla de códigos
| JSON-RPC code | message / data.code | HTTP equiv. | Significado |
|---|---|---|---|
-32001 | invalid_token | 401 | Credencial ausente, malformada o desconocida; o el usuario ya no es miembro de la empresa. |
-32002 | client_revoked | 403 | El cliente OAuth fue revocado. |
-32003 | invalid_token_type | 403 | Tipo de credencial incorrecto para esta superficie. |
-32004 | plan_limit_exceeded / plan_upgrade_required | 402 | Se alcanzó un límite de uso del plan, o la acción requiere un plan superior. data incluye resource, current, limit. |
-32005 | insufficient_scope / module_not_in_plan / feature_flag_disabled | 403 | La credencial carece del scope requerido, el módulo no está en el plan, o un feature flag está desactivado. data incluye required_scope / module / flag. |
-32006 | rate_limit_exceeded | 429 | Se superó un bucket de throttling. data incluye retry_after y bucket; la respuesta también establece la cabecera Retry-After. |
-32007 | addon_not_active | 403 | El add-on de developer API de la empresa está inactivo (fuera de su periodo de gracia). |
-32008 | (código v1) | 422 / 404 / 409 / … | Una violación de regla de negocio, recurso inexistente o conflicto. message y data.code son el código de error canónico de v1; data.http_status te indica la categoría. |
-32603 | internal_error | 500 | Error inesperado del servidor. |
-32005 y -32008 cubren cada uno varias subcausas. Ramifica siempre según
data.code (la cadena), no solo según el code numérico, cuando necesites
distinguirlas — p. ej. insufficient_scope y module_not_in_plan afloran ambos
como -32005.
Scope insuficiente
Cuando una tool necesita un scope que la credencial no tiene:
{
"jsonrpc": "2.0",
"id": "req-42",
"error": {
"code": -32005,
"message": "insufficient_scope",
"data": {
"http_status": 403,
"code": "insufficient_scope",
"required_scope": "invoices:write",
"provided_scopes": ["invoices:read", "clients:read"],
"hint": "La credencial no tiene el scope requerido para esta operación."
}
}
}Las tools que tu credencial no puede alcanzar también quedan ocultas en
tools/list, así que un agente bien comportado normalmente no las intentará —
este error es la red de seguridad.
Límites de peticiones
Las peticiones se limitan en tres buckets independientes. Superar cualquiera de
ellos devuelve -32006 con una cabecera Retry-After (segundos).
Por token, por categoría de tool
Cada credencial tiene contadores por minuto separados por categoría de tool, de modo que un uso destructivo intensivo no pueda agotar tus lecturas:
| Categoría | Límite por defecto | Tools de ejemplo |
|---|---|---|
read / write | 60 / min | search_invoices, create_invoice |
send | 20 / min | send_invoice, send_quote |
generate | 30 / min | get_invoice_facturae_link |
destructive | 10 / min | delete_invoice, bulk_delete_clients |
El bucket se resuelve a partir de la categoría de la tool. El contador se incrementa antes de que la tool se ejecute, así que las llamadas rechazadas (scope incorrecto, error de validación) también consumen cuota — esto es anti-abuso deliberado, acorde con el patrón estándar OAuth/REST.
Por plan, cada hora
Un tope horario a nivel de empresa por slug de plan. El plan Enterprise se salta este bucket por completo.
Por cliente OAuth, global
Las apps OAuth comparten además un bucket global por cliente de 1000 / min, de modo que una sola app que se porte mal no pueda saturar el servidor a través de todos sus usuarios.
Cabeceras de límite de peticiones
Las respuestas correctas llevan el presupuesto restante para que puedas reducir el ritmo de forma proactiva:
| Header | Significado |
|---|---|
X-RateLimit-Limit-Token / X-RateLimit-Remaining-Token | El bucket por token (por categoría). |
X-RateLimit-Limit-Hour / X-RateLimit-Remaining-Hour | El bucket por plan horario (ausente en Enterprise). |
Retry-After | En un 429, segundos a esperar antes de reintentar. |
Límites de los endpoints de auth
Los endpoints OAuth tienen sus propios límites, independientes de los buckets de MCP:
| Endpoint | Límite |
|---|---|
POST /api/oauth/register | 10 / hora por IP |
POST /api/oauth/token | 60 / min por (cliente, IP) |
Respeta siempre Retry-After. Reintentar antes de que transcurra mantiene el
bucket lleno y solo retrasa tu recuperación. Combínalo con idempotencia en las
escrituras para que un reintento retrasado nunca duplique un documento.