Errores del servidor MCP

Errores del servidor MCP

Cómo manejar los errores devueltos por el servidor foura-mcp.

Cada respuesta de error de cualquiera de las cuatro herramientas (foura_auto, foura_single, foura_proxy, foura_browser) está estructurada. Los agentes LLM pueden leer el campo code para la lógica de reintento sin necesidad de analizar texto libre.

Estructura del envelope

Cada error (isError: true) incluye un bloque structuredContent. Campos mínimos en cada error:

{
  "service": "auto | single | proxy | browser",
  "code": "rate_limited",
  "error": "Rate limit exceeded"
}

En errores de upstream con estado HTTP, status también está presente. Cuando la cuota compartida de la plataforma rechaza una llamada, el sobre añade retryAfter, current.{concurrency, rpm} y limits.{maxConcurrency, maxRpm}, con la misma estructura que los errores subyacentes de la API REST.

Cuando uno de los límites propios de tu plan rechaza una llamada, el código ES ese límite: plan_limit_ seguido de credits, bandwidth, rate, concurrency, browser_daily, premium o feature. retryAfter indica el tiempo de espera cuando esperar lo soluciona, y está ausente en límites que una espera no puede restablecer, como una función no incluida en el plan. plan_limit_browser_daily tampoco incluye retryAfter: se restablece a medianoche UTC.

En foura_auto, un límite del plan alcanzado dentro de su escala se devuelve como rate_limited o forbidden, con el código del plan en reason.

Valores estables de code

Code HTTP Meaning Retry safe?
ssrf_blocked n/a El destino es una dirección privada o reservada (RFC 5735, RFC 6598, IPv6 reservada), la URL no es http(s) o su nombre de host no se resolvió No, verifica la URL. Una resolución que falló brevemente se puede reintentar
upstream_non_json varía El upstream devolvió un body que no era un JSON válido Tal vez, investiga
output_validation_failed n/a El outputSchema del servidor MCP rechazó la respuesta del upstream, o la herramienta no pudo completar la llamada (no hay API key configurada, API inaccesible) Tal vez: verifica la configuración, luego reporta
bad_request 400 Estructura de entrada rechazada por la API de FourA No, corrige los argumentos
auth_failed 401 La API key de FourA falta, no es válida o está desactivada; esto no se refiere a las credenciales del sitio de destino No, corrige la key de FourA
forbidden 403 El destino rechazó la request (un bloqueo del sitio, una restricción por país) No, o cambia a foura_proxy
not_found 404 La URL o el endpoint de destino no existe No
rate_limited 429 El límite compartido por minuto de la plataforma, o un 429 del destino que tu validate rechazó. En foura_auto también pueden ser los créditos, el tráfico o el rate limit de tu plan (consulta reason) Sí, espera retryAfter cuando esté presente, de lo contrario aplica backoff
at_capacity 503 Límite de concurrencia alcanzado (current.concurrency > limits.maxConcurrency) Sí, espera retryAfter segundos
service_disabled 503 El servicio está desactivado por mantenimiento. Una herramienta que tu plan no incluye devuelve plan_limit_feature Contacta a soporte
service_unavailable 503 503 genérico del upstream Sí, backoff corto
upstream_error 500+ o 0 El destino respondió con un error de servidor, o en foura_proxy, foura_browser y foura_auto nunca respondieron Sí, backoff exponencial
upstream_client_error 4xx Otro 4xx no cubierto arriba Por lo general, no
upstream_unknown otro La request se ejecutó pero no produjo una respuesta aceptada: en foura_single el destino nunca respondió (timeout, conexión rechazada), y en cualquier herramienta tu validate rechazó una respuesta 2xx o 3xx. Lee status y error Investiga
no_eligible_proxy n/a Ningún proxy coincide con la allowlist estricta de exitCountries; details.exitCountries contiene el scope normalizado Reintenta más tarde; cambia el scope solo de forma explícita
plan_limit_credits 429 Los créditos mensuales de tu plan se han agotado Sí, después de retryAfter, o cambia de plan
plan_limit_bandwidth 429 El límite de tráfico de tu plan se ha agotado para este periodo de facturación Sí, después de retryAfter, o cambia de plan
plan_limit_rate 429 Requests por minuto de tu plan para ese endpoint Sí, después de retryAfter
plan_limit_concurrency 429 Requests simultáneas de tu plan para ese endpoint Sí, después de retryAfter
plan_limit_browser_daily 429 El límite diario de Browser de tu plan se ha agotado Sí, mañana, o usa foura_single / foura_proxy
plan_limit_premium 403 Enviaste exitClass: "premium" en un plan que no incluye salidas premium No, elimina el parámetro o cambia de plan
plan_limit_feature 403 El plan no incluye ese endpoint o esa funcionalidad No, cambia de plan

Errores a nivel HTTP del servidor MCP

Algunos fallos ocurren en la capa de transporte de MCP, antes de que se llame a cualquier tool. Estos devuelven errores JSON-RPC puros (sin structuredContent):

HTTP Cuándo Lo que ves
400 Header MCP-Protocol-Version no compatible Unsupported MCP-Protocol-Version: <value>. Supported: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07.
401 Una llamada a tool o lectura de recurso sin API key. Listar tools y prompts funciona sin ella Error JSON-RPC + WWW-Authenticate: Bearer realm="foura-mcp"
403 Header Origin o Host no permitido (defensa contra DNS-rebinding, CVE-2025-66414) Origin <value> is not in the allowlist o Host <value> is not in the allowlist
405 GET o DELETE en /mcp (modo stateless) Method not allowed in stateless mode. Use POST /mcp.
413 Cuerpo de la request > 256 KB 413 predeterminado de Express

Las listas de permitidos para 403 se pueden configurar mediante variables de entorno para implementaciones self-hosted a través de FOURA_MCP_ALLOWED_HOSTS y FOURA_MCP_ALLOWED_ORIGINS.

Perfiles de navegador rechazados

Un perfil de navegador que el catálogo no puede ofrecer, o un perfil enviado con unblocker establecido en false, se devuelve como un fallo upstream con el motivo en error y la request nunca sale de FourA. El mensaje indica lo que está disponible, así que reintenta con una de las combinaciones listadas en lugar de usar la misma.

Estos son rechazos, no interrupciones del servicio: reintentar la request idéntica no puede tener éxito y no se utilizó ningún otro navegador en su lugar.

Estrategia de reintento

Cinco categorías:

  • Tu propio plan lo rechazó, no el objetivo: cualquier código plan_limit_*. El mismo trabajo a través de otra tool también será rechazado, por lo que cambiar de endpoint solo consume tiempo. Espera a que termine retryAfter cuando exista uno; de lo contrario, el plan debe cambiar. plan_limit_premium es el que puedes solucionar tú mismo, eliminando exitClass.
  • Esperar y reintentar: rate_limited, at_capacity, service_unavailable, upstream_error. Respeta retryAfter cuando esté presente. Usa backoff exponencial con jitter cuando no esté disponible. No respondas reenviando todas las llamadas a tools en cola a la vez: reduce en su lugar cuántas ejecutas en paralelo.
  • Conservar el alcance y reintentar más tarde: no_eligible_proxy. No elimines exitCountries ni sustituyas otro país silenciosamente. Modifica o amplía la lista de permitidos únicamente cuando el usuario cambie el requisito de forma explícita.
  • No reintentar hasta que se corrija la entrada o la credencial: bad_request, auth_failed, not_found, ssrf_blocked. Para auth_failed, verifica la API key de FourA, no las credenciales del sitio objetivo.
  • Cambiar de tool cuando el contenido lo requiera: forbidden en foura_single puede justificar un intento acotado de foura_proxy. Usa foura_browser cuando el contenido deseado necesite JavaScript. Tras una selección de proxy exitosa, pasa el ID proxy devuelto a foura_browser.proxy en lugar de iniciar una nueva selección.

Ejemplo de reintento (TypeScript, lado de MCP)

async function callWithRetry(call: () => Promise<any>, maxAttempts = 3) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const r = await call();
    if (!r.isError) return r;

    const code = r.structuredContent?.code;
    const wait = r.structuredContent?.retryAfter ?? Math.min(2 ** attempt, 30);

    if (["rate_limited", "at_capacity", "service_unavailable", "upstream_error"].includes(code)) {
      await new Promise((res) => setTimeout(res, wait * 1000));
      continue;
    }
    // Non-retryable, surface to caller
    throw new Error(`${code}: ${r.structuredContent?.error}`);
  }
  throw new Error("max retries exceeded");
}

Relacionado

  • MCP Server, las cuatro herramientas y sus esquemas
  • MCP Recipes, prompts de flujo de trabajo incluidos con el servidor
  • API Errors, la misma estructura en la capa de la REST API subyacente
  • Rate Limits, los límites de cuenta y plataforma detrás de rate_limited y at_capacity
Actualizado: 27 de septiembre de 2026