MCP server : créer, tester et déployer son serveur Python
Créez un serveur MCP en Python pour Claude Code et Cursor : outil en lecture seule, tests avec Inspector, authentification et déploiement HTTP partagé.
Publié le

Un MCP server (serveur MCP) permet à Claude Code ou à Cursor de répondre à une question sur l’état d’une commande à partir des données de votre entreprise, sans coller d’enregistrement dans le chat. Créez un outil MCP en lecture seule, vérifiez son fonctionnement dans l’Inspector, puis choisissez entre un processus local et un service HTTP authentifié que votre équipe pourra partager.
Un premier serveur utile remplit une tâche précise : recevoir un identifiant de commande et renvoyer son état. Commencez par là. Un outil d’accès général à la base de données oblige le modèle à prendre trop de décisions et lui donne davantage d’accès que ce workflow n’en demande.
Ce guide suit le tutoriel officiel de création d’un serveur. Au 7 octobre 2026, la documentation s’appuie sur la spécification MCP 2026-07-28 et sur le SDK Python officiel, la bibliothèque qui traite les messages MCP, avec son API MCPServer. L’exemple fixe la version du SDK à 2.3.0 : les imports d’un ancien tutoriel ne pourront donc pas modifier à votre insu ce que vous installez.
Que peut exposer votre serveur MCP ?
Un serveur MCP joue le rôle d’un guichet contrôlé entre une application d’IA et vos systèmes. L’application peut demander ce qui est disponible, envoyer une requête et recevoir un résultat. C’est votre code qui décide de ce que ce guichet autorise.
MCP, pour Model Context Protocol, donne un format commun à ces échanges. L’hôte est l’application que vous utilisez, par exemple Claude Code ou Cursor. Son client gère les échanges de protocole avec votre serveur. Il s’agit de rôles, pas de trois applications supplémentaires à installer.
Un outil peut fonctionner en lecture seule. Présenter une information comme une ressource ne dispense pas de contrôler les accès. Un prompt donne des instructions, pas des permissions. La prise en charge et la présentation varient selon les clients : vérifiez les fonctionnalités que vous exposez réellement. Ce sont les trois primitives côté serveur ; le serveur ci-dessous n’a besoin que d’un outil.

Avant de développer, regardez si un connecteur maintenu couvre déjà votre besoin. Notre sélection des meilleurs serveurs MCP pour 2026 constitue un bon point de départ. Un serveur sur mesure se justifie lorsque vos données internes, vos règles d’accès ou votre workflow diffèrent de ce que proposent ces connecteurs.
Créer un MCP server en Python pour consulter des commandes
Laissez le SDK officiel gérer le protocole et concentrez votre code sur la consultation. Il vous faut Python 3.10 ou une version ultérieure, uv, le gestionnaire de projets Python utilisé dans le tutoriel officiel, et Node.js pour l’Inspector. La version actuelle de l’Inspector exige Node 22.19.0 ou une version ultérieure.
Dans un terminal, exécutez ces commandes dans l’ordre :
uv init orders-mcpcd orders-mcpuv venvuv add "mcp[cli]==2.3.0"
Créez orders.py dans ce dossier et collez-y le serveur complet ci-dessous. Les enregistrements sont des données fictives pour cet exercice. Ils ne contiennent ni noms de clients, ni informations de paiement, ni identifiants d’API.
import json
from mcp.server import MCPServer
mcp = MCPServer("orders")
# Fictional training data. No customer records or credentials.
ORDERS = {
"A100": {"status": "shipped", "carrier": "Demo Courier"},
"A101": {"status": "packing", "carrier": "not assigned"},
}
@mcp.tool()
def lookup_order(order_id: str) -> str:
"""Look up a fictional order by ID, such as A100. Read-only.
Args:
order_id: Exact order ID, for example A100 or A101.
"""
key = order_id.strip().upper()
order = ORDERS.get(key)
if order is None:
return json.dumps({"found": False, "order_id": key})
return json.dumps({"found": True, "order_id": key, **order})
if __name__ == "__main__":
mcp.run(transport="stdio")Cet exemple reprend le schéma documenté du tutoriel — MCPServer, @mcp.tool() et mcp.run(transport="stdio") — en remplaçant les outils météo par une consultation de commande. L’annotation de type chaîne indique au SDK que order_id est un texte obligatoire. La docstring explique au client dans quel cas utiliser l’outil. Le SDK produit la définition de l’outil et traite les messages du protocole.
Lancez uv run orders.py. Il est normal que le processus reste silencieux en attendant des données. stdio, l’entrée et la sortie standard, est le canal par lequel le client dialogue avec ce processus. Arrêtez cette exécution manuelle avant de laisser un client lancer sa propre instance.
N’envoyez pas les logs de l’application sur la sortie standard. Utilisez le module logging de Python, qui écrit par défaut sur la sortie d’erreur standard. Un print() oublié peut corrompre le flux du protocole. Il s’agit d’une contrainte documentée de stdio, pas d’une préférence de présentation des logs.
Lorsque vous remplacerez le dictionnaire par une base de données, gardez cette interface restreinte. Utilisez une requête paramétrée, un compte de base de données limité à la lecture des champs nécessaires et un contrôle des droits de l’appelant avant de renvoyer un enregistrement. Pour cette tâche, n’acceptez jamais une instruction SQL arbitraire fournie par le modèle.
Vérifier l’outil avec MCP Inspector
Vérifiez le fonctionnement de l’outil avant de demander à un modèle de s’en servir. Depuis le dossier du projet, lancez uv run mcp dev orders.py. La commande de développement du SDK ouvre MCP Inspector. Ouvrez dans votre navigateur l’URL affichée par la commande et connectez le serveur si ce n’est pas déjà fait.
Dans Tools, sélectionnez lookup_order. Le formulaire doit afficher un champ order_id obligatoire. Appelez l’outil avec A100 : le résultat doit contenir found: true, status: shipped et carrier: Demo Courier. Avec A101, vous devez obtenir packing. Avec DOES-NOT-EXIST, le résultat doit contenir found: false.
Essayez aussi une requête sans order_id. Elle doit échouer à la validation des entrées, sans lancer de recherche. Les vues Protocol et Console de l’Inspector permettent de distinguer une requête mal formée d’une défaillance du processus serveur.
Pour disposer d’une vérification reproductible en terminal, utilisez npx @modelcontextprotocol/inspector --cli uv run orders.py --method tools/list. Pour appeler l’outil, utilisez npx @modelcontextprotocol/inspector --cli uv run orders.py --method tools/call --tool-name lookup_order --tool-arg order_id=A100. Ces commandes suivent la documentation de la CLI de l’Inspector.
Le critère de réussite est concret : un outil détectable, l’état attendu pour une commande connue et une réponse explicite lorsqu’un enregistrement manque. Un paragraphe plausible rédigé par le modèle ne prouve pas que la consultation a eu lieu.
Brancher le même serveur sur Claude Code et Cursor
Chaque client local lance son propre processus serveur. Inutile de laisser l’Inspector ouvert. Utilisez des chemins absolus pour que le lancement ne dépende pas du dossier que le client a ouvert.
Claude Code : exécutez claude mcp add --transport stdio --scope local orders -- /ABSOLUTE/PATH/orders-mcp/.venv/bin/python /ABSOLUTE/PATH/orders-mcp/orders.py. Sous Windows, l’interpréteur se trouve à l’emplacement .venv\Scripts\python.exe. Cette commande respecte la syntaxe de Claude Code pour les serveurs locaux, avec le séparateur -- avant la commande de lancement.
Lancez claude mcp get orders pour vérifier la connexion. Dans une session Claude Code, ouvrez /mcp, puis demandez : « Utilise lookup_order pour vérifier A100. Indique uniquement l’état et le transporteur renvoyés. » Examinez l’appel de l’outil et ses arguments.
Cursor : créez .cursor/mcp.json dans votre projet. Ajoutez ce JSON en remplaçant les deux chemins absolus : {"mcpServers":{"orders":{"type":"stdio","command":"/ABSOLUTE/PATH/orders-mcp/.venv/bin/python","args":["/ABSOLUTE/PATH/orders-mcp/orders.py"]}}}.
Ouvrez Customize, activez le serveur et posez la même question dans Agent. Examinez l’appel selon vos paramètres d’approbation. L’emplacement du fichier, les champs de lancement et les commandes de l’interface suivent la configuration MCP de Cursor. En cas d’échec de la connexion, vérifiez le chemin de l’exécutable et la sortie d’erreur standard du serveur avant de modifier l’outil.
Choisir entre stdio en local et HTTP à distance
Restez en local pour un workflow personnel. Passez à HTTP à distance lorsque plusieurs personnes ou des clients hébergés ont besoin d’un même service géré.
Un service distant doit aussi pouvoir accéder à vos données d’entreprise par le réseau. Publier un point de terminaison ne rend pas une base privée accessible et ne règle pas ses permissions.
Le protocole HTTP 2026-07-28 utilise des requêtes autonomes. Le SDK Python actuel peut aussi servir d’anciens clients, dont les sessions peuvent nécessiter un routage persistant vers la même instance lorsque vous ajoutez des réplicas. Configurez délibérément les paramètres de compatibilité documentés avant de monter en charge ; ne supposez pas que tous les clients connectés utilisent la dernière révision.

Passer la consultation en HTTP avec authentification
Protégez l’accès HTTP avec des jetons émis pour ce service. OAuth 2.1 est le cadre d’autorisation prévu par la spécification MCP : un fournisseur d’identité connecte l’utilisateur et émet un jeton, que votre serveur MCP vérifie. Un scope désigne une permission, par exemple orders:read. L’audience indique quel service peut accepter ce jeton.
Le SDK fournit l’intégration du serveur de ressources, pas le système de connexion de votre entreprise. Pour cet exemple, configurez un fournisseur d’identité avec la découverte OAuth, l’enregistrement des clients que vous avez choisis, PKCE pour la connexion des utilisateurs — qui prouve que l’application terminant la connexion est celle qui l’a commencée — et un point de terminaison d’introspection des jetons. L’introspection demande à l’émetteur si un jeton est actif et ce qu’il autorise.
Cet adaptateur attend une introspection en HTTPS avec une authentification du client par HTTP Basic et une réponse contenant active, aud, exp, client_id et scope. Configurez l’émetteur pour qu’il inclue l’URL publique exacte de ce point de terminaison dans aud et accorde orders:read. Si votre fournisseur utilise une autre méthode d’authentification pour l’introspection, adaptez la requête à sa documentation. S’il fournit plutôt des JWT, c’est-à-dire des jetons signés, implémentez la vérification de la signature, de l’émetteur, de l’expiration et de l’audience dans la même interface TokenVerifier.
Ajoutez uvicorn avec uv add uvicorn, puis créez remote.py à côté de orders.py. L’implémentation suit l’exemple officiel d’introspection du SDK, ainsi que ses interfaces HTTP et d’authentification documentées. Elle réutilise la consultation que vous venez de tester.
import os
import time
from urllib.parse import urlsplit
import httpx2
from pydantic import AnyHttpUrl
from mcp.server import MCPServer
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
from mcp.server.transport_security import TransportSecuritySettings
from orders import lookup_order as local_lookup
RESOURCE = os.environ["MCP_RESOURCE_URL"]
ISSUER = os.environ["MCP_ISSUER_URL"]
INTROSPECT = os.environ["MCP_INTROSPECTION_URL"]
if any(urlsplit(url).scheme != "https" for url in (RESOURCE, ISSUER, INTROSPECT)):
raise ValueError("Public auth and resource URLs must use HTTPS")
class OrderTokenVerifier(TokenVerifier):
async def verify_token(self, token: str) -> AccessToken | None:
try:
async with httpx2.AsyncClient(timeout=5.0) as client:
response = await client.post(
INTROSPECT,
data={"token": token},
auth=(os.environ["MCP_INTROSPECTION_CLIENT_ID"],
os.environ["MCP_INTROSPECTION_CLIENT_SECRET"]),
)
response.raise_for_status()
data = response.json()
audiences = data.get("aud", [])
if isinstance(audiences, str):
audiences = [audiences]
expiry = data.get("exp")
if (data.get("active") is not True or RESOURCE not in audiences
or not isinstance(expiry, int) or expiry <= time.time()):
return None
if data.get("iss", ISSUER) != ISSUER:
return None
return AccessToken(
token=token, client_id=data["client_id"],
scopes=data.get("scope", "").split(), expires_at=expiry,
resource=RESOURCE, subject=data.get("sub"),
)
except Exception:
return None
mcp = MCPServer(
"orders",
token_verifier=OrderTokenVerifier(),
auth=AuthSettings(
issuer_url=AnyHttpUrl(ISSUER),
resource_server_url=AnyHttpUrl(RESOURCE),
required_scopes=["orders:read"], validate_token_resource=True,
),
)
@mcp.tool()
def lookup_order(order_id: str) -> str:
"""Look up a fictional order by ID, such as A100. Read-only."""
return local_lookup(order_id)
hostname = urlsplit(RESOURCE).hostname
security = TransportSecuritySettings(
allowed_hosts=[hostname, f"{hostname}:*"],
allowed_origins=[os.environ["MCP_ALLOWED_ORIGIN"]],
)
app = mcp.streamable_http_app(transport_security=security)Définissez ces valeurs dans l’environnement de votre déploiement ou dans son gestionnaire de secrets :
La liste des hôtes autorisés est explicite : par défaut, le SDK accepte localhost et rejette un nom d’hôte public avec 421 Misdirected Request. Les origines de navigateur font l’objet d’un contrôle distinct ; n’autorisez que celles que vous utilisez réellement. L’application renvoyée comprend déjà son cycle de démarrage et d’arrêt. Ces points suivent la documentation du déploiement du SDK et de son application ASGI. ASGI est l’interface par laquelle les serveurs web Python exécutent cette application.
Lancez-la derrière le proxy HTTPS de votre hébergeur avec uv run uvicorn remote:app --host 0.0.0.0 --port 8000. L’URL publique de la ressource reste en HTTPS, même si le proxy communique en HTTP avec le processus. Configurez la confiance accordée aux en-têtes transférés en fonction du périmètre réel du proxy de cet hébergeur.
Avant d’utiliser de vrais enregistrements, effectuez ces vérifications sur HTTP :
- Sans jeton, avec un jeton expiré ou destiné à une autre audience : l’accès est refusé.
- Avec un jeton valide dépourvu de
orders:read: l’accès est refusé. - Avec un jeton valide dont l’audience et le scope sont corrects :
lookup_orderrenvoie l’état de démonstration. /.well-known/oauth-protected-resource/mcp: les métadonnées désignent la bonne ressource et le bon émetteur.
Utilisez npx @modelcontextprotocol/inspector --server-url https://orders.example.com/mcp --transport http pour inspecter le point de terminaison déployé et effectuer son parcours d’authentification. Un test de l’outil en mémoire contourne l’autorisation HTTP : il ne prouve donc pas que ce contrôle d’accès fonctionne.
Pour Claude Code, ajoutez une connexion distincte avec claude mcp add --transport http orders-remote https://orders.example.com/mcp, puis authentifiez-vous via /mcp. Pour Cursor, ajoutez une entrée distante dans mcpServers avec "url":"https://orders.example.com/mcp" et effectuez la connexion OAuth. Cursor documente aussi un objet auth avec CLIENT_ID et scopes pour les clients préenregistrés. Enregistrez les URL de rappel appropriées auprès de votre émetteur. Consultez la documentation sur l’authentification de Claude Code et la configuration OAuth distante de Cursor.
Cet adaptateur authentifié reste limité ; il ne constitue pas tout le système de production. Avant de remplacer le dictionnaire de démonstration, appliquez les permissions par organisation et par enregistrement à partir de l’identité vérifiée, ajoutez un événement d’audit autour de l’appel, réutilisez les connexions HTTP et limitez les requêtes. Un scope autorise l’opération ; il n’établit pas que l’utilisateur est propriétaire de chaque commande.
Héberger le serveur sur Render ou Cloudflare Workers
Pour le serveur Python ci-dessus, je commencerais par Render. Un service web Python conserve l’application que vous avez déjà construite. Cloudflare Workers est un bon choix si vous souhaitez implémenter le même outil bien délimité dans son gestionnaire Worker documenté.
Voici les tarifs publiés par les fournisseurs, vérifiés le 7 octobre 2026 :
Sources : tarifs de Cloudflare Workers et tarifs de Render. L’espace de travail Pro de Render ajoute 25 USD/mois, en plus du calcul, si vous choisissez ses fonctionnalités d’équipe. Le stockage, les services d’identité, l’utilisation des modèles et les autres frais se budgètent séparément : il s’agit de tarifs d’hébergement, pas du coût d’un workflow d’IA.
Déploiement sur Render : placez orders.py, remote.py et requirements.txt dans votre dépôt. Le fichier de dépendances doit contenir mcp[cli]==2.3.0 et uvicorn, chacun sur sa propre ligne. Créez un Python Web Service, utilisez pip install -r requirements.txt comme commande de build et uvicorn remote:app --host 0.0.0.0 --port $PORT comme commande de démarrage. Ajoutez les variables d’environnement ci-dessus, puis renseignez le nom d’hôte attribué ou votre domaine personnalisé dans MCP_RESOURCE_URL. Cette procédure adapte le déploiement documenté d’un service web Python sur Render à l’application ASGI du SDK.
Le service gratuit de Render convient à une démonstration, mais il se met en veille après 15 minutes d’inactivité et prend environ une minute pour redémarrer. Pour un outil interactif partagé, je choisirais une capacité de calcul payante.
Déploiement sur Cloudflare : suivez la documentation actuelle du gestionnaire MCP et le guide des serveurs distants. L’approche TypeScript actuelle utilise createMcpHandler depuis agents/mcp/server avec @modelcontextprotocol/server. Implémentez-y la même consultation de commande et configurez l’authentification avant de partager l’URL. La commande de lancement Python uvicorn est destinée à un hébergement Python ; elle ne constitue pas une procédure de déploiement Worker.
Limiter le périmètre de sécurité
N’accordez au serveur que les accès nécessaires à son outil. Pour consulter l’état d’une commande, cela signifie un identifiant de backend en lecture seule, des champs sélectionnés et un contrôle des droits pour chaque enregistrement. Réservez les remboursements, les annulations et les changements d’adresse à des outils et à des permissions distincts. Les arguments choisis par le modèle ne valent jamais autorisation.
Vérifiez les jetons HTTP en contrôlant l’émetteur, l’expiration, l’audience et le scope. Utilisez HTTPS et des identifiants distincts lorsque le serveur appelle une API en aval. Les recommandations de sécurité MCP interdisent de retransmettre les jetons tels quels : un jeton présenté à votre point de terminaison MCP ne donne pas automatiquement accès à votre système de commandes. Pour stdio en local, restreignez le processus qui lance le serveur, son environnement et son accès au système de fichiers.
Journalisez l’appelant vérifié, le nom de l’outil, une référence d’enregistrement dont les données sensibles ont été masquées de façon appropriée, le résultat, la latence et l’identifiant de requête. N’y incluez ni jetons ni fiches clients complètes. Envoyez les logs sur stderr pour stdio et dans le système de logs de votre hébergeur pour HTTP. Traitez le texte extrait des enregistrements comme des données : une note dans une commande ne doit pas accorder le droit d’effectuer une autre action.
Placez une passerelle en amont lorsque plusieurs serveurs ou équipes ont besoin d’une politique d’identité commune, de limites de débit, d’une collecte d’audit ou de révocation. La passerelle peut centraliser ces contrôles ; chaque backend doit néanmoins appliquer les bonnes permissions sur les enregistrements. Notre guide des passerelles MCP explique comment prendre cette décision.

Six workflows classés selon leur gain immédiat
Ces usages prolongent le même schéma. Commencez par une tâche où une personne recherche régulièrement une information précise et sait reconnaître une réponse correcte.
Le calcul économique doit partir de votre propre workflow. Exemple purement illustratif : 80 consultations par jour de 2 minutes chacune représentent 160 minutes. Si des mesures montrent ensuite que le workflow connecté économise 1 minute par consultation, cela fait 80 minutes récupérées par jour. C’est un calcul, pas un benchmark de performance. Mesurez la justesse des réponses et le temps gagné avant d’affirmer que les dépenses d’hébergement sont rentabilisées.
Deux pistes de produit à développer
La meilleure piste est un adaptateur de contexte de commande pour les équipes support. Une équipe pourrait acheter une intégration ciblée qui récupère les bonnes informations d’expédition dans l’assistant qu’elle utilise déjà. Selon l’estimation de DataForSEO, « customer support automation » représente 260 recherches Google par mois aux États-Unis, d’après le relevé vérifié le 7 octobre 2026. Cela traduit un intérêt général pour ce besoin, pas un nombre d’acheteurs de MCP. Intercom affiche Fin à 0.99 USD par résultat, ce qui montre qu’un budget existe déjà pour l’automatisation du support ; ce petit adaptateur fournit du contexte plutôt que de remplacer ce produit.
La plus petite version commercialisable pourrait couvrir un backend de commandes, lookup_order, une connexion avec des scopes, une piste d’audit et un brouillon de réponse qui cite les champs renvoyés. Son avantage serait de s’adapter aux données et aux règles d’accès d’une entreprise précise. La limite : des fournisseurs existants proposent peut-être déjà le connecteur, et les licences de modèles de l’équipe, le nettoyage des données et le support restent payants. Validez ce besoin avec un responsable support avant d’ajouter des outils.
Une consultation des politiques internes qui respecte les permissions constitue la seconde piste. Un opérateur pourrait donner accès à la collection de politiques approuvées d’une entreprise au moyen de ressources ou d’un outil de recherche ciblé. Selon l’estimation de DataForSEO, « enterprise search » représente 390 recherches mensuelles aux États-Unis, d’après le relevé vérifié à la même date. Le MVP pourrait inclure une collection, des citations des sources, des contrôles de fraîcheur et un filtrage selon les droits de la personne connectée. La difficulté : la qualité de la recherche et le contrôle des accès constituent le produit ; rendre un dossier accessible via MCP se copie facilement. Le volume de recherche signale une demande pour le besoin général, pas une preuve que des utilisateurs paieront pour cette implémentation.
Ce que MCP ne règle pas
MCP standardise l’accès. Vous restez responsable de la qualité des données, des autorisations, de la fiabilité du backend et du choix des actions possibles pour un outil. Un modèle peut mal interpréter un résultat valide, et les clients connectés peuvent différer par les fonctionnalités prises en charge ou leurs règles d’approbation.
Développez ce serveur si une interface d’outils partagée améliore un workflow dont vous pouvez mesurer les résultats. Pour un traitement par lots fixe qui n’a jamais besoin qu’un assistant choisisse un outil, un appel d’API classique ou un script peut être plus adapté.
Dès lundi : choisissez avec un opérateur support une consultation récurrente, connectez les deux clients avec des enregistrements fictifs, puis remplacez le jeu de données en utilisant un compte en lecture seule et testez les permissions sur les enregistrements. Gardez les écritures hors de ce premier déploiement. Passez à un service HTTP partagé lorsque le workflow et les contrôles d’identité sont prêts.
Est-il difficile de créer un serveur MCP ?
Un petit serveur en lecture seule se crée simplement avec le SDK officiel : définissez la fonction, décrivez ses entrées et choisissez un transport. Donner accès aux données d’entreprise en toute sécurité demande davantage de travail : il faut appliquer les permissions, gérer les identifiants et exploiter le service.
Existe-t-il un serveur MCP gratuit pour faire des tests ?
Le serveur de commandes fictives de ce tutoriel peut fonctionner en local sans frais d’hébergement. MCP Inspector permet de l’appeler sans abonnement à un modèle. L’hébergement cloud et le client d’IA que vous choisirez ensuite ont leurs propres tarifs.
Combien coûte un serveur MCP ?
Un processus local ne nécessite aucun abonnement d’hébergement distinct. Cloudflare Workers propose une offre gratuite et un minimum payant de 5 USD/mois. Render affiche 7 USD/mois de calcul pour son petit service web payant. Ces montants excluent l’utilisation des modèles, les services d’identité, le stockage et le travail d’ingénierie.
Faut-il installer un serveur MCP ?
Avec stdio, le serveur fonctionne sur la machine du client : son code et son environnement d’exécution doivent donc y être disponibles. Avec HTTP à distance, vous configurez un point de terminaison et vous vous authentifiez ; le serveur tourne chez l’hébergeur. Choisissez un déploiement pris en charge par votre client.
Si vous souhaitez faire développer et exploiter un service MCP connecté aux données de votre entreprise, notre service de systèmes d’IA en production prend en charge l’intégration et ses contrôles d’accès.
- Publié
- Catégorie
- Build
- Langue







