MCP Server Errors

How to handle errors returned by the foura-mcp server.

Every error response from any of the three tools (foura_single, foura_proxy, foura_browser) is structured. LLM agents can read the code field for retry logic without parsing prose.

Envelope shape

Every error (isError: true) carries a structuredContent block. Minimum fields on every error:

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

On upstream errors with HTTP status, status is also present. On rate-limit and capacity errors, the envelope adds retryAfter, current.{concurrency, rpm}, and limits.{maxConcurrency, maxRpm}, same shape as the underlying REST API errors.

Stable code values

Code HTTP Meaning Retry safe?
ssrf_blocked n/a Target IP in a private or reserved range (RFC 5735, RFC 6598, IPv6 reserved) No, change the URL
upstream_non_json varies Upstream returned a body that wasn't valid JSON Maybe, investigate
output_validation_failed n/a The MCP server's outputSchema rejected the upstream response (server bug or unexpected upstream shape) Maybe, report
bad_request 400 Input shape rejected by the FourA API No, fix the arguments
auth_failed 401 Key missing, invalid, or deactivated No, fix the key
forbidden 403 Target rejected the request (anti-bot, geo-block) No, or switch to foura_proxy
not_found 404 Target URL or endpoint doesn't exist No
rate_limited 429 Per-key RPM cap hit Yes, wait retryAfter seconds
at_capacity 503 Concurrency cap hit (current.concurrency > limits.maxConcurrency) Yes, wait retryAfter seconds
service_disabled 503 Service disabled for your account (plan or maintenance) Contact support
service_unavailable 503 Generic 503 from upstream Yes, short backoff
upstream_error 500+ Upstream 5xx Yes, exponential backoff
upstream_client_error 4xx Other 4xx not covered above Usually no
upstream_unknown other Defensive, should not occur in practice Investigate

HTTP-level errors from the MCP server

Some failures happen at the MCP transport layer, before any tool is called. These return raw JSON-RPC errors (no structuredContent):

HTTP When What you see
400 Unsupported MCP-Protocol-Version header Unsupported MCP-Protocol-Version: <value>. Supported: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07.
401 Missing or malformed Authorization header JSON-RPC error + WWW-Authenticate: Bearer realm="foura-mcp", resource_metadata="https://foura.ai/docs/mcp/server#auth"
403 Disallowed Origin or Host header (DNS-rebinding defense, CVE-2025-66414) Origin <value> is not in the allowlist or Host <value> is not in the allowlist
405 GET or DELETE on /mcp (stateless mode) Method not allowed in stateless mode. Use POST /mcp.
413 Request body > 256 KB Express default 413

The allowlists for 403 are env-configurable for self-hosters via FOURA_MCP_ALLOWED_HOSTS and FOURA_MCP_ALLOWED_ORIGINS.

Retry strategy

Three buckets:

  • Wait + retry: rate_limited, at_capacity, service_unavailable, upstream_error. Honour retryAfter when present (server hint, seconds). Use exponential backoff with jitter when not.
  • Don't retry, fix input: bad_request, auth_failed, not_found, ssrf_blocked.
  • Switch tool: forbidden on foura_single → escalate to foura_proxy. If the page also needs JavaScript, foura_browser. If foura_browser reports forbidden, chain with foura_proxy first and pass the returned proxy ID into foura_browser.proxy.

Retry example (TypeScript, MCP-side)

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");
}
  • MCP Server, the three tools and their schemas
  • MCP Recipes, workflow prompts shipped with the server
  • API Errors, same envelope at the underlying REST API layer
Last updated: May 20, 2026