Niveau : Avancé
Créer un serveur MCP : principes et étapes avec le SDK officiel
Créer un serveur MCP consiste à écrire un petit programme qui expose vos fonctions, vos données ou vos modèles de consignes sous une forme standard que toute application d’IA compatible sait découvrir et utiliser. Avec le SDK officiel, un premier serveur utile tient en une trentaine de lignes de Python : ce tutoriel vous guide de l’installation au branchement sur un assistant, puis aux règles de sécurité.
Ce que vous allez construire
Nous allons créer un serveur « notes » qui donne à une IA l’accès en lecture à un dossier de notes au format Markdown sur votre ordinateur. Il proposera les trois briques du protocole : un outil de recherche, une ressource pour lire une note et un prompt prêt à l’emploi pour la résumer.
Prérequis :
- des bases en Python et l’usage d’un terminal ;
- Python 3.11 ou plus récent, comme l’exige la page d’installation du SDK ;
- l’outil
uv, qui gère l’environnement et les dépendances ; - une application hôte compatible MCP, ici Claude Desktop, pour l’essai final.
Si le Model Context Protocol vous est encore flou, commencez par notre explication de MCP, le Model Context Protocol : rôles d’hôte, de client et de serveur, transports, sécurité.
Les trois briques, côté code
Un serveur MCP n’invente rien : il décrit des fonctions et des données pour que le modèle sache quand et comment s’en servir. Avec le SDK Python, chaque brique correspond à un décorateur posé sur une fonction ordinaire.
| Brique | Décorateur Python | Qui la déclenche | Dans notre serveur |
|---|---|---|---|
| Outil | @mcp.tool() | Le modèle, avec accord de l’utilisateur | Chercher les notes contenant un mot |
| Ressource | @mcp.resource(...) | L’application | Lire le contenu d’une note |
| Prompt | @mcp.prompt() | L’utilisateur | Demander un résumé structuré |
Les outils sont la brique la plus utilisée par les agents : c’est la version standardisée de l’appel d’outils que les grands modèles savent déjà faire. Le nom de la fonction devient le nom de l’outil, la docstring devient sa description et les annotations de type deviennent le schéma des paramètres.
Choisir son SDK
Le site officiel classe les SDK par niveaux selon leur complétude, leur prise en charge du protocole et l’engagement de maintenance. Voici le relevé du 22 octobre 2026 :
| Niveau | Langages |
|---|---|
| Niveau 1 | TypeScript, Python, C#, Go, Rust, Ruby |
| Niveau 2 | Java |
| Niveau 3 | Swift, PHP, Kotlin |
Tous permettent de créer des serveurs qui exposent outils, ressources et prompts, en local comme à distance. Ce tutoriel utilise Python ; une variante TypeScript figure plus bas.
Étape 1 : préparer le projet
Installez uv si ce n’est pas déjà fait (voir le tutoriel officiel pour la commande de votre système), puis créez le projet et ajoutez le SDK avec ses outils en ligne de commande :
uv init notes-mcp
cd notes-mcp
uv add "mcp[cli]"
L’option cli ajoute la commande mcp, qui sert notamment à lancer l’Inspector. Créez ensuite un fichier serveur.py et un dossier notes dans votre répertoire personnel, avec deux ou trois fichiers .md pour vos essais.
Étape 2 : écrire le serveur
Voici le serveur complet. Il suit la structure du tutoriel officiel : une instance MCPServer, des fonctions décorées, puis un lancement en mode stdio.
import logging
from pathlib import Path
from mcp.server import MCPServer
logger = logging.getLogger(__name__)
mcp = MCPServer("notes")
DOSSIER = (Path.home() / "notes").resolve()
@mcp.tool()
def chercher_notes(mot_cle: str) -> list[str]:
"""Liste les notes Markdown dont le texte contient le mot-clé."""
logger.info("Recherche : %s", mot_cle)
return [
f.name
for f in DOSSIER.glob("*.md")
if mot_cle.lower() in f.read_text(encoding="utf-8").lower()
]
@mcp.resource("notes://{nom}")
def lire_note(nom: str) -> str:
"""Renvoie le contenu d'une note du dossier."""
chemin = (DOSSIER / nom).resolve()
if chemin.parent != DOSSIER:
raise ValueError("Accès refusé hors du dossier de notes")
return chemin.read_text(encoding="utf-8")
@mcp.prompt()
def resumer_note(nom: str) -> str:
"""Prépare une demande de résumé d'une note."""
return f"Résume la note {nom} en cinq puces, décisions d'abord."
if __name__ == "__main__":
mcp.run()
Trois détails comptent. D’abord, la docstring n’est pas décorative : c’est elle que le modèle lit pour décider d’appeler l’outil, rédigez-la comme une consigne précise. Ensuite, la ressource vérifie que le fichier demandé reste dans le dossier autorisé, ce qui bloque une demande du type ../../.ssh/config. Enfin, mcp.run() sans argument utilise le transport stdio, celui qu’attendent les applications de bureau.
Étape 3 : ne jamais écrire sur la sortie standard
C’est l’erreur la plus fréquente. En mode stdio, l’hôte et le serveur échangent leurs messages JSON-RPC par l’entrée et la sortie standard. La documentation officielle est formelle : écrire sur la sortie standard corrompt ces messages et casse le serveur. Un simple print() de débogage suffit.
Utilisez le module logging, qui écrit sur la sortie d’erreur, comme dans notre code. En TypeScript, la règle équivalente consiste à remplacer console.log() par console.error(). Pour un serveur HTTP, la contrainte disparaît.
Étape 4 : tester avec l’Inspector
Avant de brancher le serveur sur un assistant, testez-le seul. Le SDK fournit une commande qui le lance et ouvre l’Inspector, une interface de test officielle :
uv run mcp dev serveur.py
Dans l’Inspector, vérifiez que l’outil, la ressource et le prompt apparaissent, appelez chercher_notes avec un mot présent dans vos fichiers, puis essayez de lire une note inexistante pour voir comment l’erreur remonte. Pour des tests automatisés, la documentation du SDK montre comment ouvrir un Client en mémoire sur votre serveur avec pytest, sans réseau.
Étape 5 : brancher le serveur sur Claude Desktop
Ouvrez le fichier de configuration claude_desktop_config.json de Claude Desktop (le tutoriel officiel indique son emplacement sous macOS, Windows et Linux) et déclarez votre serveur sous la clé mcpServers :
{
"mcpServers": {
"notes": {
"command": "uv",
"args": ["--directory", "/CHEMIN/ABSOLU/VERS/notes-mcp", "run", "serveur.py"]
}
}
}
Le chemin doit être absolu ; sous Windows, doublez les barres obliques inverses ou utilisez des barres obliques. Si l’application ne trouve pas uv, indiquez son chemin complet dans command. Quittez complètement l’application (fermer la fenêtre ne suffit pas, précise la documentation), relancez-la, puis vérifiez que « notes » apparaît dans le menu des connecteurs. Demandez enfin : « Quelles notes parlent du budget ? »
En cas de problème, consultez les journaux de l’application : un fichier par serveur y recueille sa sortie d’erreur, donc vos messages logging.
Vérifiez-vous Votre serveur fonctionne dans l'Inspector mais plante dès que Claude Desktop l'appelle. Vous aviez ajouté un print() pour suivre les recherches. Quel est le lien ?
En mode stdio, print() écrit sur la sortie standard, le canal même des messages du protocole. Le texte de débogage se mêle aux messages JSON-RPC et l’hôte ne peut plus les lire. Remplacez-le par logger.info(), qui écrit sur la sortie d’erreur, et retrouvez ces lignes dans le journal du serveur.
Variante : un serveur distant en HTTP
Pour partager un serveur entre plusieurs applications ou collègues, passez au transport Streamable HTTP. D’après la documentation du SDK Python consultée le 22 octobre 2026, il suffit de changer la dernière ligne :
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Par défaut, le serveur écoute alors sur l’adresse locale 127.0.0.1, port 8000, au chemin /mcp. Mettre ce serveur en ligne demande ensuite une authentification (la spécification recommande OAuth), du HTTPS et une réflexion sur les droits de chaque utilisateur. L’ancien transport SSE est déprécié.
Et en TypeScript ?
Le tutoriel officiel propose la même démarche avec le paquet @modelcontextprotocol/server et la bibliothèque de validation zod. Point important de la version actuelle : on passe à serveStdio une fonction qui fabrique une nouvelle instance de serveur à chaque appel.
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";
function createServer() {
const server = new McpServer({ name: "notes", version: "1.0.0" });
server.registerTool(
"chercher_notes",
{
description: "Liste les notes contenant un mot-clé",
inputSchema: z.object({ motCle: z.string() }),
},
async ({ motCle }) => ({
content: [{ type: "text", text: "Recherche de " + motCle }],
}),
);
return server;
}
serveStdio(createServer);
Selon la documentation, un serveur câblé à l’ancienne avec server.connect(new StdioServerTransport()) compile encore, mais ne sert plus que les clients de l’ère 2025.
Les règles de sécurité dès le premier serveur
Un serveur MCP donne des mains à une IA. La spécification rappelle que les outils équivalent à une exécution de code et que l’hôte doit obtenir le consentement de l’utilisateur avant de les appeler. Côté serveur, quatre réflexes :
- Le moindre privilège. Exposez un dossier, pas tout le disque ; une lecture, pas une écriture, tant que ce n’est pas nécessaire.
- La validation des entrées. Les paramètres viennent d’un modèle, donc indirectement de textes que vous ne contrôlez pas : vérifiez chemins, identifiants et tailles.
- La méfiance envers le contenu renvoyé. Une note ou un courriel lu par votre outil peut contenir une injection de prompt, c’est-à-dire des consignes cachées qui tentent de détourner l’agent.
- La confirmation humaine pour les actions sensibles. Pour tout outil qui envoie, paie ou supprime, gardez un humain dans la boucle.
Notre guide pour sécuriser un agent IA détaille ces protections.
Utiliser votre serveur depuis un agent
Un serveur MCP ne sert pas qu’aux assistants de bureau : la plupart des frameworks d’agents savent le consommer. Le Claude Agent SDK, l’OpenAI Agents SDK ou Mastra peuvent ainsi charger votre serveur « notes » sans une ligne d’intégration spécifique.
| Outil | Type | Licence | MCP | Multi-agents | Niveau |
|---|---|---|---|---|---|
| Claude Agent SDK | Code | proprietary | Oui | Oui | Intermédiaire |
| OpenAI Agents SDK | Code | MIT | Oui | Oui | Intermédiaire |
| LangGraph | Code | MIT | Oui | Oui | Avancé |
| Mastra | Code | Apache-2.0 | Oui | Oui | Intermédiaire |
| goose | Low-code | Apache-2.0 | Oui | Oui | Débutant |
Pour choisir, consultez notre comparatif des frameworks d’agents IA ou le comparateur de frameworks, filtrable sur MCP. Le serveur s’insère ensuite dans l’architecture décrite dans notre guide pour créer un agent IA, du no-code au code. Une fois en place, mesurez si l’agent appelle les bons outils au bon moment : c’est l’objet de notre article sur l’évaluation d’un agent IA.
Questions fréquentes
Faut-il être développeur pour créer un serveur MCP ?
Il faut des bases de programmation, en Python ou en TypeScript par exemple. Le SDK officiel fait l'essentiel du travail protocolaire : vous écrivez des fonctions ordinaires et il génère leur description pour l'IA. Si vous ne codez pas, utilisez plutôt des serveurs existants ou un outil no-code compatible MCP.
Quel langage choisir pour son premier serveur MCP ?
Celui que vous maîtrisez le mieux parmi les SDK officiels. Python et TypeScript disposent du tutoriel officiel le plus détaillé et figurent parmi les SDK du niveau le plus élevé, avec C#, Go, Rust et Ruby. Le protocole étant le même, un serveur Python fonctionne avec un client écrit dans un autre langage.
Un serveur MCP doit-il tourner sur Internet ?
Non. Pour un usage personnel, le plus simple est un serveur local, lancé par l'application d'IA sur votre ordinateur et qui communique par l'entrée et la sortie standard. Le transport HTTP sert quand plusieurs personnes ou plusieurs applications doivent accéder au même serveur à distance.
Mon ancien serveur écrit avec FastMCP fonctionne-t-il encore ?
La version 2 du SDK Python a renommé la classe FastMCP en MCPServer et suit la spécification du 28 juillet 2026. La documentation officielle propose un guide de migration. Testez votre serveur dans l'Inspector après la mise à jour avant de le redéployer.