Comment créer son propre serveur MCP pour collecter des données sur les sites web : guide pas à pas pour débutants
Sommaire de l'article
- Introduction : ce que vous obtiendrez à la fin de ce guide
- Préparation : outils, accès et configuration requise
- Notions de base : comment fonctionne un serveur mcp et à quoi il sert à un agent ia
- Étape 1 : créer le projet et installer les dépendances
- Étape 2 : écrire un serveur mcp minimal avec un premier outil
- Étape 3 : connecter le serveur mcp au client ia
- Étape 4 : ajouter les outils d'extraction de données
- Étape 5 : connecter les proxys mobiles et la rotation d'ip
- Étape 6 : rendre le serveur robuste : répétitions, délais, cache et limites
- Vérification du résultat : checklist d'un serveur mcp prêt à l'emploi
- Erreurs courantes lors de la création d'un serveur mcp et leurs solutions
- Fonctionnalités supplémentaires : bloc pour les utilisateurs avancés
- Faq : questions fréquentes sur la création d'un serveur mcp
- Conclusion : ce que vous avez fait et où aller ensuite
Introduction : ce que vous obtiendrez à la fin de ce guide
Imaginez que vous ouvrez un chat avec un assistant IA et que vous écrivez : « Va sur la page d'un concurrent, récupère les noms et les prix de tous les produits du catalogue et présente-les dans un tableau ». L'assistant ne répond pas « je n'ai pas accès à internet », mais télécharge réellement la page, en extrait les données et vous remet un résultat prêt à l'emploi. C'est exactement ce que vous allez construire en suivant ce guide jusqu'au bout. Le lien entre le modèle de langage et le web sera votre propre serveur MCP, écrit en Python.
Une précision importante : nous n'allons pas examiner Playwright MCP ni d'autres solutions clés en main. Le blog leur consacre des articles séparés. Ici, l'objectif est différent : écrire un serveur de zéro pour que vous compreniez chaque ligne, puissiez ajouter vos propres outils, connecter des proxys mobiles et adapter la logique à des tâches concrètes. Votre propre solution est toujours plus flexible que celle des autres.
À qui s'adresse ce guide
- Aux marketeurs et chefs d'entreprise qui ont besoin de collecter rapidement des prix, des avis, des descriptions de produits et du contenu concurrentiel, sans commander un scraper à un développeur.
- Aux affiliés et spécialistes de l'arbitrage qui surveillent des offres, des landing pages et des créas et veulent déléguer la routine à un agent IA.
- Aux développeurs qui ont entendu parler du protocole MCP mais n'ont pas encore construit leur serveur et veulent un modèle fonctionnel.
- Aux utilisateurs de proxys mobiles pour qui il est important que les requêtes de l'agent passent par leur proxy et non directement depuis leur IP personnelle.
Ce qu'il faut savoir au préalable
Ce guide s'adresse aux débutants. Aucune expérience en programmation n'est obligatoire, mais une compréhension de ce qu'est une ligne de commande et de la façon d'ouvrir un fichier dans un éditeur de texte vous sera utile. Tout le code peut être copié tel quel, et chaque partie est expliquée en langage simple. Si vous programmez déjà en Python, un bloc dédié aux fonctionnalités avancées vous attend vers la fin de l'article.
Combien de temps cela prendra
Prévoyez 2 à 3 heures pour une première passe. L'installation des outils prendra environ 30 minutes, un serveur MCP minimal fonctionnel apparaîtra au bout d'une heure, et le temps restant servira à ajouter les outils d'extraction de données, connecter le proxy et tester. Reproduire l'ensemble sur un autre ordinateur vous prendra ensuite 20 à 30 minutes.
Préparation : outils, accès et configuration requise
Avant d'écrire du code, assurez-vous d'avoir tout le nécessaire. Cette section se parcourt en une demi-heure et vous évitera la moitié des problèmes typiques des étapes suivantes.
Configuration requise
- Un ordinateur sous Windows 10/11, macOS 12 ou plus récent, ou Linux (Ubuntu 22.04 ou plus récent). Tout ce qui est décrit fonctionne sur ces systèmes, seuls les chemins de fichiers diffèrent.
- Au minimum 4 Go de RAM et 1 Go d'espace disque libre.
- Un accès internet stable.
Ce qu'il faut installer
- Python 3.11 ou plus récent. En 2026, les versions 3.12 et 3.13 sont d'actualité. Téléchargez l'installateur depuis le site officiel du projet Python. Sous Windows, dans la première fenêtre de l'installateur, cochez impérativement Add python.exe to PATH, sinon la commande python sera introuvable dans le terminal. Sur macOS, il est plus simple d'installer Python via Homebrew avec la commande brew install python. Sur Ubuntu, exécutez sudo apt install python3 python3-venv python3-pip.
- Un éditeur de texte pour le code. Nous recommandons Visual Studio Code. Il est gratuit, colore la syntaxe et affiche les erreurs. N'importe quel autre éditeur fera l'affaire, même le Bloc-notes, mais VS Code vous simplifiera la vie.
- Un client MCP, c'est-à-dire une application avec un agent IA à laquelle vous connecterez le serveur. L'option la plus simple pour les débutants : Claude Desktop. L'éditeur Cursor, VS Code avec l'extension GitHub Copilot et d'autres outils prennent aussi en charge MCP. Installez au moins l'un d'entre eux avant de commencer.
- Node.js 20 ou plus récent. Il n'est pas nécessaire au serveur lui-même, mais à l'utilitaire MCP Inspector, avec lequel nous déboguerons les outils. Téléchargez l'installateur de la version LTS depuis le site officiel de Node.js et installez-le avec les paramètres par défaut.
Accès
Pour la section sur les proxys, vous aurez besoin des données de votre proxy mobile : hôte, port, identifiant et mot de passe, ainsi que du lien de rotation d'adresse IP si votre forfait le prend en charge. Tout cela se trouve dans l'espace client de votre fournisseur. Si vous n'avez pas encore de proxy, vous pouvez suivre le guide sans : le serveur fonctionnera directement, et vous ajouterez le proxy plus tard en une seule ligne.
Sauvegardes
Nous allons modifier le fichier de configuration du client MCP. Avant cela, copiez-le en lieu sûr, par exemple sur le bureau avec la mention « backup ». Si quelque chose se passe mal, vous restaurez simplement la copie. Conservez le code du serveur dans un dossier dédié et, après chaque étape fonctionnelle, sauvegardez une copie du fichier ou faites un commit dans Git si vous savez l'utiliser.
Conseil : Créez sur votre disque un dossier dédié avec un chemin court, sans espaces ni caractères cyrilliques, par exemple C:/mcp-collector sous Windows ou ~/mcp-collector sous macOS et Linux. Les espaces et les lettres accentuées dans les chemins cassent régulièrement le démarrage des serveurs depuis les fichiers de configuration, et vous perdrez une heure à chercher la cause.
Notions de base : comment fonctionne un serveur MCP et à quoi il sert à un agent IA
Avant d'écrire la première ligne de code, clarifions les termes. Sans cela, le tutoriel ressemblera à une suite de formules magiques ; avec, chaque action deviendra logique.
Qu'est-ce que MCP
MCP (Model Context Protocol) est un protocole ouvert qui décrit comment un modèle de langage communique avec des outils externes. Avant son apparition, chaque service inventait sa propre façon de « donner des mains à l'IA ». MCP a standardisé cela : si vous écrivez un serveur conforme au protocole, n'importe quel client compatible le comprendra, que ce soit Claude Desktop, Cursor ou votre propre agent. On peut comparer MCP à un port USB : peu importe ce que vous branchez, une clé USB ou une souris, le port reste le même.
Client et serveur
L'architecture MCP compte deux acteurs. Le client est l'application avec l'IA qui pose des questions et appelle les outils. Le serveur MCP est le programme qui fournit ces outils. Dans notre cas, le serveur sera la capacité de « naviguer sur internet et d'en extraire des données », et le client sera votre assistant IA. Le serveur se lance localement sur votre ordinateur, et le client communique directement avec lui.
Outils, ressources et prompts
Un serveur MCP peut fournir au client trois types d'entités :
- Les outils (tools) — des fonctions que le modèle peut appeler : « télécharge la page », « extrais tous les liens », « change l'IP du proxy ». C'est la base de notre guide.
- Les ressources (resources) — des données que le serveur expose en lecture, par exemple le contenu d'un fichier de configuration ou le résultat de la dernière collecte.
- Les prompts (prompts) — des modèles de requêtes prédéfinis que l'utilisateur peut invoquer d'une seule commande.
Pour la collecte de données, les outils suffisent. Nous aborderons les ressources et les prompts dans le bloc avancé.
Comment le modèle sait quoi appeler
Il y a ici une nuance importante. Lorsque le client se connecte au serveur, il demande la liste des outils avec leurs noms, descriptions et paramètres. Ces descriptions entrent dans le contexte du modèle. Ensuite, le modèle décide lui-même quel outil appeler et avec quels arguments, en s'appuyant précisément sur le texte de la description. C'est pourquoi les descriptions de fonctions dans notre code ne sont pas une formalité, mais une instruction pour l'IA. Plus vous décrivez clairement ce que fait l'outil et quand l'utiliser, plus l'agent travaillera avec précision.
Transport : stdio et HTTP
Le serveur et le client doivent échanger des messages d'une manière ou d'une autre. Le protocole prévoit deux méthodes principales. stdio — le client lance lui-même votre script en tant que processus enfant et communique via l'entrée et la sortie standard. C'est l'option la plus simple pour un usage local, et c'est par elle que nous commencerons. Streamable HTTP — le serveur fonctionne comme un service web auquel le client se connecte par une adresse. Cette option est nécessaire si le serveur réside sur une machine distante ou si plusieurs clients s'y connectent. Nous l'aborderons dans le bloc avancé.
⚠️ Attention : Avec le transport stdio, toute la sortie standard du processus est occupée par les messages protocolaires. Si vous écrivez un simple print de débogage dans le code, le client recevra des déchets au lieu d'une réponse correcte et coupera la connexion. Les messages de débogage ne peuvent être envoyés que vers le flux d'erreur stderr. Retenez cette règle, elle vous fera gagner beaucoup de temps.
Pourquoi la collecte de données via MCP est pratique
Un scraper classique est figé : il sait collecter des champs précis sur un site précis. Dès que le balisage change, le scraper casse. Le duo « agent IA + serveur MCP » fonctionne autrement : le serveur fournit des outils universels (télécharger, extraire le texte, trouver des éléments par sélecteur), et le modèle se débrouille lui-même avec la structure de la page et formule le résultat. Vous gagnez en flexibilité sans réécrire le code pour chaque nouvelle source.
Étape 1 : Créer le projet et installer les dépendances
Objectif de l'étape : préparer un environnement Python isolé et installer les bibliothèques nécessaires au serveur MCP. À la fin de cette étape, vous aurez un dossier de projet avec un environnement virtuel fonctionnel.
Pourquoi un environnement virtuel
Un environnement virtuel est une copie séparée de Python avec ses propres bibliothèques à l'intérieur du dossier du projet. Il sert à ce que notre serveur n'entre pas en conflit avec d'autres programmes Python de l'ordinateur, et à ce que le client MCP sache exactement quel interpréteur lancer. Sans lui, la moitié des problèmes « ça marche dans mon terminal mais pas dans le client » est garantie.
Instructions pas à pas
- Ouvrez un terminal. Sous Windows, appuyez sur Win+R, tapez powershell et validez avec Entrée. Sur macOS, ouvrez l'application Terminal via Spotlight (Cmd+Espace, puis tapez Terminal). Sur Linux, appuyez sur Ctrl+Alt+T.
- Créez le dossier du projet et placez-vous dedans. Sous Windows, exécutez deux commandes : mkdir C:/mcp-collector, puis cd C:/mcp-collector. Sur macOS et Linux : mkdir ~/mcp-collector, puis cd ~/mcp-collector.
- Vérifiez la version de Python avec la commande python --version (sur macOS et Linux, il peut falloir python3 --version). Vous devez voir une ligne du type Python 3.12.x. Si la version est inférieure à 3.11 ou si la commande est introuvable, revenez à la section de préparation et réinstallez Python.
- Créez l'environnement virtuel avec la commande python -m venv .venv. Un dossier caché .venv apparaîtra dans le dossier du projet. Cela prendra 10 à 20 secondes.
- Activez l'environnement. Sous Windows dans PowerShell : .venv/Scripts/Activate.ps1. Si PowerShell indique que l'exécution de scripts est interdite, exécutez la commande Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, confirmez avec Y et répétez l'activation. Sur macOS et Linux : source .venv/bin/activate. Après activation, la mention (.venv) apparaîtra au début de la ligne du terminal.
- Mettez à jour le gestionnaire de paquets : python -m pip install --upgrade pip.
- Installez les bibliothèques en une seule commande : pip install "mcp[cli]" httpx beautifulsoup4. Ici, mcp est le SDK Python officiel du protocole (la branche 1.x est d'actualité en 2026), httpx est une bibliothèque moderne pour les requêtes HTTP avec prise en charge des proxys, beautifulsoup4 est un outil d'analyse du HTML. L'installation prendra 1 à 2 minutes.
- Créez un fichier vide server.py dans le dossier du projet. Dans VS Code : ouvrez le dossier via File, Open Folder, puis cliquez sur l'icône de nouveau fichier dans le panneau de gauche et saisissez le nom.
Que signifient ces bibliothèques
- mcp prend en charge tout le protocole : l'enregistrement des outils, l'échange de messages, la description des paramètres. Le module FastMCP qu'il contient permet de déclarer un outil comme une simple fonction avec un décorateur.
- httpx télécharge les pages. Contrairement à requests, obsolète, il prend en charge HTTP/2, l'asynchrone et une configuration de proxy pratique.
- beautifulsoup4 transforme le HTML en un arbre dans lequel il est facile de chercher des éléments par balises et sélecteurs CSS.
Conseil : Mémorisez tout de suite le chemin complet vers l'interpréteur à l'intérieur de l'environnement virtuel. Sous Windows, c'est C:/mcp-collector/.venv/Scripts/python.exe ; sur macOS et Linux, c'est /Users/nom/mcp-collector/.venv/bin/python (ou /home/nom/... sur Linux). Il vous sera nécessaire lors de la connexion au client. Pour connaître le chemin exact, utilisez la commande where python sous Windows ou which python sous macOS et Linux avec l'environnement activé.
✅ Vérification : Exécutez la commande pip list. Les paquets mcp, httpx et beautifulsoup4 doivent apparaître dans la liste. Exécutez aussi python -c "import mcp, httpx, bs4; print('ok')" — la réponse doit afficher le mot ok sans erreur.
Problèmes possibles
- La commande python est introuvable. Sous Windows, réinstallez Python en cochant Add to PATH. Sur macOS, utilisez python3 au lieu de python.
- pip signale un problème de droits d'accès. L'environnement n'est probablement pas activé et vous installez les paquets dans le Python système. Vérifiez la mention (.venv) en début de ligne.
- Erreur de compilation à l'installation. Mettez à jour pip et réessayez. Si cela ne suffit pas, vérifiez que la version de Python n'est pas inférieure à 3.11.
Étape 2 : Écrire un serveur MCP minimal avec un premier outil
Objectif de l'étape : écrire un serveur MCP fonctionnel avec un seul outil qui télécharge une page à une adresse donnée et renvoie son HTML. C'est la fondation sur laquelle nous allons empiler les fonctions.
Code du serveur
Ouvrez le fichier server.py et collez-y le code suivant en entier :
import sys
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('web-collector')
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}
def log(message: str) -> None:
print(message, file=sys.stderr)
@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Скачивает страницу по указанному URL и возвращает её HTML-код.
Используй, когда нужно посмотреть исходную разметку страницы.
Параметр max_chars ограничивает длину ответа, чтобы не переполнять контекст.'''
log(f'fetch_page: {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text[:max_chars]
if __name__ == '__main__':
mcp.run()Analyse du code ligne par ligne
- FastMCP('web-collector') crée un objet serveur nommé web-collector. C'est ce nom que le client affichera dans la liste des serveurs connectés.
- HEADERS — les en-têtes que nous envoyons aux sites. De nombreux sites renvoient un contenu incomplet ou une erreur si la requête arrive sans un User-Agent de navigateur habituel. L'en-tête Accept-Language indique que nous voulons la version francophone de la page.
- La fonction log écrit les messages dans stderr. C'est ainsi, et non via un print ordinaire, car stdout est occupé par le protocole. Vous verrez ces messages dans les journaux du client et dans MCP Inspector.
- @mcp.tool() — le décorateur qui transforme une simple fonction en outil MCP. Le SDK lit automatiquement le nom de la fonction, les types des paramètres et la docstring et forme une description pour le modèle. La valeur par défaut max_chars = 20000 signifie que le paramètre est optionnel.
- La docstring entre triples guillemets est ce que lira l'IA. Nous y expliquons ce que fait l'outil et quand l'utiliser. Rédigez ces descriptions en détail et dans la langue avec laquelle vous communiquez avec l'agent.
- httpx.Client avec le paramètre follow_redirects=True suit automatiquement les redirections, et timeout=20.0 empêche la requête de rester suspendue indéfiniment.
- raise_for_status() lève une erreur si le site renvoie un code 4xx ou 5xx. Le SDK l'interceptera et renverra au client un message d'erreur clair au lieu de rien.
- mcp.run() lance le serveur avec le transport stdio par défaut. Il attendra les commandes du client.
Premier test via MCP Inspector
Lancer server.py directement ne sert à rien : il attendra des messages du client et n'affichera rien. Pour tester, utilisons MCP Inspector — une interface web qui simule un client et permet d'appeler les outils à la main.
- Assurez-vous que l'environnement virtuel est activé et que vous êtes dans le dossier du projet.
- Exécutez la commande mcp dev server.py. Cette commande fait partie du paquet mcp installé avec l'extension cli. Au premier lancement, elle téléchargera Inspector via npx, ce qui prendra environ une minute.
- Une adresse du type http://localhost:6274 apparaîtra dans le terminal ainsi que, dans les nouvelles versions, un jeton d'accès. Ouvrez l'adresse dans un navigateur (elle s'ouvre souvent toute seule).
- Dans le panneau de gauche d'Inspector, vérifiez que le transport sélectionné est STDIO, la commande — python, les arguments — server.py. Cliquez sur le bouton Connect.
- L'indicateur d'état deviendra vert avec la mention Connected. Allez dans l'onglet Tools du menu supérieur et cliquez sur List Tools.
- L'outil fetch_page apparaîtra dans la liste avec la description issue de la docstring et deux paramètres. Cliquez dessus.
- Dans le champ url, saisissez https://example.com, laissez le champ max_chars vide ou entrez 5000. Cliquez sur Run Tool.
- Le résultat apparaîtra à droite : le code HTML de la page, commençant par la balise doctype. En bas, dans l'onglet des journaux du serveur, vous verrez la ligne fetch_page: https://example.com.
✅ Vérification : Inspector affiche le statut Connected, fetch_page figure dans la liste Tools, un appel avec l'adresse example.com renvoie du HTML sans erreur. Si c'est le cas, votre premier serveur MCP fonctionne.
Problèmes possibles
- mcp dev indique que npx est introuvable. Node.js n'est pas installé. Installez-le et redémarrez le terminal.
- Inspector s'est ouvert mais Connect renvoie une erreur. Vérifiez que le champ commande indique bien le python de l'environnement activé. Vous pouvez y saisir le chemin complet vers python.exe à l'intérieur de .venv.
- Erreur SyntaxError à la connexion. Le code a été copié avec perte d'indentations. En Python, les indentations sont obligatoires : le corps des fonctions est décalé de quatre espaces. Vérifiez le fichier dans l'éditeur.
- L'outil renvoie une erreur 403. Le site n'a pas accepté la requête. Cela n'arrivera pas pour example.com, mais pour de vrais sites, nous y reviendrons à l'étape sur les proxys.
Étape 3 : Connecter le serveur MCP au client IA
Objectif de l'étape : enregistrer le serveur dans les paramètres du client IA pour que l'agent voie votre outil et puisse l'appeler depuis un chat ordinaire. Nous examinerons la connexion à Claude Desktop comme option la plus répandue et présenterons brièvement les alternatives.
Connexion à Claude Desktop
- Ouvrez Claude Desktop. Accédez aux paramètres : sous Windows via le menu en haut à gauche, option Settings ; sur macOS via le menu Claude, option Settings.
- Allez dans l'onglet Developer et cliquez sur le bouton Edit Config. Le dossier contenant le fichier claude_desktop_config.json s'ouvrira. Si le fichier n'existe pas, le client le créera.
- Faites une sauvegarde de ce fichier en le copiant sur le bureau.
- Ouvrez le fichier dans VS Code ou un autre éditeur. S'il est vide, collez le contenu en entier. S'il contient déjà d'autres serveurs, ajoutez votre bloc à l'intérieur de l'objet mcpServers, séparé par une virgule.
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"]
}
}
}Sur macOS et Linux, remplacez les chemins par les vôtres, par exemple /Users/ivan/mcp-collector/.venv/bin/python et /Users/ivan/mcp-collector/server.py. Notez que même sous Windows, les chemins sont écrits avec des barres obliques. C'est plus simple, car les antislashs doivent être doublés en JSON, alors que Windows comprend les barres obliques sans problème.
- Enregistrez le fichier. Vérifiez qu'il ne contient pas de virgules superflues après le dernier élément et que toutes les accolades sont fermées. Une seule virgule en trop rend le JSON invalide, et le client ignorera silencieusement la configuration.
- Fermez complètement Claude Desktop et relancez-le. Sous Windows, fermer la fenêtre ne suffit pas : cliquez droit sur l'icône dans la barre système et choisissez Quit. Le client ne lit la configuration qu'au démarrage.
- Après le lancement, ouvrez un nouveau chat. Sous le champ de saisie, trouvez l'icône des outils (symbole de curseurs ou de prise). Cliquez dessus : le serveur web-collector avec l'outil fetch_page doit figurer dans la liste.
- Écrivez dans le chat : « Télécharge la page https://example.com avec fetch_page et dis-moi quel est le titre de cette page ». Le client demandera l'autorisation d'appeler l'outil. Cliquez sur Allow ou Allow for this chat.
- Quelques secondes plus tard, l'agent répondra que le titre de la page est Example Domain. Il a effectué une vraie requête via votre serveur.
Connexion à Cursor et VS Code
Dans Cursor, ouvrez Settings, section MCP, cliquez sur Add new global MCP server. Le fichier mcp.json s'ouvrira avec exactement la même structure que celle de Claude Desktop. Collez le même bloc et enregistrez. Dans VS Code avec Copilot, créez à la racine du dossier de travail un fichier .vscode/mcp.json, où la clé mcpServers est remplacée par la clé servers, et à l'intérieur les mêmes command et args. Après enregistrement, un bouton Start apparaîtra au-dessus du bloc du serveur. Dans tous les clients, le principe est identique : indiquer la commande de lancement de l'interpréteur et le chemin vers le script.
Conseil : Indiquez dans command le python de l'environnement virtuel, et non le simple mot python. Le client lance le processus avec son propre ensemble de variables d'environnement, et la commande python du système peut être une autre version sans les bibliothèques installées. Le chemin complet élimine ce problème une fois pour toutes.
✅ Vérification : Le serveur web-collector est visible dans l'interface du client, l'agent appelle fetch_page sur demande et reformule correctement le contenu de la page example.com. Dans les journaux du client (dans Claude Desktop, c'est le dossier logs à côté de la configuration, fichier mcp-server-web-collector.log), la ligne fetch_page: https://example.com est visible.
Problèmes possibles
- Le serveur n'apparaît pas dans la liste. Vérifiez la validité du JSON : collez le contenu dans n'importe quel validateur JSON en ligne ou ouvrez-le dans VS Code, qui soulignera les erreurs. Assurez-vous que le client a été complètement redémarré.
- Un indicateur d'erreur rouge s'affiche à côté du serveur. Ouvrez le fichier journal. Le plus souvent, on y trouve ModuleNotFoundError : le mauvais python est indiqué. Vérifiez le chemin dans command.
- L'agent dit qu'il ne peut pas accéder à internet. Il n'a pas vu l'outil. Assurez-vous que les outils sont activés dans le panneau à curseurs et demandez explicitement : « utilise l'outil fetch_page ».
- Erreur spawn ENOENT. Le chemin vers python ou vers server.py comporte une erreur. Copiez le chemin depuis l'explorateur et remplacez les antislashs par des barres obliques.
Étape 4 : Ajouter les outils d'extraction de données
Objectif de l'étape : apprendre au serveur à renvoyer non pas du HTML brut, mais des données utiles : du texte propre, une liste de liens et des éléments par sélecteur CSS. L'agent pourra alors collecter des informations structurées sans gaspiller le contexte en balisage.
Pourquoi fetch_page seul ne suffit pas
Le HTML d'une vraie page pèse des centaines de kilooctets, et la majeure partie est constituée de scripts, de styles et de balisage technique. Si l'on renvoie tout au modèle à chaque fois, il atteindra vite la limite de contexte, et vous paierez pour des tokens superflus. La bonne stratégie : le serveur effectue un nettoyage grossier et une structuration, et le modèle travaille ensuite avec des données compactes. C'est pourquoi nous ajouterons trois outils spécialisés.
Code mis à jour
Remplacez le contenu de server.py par la version étendue. La fonction fetch_page est conservée, mais la logique commune de téléchargement a été extraite dans une fonction _get_html utilisée par tous les outils.
import sys
from urllib.parse import urljoin
import httpx
from bs4 import BeautifulSoup
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('web-collector')
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}
def log(message: str) -> None:
print(message, file=sys.stderr)
def _get_html(url: str) -> str:
log(f'GET {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text
def _clean(text: str) -> str:
return ' '.join(text.split())
@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Возвращает сырой HTML страницы. Используй только когда нужна именно разметка,
например чтобы подобрать CSS-селектор. Для чтения содержимого используй extract_text.'''
return _get_html(url)[:max_chars]
@mcp.tool()
def extract_text(url: str, max_chars: int = 15000) -> str:
'''Возвращает чистый текст страницы без скриптов, стилей и разметки.
Лучший выбор, когда нужно прочитать статью, описание товара или отзывы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
for tag in soup(['script', 'style', 'noscript', 'svg', 'header', 'footer', 'nav']):
tag.decompose()
title = _clean(soup.title.get_text()) if soup.title else ''
body = _clean(soup.get_text(' '))
return f'Заголовок: {title}. Текст: {body}'[:max_chars]
@mcp.tool()
def extract_links(url: str, limit: int = 100, contains: str = '') -> list[dict]:
'''Возвращает список ссылок со страницы: текст ссылки и полный адрес.
Параметр contains фильтрует ссылки, в адресе которых есть указанная подстрока,
например /product/ или /catalog/.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
result = []
seen = set()
for a in soup.find_all('a', href=True):
full = urljoin(url, a['href'])
if full in seen or (contains and contains not in full):
continue
seen.add(full)
result.append({'text': _clean(a.get_text())[:120], 'url': full})
if len(result) >= limit:
break
return result
@mcp.tool()
def select_elements(url: str, css_selector: str, limit: int = 50) -> list[str]:
'''Находит на странице элементы по CSS-селектору и возвращает их текст.
Примеры селекторов: h2, .price, div.product-card, table tr.
Используй, когда нужны конкретные повторяющиеся блоки: цены, названия, строки таблицы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
elements = soup.select(css_selector)[:limit]
return [_clean(el.get_text(' ')) for el in elements]
if __name__ == '__main__':
mcp.run()Ce que fait chaque outil
- extract_text supprime du document les scripts, les styles, l'en-tête, le pied de page et le menu, puis assemble le texte restant en une seule ligne avec des espaces simples. La fonction _clean, via split et join, supprime les retours à la ligne et tabulations superflus. Le titre de la page est ajouté au début de la réponse pour que l'agent comprenne immédiatement ce qu'il a sous les yeux.
- extract_links collecte toutes les balises a, transforme les adresses relatives en adresses absolues avec urljoin, élimine les doublons via l'ensemble seen et permet de filtrer les liens par sous-chaîne. Ainsi, l'agent obtient en un appel, par exemple, toutes les fiches produits d'un catalogue.
- select_elements — l'outil le plus puissant. Il prend un sélecteur CSS et renvoie le texte des éléments trouvés. L'agent peut d'abord examiner un morceau de HTML via fetch_page, comprendre que les prix se trouvent dans la classe price, puis appeler select_elements avec le sélecteur .price.
Prêtez attention aux docstrings : nous indiquons explicitement au modèle quel outil choisir dans quelle situation. Cela améliore nettement la qualité du travail de l'agent.
Comment tester
- Lancez mcp dev server.py et connectez-vous dans Inspector. La liste Tools compte désormais quatre outils.
- Appelez extract_links avec l'url d'un site d'actualités ou d'un catalogue et le paramètre contains égal à une partie de l'adresse de la rubrique. Le résultat est une liste d'objets avec les champs text et url.
- Appelez select_elements avec la même adresse et le sélecteur h2. Vous obtiendrez une liste de titres.
- Redémarrez Claude Desktop (pas besoin de modifier la configuration, seul le code a changé) et demandez : « Collecte depuis la page d'accueil de tel site tous les titres h2 et les liens qui mènent à la rubrique actualités, et présente-les dans un tableau ».
Conseil : Si vous ne savez pas quel sélecteur utiliser, ouvrez la page dans un navigateur, appuyez sur F12, choisissez l'outil de sélection d'élément (icône avec une flèche en haut à gauche du panneau) et cliquez sur le bloc souhaité. Vous verrez sa classe dans le code. Un sélecteur avec un point et le nom de la classe, par exemple .product-title, fonctionne généralement. Mieux encore, vous pouvez simplement demander à l'agent : « charge le HTML et trouve toi-même le sélecteur pour les prix ».
✅ Vérification : Les quatre outils sont visibles dans Inspector et dans le client, extract_text renvoie un texte lisible sans balises, extract_links renvoie une liste avec des adresses absolues, select_elements avec le sélecteur h2 renvoie les titres.
Problèmes possibles
- select_elements renvoie une liste vide. Soit le sélecteur est incorrect, soit le contenu est chargé par JavaScript après le chargement de la page. Vérifiez via fetch_page : si les données nécessaires ne sont pas dans le HTML, le site les rend côté client. Pour de tels sites, un moteur de navigateur est nécessaire, c'est déjà le sujet d'un article séparé.
- extract_text renvoie des caractères illisibles. Le site renvoie un encodage non standard. Ajoutez après response.raise_for_status() la ligne response.encoding = response.charset_encoding or 'utf-8'.
- La réponse est tronquée. Augmentez max_chars dans l'appel ou demandez à l'agent de récupérer la page par morceaux via plusieurs sélecteurs.
Étape 5 : Connecter les proxys mobiles et la rotation d'IP
Objectif de l'étape : diriger toutes les requêtes du serveur MCP via un proxy mobile, ajouter un outil de changement d'IP et de vérification de l'adresse actuelle. L'agent travaillera alors au nom d'un opérateur mobile, et non depuis votre IP personnelle ou professionnelle.
Pourquoi un proxy mobile pour un collecteur de données
Lorsque vous collectez des données depuis une seule adresse IP, les sites voient des dizaines de requêtes identiques à la suite et commencent à renvoyer un captcha, un contenu réduit ou une erreur 429 « trop de requêtes ». Un proxy mobile résout plusieurs problèmes à la fois. Premièrement, l'adresse appartient à un véritable opérateur mobile, et ces adresses sont partagées entre des milliers d'abonnés, ce qui rend les sites plus tolérants. Deuxièmement, vous pouvez changer d'IP via un lien ou un minuteur, en répartissant la charge. Troisièmement, vous séparez l'activité professionnelle de l'agent de vos sessions personnelles. Pour un marketeur, c'est aussi un moyen de voir le site tel que le voit un utilisateur mobile d'une région donnée.
⚠️ Attention : Le proxy est un outil pour le fonctionnement stable et correct du collecteur, et non pour enfreindre les règles. Collectez uniquement des données publiquement accessibles, respectez les conditions d'utilisation des sites et le fichier robots.txt, ne créez pas de charge excessive et ne collectez pas de données personnelles sans base légale. La responsabilité de l'usage de l'outil vous incombe.
Instructions pas à pas
- Ouvrez l'espace client de votre fournisseur de proxys mobiles et trouvez les données de connexion : hôte, port, identifiant, mot de passe. Elles sont généralement regroupées sur une ligne du type login:password@host:port. Copiez également le lien de rotation d'IP, s'il existe.
- Dans le fichier server.py, ajoutez en tête, après les autres imports, la ligne import os. Puis, sous le bloc HEADERS, ajoutez les paramètres :
PROXY_URL = os.environ.get('MOBILE_PROXY_URL', '')
ROTATE_URL = os.environ.get('PROXY_ROTATE_URL', '')
def _client() -> httpx.Client:
kwargs = {'headers': HEADERS, 'timeout': 30.0, 'follow_redirects': True}
if PROXY_URL:
kwargs['proxy'] = PROXY_URL
return httpx.Client(**kwargs)- Dans la fonction _get_html, remplacez la ligne avec httpx.Client par l'appel _client(). Elle ressemble maintenant à ceci : with _client() as client. Tous les outils passeront automatiquement par le proxy.
- Ajoutez deux nouveaux outils avant la ligne if __name__ :
@mcp.tool()
def current_ip() -> str:
'''Показывает IP-адрес, с которого сервер сейчас выходит в интернет.
Используй, чтобы убедиться, что прокси подключён, или после смены IP.'''
with _client() as client:
return client.get('https://api.ipify.org').text.strip()
@mcp.tool()
def rotate_ip() -> str:
'''Запрашивает смену IP-адреса мобильного прокси через ссылку из личного кабинета.
Вызывай, если сайт начал отдавать ошибки 429 или капчу. После вызова подожди 5-10 секунд.'''
if not ROTATE_URL:
return 'Ссылка смены IP не настроена в переменной PROXY_ROTATE_URL'
response = httpx.get(ROTATE_URL, timeout=15.0)
log(f'rotate_ip: status {response.status_code}')
return f'Запрос смены IP отправлен, ответ прокси-сервиса: {response.status_code}'- Transmettez les données du proxy via les variables d'environnement dans la configuration du client. Nous n'inscrivons volontairement pas l'identifiant et le mot de passe dans le code, pour ne pas les envoyer quelque part avec le fichier par accident. Ouvrez claude_desktop_config.json et complétez le bloc du serveur avec la section env :
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"],
"env": {
"MOBILE_PROXY_URL": "http://login:password@proxy-host:port",
"PROXY_ROTATE_URL": "https://lien-rotation-ip-du-compte"
}
}
}
}- Remplacez par les valeurs réelles à la place de login, password, proxy-host et port. Si le fournisseur propose un proxy au protocole SOCKS5, remplacez http:// par socks5:// et installez le paquet supplémentaire avec la commande pip install httpx[socks].
- Enregistrez la configuration, redémarrez complètement le client.
- Demandez à l'agent : « Appelle current_ip et dis-moi quelle est notre adresse. Puis appelle rotate_ip, attends dix secondes et vérifie à nouveau l'IP ». Les adresses doivent différer.
Test via Inspector avec le proxy
Inspector sait aussi transmettre des variables d'environnement. Dans le panneau de gauche, dépliez la section Environment Variables, ajoutez MOBILE_PROXY_URL et PROXY_ROTATE_URL avec vos valeurs, connectez-vous et appelez current_ip. La réponse doit correspondre à l'IP affichée dans l'espace client du fournisseur.
Conseil : N'appelez pas rotate_ip avant chaque requête. Chez la plupart des fournisseurs, le changement d'IP prend quelques secondes, et des requêtes trop fréquentes peuvent atteindre la limite de rotation. Une stratégie raisonnable : changer d'adresse tous les 30 à 100 requêtes ou uniquement en cas d'erreurs 429 et 403. On peut intégrer cette logique directement dans _get_html, ce que nous ferons à l'étape suivante.
✅ Vérification : L'outil current_ip renvoie l'adresse du proxy, et non votre adresse personnelle. Après rotate_ip et une pause, l'adresse change. Les outils extract_text et extract_links continuent de fonctionner, et les lignes GET avec les adresses des pages apparaissent dans les journaux.
Problèmes possibles
- Erreur 407 Proxy Authentication Required. Identifiant ou mot de passe incorrect, ou présence de caractères spéciaux. Les caractères comme @ ou : dans le mot de passe doivent être encodés : @ remplacé par %40, : par %3A.
- Erreur ConnectTimeout. Hôte ou port incorrect, ou votre IP n'est pas ajoutée à la liste des autorisées dans l'espace fournisseur, si le forfait prévoit une telle restriction.
- current_ip affiche votre propre adresse. La variable d'environnement n'est pas parvenue au serveur. Vérifiez l'orthographe de MOBILE_PROXY_URL dans la configuration et assurez-vous que le client a redémarré.
- rotate_ip renvoie le statut 429 ou un message de limite. Vous changez d'IP plus souvent que le forfait ne l'autorise. Augmentez l'intervalle.
Étape 6 : Rendre le serveur robuste : répétitions, délais, cache et limites
Objectif de l'étape : transformer l'exemple pédagogique en un outil qui ne tombe pas à la première erreur réseau, ne bombarde pas les sites de requêtes et ne sature pas le contexte du modèle. C'est la dernière étape obligatoire avant une utilisation à part entière.
Ce que nous ajoutons et pourquoi
- Répétitions automatiques. Les erreurs réseau arrivent. Plutôt que de renvoyer immédiatement une erreur à l'agent, nous retenterons la requête deux fois avec une pause.
- Changement d'IP automatique en cas de blocage. Si le site répond 429 ou 403 et que le lien de rotation est configuré, le serveur change lui-même d'adresse et répète la requête.
- Délai entre les requêtes. Un collecteur courtois n'envoie pas des dizaines de requêtes par seconde. Une pause d'une à deux secondes réduit la charge sur le site et le risque de blocage.
- Cache. L'agent demande souvent la même page plusieurs fois avec des outils différents. Un cache en mémoire de quelques minutes évitera des téléchargements répétés.
- Limite de taille. Nous ne téléchargerons pas les pages de plus de quelques mégaoctets.
Code
Ajoutez import time au début du fichier et remplacez la fonction _get_html par celle-ci :
CACHE: dict[str, tuple[float, str]] = {}
CACHE_TTL = 300
REQUEST_DELAY = 1.5
MAX_BYTES = 3_000_000
_last_request = 0.0
def _get_html(url: str) -> str:
global _last_request
now = time.time()
cached = CACHE.get(url)
if cached and now - cached[0] < CACHE_TTL:
log(f'cache hit: {url}')
return cached[1]
last_error = None
for attempt in range(3):
wait = REQUEST_DELAY - (time.time() - _last_request)
if wait > 0:
time.sleep(wait)
try:
with _client() as client:
_last_request = time.time()
response = client.get(url)
if response.status_code in (403, 429) and ROTATE_URL:
log(f'status {response.status_code}, rotating ip')
httpx.get(ROTATE_URL, timeout=15.0)
time.sleep(8)
continue
response.raise_for_status()
if len(response.content) > MAX_BYTES:
raise ValueError(f'Страница слишком большая: {len(response.content)} байт')
html = response.text
CACHE[url] = (time.time(), html)
return html
except httpx.HTTPError as error:
last_error = error
log(f'attempt {attempt + 1} failed: {error}')
time.sleep(2 * (attempt + 1))
raise RuntimeError(f'Не удалось загрузить {url} после 3 попыток: {last_error}')Comment cela fonctionne
- Le dictionnaire CACHE stocke pour chaque adresse l'heure de téléchargement et le HTML. Si la page a été demandée il y a moins de cinq minutes, nous renvoyons la copie enregistrée sans faire de requête.
- Avant chaque requête, nous calculons le temps écoulé depuis la précédente et ajoutons si nécessaire une pause jusqu'à REQUEST_DELAY secondes.
- Boucle de trois tentatives. En cas de réponse 403 ou 429 avec rotation configurée, le serveur change d'IP, attend huit secondes et réessaie. En cas d'erreurs réseau, il attend deux, quatre, six secondes entre les tentatives.
- Si la page dépasse trois mégaoctets, nous considérons cela comme une erreur : de tels documents ne tiendront de toute façon pas dans le contexte.
- Après trois échecs, nous levons une erreur claire avec l'adresse et la cause. L'agent la recevra sous forme de texte et pourra vous la signaler ou essayer un autre chemin.
Nous vous recommandons également d'ajouter un outil de nettoyage du cache, pour que l'agent puisse forcer le rechargement d'une page :
@mcp.tool()
def clear_cache() -> str:
'''Очищает кэш загруженных страниц. Вызывай, если нужно получить свежую версию страницы.'''
count = len(CACHE)
CACHE.clear()
return f'Кэш очищен, удалено записей: {count}'Conseil : Les valeurs REQUEST_DELAY et CACHE_TTL méritent d'être placées dans des variables d'environnement, à l'instar du proxy, pour les modifier sans toucher au code. Pour la surveillance des prix, une pause de deux à trois secondes et un cache d'une minute conviendront ; pour la collecte d'articles, une pause d'une seconde et un cache d'une heure.
✅ Vérification : Appelez extract_text pour une même page deux fois de suite. La deuxième fois, la ligne cache hit apparaîtra dans les journaux, et la réponse arrivera instantanément. Indiquez un domaine inexistant — après quelques secondes, l'agent recevra le message « Не удалось загрузить... после 3 попыток » au lieu de rester bloqué.
Problèmes possibles
- NameError : ROTATE_URL n'est pas défini. La fonction _get_html est déclarée avant le bloc des paramètres de proxy. Déplacez les paramètres PROXY_URL et ROTATE_URL plus haut dans le fichier.
- L'agent se plaint de lenteur. C'est normal : les délais et la rotation d'IP prennent du temps. Si vous êtes pressé, réduisez REQUEST_DELAY à 0.5, mais gardez à l'esprit le risque de blocage.
- La mémoire augmente. Le cache conserve toutes les pages de la session. Pour les sessions longues, ajoutez un nettoyage des entrées plus anciennes que TTL à chaque appel ou limitez la taille du dictionnaire.
Vérification du résultat : checklist d'un serveur MCP prêt à l'emploi
Parcourez la checklist et cochez chaque point. Si tous sont remplis, votre serveur MCP de collecte de données est prêt pour un usage réel.
Ce qui doit fonctionner
- La commande mcp dev server.py se lance sans erreur, Inspector se connecte et affiche le statut Connected.
- La liste des outils comprend fetch_page, extract_text, extract_links, select_elements, current_ip, rotate_ip et clear_cache.
- Le serveur web-collector apparaît dans le panneau des outils du client IA sans indicateur d'erreur.
- L'agent, sur une demande en langage libre, choisit lui-même l'outil approprié et l'appelle.
- current_ip affiche l'adresse du proxy mobile, et après rotate_ip l'adresse change.
- Une nouvelle requête sur la même page est servie depuis le cache.
- Une adresse erronée produit un message d'erreur clair et non un blocage.
Test complet
- Choisissez un site public avec un catalogue ou un fil d'articles, dont les données peuvent être utilisées.
- Demandez à l'agent : « Ouvre la page d'accueil du site, trouve les liens vers la rubrique catalogue, entre dans les cinq premières fiches, collecte le nom et le prix et présente un tableau avec les colonnes Nom, Prix, Lien ».
- Observez la chaîne d'appels : l'agent doit appeler extract_links avec un filtre, puis plusieurs fois select_elements ou extract_text, et enfin former le tableau.
- Vérifiez quelques lignes manuellement en ouvrant les fiches dans un navigateur. Les données doivent correspondre.
Indicateurs de réussite
La collecte de cinq fiches prend au maximum 30 à 40 secondes en tenant compte des délais. Les journaux du client ne contiennent pas d'erreurs de type traceback. L'agent ne redemande pas quel outil utiliser, mais agit de lui-même. Si c'est le cas, félicitations : vous avez construit votre propre serveur MCP et connecté un agent IA au web.
Erreurs courantes lors de la création d'un serveur MCP et leurs solutions
Voici les problèmes que presque tout le monde rencontre lors de la première passe. Format : problème, cause, solution.
1. Le serveur se connecte dans Inspector mais ne fonctionne pas dans le client
Cause : la configuration du client indique le python système sans les bibliothèques installées, ou un chemin de fichier incorrect. Solution : indiquez le chemin complet vers le python à l'intérieur de .venv et le chemin complet vers server.py, utilisez des barres obliques, redémarrez complètement le client.
2. Le client coupe la connexion juste après le lancement
Cause : un print ordinaire sans file=sys.stderr est resté dans le code, et le flux stdout protocolaire est pollué. Solution : remplacez tous les print par la fonction log. Vérifiez aussi que les bibliothèques n'écrivent pas dans stdout : par exemple, certaines barres de progression le font par défaut.
3. L'agent n'appelle pas les outils et répond à partir de ses connaissances
Cause : les descriptions des outils sont trop courtes ou vagues, et le modèle ne comprend pas quand les utiliser. Solution : enrichissez les docstrings, ajoutez des formulations « utilise quand... » et des exemples. Dans les premières requêtes, nommez explicitement l'outil.
4. Erreur 403 lors du chargement de vrais sites
Cause : le site n'accepte pas les requêtes sans en-têtes de navigateur ou depuis une IP suspecte. Solution : vérifiez que les HEADERS sont transmis, mettez à jour le User-Agent vers une version récente de navigateur, connectez un proxy mobile et assurez-vous que la rotation fonctionne.
5. Résultat vide de select_elements avec un sélecteur correct
Cause : les données sont chargées par JavaScript après le chargement de la page, et ne figurent pas dans le HTML source. Solution : vérifiez via fetch_page. Si les données sont absentes, essayez de trouver l'API interne du site dans l'onglet Network du navigateur : souvent, les fiches arrivent en JSON à une adresse séparée, qu'on peut interroger directement avec extract_text.
6. Erreur 407 ou ConnectTimeout via un proxy
Cause : identifiants incorrects, caractères spéciaux non encodés dans le mot de passe, ou port incorrect. Solution : recopiez la chaîne de connexion depuis l'espace client, encodez les caractères spéciaux, vérifiez le protocole http ou socks5.
7. La configuration JSON ne s'applique pas
Cause : virgule superflue, guillemet manquant ou antislashs dans les chemins. Solution : vérifiez le fichier dans un validateur, remplacez les antislashs par des barres obliques, assurez-vous qu'il n'y a pas de virgule après le dernier élément.
8. Le serveur fonctionne, mais les données arrivent dans un encodage incorrect
Cause : le site n'indique pas l'encodage dans les en-têtes. Solution : définissez response.encoding explicitement ou utilisez l'attribut response.content avec un décodage manuel via decode('utf-8', errors='ignore').
Fonctionnalités supplémentaires : bloc pour les utilisateurs avancés
Le serveur de base est prêt. Si vous programmez en Python avec assurance et voulez aller plus loin, voici des pistes de développement, chacune réalisable en une soirée.
Serveur distant via Streamable HTTP
Pour que le serveur fonctionne sur une machine séparée ou que plusieurs clients s'y connectent, remplacez la dernière ligne par mcp.run(transport='streamable-http'). Par défaut, le serveur démarrera sur le port 8000, et l'adresse de connexion sera http://adresse-machine:8000/mcp. Dans la configuration du client, remplacez command et args par la clé url avec cette adresse. Dans ce mode, vous pouvez écrire dans stdout, mais mieux vaut garder l'habitude de journaliser dans stderr. Fermez impérativement le port au monde extérieur et ajoutez une vérification de jeton dans l'en-tête si le serveur est accessible au-delà du réseau local.
Ressources et prompts
Une ressource avec les paramètres actuels aidera l'agent à comprendre le contexte de son travail :
@mcp.resource('collector://settings')
def settings() -> str:
'''Текущие настройки сборщика.'''
return f'proxy: {"on" if PROXY_URL else "off"}, delay: {REQUEST_DELAY}, cache ttl: {CACHE_TTL}'Un prompt définit un scénario prêt à l'emploi que l'utilisateur invoque d'une seule commande :
@mcp.prompt()
def price_monitor(url: str) -> str:
'''Сценарий мониторинга цен в каталоге.'''
return f'Открой {url}, собери ссылки на карточки товаров, зайди в каждую, вытащи название и цену и составь таблицу. Если увидишь ошибку 429, вызови rotate_ip и продолжи.'Enregistrement des résultats dans un fichier
Ajoutez un outil save_csv qui prend une liste de dictionnaires et un chemin de fichier et écrit les données via le module csv. L'agent pourra non seulement collecter, mais aussi consigner les résultats dans un tableau que vous ouvrirez dans Excel. Limitez le chemin d'enregistrement à un seul dossier, afin que l'agent ne puisse pas écrire n'importe où sur le disque.
Asynchrone et collecte parallèle
FastMCP prend en charge les fonctions asynchrones : déclarez un outil avec async def et utilisez httpx.AsyncClient. L'outil fetch_many pourra alors charger dix pages simultanément via asyncio.gather. N'oubliez pas le sémaphore qui limite le nombre de requêtes parallèles, et le fait que le délai entre requêtes doit être calculé différemment en parallèle.
Plusieurs proxys et rotation intelligente
Si vous disposez de plusieurs proxys mobiles pour différentes régions, stockez-les dans une variable d'environnement sous forme de liste séparée par des virgules et ajoutez un paramètre region à l'outil. Le serveur choisira le proxy par région, et l'agent pourra comparer les prix affichés aux utilisateurs de différentes villes. C'est l'une des tâches les plus demandées par les marketeurs et les arbitragistes.
Conditionnement dans Docker
Pour exécuter le serveur sur une machine, construisez une image basée sur python:3.12-slim, copiez server.py et le fichier des dépendances, installez les paquets et indiquez le point d'entrée avec le transport HTTP. Transmettez les variables de proxy au lancement du conteneur, au lieu de les intégrer à l'image.
⚠️ Attention : Ne publiez jamais de code contenant des identifiants, mots de passe et liens de rotation dans des dépôts publics. Gardez-les uniquement dans des variables d'environnement ou dans un fichier .env ajouté à .gitignore. La fuite d'un lien de rotation d'IP permettrait à des tiers de contrôler votre proxy.
FAQ : questions fréquentes sur la création d'un serveur MCP
Peut-on écrire un serveur MCP dans un autre langage que Python ?
Oui. Des SDK officiels existent pour TypeScript, Java, Kotlin, C# et d'autres langages. Les principes sont identiques : déclarer des outils avec des descriptions et lancer le transport. Python a été choisi dans ce guide pour sa simplicité et sa riche collection de bibliothèques pour le traitement du HTML.
Faut-il un forfait payant de client IA pour utiliser MCP ?
Claude Desktop prend en charge les serveurs MCP locaux même sur le forfait gratuit, mais avec des limites sur le nombre de messages. Cursor et VS Code permettent aussi de connecter des serveurs. Vérifiez les conditions actuelles auprès de chaque client.
Est-il obligatoire d'utiliser un proxy ?
Non, le serveur fonctionne aussi directement. Le proxy est nécessaire lorsque le volume de requêtes est notable, que les sites sont sensibles à la fréquence des appels ou qu'il est important pour vous de voir le contenu d'une région donnée et depuis une IP mobile.
Comment savoir si les requêtes passent réellement par le proxy ?
Appelez l'outil current_ip et comparez l'adresse avec celle affichée dans l'espace client du fournisseur. Vous pouvez aussi demander à l'agent de charger la page d'un service de détection d'IP via extract_text.
Combien d'outils peut-on ajouter à un seul serveur ?
Techniquement, il n'y a presque aucune limite, mais chaque description occupe de la place dans le contexte du modèle. La pratique montre que 5 à 15 outils bien décrits fonctionnent mieux que 50 outils minuscules. Regroupez les fonctions proches à l'aide de paramètres.
Comment mettre à jour le serveur sans redémarrer le client ?
Avec le transport stdio, le client lance le processus au démarrage, donc les modifications de code ne seront prises en compte qu'après un redémarrage du client. En mode développement, il est plus pratique de tester les modifications via Inspector et de redémarrer le client à la fin.
Que faire si le site ne fournit les données qu'après exécution de JavaScript ?
Notre serveur travaille avec le HTML source et ne verra pas ces données. Options : trouver l'API interne du site dans l'onglet Network du navigateur ou connecter un moteur de navigateur. La seconde voie est décrite dans d'autres articles du blog, nous ne l'abordons volontairement pas ici.
Comment limiter l'agent pour qu'il n'aille pas sur des sites indésirables ?
Ajoutez dans _get_html une vérification du domaine par liste blanche ou noire issue d'une variable d'environnement et renvoyez une erreur claire pour les adresses interdites. C'est plus fiable que de se fier aux instructions du chat.
Peut-on utiliser un même serveur MCP depuis plusieurs clients simultanément ?
Avec stdio, chaque client lance sa propre copie du processus, et c'est normal : ils ne se gênent pas, mais leur cache est séparé. Pour un cache commun et un proxy unique, passez au transport HTTP du bloc avancé.
Conclusion : ce que vous avez fait et où aller ensuite
Résumons. Vous avez préparé l'environnement Python et installé le SDK officiel du protocole. Vous avez écrit un serveur MCP de zéro et compris comment le modèle saisit les outils via leurs descriptions. Vous avez connecté le serveur au client IA et vu l'agent télécharger lui-même les pages. Vous avez ajouté des outils d'extraction de texte, de liens et d'éléments par sélecteurs. Vous avez fait passer le trafic par un proxy mobile avec rotation d'IP. Enfin, vous avez rendu le serveur robuste : répétitions, délais, cache et limites. Ce n'est plus un exemple pédagogique, mais un outil de travail pour vos tâches quotidiennes.
Que faire ensuite ? Commencez à utiliser le serveur dans des scénarios réels : surveillance des prix concurrents, collecte d'avis, vérification de landing pages, analyse de contenu dans une niche. Au fil de l'usage, vous comprendrez quels outils vous manquent et vous les ajouterez sur le modèle de ceux qui existent. Chaque nouvel outil est une fonction avec une description claire, rien de plus compliqué.
Le niveau suivant, c'est le bloc avancé : serveur distant en HTTP, collecte parallèle, gestion de plusieurs proxys par région et enregistrement des résultats dans des tableaux. Et lorsque vous tomberez sur des sites à contenu dynamique, jetez un œil aux articles connexes du blog sur l'automatisation par navigateur. L'essentiel est déjà fait : votre agent IA est sorti sur le web via votre propre serveur MCP, et vous contrôlez entièrement la façon dont il le fait.