DEV-AI

Votre LLM ne peut pas lire votre base de données. Ni appeler votre API interne. Ni exécuter du code sur votre machine. Avec MCP, en 50 lignes de Python, vous donnez à Claude (ou n'importe quel client compatible) un accès contrôlé à vos systèmes. Ce tutoriel MCP Python montre comment créer un serveur MCP avec FastMCP et l'intégrer à Claude Desktop — pas-à-pas, code prêt à copier-coller.

Modèle mental à garder en tête : un serveur MCP n'est pas une API classique. C'est une couche d'abstraction qui expose vos systèmes sous forme d'outils compréhensibles par un LLM — typés, documentés, invocables en langage naturel. Vous ne pensez plus en termes de routes REST, mais de capacités métier.

Créer un serveur MCP (Model Context Protocol) en Python 2026 : tutoriel FastMCP pas-à-pas

À qui s'adresse cet article ?

TL;DR

· ~20 min de lecture · mcp SDK · Python 3.10+
10 lignes
Serveur minimal
3
Primitives MCP
MIT
Licence SDK
Py 3.10+
Requis

1. Pourquoi créer son propre serveur MCP ?

Il existe déjà une centaine de serveurs MCP publics — filesystem, Postgres, GitHub, Slack, Google Drive. Pour 80 % des cas d'usage grand public, installer un serveur existant suffit. Mais dès que vous avez des données ou des APIs propres à votre organisation, créer votre propre serveur devient incontournable.

1.1 Trois cas où créer votre serveur

Exposer une base de données métier

Votre CRM interne, votre base produits, votre historique clients. Un tool search_customer donne à Claude un accès lecture contrôlé sans tout exporter.

Encapsuler une API interne

Votre API de facturation, votre système de tickets, vos webhooks. Claude n'a pas besoin de connaître vos endpoints — il voit des fonctions typées et documentées.

Agréger des sources hétérogènes

Un tool summarize_week qui combine Jira + Slack + emails. Vous contrôlez la logique de fusion ; Claude reçoit juste la réponse synthétisée.

1.2 Tools vs Resources vs Prompts — ce que vous allez exposer

Primitive Définition Exemple
Tool Fonction que le LLM peut invoquer avec des paramètres search_orders(customer_id, limit)
Resource Données en lecture seule identifiées par une URI docs://readme.md
Prompt Template de prompt paramétrable invocable par l'utilisateur /review-pr pr_number=42

2. Architecture MCP — rappel express

MCP suit une architecture client-serveur. Le client (Claude Desktop, VS Code, Cursor, Zed, ou votre propre app) se connecte à un ou plusieurs serveurs MCP. Le protocole utilise JSON-RPC 2.0 sur trois transports possibles :

Transport Cas d'usage Caractéristiques
stdio Intégration locale (Claude Desktop, IDE) Simple, pas d'infra — le client spawn le process
Streamable HTTP Serveur distant, multi-client Recommandé en prod — remplace l'ancien SSE
HTTP+SSE (legacy) Ancien transport séparant endpoints requête/SSE Déprécié, remplacé par Streamable HTTP (qui peut encore utiliser SSE en interne pour streamer plusieurs messages)

Commencez par stdio. C'est le plus simple à développer et tester. Vous passerez à HTTP uniquement si vous devez partager le serveur en équipe ou l'exposer à plusieurs utilisateurs.

3. Setup — SDK MCP Python + FastMCP

Le SDK officiel Python s'installe en une commande. Utilisez uv (plus rapide que pip) ou un virtualenv classique :

# Option 1 : avec uv (recommandé, 10× plus rapide que pip)
uv init mon-serveur-mcp
cd mon-serveur-mcp
uv add "mcp[cli]" httpx

# Option 2 : avec venv classique
python -m venv .venv
source .venv/bin/activate  # Linux/Mac
# .venv\Scripts\activate       # Windows
pip install "mcp[cli]" httpx

L'extra [cli] installe également les outils CLI associés (entre autres la commande mcp dev pour lancer/déboguer rapidement un serveur) — c'est la forme d'installation recommandée par la doc officielle MCP.

# Si vous n'avez pas besoin des outils CLI, mcp seul suffit
# pip install mcp

Le package mcp contient à la fois FastMCP (API haut niveau avec décorateurs) et les primitives bas niveau du protocole. Sauf cas avancé, utilisez toujours FastMCP — c'est 10× plus productif.

4. Premier serveur MCP en 10 lignes

Créez un fichier server.py. Voici un serveur MCP minimal qui expose un tool de calcul :

from mcp.server.fastmcp import FastMCP

# Instancier le serveur avec un nom
mcp = FastMCP("Mon Serveur Calcul")

@mcp.tool()
def addition(a: float, b: float) -> float:
    """Additionne deux nombres et retourne le résultat."""
    return a + b

if __name__ == "__main__":
    mcp.run()  # stdio par défaut

C'est tout. Votre serveur expose un tool nommé addition avec deux paramètres typés. Le docstring devient la description vue par le LLM — soignez-le comme un message pour un collègue qui ne connaît pas le code.

Ce qui se passe en coulisse : FastMCP inspecte les type hints Python (a: float, b: float) et génère automatiquement un JSON Schema que Claude reçoit. Le docstring devient la description du tool. Zero boilerplate.

5. Exposer des tools — fonctions appelables par le LLM

Les tools sont le cœur de MCP. Passons à un exemple réaliste : un tool qui cherche des clients dans une base SQLite.

from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, Field
import sqlite3

mcp = FastMCP("CRM Search")

class Customer(BaseModel):
    id: int
    name: str
    email: str
    total_orders: int

@mcp.tool()
def search_customers(
    query: str = Field(description="Recherche par nom ou email"),
    limit: int = Field(default=10, ge=1, le=100),
) -> list[Customer]:
    """Recherche des clients par nom ou email.

    Retourne une liste triée par nombre de commandes décroissant.
    Limite à 100 résultats maximum pour éviter les gros retours.
    """
    conn = sqlite3.connect("crm.db")
    conn.row_factory = sqlite3.Row
    cur = conn.execute(
        """SELECT id, name, email, total_orders FROM customers
           WHERE name LIKE ? OR email LIKE ?
           ORDER BY total_orders DESC LIMIT ?""",
        (f"%{query}%", f"%{query}%", limit),
    )
    results = [Customer(**dict(r)) for r in cur.fetchall()]
    conn.close()
    return results

Points clés de cet exemple :

⚠️ Traiter le LLM comme une source hostile

Un LLM peut appeler un tool avec des paramètres absurdes ou malveillants — pas par malveillance intentionnelle, mais parce qu'il hallucine ou parce qu'un utilisateur a injecté un prompt en amont. Exemples réels :

Votre serveur MCP doit être conçu comme une API publique hostile, même s'il est utilisé en interne. Validation Pydantic stricte, rate limiting, timeouts agressifs, et logs de tout appel suspect.

5.1 Tool async pour les appels IO

Si votre tool appelle une API externe ou une DB async, déclarez-le async def — FastMCP gère le cycle asyncio pour vous :

import httpx

@mcp.tool()
async def fetch_weather(city: str) -> dict:
    """Récupère la météo actuelle pour une ville."""
    async with httpx.AsyncClient(timeout=5.0) as client:
        r = await client.get(f"https://wttr.in/{city}?format=j1")
        r.raise_for_status()
        data = r.json()
    return {
        "city": city,
        "temp_c": int(data["current_condition"][0]["temp_C"]),
        "desc": data["current_condition"][0]["weatherDesc"][0]["value"],
    }

6. Exposer des resources — données lisibles

Les resources sont identifiées par des URI. Contrairement aux tools (appelés par le LLM), les resources sont lues par le client quand il en a besoin comme contexte.

@mcp.resource("config://server-info")
def get_server_info() -> str:
    """Informations de configuration du serveur."""
    return """# Serveur MCP CRM DEV-AI
Version: 1.0
Base clients: 2 347 entrées
Dernière synchronisation: 22 avril 2026
"""

# Resource avec paramètre dynamique dans l'URI
@mcp.resource("customer://{customer_id}/profile")
def get_customer_profile(customer_id: str) -> str:
    """Profil détaillé d'un client (markdown formaté)."""
    # ... lecture DB ...
    return f"# Client {customer_id}\n\nNom: ...\nEmail: ..."

Les resources sont utiles quand l'utilisateur veut injecter du contexte dans la conversation (via un bouton "Attach resource" dans Claude Desktop), plutôt que de laisser le LLM décider d'appeler un tool.

7. Exposer des prompts — templates réutilisables

Les prompts sont des templates paramétrables que l'utilisateur déclenche explicitement. Selon le client MCP, ils peuvent être exposés comme commandes/raccourcis (par exemple des slash commands dans certains clients) — les clients ne supportent pas tous les primitives MCP de manière identique, consultez la matrice de support de votre client.

from mcp.server.fastmcp.prompts import base

@mcp.prompt()
def review_customer(customer_id: str) -> list[base.Message]:
    """Analyse complète d'un client : commandes, réclamations, recommandations."""
    return [
        base.UserMessage(
            f"""Analyse le client {customer_id}. Utilise le tool search_customers
pour récupérer ses données, puis :
1. Résume son historique en 3 bullets
2. Identifie les risques potentiels (churn, litiges)
3. Propose 2 actions commerciales concrètes"""
        )
    ]

L'utilisateur tape /review_customer customer_id=42 dans Claude Desktop, et le LLM reçoit un prompt structuré + les tools disponibles pour y répondre. C'est un pattern réutilisable qui capitalise votre expertise métier.

8. Tester avec MCP Inspector

Avant de connecter votre serveur à Claude Desktop, testez-le avec MCP Inspector — l'outil officiel de debug. Il lance une interface web qui se connecte à votre serveur et liste tous ses tools/resources/prompts.

# Mode stdio — Inspector lance lui-même le serveur
npx -y @modelcontextprotocol/inspector python server.py

# Mode Streamable HTTP — serveur déjà lancé séparément
# Terminal 1 :
python server.py  # écoute sur http://localhost:8000
# Terminal 2 :
npx -y @modelcontextprotocol/inspector
# Dans l'UI Inspector → onglet Transport → Streamable HTTP
# URL : http://localhost:8000/mcp

# Dans les deux cas, l'interface ouvre http://localhost:5173
# Connect → liste des tools/resources/prompts, logs JSON-RPC en direct

L'option -y de npx auto-valide le téléchargement du package (utile en CI ou en première utilisation). Choisissez le mode selon votre transport cible : stdio pour un serveur local qui sera intégré à Claude Desktop, Streamable HTTP pour un serveur qui tournera en standalone.

Workflow conseillé : toujours tester avec Inspector avant d'intégrer à Claude Desktop. Vous gagnez un temps fou sur le debug — les erreurs dans Claude Desktop sont plus difficiles à diagnostiquer (logs cachés, silencieux en cas d'erreur de schema).

9. Intégrer à Claude Desktop

Une fois votre serveur testé, ajoutez-le à Claude Desktop en éditant claude_desktop_config.json.

Emplacement du fichier :

Note : Claude Desktop est officiellement distribué pour macOS et Windows. Les builds Linux communautaires existent mais l'emplacement du fichier de config peut varier — consultez la documentation du build que vous utilisez.

// claude_desktop_config.json
{
  "mcpServers": {
    "crm-search": {
      "command": "python",
      "args": ["/chemin/absolu/vers/server.py"],
      "env": {
        "DATABASE_URL": "sqlite:///crm.db"
      }
    }
  }
}

Redémarrez Claude Desktop. Votre serveur apparaît dans la barre inférieure (icône outil 🔨). Vous pouvez maintenant demander : "Cherche les clients qui ont 'Dupont' dans leur nom" — Claude appellera automatiquement search_customers.

10. Déployer en HTTP (Streamable HTTP)

Pour partager votre serveur avec une équipe, exposez-le en Streamable HTTP. C'est aussi simple qu'un mcp.run(transport="streamable-http") :

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("CRM Search", host="0.0.0.0", port=8000)

@mcp.tool()
def search_customers(query: str) -> list[dict]:
    # ... même logique que précédemment ...
    return []

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

Déployez ensuite derrière NGINX avec HTTPS + authentification (API key via header). Les clients MCP compatibles HTTP peuvent ensuite s'y connecter via l'URL https://mcp.votre-domaine.fr — consultez la doc de chaque client pour vérifier le support du transport HTTP/Streamable HTTP.

11. Sécurité — 4 règles d'or

Un serveur MCP expose vos données à un LLM, qui peut halluciner ou recevoir des prompts malveillants (prompt injection). Quatre règles non négociables :

⚠️ Ne jamais faire confiance aux paramètres envoyés par le LLM.

  1. Validation Pydantic stricte : contraintes ge, le, pattern, max_length sur tous les paramètres
  2. Scopes minimaux : un tool de lecture DB ne doit jamais pouvoir écrire. Utilisez un utilisateur DB read-only
  3. Rate limiting par session MCP : slowapi ou limiteur maison pour éviter qu'un LLM en boucle épuise vos ressources
  4. Logs structurés de chaque appel : ID session, tool appelé, paramètres, durée, résultat. Indispensable pour l'audit

Pour un déploiement HTTP, minimum vital : CORS restreint aux clients autorisés, HTTPS obligatoire (pas de HTTP en clair en production), et une forme d'authentification.

Authentification — niveaux de maturité :

Pour un premier serveur partagé en équipe, une API key suffit. Dès que vous visez un vrai serveur distant multi-utilisateurs, privilégiez le flow OAuth 2.1 défini par la spec MCP plutôt qu'une solution ad hoc — c'est ce que les clients MCP majeurs (Claude Desktop, Claude API Connectors) sont conçus pour consommer.

Ressources officielles MCP

FAQ

Quelle est la différence entre MCP et les tool calls classiques d'OpenAI ?

Les tool calls OpenAI sont propriétaires et spécifiques à chaque provider. MCP est un standard ouvert : un même serveur MCP peut être utilisé par Claude Desktop, Cursor, Zed, VS Code, ou n'importe quel client compatible. C'est l'équivalent de USB-C pour les LLMs : une prise standard qui fonctionne partout.

Faut-il utiliser FastMCP ou l'API bas niveau du SDK ?

FastMCP est recommandé pour 95% des cas : API haute productivité avec décorateurs, typage Pydantic automatique, gestion du protocole JSON-RPC transparente. L'API bas niveau est utile uniquement si vous avez besoin de contrôle fin sur le handshake, les notifications ou les transports custom.

Quels transports MCP choisir : stdio, SSE ou Streamable HTTP ?

stdio est le transport par défaut pour les intégrations locales (Claude Desktop, IDE) — simple et sans infrastructure. Streamable HTTP est recommandé pour les serveurs distants en production (remplace l'ancien SSE). Commencez par stdio puis migrez à HTTP uniquement si vous voulez partager en équipe.

Comment sécuriser un serveur MCP exposé en HTTP ?

Quatre règles : (1) valider toutes les entrées avec Pydantic, (2) limiter les scopes (lecture seule si possible), (3) rate limiting par session, (4) logs structurés pour audit. Ajoutez auth par API key + HTTPS obligatoire + CORS restreint. Ne jamais exposer un serveur MCP sans authentification.

Un serveur MCP peut-il appeler des APIs externes ?

Oui, c'est même le cas d'usage principal. Vos tools peuvent appeler n'importe quelle API (requests, httpx), interroger une DB (SQLAlchemy, asyncpg), lire des fichiers, exécuter des calculs. Le serveur MCP est un pont entre le LLM et vos systèmes.

Articles liés

Cas d'usage métier concret

Dans un ATS (Applicant Tracking System) ou un CRM, un serveur MCP permet à un LLM d'interroger les candidats, scorer des profils selon une fiche de poste, ou générer des synthèses — sans exposer directement la base de données. Le LLM voit des tools métier (search_candidates(skills, seniority), score_match(candidate_id, job_id)) au lieu de requêtes SQL brutes. Résultat : un assistant de recrutement conversationnel, en Français, sur vos données internes, avec traçabilité complète des appels.

Consulting DEV-AI

Vous voulez exposer vos systèmes à Claude en toute sécurité ?

Conception d'architecture MCP, développement de serveurs sur mesure, audit sécurité, intégration Claude Desktop ou API. Accompagnement expert.

Contacter l'équipe →

Newsletter IA

Restez à jour sur l'IA & le Machine Learning

Actus, tutos, outils — chaque semaine en français. Sans spam.