Ce tutoriel construit un petit serveur qui recherche une technologie dans un catalogue local et expose sa fiche comme ressource. L’exemple reste volontairement sans base de données afin de rendre visibles les primitives MCP.
Prérequis
Vous avez besoin de Python récent et d’un gestionnaire d’environnement. Créez un projet isolé :
mkdir catalogue-mcp
cd catalogue-mcp
python -m venv .venv
source .venv/bin/activate
pip install fastmcpSous Windows PowerShell, l’activation utilise .venv\Scripts\Activate.ps1.
Créer le serveur
Ajoutez un fichier server.py :
from fastmcp import FastMCP
mcp = FastMCP(
"Catalogue de technologies",
instructions=(
"Recherchez une technologie avant de lire sa fiche. "
"N’inventez pas de résultat absent du catalogue."
),
)
CATALOGUE = {
"chromadb": {
"name": "ChromaDB",
"summary": "Base orientée embeddings pour des applications de recherche.",
},
"faiss": {
"name": "FAISS",
"summary": "Bibliothèque de recherche de similarité sur des vecteurs denses.",
},
}L’objet FastMCP contient les outils, ressources et prompts du serveur. Les instructions aident le client, mais ne doivent pas porter une règle de sécurité.
Ajouter un outil de recherche
@mcp.tool
def search_technologies(query: str, limit: int = 5) -> list[dict[str, str]]:
"""Recherche les technologies dont le nom ou le résumé contient la requête."""
normalized = query.strip().casefold()
bounded_limit = max(1, min(limit, 20))
matches = []
for slug, technology in CATALOGUE.items():
haystack = f"{technology['name']} {technology['summary']}".casefold()
if normalized in haystack:
matches.append({"slug": slug, **technology})
return matches[:bounded_limit]La signature et les annotations servent à produire le schéma d’entrée. La borne appliquée à limit illustre une règle essentielle : validez et limitez les arguments dans le code, même si le schéma les décrit déjà.
Exposer une ressource paramétrée
@mcp.resource("technology://{slug}")
def get_technology(slug: str) -> dict[str, str]:
"""Retourne la fiche d’une technologie du catalogue."""
normalized = slug.strip().casefold()
if normalized not in CATALOGUE:
raise ValueError("Technologie inconnue")
return {"slug": normalized, **CATALOGUE[normalized]}L’URI donne une identité stable à la donnée. Dans une application réelle, la fonction vérifierait aussi que l’utilisateur courant a le droit de lire la fiche demandée.
Ajouter un prompt facultatif
@mcp.prompt
def compare_technologies(left: str, right: str) -> str:
"""Prépare une comparaison factuelle entre deux technologies."""
return (
f"Compare {left} et {right} uniquement à partir des ressources du catalogue. "
"Présente usages, limites et critères de choix. Signale toute donnée absente."
)Le prompt guide la conversation. Il ne lit pas lui-même les ressources et ne garantit pas la véracité de la réponse.
Lancer le serveur localement
Ajoutez en bas du fichier :
if __name__ == "__main__":
mcp.run()Puis lancez :
python server.pyLe transport par défaut convient aux clients qui démarrent le processus et communiquent avec lui par entrée-sortie standard. N’écrivez pas de messages de diagnostic arbitraires sur la sortie réservée au protocole ; utilisez un système de logs approprié.
FastMCP permet également d’inspecter un serveur avec sa ligne de commande. Vérifiez la liste et les schémas des composants avant de le connecter à un modèle.
Préparer un transport HTTP
Pour un service distant, le serveur peut utiliser le transport HTTP :
if __name__ == "__main__":
mcp.run(transport="http", host="127.0.0.1", port=8000)Conservez 127.0.0.1 pendant le développement. Exposer le service sur le réseau implique d’ajouter authentification, terminaison TLS, limites de débit, délais, supervision et politique d’origine adaptées au client.
Tester sans modèle
Les fonctions métier doivent rester testables directement :
def test_search_is_bounded():
results = search_technologies("a", limit=10_000)
assert len(results) <= 20
def test_unknown_technology_is_rejected():
try:
get_technology("absente")
except ValueError as error:
assert str(error) == "Technologie inconnue"
else:
raise AssertionError("Une technologie inconnue doit être refusée")Ajoutez ensuite des tests de protocole pour l’initialisation, la découverte des composants et les appels. Les tests avec un vrai modèle viennent en dernier : ils évaluent la capacité du modèle à choisir correctement l’outil, pas la validation métier.
Passer d’une démonstration à un service
Avant un déploiement :
- remplacez le dictionnaire par une couche métier qui applique les droits ;
- utilisez des identifiants stables et des erreurs prévisibles ;
- limitez temps, volume et concurrence ;
- distinguez les opérations de lecture des actions à effet externe ;
- n’inscrivez ni secrets ni données sensibles dans les résultats ou journaux ;
- mesurez appels, erreurs et latence sans enregistrer plus de contenu que nécessaire ;
- testez annulation et répétition des appels.
Résultat
Vous disposez d’un serveur MCP minimal avec un outil, une ressource et un prompt. La prochaine étape utile n’est pas d’ajouter beaucoup de composants : connectez une seule source réelle, définissez son modèle d’autorisation et observez comment un client utilise les primitives existantes.