Aller au contenu
sobolewski.proL'IA du jour, chaque soirS'inscrire

Une fois par jour. Désinscription en un clic. Politique de confidentialité

Créer un serveur MCP en Python pas à pas

Comment créer un serveur MCP ? On écrit ses outils en Python avec le SDK 2.0, on les teste dans MCP Inspector, puis on les branche à Claude Code et Claude Desktop.

7 min de lecture

Cet article dans d’autres langues :العربيةDeutschEnglishEspañolItaliano日本語Polski简体中文

Dans cet article
  1. De quoi a-t-on besoin ?
  2. Étape 1 : comment préparer le projet ?
  3. Étape 2 : comment créer un serveur MCP avec un premier outil ?
  4. Étape 3 : pourquoi ne faut-il pas utiliser print() ?
  5. Étape 4 : comment tester le serveur dans MCP Inspector ?
  6. Étape 5 : comment brancher le serveur à Claude Code ?
  7. Étape 6 : comment ajouter le serveur à Claude Desktop ?
  8. Étape 7 : comment lancer un serveur MCP en HTTP ?
  9. À quoi faire attention ?
  10. FAQ

Comment créer un serveur MCP ? En Python, il suffit d’un fichier et du MCP Python SDK officiel : on écrit une fonction ordinaire avec des types et une docstring, on ajoute le décorateur @mcp.tool(), et le SDK en fait un outil que Claude, ChatGPT ou Cursor peuvent appeler. Le serveur d’exemple de la documentation tient en une quinzaine de lignes.

Dans ce tutoriel, on écrit un serveur de zéro, on le teste dans MCP Inspector, puis on le branche à Claude Code et à Claude Desktop. Les commandes et le code viennent du tutoriel officiel « Build an MCP server », du README du SDK et de la documentation de Claude Code.

De quoi a-t-on besoin ?

Je pars du principe que vous savez déjà ce qu’est MCP, c’est-à-dire l’hôte, le client, le serveur et les outils (sinon, commencez par le tutoriel MCP, c’est quoi). Il nous faut :

  1. Python 3.11+ (c’est ce qu’exige le README du SDK actuel),
  2. le gestionnaire de paquets uv, celui qu’utilise le tutoriel officiel,
  3. Node.js 22.19.0 ou plus récent, si on veut tester le serveur dans MCP Inspector,
  4. un hôte MCP pour vérifier l’ensemble, par exemple Claude Code ou Claude Desktop.

Une remarque avant de commencer : la version 2.0 du SDK a renommé la classe principale. D’après la liste des changements de la v2, l’ancien from mcp.server.fastmcp import FastMCP s’écrit désormais from mcp.server import MCPServer. Beaucoup de tutoriels en ligne montrent encore l’ancienne version, alors que le tutoriel officiel demande le SDK 2.0.0 ou plus récent.

Étape 1 : comment préparer le projet ?

On installe d’abord uv (macOS et Linux) :

curl -LsSf https://astral.sh/uv/install.sh | sh

Sous Windows, dans PowerShell :

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Après l’installation, on redémarre le terminal pour que la commande uv soit reconnue. On crée ensuite le projet et on installe le SDK :

uv init mon-serveur
cd mon-serveur
uv venv
source .venv/bin/activate
uv add "mcp[cli]"
touch server.py

L’extra [cli] installe la commande mcp (avec les sous-commandes mcp dev, mcp run et mcp install), qui servira pour les tests (sous Windows, on active l’environnement avec .venv\Scripts\activate).

Étape 2 : comment créer un serveur MCP avec un premier outil ?

Dans le fichier server.py, on colle l’exemple du README du SDK et on ajoute à la fin le lancement du serveur, comme dans le tutoriel officiel :

from mcp.server import MCPServer

mcp = MCPServer("Demo")


@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"


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

C’est un serveur MCP complet, avec un outil (add) et une ressource dont l’adresse suit un modèle (greeting://{name}). Point intéressant, on n’écrit aucun JSON Schema : d’après le README, la signature a: int, b: int fait office de schéma, et la docstring devient la description de l’outil que lit le modèle. Le SDK se charge de l’analyse des requêtes, de la validation et du protocole.

Les docstrings méritent donc du soin. Le modèle choisit un outil d’après son nom et sa description : « Add two numbers. » est un minimum, et pour de vrais outils on décrit aussi les arguments, comme dans l’exemple officiel de la météo :

@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location.

    Args:
        latitude: Latitude of the location
        longitude: Longitude of the location
    """

(cet exemple utilise l’API du NWS, le service météorologique américain, il ne fonctionne donc que pour des lieux situés aux États-Unis)

Étape 3 : pourquoi ne faut-il pas utiliser print() ?

C’est l’erreur la plus fréquente sur un premier serveur. Un serveur local communique avec l’hôte par l’entrée et la sortie standard (stdio), et les messages sont au format JSON-RPC. La documentation prévient sans détour : écrire sur stdout corrompt les messages JSON-RPC et fait tomber le serveur, et print() écrit par défaut sur stdout.

À la place, on utilise le module logging, qui écrit sur stderr :

import logging

logger = logging.getLogger(__name__)

logger.info("Processing request")  # part sur stderr

Les serveurs HTTP n’ont pas ce problème, car les logs sur stdout ne se mélangent pas aux réponses HTTP.

Étape 4 : comment tester le serveur dans MCP Inspector ?

MCP Inspector est l’outil officiel pour tester les serveurs. Avec le SDK, une commande suffit pour le lancer :

uv run mcp dev server.py

Le navigateur s’ouvre sur l’Inspector. D’après le README, l’appel de add avec les arguments a=1 et b=2 renvoie 3. On y voit aussi la liste des outils et des ressources, ainsi que les messages JSON-RPC bruts, ce qui aide beaucoup quand quelque chose ne marche pas.

L’Inspector existe aussi en version terminal (--tui) et en mode script (--cli). Ce dernier affiche par exemple la liste des outils puis s’arrête, il convient donc à la CI :

npx @modelcontextprotocol/inspector --cli uv run server.py --method tools/list

(vérifiez votre version de Node.js avec node --version, l’Inspector demande la 22.19.0 ou une version plus récente)

Étape 5 : comment brancher le serveur à Claude Code ?

Un serveur local s’ajoute comme serveur de type stdio. Tout ce qui suit -- est la commande que Claude Code lancera :

claude mcp add --transport stdio demo -- uv --directory /CHEMIN/COMPLET/mon-serveur run server.py

Le chemin doit être absolu (on l’obtient avec pwd dans le dossier du projet). L’état de la connexion s’affiche avec claude mcp get demo ou, dans une session Claude Code, avec la commande /mcp. On peut maintenant demander, par exemple, « additionne 1234 et 5678 avec l’outil add », puis valider l’appel.

Deux points de la documentation de Claude Code servent tout de suite :

  1. le délai de démarrage du serveur se règle avec la variable MCP_TIMEOUT, par exemple MCP_TIMEOUT=10000 claude laisse 10 secondes au serveur,
  2. Claude Code affiche un avertissement quand le résultat d’un outil dépasse 10 000 tokens et le tronque par défaut à 25 000 tokens (la limite se change avec la variable MAX_MCP_OUTPUT_TOKENS), les outils ne doivent donc pas renvoyer des bases de données entières.

Étape 6 : comment ajouter le serveur à Claude Desktop ?

Dans Claude Desktop, les serveurs locaux se déclarent dans le fichier de configuration claude_desktop_config.json. Il se trouve dans ~/Library/Application Support/Claude/ sous macOS, dans ~/.config/Claude/ sous Linux et dans %AppData%\Claude\ sous Windows (s’il n’existe pas, on le crée). L’entrée ressemble à ceci :

{
  "mcpServers": {
    "demo": {
      "command": "uv",
      "args": [
        "--directory",
        "/CHEMIN/COMPLET/mon-serveur",
        "run",
        "server.py"
      ]
    }
  }
}

Ensuite, on quitte complètement l’application (Cmd+Q sous macOS, fermer la fenêtre ne suffit pas) et on la relance. Le serveur doit apparaître dans le menu « Connectors », sous l’icône plus. S’il n’y est pas, la documentation conseille de vérifier la syntaxe du JSON, que le chemin est bien absolu, et d’indiquer dans le champ command le chemin complet de uv (which uv le donne). Les logs sont dans ~/Library/Logs/Claude (macOS) ou ~/.config/Claude/logs/ (Linux), dans les fichiers mcp.log et mcp-server-NOM.log.

Étape 7 : comment lancer un serveur MCP en HTTP ?

Un serveur stdio ne fonctionne que sur notre machine. Pour l’exposer comme serveur distant, on le lance en Streamable HTTP, le transport que le README du SDK destine à la production :

uv run mcp run server.py --transport streamable-http

Le serveur écoute alors à l’adresse http://localhost:8000/mcp, et on l’ajoute dans Claude Code comme n’importe quel serveur distant :

claude mcp add --transport http demo-http http://localhost:8000/mcp

Pour qu’un tel serveur fonctionne dans l’application web de Claude en tant que « custom connector », il doit être accessible depuis internet, car Claude s’y connecte depuis le cloud d’Anthropic. Une authentification devient alors utile : la documentation de MCP décrit l’autorisation des serveurs avec OAuth 2.1.

À quoi faire attention ?

D’abord, à ce que l’outil permet de faire. Un serveur MCP donne au modèle un vrai pouvoir d’action sur notre ordinateur, alors écrivons des outils aussi étroits que possible : plutôt « lis un fichier de ce dossier » que « lance n’importe quelle commande ».

Ensuite, aux données venues de l’extérieur. Un outil qui récupère du contenu sur internet ou dans des e-mails peut ramener avec lui une injection de prompt (prompt injection), c’est-à-dire des instructions cachées destinées au modèle. J’en dis plus dans le tutoriel Sécurité des agents IA.

Enfin, aux secrets. Les clés API se passent par des variables d’environnement (--env dans Claude Code), pas dans le code. D’après la documentation, l’Inspector enregistre les jetons dans le trousseau du système et, quand il n’y en a pas (dans un conteneur, par exemple), dans un fichier non chiffré, ~/.mcp-inspector/secrets.json.

Ce serveur peut ensuite être branché à votre propre agent, ce que je montre dans le tutoriel Créer un agent IA en Python.

FAQ

Comment créer un serveur MCP le plus simplement possible ?

Le serveur le plus simple, celui du README du SDK, fait une quinzaine de lignes : un objet MCPServer, une fonction avec le décorateur @mcp.tool() et mcp.run(). Le reste, c’est-à-dire le schéma des arguments et la gestion du protocole, le SDK s’en occupe.

Qu’est-ce que FastMCP ?

C’est l’ancien nom de la classe principale du serveur dans le MCP Python SDK. La version 2.0 l’a renommée MCPServer, et l’import s’écrit from mcp.server import MCPServer.

Peut-on écrire un serveur MCP dans un autre langage que Python ?

Oui. Le tutoriel officiel existe entre autres pour TypeScript, Java, Kotlin, C#, Ruby, Rust et Go.

Un serveur MCP ne fonctionne-t-il qu’avec Claude ?

Non. MCP est un standard ouvert, le même serveur fonctionne donc dans tout hôte qui prend en charge le protocole, par exemple ChatGPT, Visual Studio Code ou Cursor.

  • IA
  • agents IA
  • Claude Code
  • programmation
  • tutoriel

L'IA du jour, chaque soir

Chaque soir, l'essentiel de l'actualité de l'IA et les nouveaux articles du blog. Court, avec les sources.

Une fois par jour. Désinscription en un clic. Politique de confidentialité