Serveur MCP

Serveur MCP

Utilisez FourA depuis n'importe quel client Model Context Protocol (Claude Desktop, Claude Code, Cursor, Windsurf, VS Code) sous la forme de quatre outils natifs et six prompts de workflow. Aucun code d'intégration, aucun client HTTP personnalisé.

Open source sur GitHub ; sur npm sous @fouradata/mcp. Version actuelle : 0.7.3.

Démarrage rapide : stdio local (recommandé pour Claude Desktop)

Obtenez une clé sur foura.ai/dashboard#api-keys (en un clic, affichée une seule fois à la création, format pk_live_...). Ajoutez ceci dans la configuration de votre client MCP :

{
  "mcpServers": {
    "foura": {
      "command": "npx",
      "args": ["-y", "@fouradata/mcp"],
      "env": { "FOURA_API_KEY": "pk_live_..." }
    }
  }
}

Piège avec Claude Desktop : quittez complètement Claude Desktop (Cmd+Q sur macOS) avant de modifier le fichier de configuration. Si l'application est toujours en cours d'exécution, elle écrasera vos modifications avec sa configuration en mémoire lors de sa fermeture.

La commande npx télécharge @fouradata/mcp lors du premier lancement et l'exécute en tant que sous-processus de votre client MCP. Aucune installation globale n'est requise.

Client Emplacement de la configuration
Claude Desktop (macOS) ~/Library/Application Support/Claude/claude_desktop_config.json
Claude Desktop (Windows) %APPDATA%\Claude\claude_desktop_config.json
Claude Code claude mcp add foura -- npx -y @fouradata/mcp (définissez d'abord FOURA_API_KEY dans l'environnement)
Cursor ~/.cursor/mcp.json
Windsurf ~/.codeium/windsurf/mcp_config.json
VS Code (extension MCP) .vscode/mcp.json

Redémarrez le client. Les outils (foura_auto, foura_single, foura_proxy, foura_browser) et six prompts apparaissent dans votre liste d'outils.

Démarrage rapide : hébergé (Streamable HTTP)

Pour les clients prenant en charge le transport Streamable HTTP (Cursor, Windsurf, VS Code, Claude Code avec --transport http), pointez-les vers l'endpoint hébergé au lieu d'exécuter un sous-processus local :

{
  "mcpServers": {
    "foura": {
      "url": "https://mcp.foura.ai/mcp",
      "headers": {
        "Authorization": "Bearer pk_live_..."
      }
    }
  }
}

Pour Claude Desktop, utilisez la configuration stdio ci-dessus ou reliez l'endpoint hébergé via mcp-remote :

{
  "mcpServers": {
    "foura": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://mcp.foura.ai/mcp", "--header", "Authorization: Bearer pk_live_..."]
    }
  }
}

Référence de l'endpoint hébergé

Propriété Valeur
URL https://mcp.foura.ai/mcp
Transport Streamable HTTP (POST /mcp, réponses SSE)
Authentification Authorization: Bearer pk_live_... par requête
MCP-Protocol-Version Selon @modelcontextprotocol/sdk (actuellement 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07)
Challenge 401 WWW-Authenticate: Bearer realm="foura-mcp"

Le challenge 401 ne comporte aucun paramètre RFC 9728 resource_metadata, à dessein. En annoncer un inciterait un client compatible OAuth à initier un flux que ce serveur n'implémente pas. Envoyez votre clé pk_live_ sous forme de token Bearer et l'erreur 401 disparaîtra.

Le serveur hébergé est sans état. Chaque requête fournit sa propre clé, que le serveur transmet à l'API FourA en tant que X-API-Key. Une seule clé donne accès aux quatre outils.

Pour vous protéger contre le re-binding DNS (CVE-2025-66414), le serveur valide l'en-tête Host (qui doit être mcp.foura.ai ou localhost) ainsi que l'en-tête Origin lorsqu'il est présent (liste d'autorisation: mcp.foura.ai, claude.ai, app.cursor.sh, app.cursor.com). Les appelants serveur à serveur (curl, clients MCP en mode pont stdio) n'envoient aucun en-tête Origin et passent directement.

Outils

Les quatre outils portent les annotations readOnlyHint: true et openWorldHint: true conformément à la spécification MCP du 18/06/2025. Les clients qui approuvent automatiquement les outils fiables en lecture seule les appellent sans fenêtre modale de confirmation par requête.

foura_auto est le choix par défaut intelligent: donnez-lui une URL et il retourne le contenu, en choisissant la méthode de récupération pour vous. Les trois autres sont les primitives de niveau inférieur qu'il orchestre; utilisez-les lorsque vous souhaitez un contrôle explicite.

foura_auto

Fournissez-lui une URL lorsque vous voulez que FourA choisisse la méthode de requête. Il effectue des tentatives limitées à travers les différents chemins HTTP, proxy et navigateur disponibles. Passez validate sur les cibles protégées pour vous assurer que la réponse contienne du contenu identifiant la page réelle. Si aucune tentative ne satisfait à la validation, l'outil retourne une erreur au lieu de présenter une page de challenge comme un succès.

La réponse inclut les détails de complétion dans meta et, par défaut, un objet session réutilisable avec proxy, cookies et userAgent. Pour une requête de suivi simple, appelez foura_single avec session.proxy sous proxy, sérialisez les cookies dans un en-tête Cookie et envoyez session.userAgent dans l'en-tête User-Agent. Pour le rendu JavaScript, transmettez les valeurs de session aux champs foura_browser correspondants.

foura_single

Une requête HTTP, une réponse en retour. Correspond exactement à POST /api/single/.

À utiliser pour les pages statiques, les API JSON et le HTML généré côté serveur.

Choisir le navigateur que vous présentez

Une requête présente la dernière version de Google Chrome par défaut. Lorsqu'une cible accepte un navigateur et en refuse un autre, définissez browser (Chrome, Edge, Safari, Firefox ou Tor), os (Windows, macOS, Android ou iOS) ou version, ou transmettez un identifiant profile exact:

{
  "method": "GET",
  "url": "https://example.com",
  "browser": "Firefox",
  "os": "Windows"
}

La version la plus récente l'emporte lorsque plusieurs profils correspondent. Une combinaison qui n'existe pas renvoie une erreur listant les options disponibles, afin qu'une request ne soit jamais envoyée sous l'identité d'un navigateur que vous n'avez pas choisi. La sélection nécessite unblocker, activé par défaut. Le catalogue est publié à l'adresse GET /api/profiles et ne requiert aucune clé d'API.

Les quatre mêmes champs se trouvent dans l'objet request de foura_proxy.

foura_proxy

Acheminez une request HTTP via des proxys tournants avec nouvelle tentative automatique. Utilisez-le lorsque foura_single est bloqué ou que la cible exige un pays de sortie spécifique.

Définissez exitCountries sur une allowlist stricte de codes pays à deux lettres visibles par la cible, fournis par l'utilisateur ou selon les exigences de la cible :

{
  "maxTries": 5,
  "exitCountries": ["CZ", "GB"],
  "request": {
    "method": "GET",
    "url": "https://example.com/pricing",
    "browser": "Chrome",
    "os": "Windows"
  }
}

Les valeurs sont nettoyées des espaces, converties en majuscules et dédupliquées. Les proxys avec des sorties inconnues sont exclus, et la requête ne bascule jamais vers un pays non demandé. La sélection utilise les métadonnées de pays visibles par la cible les plus récentes, généralement mises à jour sous dix minutes ; il ne s'agit pas d'une recherche de géolocalisation en direct pendant la requête. Ne déduisez pas le pays de distribution à partir de l'adresse de l'hôte proxy.

Un succès ciblé renvoie exitCountry et l'ID réutilisable proxy. Vérifiez que exitCountry appartient à la liste d'autorisation demandée. Si le pool actuel n'a aucune correspondance, l'outil renvoie code: "no_eligible_proxy" avec le périmètre normalisé dans details.exitCountries. Conservez ce périmètre et réessayez plus tard. Ne le modifiez ou ne l'élargissez que si l'utilisateur modifie explicitement le besoin. Le ciblage géographique est inclus à partir du forfait Startup. Sur un forfait qui ne l'inclut pas, un appel envoyant exitCountries est refusé avec 403 et X-FourA-Limit: plan_limit_feature.

Si la page sélectionnée a ensuite besoin de JavaScript, transmettez l'ID proxy renvoyé à foura_browser.proxy afin que le navigateur réutilise la même sortie.

Définissez exitClass: "premium" pour une cible que le pool standard ne peut pas atteindre quel que soit le nombre de sorties essayées. Il s'agit d'une autorisation, pas d'une instruction : le pool standard reste en concurrence pour obtenir la réponse et l'emporte généralement, et une requête à laquelle il répond avant qu'une sortie premium ne soit essayée ne consomme aucun trafic premium. Une tentative premium comptabilise le trafic qu'elle a transporté même en cas d'échec. La réponse renvoie exitClass, premium ou standard, afin que vous puissiez voir par requête quelle classe vous a servi. standard est également la réponse dès que le trafic premium inclus dans votre forfait est épuisé, et constitue un résultat normal plutôt qu'une erreur. exitClass: "standard" interdit purement et simplement l'escalade. exitClass: "premium" sur un forfait sans sorties premium est refusé avec code: "plan_limit_premium". Voir exitClass.

Lorsque la rotation a dû passer à une autre famille de navigateurs pour obtenir une réponse, une réponse réussie contient profile avec la famille retenue. Rejouez avec celle-ci, sinon le prochain appel répète la version qui a échoué.

Une rotation ayant échoué contient attemptReport à côté de l'erreur : une phrase summary, ainsi que des compteurs qui séparent les sorties qui n'ont jamais répondu (noResponse), les sorties refusées par un contrôle de bot (defense, avec les fournisseurs dans vendors), les pages reçues et rejetées uniquement par votre propre validate.data (contentRejected), statusRejected et other. profilesTried liste les navigateurs envoyés par la tâche, par ordre de première utilisation, default signifiant que la requête a été envoyée exactement comme écrite. Une valeur élevée pour contentRejected signifie que FourA a fourni de vraies pages et que votre propre règle les a rejetées. Voir Why a Proxy Request Ran Out of Tries.

foura_browser

Session de navigateur complète. JavaScript s'exécute, le DOM s'affiche, les cookies sont renvoyés. Reproduit fidèlement POST /api/browser/.

À utiliser pour les applications monopages, le contenu en chargement différé ou les pages comportant une vérification nécessitant un vrai navigateur pour aboutir.

Pour les formats d'entrée, les valeurs par défaut et les règles de validation de chaque outil, consultez la référence des endpoints REST. Les schémas des outils correspondent champ pour champ à l'API REST, avec en plus l'option MCP exclusive offload_large (voir ci-dessous).

Quand une cible exécute un contrôle anti-bot

foura_single et foura_proxy renvoient defense lorsque la cible a exécuté une vérification anti-bot avant d'atteindre le corps de la réponse. defense.solved: true signifie que le contrôle a été validé et que data est la véritable page ; false signifie que le corps peut être une page de challenge. Réessayez avec un navigateur, un OS ou une version différente, ou passez à foura_proxy ou foura_browser, au lieu de traiter la page de challenge comme du contenu.

Réponses typées

Chaque réponse d'outil comprend à la fois content (résumé textuel lisible par l'humain) et structuredContent (JSON typé validé par rapport au outputSchema de l'outil). Chaque outil a sa propre structure :

  • foura_auto : structure simple { status, headers, data } plus meta ({ rung, solved, attempts, credits }, toujours présent, où rung est l'un de cache, probe, proxy, browser, warmup, fail) et, par défaut, session ({ proxy, cookies, userAgent }) pour le rejeu via les outils de niveau inférieur. Pas de total_time.
  • foura_single : { status, headers, data, total_time, ... } (headers est un tableau, une entrée par saut de redirection)
  • foura_proxy : identique à single plus { proxy, total } ; un succès ciblé inclut également exitCountry, une requête ayant nommé une classe inclut exitClass, une rotation ayant changé de famille de navigateur inclut profile, et un échec inclut attemptReport
  • foura_browser : structure distincte { status, headers: object, body, cookies, userAgent } (remarque : body peut être une chaîne ou un objet selon le content-type)

Chaque outil indique également le coût de l'appel et la manière de le tracer, lus à partir des en-têtes de réponse de l'API :

  • credits : crédits consommés par cet appel. Présent également en cas d'échec, car le travail a été effectué dans les deux cas. Vous n'êtes facturé que pour un appel réussi, un échec affiche donc ses crédits ici mais ne vous coûte rien.
  • request_id : identifiant FourA pour l'appel. Mentionnez-le dans une demande d'assistance.
  • exitClass : premium lorsqu'une sortie premium a traité l'appel. Sur foura_single et foura_browser, cela se produit lorsque proxy rejoue une sortie trouvée par foura_proxy.

Chacun est absent lorsque l'API n'a rien signalé, de sorte qu'un client conçu pour une version antérieure continue de fonctionner sans modification. Ces mêmes valeurs sont documentées dans Response Headers.

Les clients prenant en charge structuredContent peuvent transmettre l'objet typé directement au LLM au lieu de lui demander d'extraire le JSON du texte brut.

En-têtes de réponse à valeurs multiples

Les en-têtes qui apparaissent plusieurs fois (Set-Cookie, Link, WWW-Authenticate) sont renvoyés sous forme de tableaux :

{
  "headers": [
    {
      "result": { "version": "HTTP/2", "code": 200, "reason": "" },
      "content-type": "text/html",
      "set-cookie": ["a=1; Path=/", "b=2; Path=/"]
    }
  ]
}

Cela est important pour les sites qui définissent des cookies de session, de tracking et de consentement dans une seule réponse (la plupart des sites d'e-commerce).

Réponses volumineuses : offload_large (par défaut : inline)

Par défaut (depuis la version v0.2.0), les corps de réponse complets sont renvoyés inline dans structuredContent, quelle que soit leur taille. Cela fonctionne immédiatement dans chaque client MCP.

Si votre client prend en charge resources/read de MCP ET que vous souhaitez économiser des tokens sur les pages volumineuses, transmettez offload_large: true par appel d'outil. Les réponses >= 50 Ko sont alors écrites sur le disque, renvoyées sous forme de resource_link, et votre client ne récupère le corps de la réponse que lorsqu'il en a réellement besoin. Sur le serveur hébergé, les payloads en cache expirent au bout d'une heure. Sur votre propre instance, rien ne supprime les payloads stockés : nettoyez vous-même les fichiers de plus d'une heure dans le répertoire des payloads.

{
  "method": "GET",
  "url": "https://en.wikipedia.org/wiki/Web_scraping",
  "offload_large": true
}
Client offload_large: true
Claude Desktop pas encore, laissez par défaut false
Claude Code, Cursor, Windsurf pris en charge
Extension VS Code MCP pris en charge

Isolation par tenant: chaque clé API dispose de son propre namespace (sha256(apiKey)[:16]). Seule la clé ayant stocké un payload peut le relire. Les lectures cross-tenant renvoient Payload not found sans fuite d'information sur son existence.

Prompts intégrés

Six modèles de workflow apparaissent sous /prompts dans n'importe quel client MCP. Chacun prend des arguments nommés et renvoie un message utilisateur sous forme de template orchestrant un ou plusieurs outils.

Prompt Arguments Description
smart_fetch url, optionnel must_contain, extract Auto fetch (sélectionne la méthode, gère la protection anti-bot), puis renvoie ou extrait le contenu
scrape_product_page url Fetch navigateur, puis extrait le titre du produit, le prix, l'image, le stock et le SKU au format JSON
extract_article url Single avec fallback proxy, puis supprime la navigation/publicités et renvoie un JSON d'article nettoyé
monitor_pricing url, optionnel target_price Fetch proxy, extrait le prix actuel et le compare à la cible
check_endpoint_health url, optionnel expected_text Single avec validation stricte, renvoie l'accessibilité et les métriques de temps
bulk_fetch_urls urls (séparées par des virgules) Single en parallèle, fallback automatique vers proxy par URL, renvoie uniquement les métadonnées

Les prompts ne consomment aucun token au repos. Seuls les prompts exécutés intègrent le contexte du LLM.

Texte complet et prompts de fallback manuel: MCP Recipes.

Enveloppe d'erreur

Chaque erreur (isError: true) comporte une enveloppe structuredContent. Champs minimaux pour 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. En cas d'erreurs de rate limit et de capacité, l'enveloppe en amont ajoute retryAfter, current.{concurrency, rpm} et limits.{maxConcurrency, maxRpm}. Consultez API Errors pour la structure REST sous-jacente.

Valeurs code stables :

Code HTTP Signification Nouvelle tentative sans risque ?
ssrf_blocked n/a La cible est une adresse privée ou réservée (RFC 5735, 6598, IPv6 réservé), 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 variable Le serveur en amont a renvoyé un corps malformé Peut-être, examinez le problème
output_validation_failed n/a Le outputSchema du serveur MCP a rejeté la réponse en amont, ou l'outil n'a pas pu effectuer l'appel (aucune clé API configurée, API inaccessible) Peut-être : vérifiez la configuration, puis signalez l'erreur
bad_request 400 Format d'entrée rejeté Non, corrigez les arguments
auth_failed 401 Clé manquante, invalide ou désactivée Non, corrigez la clé
forbidden 403 La cible a répondu 403 et votre validate l'a rejetée (vérification du site, restriction géographique) Non, ou passez à foura_proxy
not_found 404 Cible ou endpoint manquant Non
rate_limited 429 Limite RPM atteinte Oui, attendez retryAfter
at_capacity 503 Limite de concurrence atteinte Oui, attendez retryAfter
service_disabled 503 Le service est désactivé pour maintenance. Un outil non inclus dans votre forfait renvoie plan_limit_feature Contactez le support
service_unavailable 503 503 générique 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 4xx 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 Examinez le problème
no_eligible_proxy n/a Aucun proxy ne correspond au périmètre strict exitCountries Réessayez plus tard; ne modifiez le périmètre qu'explicitement
plan_limit_* 403 ou 429 L'une des limites de votre forfait a refusé l'appel : plan_limit_ suivi de feature, premium, concurrency, rate, browser_daily, credits ou bandwidth. Consultez MCP Server Errors Attendez retryAfter si présent; sinon pas avant la réinitialisation de la limite ou le changement de forfait

Les agents LLM peuvent lire code directement pour la logique de nouvelle tentative sans analyser le texte. Guide d'authentification : Authentication.

Limites

  • Corps de réponse inline par défaut. Avec offload_large: true, les réponses >= 50 Ko sont écrites sur disque + resource_link (par tenant, TTL de 1 heure).
  • Les cibles privées sont refusées (RFC 5735, RFC 6598, blocs réservés IPv6) au niveau de la couche MCP. Seuls les hôtes publics sont transmis.
  • Limite de taille du corps de requête à 256 Ko sur les requêtes /mcp entrantes (les charges utiles MCP réelles font < 4 Ko).
  • Les rate limits sont appliqués par l'API FourA par service. Consultez Rate Limits.

Auto-hébergement

Le code source complet du serveur est public sur GitHub sous licence @fouradata/mcp. Clonez le dépôt, npm install, npm run build, et exécutez node dist/http.js pour déployer votre propre instance. Fonctionne sans état dans un conteneur unique derrière n'importe quel load balancer.

Environnement configurable :

Variable Valeur par défaut Description
PORT 3076 Port d'écoute HTTP
FOURA_API_BASE https://api.foura.ai/api URL de base REST FourA en amont
FOURA_MCP_PAYLOADS_DIR un dossier foura-mcp-payloads dans le répertoire temporaire système (le fichier Docker Compose fourni définit /data/payloads) Emplacement où les réponses >= 50 Ko sont mises en cache sur disque (avec offload_large: true)
FOURA_MCP_ALLOWED_HOSTS mcp.foura.ai,localhost,127.0.0.1,[::1] Liste d'autorisation de noms d'hôte pour l'en-tête Host (protection contre le DNS rebinding)
FOURA_MCP_ALLOWED_ORIGINS https://mcp.foura.ai,https://claude.ai,https://app.cursor.sh,https://app.cursor.com Liste d'autorisation d'origines pour les appelants navigateurs

Le conteneur officiel s'exécute en tant que uid 1001 (non-root). Le montage hôte /data/payloads doit être accessible en écriture par cet UID.

Mise à l'échelle horizontale derrière n'importe quel load balancer. Les clients fournissent leur clé à chaque requête, il n'y a donc pas de session persistante.

Mis à jour : 27 septembre 2026