Serveur MCP
Serveur MCP
Utilisez FourA depuis n'importe quel client Model Context Protocol (Claude Desktop, Claude Code, Cursor, Windsurf, VS Code) sous forme de quatre outils natifs et de six invites de flux de travail. Aucun code d'intégration, aucun client HTTP personnalisé.
Open source sur GitHub ; sur npm sous le nom de @fouradata/mcp. Version actuelle : 0.5.0.
Démarrage rapide : stdio local (recommandé pour Claude Desktop)
Récupérez une clé sur foura.ai/dashboard#api-keys (en un clic, affichée une seule fois à la création, format pk_live_...). Ajoutez ceci à la configuration de votre client MCP :
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "@fouradata/mcp"],
"env": { "FOURA_API_KEY": "pk_live_..." }
}
}
}
Piège de Claude Desktop : quittez complètement Claude Desktop (
Cmd+Qsur 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 à la 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 nécessaire.
| 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 qui prennent en charge le transport Streamable HTTP (Cursor, Windsurf, VS Code, Claude Code avec --transport http), dirigez-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 connectez le 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 du endpoint hébergé
| Propriété | Valeur |
|---|---|
| URL | https://mcp.foura.ai/mcp |
| Transport | HTTP en continu (POST /mcp, responses SSE) |
| Authentification | Authorization: Bearer pk_live_... par request |
| MCP-Protocol-Version | Selon @modelcontextprotocol/sdk (actuellement 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07) |
| Défi 401 | WWW-Authenticate: Bearer realm="foura-mcp", resource_metadata="https://foura.ai/docs/mcp/server#auth" |
Le serveur hébergé est sans état. Chaque request apporte sa propre clé, que le serveur transmet à l'API FourA comme X-API-Key. Une clé ouvre les quatre outils.
Pour la protection contre le DNS-rebinding (CVE-2025-66414), le serveur valide le header Host (doit être mcp.foura.ai ou localhost) et le header Origin s'il est présent (liste blanche : mcp.foura.ai, claude.ai, app.cursor.sh, app.cursor.com). Les appelants de serveur à serveur (curl, clients MCP en mode pont stdio) n'envoient pas de Origin et passent outre.
Outils
Les quatre outils sont annotés readOnlyHint: true et openWorldHint: true selon la spécification MCP du 2025-06-18. Les clients qui approuvent automatiquement les outils en lecture seule de confiance les appellent sans fenêtre de confirmation par request.
foura_auto est l'option par défaut intelligente : 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 plus bas niveau qu'il orchestre. Utilisez-les quand vous voulez un contrôle explicite.
foura_auto
Donnez-lui une URL quand vous voulez que FourA choisisse la méthode de request. Il effectue des tentatives limitées à travers les chemins HTTP, proxy et navigateur disponibles. Passez validate sur les cibles protégées pour que la response doive contenir du contenu qui identifie la vraie page. Si aucune tentative ne satisfait la validation, l'outil retourne une erreur au lieu de présenter une page de défi comme un succès.
La response inclut les détails d'achèvement dans meta et, par défaut, une session réutilisable avec proxy, cookies et userAgent. Pour un suivi simple, appelez foura_single avec session.proxy comme proxy, sérialisez les cookies comme header Cookie et envoyez session.userAgent comme header User-Agent. Pour le rendu JavaScript, passez les valeurs de session aux champs foura_browser correspondants.
foura_single
Une HTTP request, une response en retour. Reflète fidèlement POST /api/single/.
À utiliser pour les pages statiques, les API JSON et le HTML rendu par le serveur.
Choisir le navigateur que vous présentez
Une request présente le dernier Google Chrome par défaut. Quand 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 passez 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 inexistante renvoie une erreur listant ce qui est disponible, afin qu'une request ne soit jamais envoyée en tant que navigateur que vous n'avez pas choisi. La sélection nécessite unblocker, qui est activé par défaut. Le catalogue est publié sur GET /api/profiles et ne nécessite aucune clé API.
Les quatre mêmes champs se trouvent dans l'objet request de foura_proxy.
foura_proxy
Acheminez une request HTTP via des proxies rotatifs avec réessai automatique. Utilisez-le lorsque foura_single est bloqué ou que la cible nécessite un pays de sortie spécifique.
Définissez exitCountries sur une liste d'autorisation stricte de codes pays à deux lettres visibles par la cible, fournis par l'utilisateur ou par 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 rognées, mises en majuscules et dédupliquées. Les proxys avec des sorties inconnues sont exclus, et la requête ne se rabat jamais sur un pays non demandé. La sélection utilise les métadonnées les plus récentes du pays visible par la cible, normalement mises à jour dans les dix minutes ; ce n'est pas une recherche de géolocalisation en direct pendant la requête. Ne déduisez pas le pays de service à partir de l'adresse de l'hôte du proxy.
Un succès ciblé retourne exitCountry et l'ID proxy réutilisable. Vérifiez que exitCountry appartient à l'allowlist demandée. Si le pool actuel n'a aucune correspondance, l'outil retourne code: "no_eligible_proxy" avec la portée normalisée dans details.exitCountries. Conservez cette portée et réessayez plus tard. Ne la modifiez ou ne l'élargissez que lorsque l'utilisateur modifie explicitement l'exigence.
Si la page sélectionnée a besoin de JavaScript par la suite, passez l'ID proxy retourné à foura_browser.proxy pour que le navigateur réutilise la même sortie.
foura_browser
Session complète du navigateur. JavaScript s'exécute, le DOM s'affiche, les cookies reviennent. Reflète POST /api/browser/.
Utilisez-le pour les applications monopages, le contenu chargé de manière asynchrone, ou les pages derrière des défis anti-bot qui nécessitent un vrai navigateur pour passer.
Pour les structures d'entrée, les valeurs par défaut et les règles de validation de chaque outil, référez-vous à la référence de l'endpoint REST. Les schémas des outils correspondent à l'API REST champ par champ, plus l'option offload_large réservée à MCP (voir ci-dessous).
Lorsqu'une cible exécute une vérification de bot
foura_single et foura_proxy retournent defense lorsque la cible a exécuté une vérification de bot sur le chemin vers le corps. defense.solved: true signifie que la vérification a été réussie et que data est la vraie page ; false signifie que le corps peut être une page de défi. Réessayez avec un navigateur, un système d'exploitation ou une version différente, ou passez à foura_proxy ou foura_browser, au lieu de traiter la page de défi comme du contenu.
Réponses typées
Chaque réponse de l'outil inclut à la fois content (résumé textuel lisible par un humain) et structuredContent (JSON typé et validé selon le outputSchema de l'outil). Chaque outil a sa propre structure unique :
foura_auto:{ status, headers, data }à structure unique plusmeta({ rung, solved, attempts, credits }, toujours présent, oùrungest l'un decache,probe,proxy,browser,fail) et, par défaut,session({ proxy, cookies, userAgent }) pour rejouer à travers les outils de bas niveau. Pas detotal_time.foura_single:{ status, headers, data, total_time, ... }(les headers sont un tableau, une entrée par saut de redirection)foura_proxy: identique à single plus{ proxy, total }; un succès ciblé inclut égalementexitCountryfoura_browser: structure distincte{ status, headers: object, body, cookies, userAgent }(remarque :bodypeut être une chaîne de caractères ou un objet selon le content-type)
Les clients qui supportent structuredContent peuvent passer l'objet typé directement au LLM au lieu de lui demander de parser du JSON à partir d'un texte.
Headers de réponse à valeurs multiples
Les headers qui apparaissent plusieurs fois (Set-Cookie, Link, WWW-Authenticate) reviennent 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 suivi et de consentement dans une seule réponse (la majorité du commerce en ligne).
Réponses volumineuses : offload_large (par défaut : en ligne)
Par défaut (depuis la v0.2.0), les corps de réponse complets sont renvoyés en ligne dans structuredContent quelle que soit leur taille. Cela fonctionne dans chaque client MCP sans configuration préalable.
Si votre client prend en charge MCP resources/read ET que vous souhaitez économiser des jetons sur les grandes pages, transmettez offload_large: true par appel d'outil. Les réponses >= 50 Ko sont ensuite écrites sur le disque, renvoyées sous forme de resource_link, et votre client récupère le corps uniquement lorsqu'il en a réellement besoin. Les données en cache expirent après 1 heure.
{
"method": "GET",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"offload_large": true
}
| Client | offload_large: true |
|---|---|
| Claude Desktop | pas encore, laissez la valeur par défaut false |
| Claude Code, Cursor, Windsurf | pris en charge |
| VS Code MCP extension | pris en charge |
Isolé par locataire : chaque clé API obtient son propre espace de noms (sha256(apiKey)[:16]). Seule la clé qui a stocké un payload peut le relire. Les lectures inter-locataires renvoient Payload not found sans fuite d'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 basé sur un modèle, orchestrant un ou plusieurs outils.
| Prompt | Arguments | Ce qu'il fait |
|---|---|---|
smart_fetch |
url, must_contain facultatif, extract |
Fetch automatique (choisit la méthode, gère la protection contre les bots), puis renvoie ou extrait le contenu |
scrape_product_page |
url |
Fetch par navigateur, puis extrait le titre du produit, le prix, l'image, le stock, le SKU en JSON |
extract_article |
url |
Requête unique avec fallback sur proxy, puis supprime la navigation et les publicités et renvoie l'article propre en JSON |
monitor_pricing |
url, target_price facultatif |
Fetch par proxy, extrait le prix actuel, le compare à la cible |
check_endpoint_health |
url, expected_text facultatif |
Requête unique avec validation stricte, renvoie l'accessibilité et les temps d'exécution |
bulk_fetch_urls |
urls (séparés par des virgules) |
Requêtes uniques parallèles, fallback automatique sur proxy par URL, renvoie uniquement les métadonnées |
Les prompts coûtent zéro token au repos. Seuls les prompts invoqués entrent dans le contexte LLM.
Texte intégral plus prompts de fallback manuel : Recettes MCP.
Enveloppe d'erreur
Chaque erreur (isError: true) comporte une enveloppe structuredContent. Champs minimums pour chaque erreur :
{
"service": "auto | single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
En cas d'erreurs en amont avec un statut HTTP, status est également présent. En cas d'erreurs de limite de débit (rate limit) et de capacité, l'enveloppe amont ajoute retryAfter, current.{concurrency, rpm} et limits.{maxConcurrency, maxRpm}. Consultez Erreurs API pour la forme REST sous-jacente.
Valeurs code stables :
| Code | HTTP | Signification | Tentative sûre ? |
|---|---|---|---|
ssrf_blocked |
n/a | Adresse IP cible dans une plage privée ou réservée (RFC 5735, 6598, IPv6 réservé) | Non, modifiez l'URL |
upstream_non_json |
varie | L'amont a renvoyé un corps malformé | Peut-être, enquêtez |
output_validation_failed |
n/a | Le outputSchema du serveur MCP a rejeté la réponse en amont (bug du serveur ou forme inattendue en amont) |
Peut-être, signalez |
bad_request |
400 | Forme d'entrée rejetée | Non, corrigez les arguments |
auth_failed |
401 | Clé manquante, invalide ou désactivée | Non, corrigez la clé |
forbidden |
403 | Authentifié mais non autorisé | 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 | Fenêtre de maintenance ou votre plan n'inclut pas cet outil | Contactez le support |
service_unavailable |
503 | 503 générique | Oui, délai d'attente court |
upstream_error |
500+ | 5xx en amont | Oui, délai d'attente exponentiel |
upstream_client_error |
4xx | Autre 4xx | Généralement non |
upstream_unknown |
autre | Défensif, ne devrait pas se produire en pratique | Enquêtez |
no_eligible_proxy |
n/a | Aucun proxy ne correspond à la portée exitCountries stricte |
Réessayez plus tard ; modifiez la portée uniquement de manière explicite |
Les agents LLM peuvent lire code directement pour la logique de nouvelle tentative sans analyser le texte. Procédure d'authentification : Authentification.
Limites
- Corps en ligne par défaut. Avec
offload_large: true, les réponses >= 50 Ko vont sur le disque +resource_link(par locataire, 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 transférés.
- Limite du corps de la requête de 256 Ko sur les requêtes
/mcpentrantes (les vrais payloads MCP font < 4 Ko). - Les limites de débit sont appliquées par l'API FourA pour chaque service. Consultez Limites de débit.
Auto-hébergement
Le code source complet du serveur est public sur GitHub sous @fouradata/mcp. Clonez le dépôt, npm install, npm run build, et exécutez node dist/http.js pour configurer votre propre instance. S'exécute sans état dans un seul conteneur derrière n'importe quel répartiteur de charge.
Environnement configurable :
| Variable | Défaut | Objectif |
|---|---|---|
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 |
/data/payloads |
Où les response >= 50 Ko sont mises en cache sur le disque (avec offload_large: true) |
FOURA_MCP_ALLOWED_HOSTS |
mcp.foura.ai,localhost,127.0.0.1,[::1] |
Liste blanche de noms d'hôtes pour le header Host (défense contre le DNS-rebinding) |
FOURA_MCP_ALLOWED_ORIGINS |
https://mcp.foura.ai,https://claude.ai,https://app.cursor.sh,https://app.cursor.com |
Liste blanche d'origines pour les appels depuis le navigateur |
FOURA_MCP_RESOURCE_METADATA_URL |
https://foura.ai/docs/mcp/server#auth |
URL renvoyée dans WWW-Authenticate lors d'une erreur 401 |
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.
Mettez à l'échelle horizontalement derrière n'importe quel équilibreur de charge. Les clients fournissent leur clé à chaque request, il n'y a donc pas de session persistante.