Créer son premier serveur MCP en Python : tutoriel pas à pas

Vous utilisez des serveurs MCP tous les jours dans Claude, Cursor ou VS Code ? L’étape suivante, c’est d’écrire le vôtre. Bonne nouvelle : avec le SDK Python officiel et son API FastMCP, un serveur fonctionnel tient en une cinquantaine de lignes. Pas besoin de connaître le protocole en détail : quelques fonctions Python bien typées suffisent.

Dans ce tutoriel, vous allez créer un petit serveur de prise de notes, le tester avec MCP Inspector, puis le brancher sur Claude Desktop et Claude Code. Au passage, vous découvrirez les trois briques de base du protocole : les outils, les ressources et les prompts.

Le tutoriel en bref

Point cléDétail
LangagePython 3.10 ou plus récent
BibliothèqueSDK officiel mcp, avec l’API FastMCP intégrée
Gestionnaire de projetuv, recommandé par la documentation officielle
Transportstdio, pour un usage local
TestMCP Inspector
ClientsClaude Desktop, Claude Code, Cursor, VS Code…
Durée20 à 30 minutes

📇 Besoin d’inspiration ? Parcourez notre annuaire des serveurs MCP pour voir ce que d’autres développeurs ont déjà construit.

Outils, ressources, prompts : les trois briques d’un serveur MCP

Un serveur MCP expose des capacités à un client (Claude Desktop, un IDE…) qui les met à disposition du modèle. Il en existe trois types :

  • Les outils (tools) : des fonctions que le modèle peut décider d’appeler pour agir ou récupérer une information, comme « ajouter une note » ou « lancer une requête SQL ».
  • Les ressources (resources) : des données en lecture, identifiées par une URI, que l’application peut joindre au contexte (un fichier, une liste d’enregistrements…).
  • Les prompts : des modèles de demandes réutilisables, que l’utilisateur déclenche lui-même, souvent sous forme de commande.

Sous le capot, client et serveur échangent des messages JSON-RPC 2.0. Le SDK s’occupe de tout le protocole : vous écrivez des fonctions, il génère les schémas et gère les échanges.

Prérequis

  • Python 3.10 ou plus récent.
  • uv, le gestionnaire de projets Python d’Astral (un pip classique fonctionne aussi).
  • Un client MCP pour les tests finaux : Claude Desktop ou Claude Code.

Étape 1 : créer le projet

Initialisez un projet et ajoutez le SDK avec ses outils en ligne de commande :

uv init serveur-notes
cd serveur-notes
uv add "mcp[cli]"

L’extra [cli] installe la commande mcp, qui servira à lancer l’inspecteur de test.

Étape 2 : écrire le serveur

Créez un fichier server.py à la racine du projet avec le code suivant :

import json
from pathlib import Path

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("notes")

FICHIER = Path(__file__).parent / "notes.json"


def charger() -> list[dict]:
    if FICHIER.exists():
        return json.loads(FICHIER.read_text(encoding="utf-8"))
    return []


def sauver(notes: list[dict]) -> None:
    FICHIER.write_text(json.dumps(notes, ensure_ascii=False, indent=2), encoding="utf-8")


@mcp.tool()
def ajouter_note(titre: str, contenu: str) -> str:
    """Ajoute une note avec un titre et un contenu."""
    notes = charger()
    notes.append({"titre": titre, "contenu": contenu})
    sauver(notes)
    return f"Note « {titre} » enregistrée ({len(notes)} au total)."


@mcp.tool()
def rechercher_notes(mot_cle: str) -> list[dict]:
    """Retourne les notes dont le titre ou le contenu contient le mot-clé."""
    mot = mot_cle.lower()
    return [n for n in charger() if mot in n["titre"].lower() or mot in n["contenu"].lower()]


@mcp.resource("notes://toutes")
def toutes_les_notes() -> str:
    """Toutes les notes enregistrées, au format JSON."""
    return json.dumps(charger(), ensure_ascii=False, indent=2)


@mcp.prompt()
def resumer_notes(sujet: str) -> str:
    """Prépare une demande de synthèse des notes sur un sujet."""
    return f"Cherche les notes liées à « {sujet} » avec l'outil rechercher_notes, puis fais-en une synthèse en 5 points."


if __name__ == "__main__":
    mcp.run()

Quelques points à retenir :

  • La docstring devient la description de l’outil. C’est elle que le modèle lit pour décider quand l’appeler : soyez précis.
  • Les annotations de type deviennent le schéma des paramètres. titre: str impose une chaîne de caractères, sans que vous écriviez une ligne de JSON Schema.
  • La valeur de retour est convertie automatiquement en réponse MCP, qu’il s’agisse d’un texte ou d’une structure comme une liste de dictionnaires.
  • mcp.run() démarre le serveur en stdio par défaut : le client le lance comme un sous-processus et dialogue avec lui via l’entrée et la sortie standard.

Étape 3 : tester avec MCP Inspector

Avant de brancher un vrai client, vérifiez que tout fonctionne avec l’inspecteur officiel :

uv run mcp dev server.py

La commande ouvre MCP Inspector dans votre navigateur. Cliquez sur Connect, puis explorez les onglets Tools, Resources et Prompts. Appelez ajouter_note avec un titre et un contenu, puis rechercher_notes : si la note revient, votre serveur est prêt.

Étape 4 : connecter le serveur à Claude

Claude Desktop

Ouvrez le fichier de configuration de Claude Desktop, accessible depuis les paramètres de l’application (section Développeur) ou directement :

  • macOS : ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows : %APPDATA%\Claude\claude_desktop_config.json

Ajoutez votre serveur en indiquant le chemin absolu du dossier du projet :

{
  "mcpServers": {
    "notes": {
      "command": "uv",
      "args": ["--directory", "/chemin/absolu/vers/serveur-notes", "run", "server.py"]
    }
  }
}

Redémarrez complètement Claude Desktop. Les outils du serveur apparaissent alors dans la liste des connecteurs, et vous pouvez demander : « Ajoute une note intitulée Idées d’articles avec trois sujets sur le MCP ».

Claude Code

Une seule commande suffit :

claude mcp add notes -- uv --directory /chemin/absolu/vers/serveur-notes run server.py

Vérifiez ensuite avec /mcp dans Claude Code que le serveur est bien connecté.

Les pièges les plus fréquents

  • Un print() qui casse tout : en stdio, la sortie standard est réservée aux messages du protocole. Un simple print() corrompt les échanges. Utilisez le module logging, qui écrit sur la sortie d’erreur.
  • « Commande introuvable » : Claude Desktop ne voit pas toujours le même PATH que votre terminal. Indiquez le chemin complet de uv, obtenu avec which uv sur macOS et Linux ou where uv sous Windows.
  • Chemins relatifs : le client ne lance pas le serveur depuis le dossier du projet. D’où l’usage de Path(__file__).parent pour le fichier de notes, et d’un chemin absolu dans la configuration.
  • Descriptions trop vagues : si le modèle n’appelle pas vos outils, réécrivez les docstrings en précisant quand et pourquoi les utiliser.
  • Configuration non rechargée : après chaque modification du serveur ou de la configuration, redémarrez le client.

Aller plus loin

Votre serveur fonctionne en local. Pour le rendre accessible à distance ou à plusieurs utilisateurs, il suffit de changer de transport :

mcp.run(transport="streamable-http")

Le serveur écoute alors en HTTP, par défaut sur http://127.0.0.1:8000/mcp. Avant de l’exposer sur Internet, lisez notre comparatif stdio ou Streamable HTTP et notre guide pour sécuriser un serveur MCP : authentification, validation des entrées et permissions minimales deviennent indispensables.

Pour vous inspirer de serveurs réels, les guides Context7 MCP et Supabase MCP montrent comment des éditeurs ont conçu leurs outils.

Questions fréquentes

Faut-il obligatoirement coder en Python ?

Non. Des SDK officiels existent aussi notamment pour TypeScript, Java, Kotlin, C#, Go et Rust. Python et TypeScript restent les plus utilisés et les mieux documentés.

Quelle différence entre FastMCP et le SDK officiel ?

La première version de FastMCP a été intégrée au SDK Python officiel : c'est l'API mcp.server.fastmcp utilisée dans ce tutoriel. Un projet FastMCP indépendant continue d'évoluer séparément avec des fonctions supplémentaires, mais les deux restent très proches à l'usage.

Quand utiliser un outil plutôt qu'une ressource ?

Utilisez un outil quand le modèle doit agir, ou décider lui-même d'aller chercher une information. Une ressource convient aux données en lecture que l'application ou l'utilisateur choisit de joindre au contexte.

Mon serveur fonctionnera-t-il avec Cursor ou VS Code ?

Oui, c'est tout l'intérêt du protocole : un serveur MCP standard fonctionne avec tous les clients compatibles, seule la manière de le déclarer change. Certains clients, comme les interfaces web des assistants, n'acceptent toutefois que des serveurs distants en HTTP.

Conclusion

Créer un serveur MCP en Python est surtout une affaire de bonnes fonctions : un nom clair, une docstring précise et des types stricts. Le SDK se charge du protocole. Partez d’un besoin concret de votre quotidien (vos notes, une API interne, un dossier de documents), testez avec l’inspecteur, puis branchez le serveur sur votre assistant préféré.