FRENES

MCP & automatisation

Créer son propre serveur MCP en 30 minutes

Par · · 6 min

Mains sur un clavier devant un éditeur de code flou, un carnet avec un schéma de connexions posé à côté

Un serveur MCP se crée en une trentaine de lignes de Python avec le SDK officiel : vous écrivez des fonctions annotées, le SDK en déduit le schéma des paramètres et gère le protocole. Comptez 30 minutes pour un premier serveur qui expose deux outils et une ressource, testé dans l’Inspector puis branché à Claude, Cursor ou VS Code. Ce tutoriel suit la version 2 du SDK Python, sortie le 28 juillet 2026 (v2.3.0 au 2 octobre 2026).

Ce que vous allez construire

Un serveur « Notes » qui donne à votre assistant IA un accès en lecture seule à un dossier de notes Markdown :

  • un outil chercher_notes qui renvoie les notes contenant un mot ;
  • un outil lire_note qui renvoie le contenu d’une note ;
  • une ressource notes://liste avec la liste des fichiers.

Le choix de la lecture seule n’est pas anodin : c’est la règle de base pour un premier serveur. Un outil qui écrit, supprime ou envoie quelque chose peut être déclenché par erreur, ou par une injection de prompt cachée dans un document que l’agent a lu.

Si le vocabulaire vous est nouveau, la page Serveur MCP : définition et les meilleurs serveurs à connaître pose les bases, et le terme serveur MCP est défini dans le glossaire.

Prérequis

  • Python 3.11 ou plus récent (exigence du SDK v2).
  • uv, le gestionnaire de paquets Python recommandé par la documentation du SDK. pip fonctionne aussi.
  • Un hôte MCP pour l’essai final : Claude Desktop, Claude Code, Cursor ou VS Code avec GitHub Copilot.
  • Un dossier avec quelques fichiers .md pour tester.

Les trois briques d’un serveur MCP

La documentation du SDK Python les distingue selon qui décide de s’en servir :

BriqueQui la déclencheÉquivalent webExemple
Outil (tool)Le modèleRequête POST : agit, peut modifierChercher dans une base, créer un ticket
Ressource (resource)L’application hôteRequête GET : lit, ne modifie rienLe contenu d’un fichier
PromptL’utilisateurCommande enregistréeUne commande « /résumer »

Le serveur ne parle jamais directement au modèle : c’est le client MCP, à l’intérieur de l’hôte, qui lui transmet les appels.

Étape 1 : créer le projet

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

L’option [cli] installe la commande mcp (mcp dev, mcp run, mcp install) en plus du SDK. Avec pip : pip install "mcp[cli]".

Étape 2 : écrire le serveur

Créez server.py :

from pathlib import Path

from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError

# Dossier exposé, en lecture seule. Rien en dehors de ce dossier n'est accessible.
NOTES = Path.home() / "notes"

mcp = MCPServer("Notes")


def _fichier(nom: str) -> Path:
    """Chemin d'une note, refusé s'il sort du dossier NOTES."""
    chemin = (NOTES / nom).resolve()
    if not chemin.is_relative_to(NOTES.resolve()) or chemin.suffix != ".md":
        raise ToolError(f"Note refusée : {nom!r}")
    if not chemin.is_file():
        raise ToolError(f"Aucune note nommée {nom!r}")
    return chemin


@mcp.tool()
def chercher_notes(mot: str) -> list[str]:
    """Liste les notes Markdown qui contiennent ce mot (sans tenir compte des majuscules)."""
    mot = mot.lower()
    return sorted(
        f.name for f in NOTES.glob("*.md")
        if mot in f.read_text(encoding="utf-8", errors="ignore").lower()
    )


@mcp.tool()
def lire_note(nom: str) -> str:
    """Renvoie le contenu complet d'une note, par exemple « reunion-lundi.md »."""
    return _fichier(nom).read_text(encoding="utf-8", errors="ignore")


@mcp.resource("notes://liste")
def liste() -> str:
    """Toutes les notes disponibles, une par ligne."""
    return "\n".join(sorted(f.name for f in NOTES.glob("*.md")))


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

Trois points à remarquer :

  1. Les annotations de type sont le schéma. mot: str suffit : le SDK génère le schéma JSON que le client montre au modèle. Vous n’écrivez ni validation ni analyse de requête.
  2. La docstring est la description que le modèle lit pour choisir l’outil. Soignez-la : c’est elle qui décide si l’outil sera appelé au bon moment.
  3. _fichier bloque la sortie du dossier. Sans ce contrôle, un nom comme ../.ssh/id_rsa ferait lire n’importe quel fichier de votre compte. C’est le défaut le plus fréquent des serveurs qui touchent au disque.

Si vous venez de la version 1 du SDK : FastMCP s’appelle désormais MCPServer, et l’import mcp.server.fastmcp n’existe plus. Le guide de migration liste les autres changements.

Étape 3 : tester dans l’Inspector

uv run mcp dev server.py

La commande lance le MCP Inspector et affiche une adresse locale à ouvrir dans le navigateur. Vérifiez trois choses :

  • onglet Tools : chercher_notes et lire_note apparaissent avec leur description et un champ de saisie ;
  • un appel à lire_note avec ../secret.md renvoie bien l’erreur « Note refusée » ;
  • onglet Resources : notes://liste renvoie vos fichiers.

Testez toujours le serveur seul avant de le brancher : une erreur se lit bien plus facilement ici qu’à travers un hôte.

Étape 4 : le brancher à votre assistant

Tous les hôtes font la même chose : ils lancent votre serveur comme un processus et lui parlent par l’entrée et la sortie standard (transport stdio). Il suffit donc de leur donner la commande de lancement, toujours avec un chemin absolu :

uv run --with "mcp[cli]" mcp run /chemin/absolu/vers/server.py

Claude Desktop — le SDK écrit la configuration pour vous :

uv run mcp install server.py

Quittez complètement Claude Desktop (pas seulement la fenêtre) puis relancez-le.

Claude Code — une commande :

claude mcp add notes -- uv run --with "mcp[cli]" mcp run /chemin/absolu/vers/server.py

Tapez /mcp dans une session pour vérifier que notes est connecté.

Cursor — fichier .cursor/mcp.json à la racine du projet :

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

VS Code — fichier .vscode/mcp.json ; la clé est servers et chaque entrée déclare son type :

{
  "servers": {
    "notes": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "--with", "mcp[cli]", "mcp", "run", "/chemin/absolu/vers/server.py"]
    }
  }
}

Ces commandes et fichiers sont ceux de la page Connect to a real host de la documentation officielle. Pour l’installation d’un serveur existant (et non le vôtre), suivez plutôt Installer un serveur MCP dans Claude, ChatGPT ou Cursor.

Étape 5 : l’essayer pour de vrai

Demandez à votre assistant : « Dans mes notes, retrouve ce qui a été décidé sur le budget et résume-le. » Il devrait appeler chercher_notes avec « budget », puis lire_note sur les fichiers trouvés, et vous demander l’autorisation avant chaque appel si votre hôte est configuré ainsi. Gardez cette validation activée tant que vous n’avez pas observé le comportement du serveur sur plusieurs jours.

Problèmes fréquents

SymptômeCause probableSolution
Le serveur n’apparaît pas dans l’hôteChemin relatif vers server.pyMettre le chemin absolu, puis relancer l’hôte
« command not found: uv » côté hôteL’hôte lance le serveur avec un PATH minimalRemplacer uv par son chemin absolu (which uv ou where uv)
Rien ne change après une modification de la configurationL’hôte lit sa configuration au démarrageQuitter complètement l’hôte et le relancer
Le serveur plante au premier appelUn print() écrit sur la sortie standard, réservée au protocole en stdioÉcrire les journaux sur la sortie d’erreur (sys.stderr) ou avec logging
ImportError: mcp.server.fastmcpCode écrit pour le SDK v1Passer à from mcp.server import MCPServer

Lancez aussi la commande de démarrage à la main : un serveur stdio sain n’affiche rien et attend. Une trace d’erreur ou un arrêt immédiat indique le vrai problème.

Aller plus loin

  • Le partager : uv run mcp run server.py --transport streamable-http sert le même serveur en HTTP sur http://localhost:8000/mcp. Avant de l’exposer sur Internet, ajoutez une authentification (le SDK prend en charge OAuth) et limitez ce que chaque outil peut faire.
  • Le tester automatiquement : le SDK fournit un Client qui se connecte directement à l’objet mcp en mémoire, sans processus ni port, pratique pour des tests pytest.
  • Le publier : le registre MCP officiel référence les serveurs publics ; notre annuaire des serveurs MCP les reprend avec l’activité de leur dépôt et un niveau de risque.
  • Le choisir plutôt que le coder : un serveur existe peut-être déjà pour votre besoin. Le guide Choisir un serveur MCP explique comment vérifier qu’il est maintenu et sans danger, et MCP et skills malveillants : vérifier avant d’installer détaille les pièges.

Checklist avant de vous en servir au quotidien

  • Le serveur fonctionne seul (mcp dev) et chaque outil a une docstring claire
  • Les chemins, adresses ou requêtes acceptés sont limités au strict nécessaire
  • Aucun outil ne supprime, n’envoie ou ne paie sans validation humaine
  • Aucun secret (clé d’API, mot de passe) n’est écrit dans server.py : passez-les par variables d’environnement
  • Le chemin vers server.py dans la configuration de l’hôte est absolu
  • Vous avez passé le diagnostic de sécurité d’agent IA sur l’ensemble de votre configuration

Questions fréquentes

Faut-il savoir programmer pour créer un serveur MCP ?

Il faut connaître les bases de Python ou de TypeScript : écrire une fonction, installer un paquet, lancer un script. Le SDK officiel se charge du protocole, du schéma des paramètres et de la validation : un serveur utile tient en une trentaine de lignes.

Python ou TypeScript pour un serveur MCP ?

Les deux SDK sont officiels et maintenus par le projet Model Context Protocol. Prenez le langage de l'outil que vous voulez exposer : Python pour des scripts de données ou d'automatisation, TypeScript si votre code existant est en Node.js. Le protocole est le même, un client ne voit pas la différence.

Mon serveur MCP peut-il être utilisé par d'autres personnes ?

En local (transport stdio), seul votre ordinateur le lance. Pour le partager, servez le même code en Streamable HTTP derrière une adresse web, avec une authentification : le SDK fournit le transport, mais l'hébergement, l'accès et la sécurité restent à votre charge.

Quelle différence entre un outil et une ressource MCP ?

Un outil est une fonction que le modèle décide d'appeler pour agir ou chercher (comme une requête POST). Une ressource est une donnée que l'application charge dans le contexte du modèle, sans effet de bord (comme une requête GET). Un troisième type, le prompt, est un modèle de message que l'utilisateur déclenche par son nom.

Dans la même rubrique

Neutralité. Aucun lien d'affiliation. Aucun éditeur ne paie pour être évalué, noté ou classé. Les évaluations sont dirigées par François Chollet, neutres et factuelles, et chaque donnée est datée et sourcée. Comment nous notons