Erreurs du serveur MCP

Erreurs du serveur MCP

Comment gérer les erreurs renvoyées par le foura-mcp server.

Chaque réponse d'erreur de l'un des quatre outils (foura_auto, foura_single, foura_proxy, foura_browser) est structurée. Les agents LLM peuvent lire le champ code pour la logique de nouvelle tentative sans analyser de texte brut.

Structure de l'enveloppe

Chaque erreur (isError: true) contient un bloc structuredContent. Champs minimaux présents sur chaque erreur :

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

Lors d'erreurs en amont avec un statut HTTP, status est également présent. Lorsque le quota partagé de la plateforme refuse un appel, l'enveloppe ajoute retryAfter, current.{concurrency, rpm} et limits.{maxConcurrency, maxRpm}, selon le même format que les erreurs de l'API REST sous-jacentes.

Lorsque l'une des limites propres à votre forfait refuse un appel, le code EST cette limite : plan_limit_ suivi de credits, bandwidth, rate, concurrency, browser_daily, premium ou feature. retryAfter indique le temps d'attente lorsqu'une attente permet de la débloquer, et est absent pour une limite qu'une attente ne peut pas débloquer, comme une fonctionnalité non incluse dans le forfait. plan_limit_browser_daily ne comporte pas non plus de retryAfter : elle se réinitialise à minuit UTC.

Sur foura_auto, une limite de forfait atteinte dans sa hiérarchie est renvoyée sous la forme rate_limited ou forbidden, avec le code du forfait dans reason.

Valeurs stables de code

Code HTTP Signification Retry sans risque ?
ssrf_blocked n/a La cible est une adresse privée ou réservée (RFC 5735, RFC 6598, IPv6 réservée), l'URL n'est pas http(s), ou son nom d'hôte n'a pas pu être résolu Non, vérifiez l'URL. Une résolution ayant échoué brièvement peut être retentée
upstream_non_json varie Le serveur amont a renvoyé un corps qui n'était pas un JSON valide Peut-être, à analyser
output_validation_failed n/a Le outputSchema du serveur MCP a rejeté la réponse en amont, ou l'outil n'a pas pu terminer l'appel (aucune clé API configurée, API inaccessible) Peut-être : vérifiez la configuration, puis signalez
bad_request 400 Structure des données d'entrée rejetée par l'API FourA Non, corrigez les arguments
auth_failed 401 La clé d'API FourA est manquante, invalide ou désactivée ; cela ne concerne pas les identifiants du site cible Non, corrigez la clé FourA
forbidden 403 La cible a rejeté la requête (vérification du site, restriction géographique) Non, ou passez à foura_proxy
not_found 404 L'URL cible ou l'endpoint n'existe pas Non
rate_limited 429 Quota partagé par minute de la plateforme, ou un 429 de la cible rejeté par votre validate. Sur foura_auto, il peut aussi s'agir des crédits, du trafic ou du rate limit de votre forfait (voir reason) Oui, attendez retryAfter lorsqu'il est présent, sinon appliquez un backoff
at_capacity 503 Limite de concurrence atteinte (current.concurrency > limits.maxConcurrency) Oui, attendez retryAfter secondes
service_disabled 503 Le service est interrompu pour maintenance. Un outil non inclus dans votre forfait renvoie plan_limit_feature Contactez le support
service_unavailable 503 Erreur 503 générique en provenance de l'amont Oui, court backoff
upstream_error 500+ ou 0 La cible a répondu par une erreur serveur, ou sur foura_proxy, foura_browser et foura_auto n'ont jamais répondu Oui, backoff exponentiel
upstream_client_error 4xx Autre erreur 4xx non couverte ci-dessus Généralement non
upstream_unknown autre La requête a été exécutée mais n'a produit aucune réponse acceptée : sur foura_single la cible n'a jamais répondu (timeout, connexion refusée), et sur n'importe quel outil votre validate a rejeté une réponse 2xx ou 3xx. Lisez status et error À analyser
no_eligible_proxy n/a Aucun proxy ne correspond à la liste d'autorisation stricte exitCountries ; details.exitCountries contient le périmètre normalisé Réessayez plus tard ; modifiez le périmètre uniquement de manière explicite
plan_limit_credits 429 Les crédits mensuels de votre forfait sont épuisés Oui, après retryAfter, ou modifiez votre forfait
plan_limit_bandwidth 429 Le quota de trafic de votre forfait est épuisé pour cette période de facturation Oui, après retryAfter, ou modifiez votre forfait
plan_limit_rate 429 Limite de requêtes par minute de votre forfait pour cet endpoint Oui, après retryAfter
plan_limit_concurrency 429 Limite de requêtes simultanées de votre forfait pour cet endpoint Oui, après retryAfter
plan_limit_browser_daily 429 Le quota quotidien de Browser de votre forfait est épuisé Oui, demain, ou utilisez foura_single / foura_proxy
plan_limit_premium 403 Vous avez envoyé exitClass: "premium" avec un forfait qui n'inclut pas les sorties premium Non, supprimez le paramètre ou modifiez votre forfait
plan_limit_feature 403 Le forfait n'inclut pas cet endpoint ou cette fonctionnalité Non, modifiez votre forfait

Erreurs de niveau HTTP provenant du serveur MCP

Certaines défaillances surviennent au niveau de la couche de transport MCP, avant même l'appel d'un outil. Celles-ci renvoient des erreurs JSON-RPC brutes (pas de structuredContent) :

HTTP Circonstance Ce que vous voyez
400 Header MCP-Protocol-Version non pris en charge Unsupported MCP-Protocol-Version: <value>. Supported: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07.
401 Appel d'outil ou lecture de ressource sans clé API. Le listage des outils et des prompts fonctionne sans clé Erreur JSON-RPC + WWW-Authenticate: Bearer realm="foura-mcp"
403 Header Origin ou Host non autorisé (défense contre le DNS-rebinding, CVE-2025-66414) Origin <value> is not in the allowlist ou Host <value> is not in the allowlist
405 GET ou DELETE sur /mcp (mode stateless) Method not allowed in stateless mode. Use POST /mcp.
413 Corps de la requête > 256 KB 413 par défaut d'Express

Les listes d'autorisation pour le code 403 sont configurables par variables d'environnement pour les auto-hébergeurs via FOURA_MCP_ALLOWED_HOSTS et FOURA_MCP_ALLOWED_ORIGINS.

Profils de navigateur refusés

Un profil de navigateur que le catalogue ne peut pas fournir, ou un profil envoyé avec unblocker défini sur false, est renvoyé comme un échec en amont avec la raison dans error et la requête ne quitte jamais FourA. Le message précise les options disponibles ; réessayez donc avec l'une des combinaisons listées plutôt qu'avec la même.

Il s'agit de refus et non d'interruptions de service : réessayer la requête identique ne peut pas réussir, et aucun autre navigateur n'a été utilisé à la place.

Stratégie de nouvelle tentative

Cinq catégories :

  • Votre propre plan l'a refusé, pas la cible : tout code plan_limit_*. La même opération via un autre outil sera également refusée ; changer d'endpoint ne fait donc que perdre du temps. Patientez jusqu'à l'expiration de retryAfter s'il existe ; sinon, le plan doit être modifié. Le code plan_limit_premium est le seul que vous pouvez résoudre vous-même en retirant exitClass.
  • Attendre et réessayer : rate_limited, at_capacity, service_unavailable, upstream_error. Respectez retryAfter lorsqu'il est présent. Utilisez un backoff exponentiel avec gigue en son absence. Ne répondez pas en relançant simultanément tous les appels d'outils en file d'attente : réduisez plutôt le nombre d'exécutions en parallèle.
  • Conserver le périmètre et réessayer plus tard : no_eligible_proxy. Ne supprimez pas exitCountries et ne substituez pas un autre pays de manière silencieuse. Modifiez ou élargissez la liste d'autorisation uniquement si l'utilisateur modifie explicitement cette exigence.
  • Ne pas réessayer avant d'avoir corrigé la saisie ou l'identifiant : bad_request, auth_failed, not_found, ssrf_blocked. Pour auth_failed, vérifiez la clé API FourA, pas les identifiants du site cible.
  • Changer d'outil lorsque le contenu l'exige : forbidden sur foura_single peut justifier une tentative limitée avec foura_proxy. Utilisez foura_browser lorsque le contenu visé nécessite JavaScript. Après une sélection de proxy réussie, transmettez l'ID proxy renvoyé dans foura_browser.proxy au lieu de relancer une nouvelle sélection.

Exemple de nouvelle tentative (TypeScript, côté 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");
}

Voir aussi

  • Serveur MCP, les quatre outils et leurs schémas
  • Recettes MCP, prompts de workflow fournis avec le serveur
  • Erreurs API, même structure au niveau de l'API REST sous-jacente
  • Limites de débit, les limites de compte et de plateforme derrière rate_limited et at_capacity
Mis à jour : 27 septembre 2026