Errores del servidor MCP

Errores del servidor de 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 analizar el texto.

Estructura del envoltorio

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

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

En errores del upstream con estado HTTP, status también está presente. En errores de rate limit y capacidad, la envoltura añade retryAfter, current.{concurrency, rpm} y limits.{maxConcurrency, maxRpm}, con la misma estructura que los errores subyacentes de la API REST.

Valores code estables

Código HTTP Significado ¿Es seguro reintentar?
ssrf_blocked n/a IP de destino en un rango privado o reservado (RFC 5735, RFC 6598, IPv6 reservado) No, cambia la URL
upstream_non_json varía El upstream devolvió un cuerpo que no era un JSON válido Quizás, investiga
output_validation_failed n/a El outputSchema del servidor MCP rechazó la respuesta del upstream (error del servidor o estructura inesperada del upstream) Quizás, repórtalo
bad_request 400 Estructura de entrada rechazada por la API de FourA No, corrige los argumentos
auth_failed 401 La clave API de FourA falta, es inválida o está desactivada (no se trata de credenciales del sitio de destino) No, corrige la clave de FourA
forbidden 403 El destino rechazó la request (antibot, geobloqueo) No, o cambia a foura_proxy
not_found 404 La URL o el endpoint de destino no existe No
rate_limited 429 Límite de RPM por clave alcanzado Sí, espera retryAfter segundos
at_capacity 503 Límite de concurrencia alcanzado (current.concurrency > limits.maxConcurrency) Sí, espera retryAfter segundos
service_disabled 503 Servicio deshabilitado para tu cuenta (plan o mantenimiento) Contacta a soporte
service_unavailable 503 503 genérico del upstream Sí, backoff corto
upstream_error 500+ 5xx del upstream Sí, backoff exponencial
upstream_client_error 4xx Otro 4xx no cubierto arriba Normalmente no
upstream_unknown otro Defensivo, no debería ocurrir en la práctica Investiga
no_eligible_proxy n/a Ningún proxy coincide con la estricta allowlist exitCountries; details.exitCountries contiene el scope normalizado Reintenta más tarde, cambia el scope solo explícitamente

Errores a nivel HTTP del servidor MCP

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

HTTP Cuándo Qué ves
400 Header MCP-Protocol-Version no soportado Unsupported MCP-Protocol-Version: <value>. Supported: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07.
401 Header Authorization ausente o mal formado Error JSON-RPC + WWW-Authenticate: Bearer realm="foura-mcp", resource_metadata="https://foura.ai/docs/mcp/server#auth"
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 Request body > 256 KB 413 por defecto de Express

Las allowlists para 403 se pueden configurar por variables de entorno para hostings propios vía FOURA_MCP_ALLOWED_HOSTS y FOURA_MCP_ALLOWED_ORIGINS.

Perfiles de navegador rechazados

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

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

Estrategia de reintentos

Cuatro categorías:

  • Esperar y reintentar: rate_limited, at_capacity, service_unavailable, upstream_error. Respeta retryAfter cuando esté presente. Usa retroceso exponencial (exponential backoff) con jitter cuando esté ausente.
  • Preservar el scope y reintentar más tarde: no_eligible_proxy. No elimines exitCountries ni sustituyas otro país de forma silenciosa. Cambia o amplía la allowlist solo cuando el usuario cambie explícitamente el requisito.
  • No reintentar hasta que se corrija el input 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 de destino.
  • Cambiar de herramienta cuando el contenido lo requiera: forbidden en foura_single puede justificar un intento limitado de foura_proxy. Usa foura_browser cuando el contenido deseado necesite JavaScript. Después de una selección de proxy exitosa, pasa el ID de proxy devuelto a foura_browser.proxy en lugar de iniciar una nueva selección.

Ejemplo de reintento (TypeScript, lado del 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

Actualizado: 6 de agosto de 2026