Erros do Servidor MCP

Como tratar erros retornados pelo servidor foura-mcp.

Toda resposta de erro de qualquer uma das três ferramentas (foura_single, foura_proxy, foura_browser) é estruturada. Agentes de LLM podem ler o campo code para lógica de nova tentativa sem analisar texto corrido.

Formato do envelope

Todo erro (isError: true) carrega um bloco structuredContent. Campos mínimos em cada erro:

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

Em erros de upstream com status HTTP, status também está presente. Em erros de rate limit e capacidade, o envelope adiciona retryAfter, current.{concurrency, rpm} e limits.{maxConcurrency, maxRpm}, o mesmo formato dos erros da API REST subjacentes.

Valores estáveis de code

Código HTTP Significado Seguro para tentar novamente?
ssrf_blocked n/a IP de destino em um intervalo privado ou reservado (RFC 5735, RFC 6598, IPv6 reservado) Não, altere a URL
upstream_non_json varia O upstream retornou um corpo que não era um JSON válido Talvez, investigue
output_validation_failed n/a O outputSchema do servidor MCP rejeitou a resposta do upstream (bug do servidor ou formato inesperado do upstream) Talvez, relate
bad_request 400 Formato de entrada rejeitado pela API FourA Não, corrija os argumentos
auth_failed 401 Chave ausente, inválida ou desativada Não, corrija a chave
forbidden 403 O destino rejeitou a request (anti-bot, geo-block) Não, ou mude para foura_proxy
not_found 404 A URL ou endpoint de destino não existe Não
rate_limited 429 Limite de RPM por chave atingido Sim, aguarde retryAfter segundos
at_capacity 503 Limite de concorrência atingido (current.concurrency > limits.maxConcurrency) Sim, aguarde retryAfter segundos
service_disabled 503 Serviço desativado para sua conta (plano ou manutenção) Contate o suporte
service_unavailable 503 503 genérico do upstream Sim, backoff curto
upstream_error 500+ 5xx do upstream Sim, backoff exponencial
upstream_client_error 4xx Outro 4xx não coberto acima Geralmente não
upstream_unknown outro Defensivo, não deve ocorrer na prática Investigue

Erros de nível HTTP do servidor MCP

Algumas falhas ocorrem na camada de transporte do MCP, antes de qualquer ferramenta ser chamada. Elas retornam erros JSON-RPC brutos (sem structuredContent):

HTTP Quando O que você vê
400 Header MCP-Protocol-Version não suportado 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 ou malformado Erro JSON-RPC + WWW-Authenticate: Bearer realm="foura-mcp", resource_metadata="https://foura.ai/docs/mcp/server#auth"
403 Header Origin ou Host não permitido (defesa contra DNS-rebinding, CVE-2025-66414) Origin <value> is not in the allowlist ou Host <value> is not in the allowlist
405 GET ou DELETE em /mcp (modo stateless) Method not allowed in stateless mode. Use POST /mcp.
413 Corpo da request > 256 KB Padrão do Express 413

As allowlists para 403 são configuráveis por variáveis de ambiente para self-hosters via FOURA_MCP_ALLOWED_HOSTS e FOURA_MCP_ALLOWED_ORIGINS.

Estratégia de nova tentativa

Três categorias:

  • Aguardar + tentar novamente: rate_limited, at_capacity, service_unavailable, upstream_error. Respeite retryAfter quando presente (indicação do servidor, em segundos). Use backoff exponencial com jitter caso contrário.
  • Não tentar novamente, corrigir entrada: bad_request, auth_failed, not_found, ssrf_blocked.
  • Mudar de ferramenta: forbidden em foura_single → escalone para foura_proxy. Se a página também precisar de JavaScript, use foura_browser. Se o foura_browser relatar forbidden, encadeie com foura_proxy primeiro e passe o ID de proxy retornado em foura_browser.proxy.

Exemplo de nova tentativa (TypeScript, lado do 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

  • Servidor MCP, as três ferramentas e seus schemas
  • Receitas MCP, prompts de fluxo de trabalho enviados com o servidor
  • Erros da API, mesmo envelope na camada da API REST subjacente
Atualizado em: 1 de julho de 2026