Architecture d'un Serveur MCP Custom
Concevoir un serveur MCP de production
Passer d’un prototype à un serveur MCP robuste nécessite une architecture réfléchie. Dans cette leçon, vous découvrirez les patterns de conception, la structure de projet recommandée, et les frameworks disponibles pour créer des serveurs MCP professionnels.
Frameworks pour créer un serveur MCP
FastMCP (Python) — Recommandé
FastMCP est la bibliothèque de référence pour créer des serveurs MCP en Python. Elle fournit une API simple à base de décorateurs et gère automatiquement le protocole MCP :
from mcp.server.fastmcp import FastMCP
app = FastMCP(
"Mon Serveur",
description="Serveur MCP pour la gestion de projets",
)
MCP SDK (TypeScript)
Pour les développeurs JavaScript/TypeScript, le SDK officiel MCP d’Anthropic est disponible :
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({
name: "Mon Serveur",
version: "1.0.0",
});
Choix du framework
| Critère | FastMCP (Python) | MCP SDK (TypeScript) |
|---|---|---|
| Maturité | Très mature | Mature |
| Décorateurs | @app.tool() | Méthode server.tool() |
| Transport HTTP | Intégré (FastAPI) | Intégré (Express) |
| Communauté | Large | Large |
Structure de projet recommandée
mon-serveur-mcp/
├── server.py # Point d'entrée FastAPI + montage MCP
├── tools/
│ ├── __init__.py
│ ├── project_tools.py # Tools de gestion de projet
│ ├── file_tools.py # Tools de gestion de fichiers
│ └── search_tools.py # Tools de recherche
├── services/
│ ├── __init__.py
│ ├── database.py # Accès base de données
│ └── external_api.py # Appels API externes
├── auth/
│ ├── __init__.py
│ └── middleware.py # Middleware d'authentification
├── config.py # Configuration (env vars)
├── Dockerfile # Conteneurisation
├── requirements.txt # Dépendances Python
├── .env # Variables d'environnement (non commité)
└── tests/
├── test_tools.py
└── test_integration.py
Le point d’entrée : server.py
Le fichier principal monte les serveurs MCP sur FastAPI :
# server.py
"""Point d'entrée du serveur MCP."""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from tools.project_tools import project_mcp
from tools.search_tools import search_mcp
from auth.middleware import AuthMiddleware
# Application FastAPI
api = FastAPI(
title="Mon Serveur MCP",
version="1.0.0",
)
# CORS pour les clients web
api.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# Middleware d'authentification
api.add_middleware(AuthMiddleware)
# Monter les serveurs MCP sur des routes distinctes
project_mcp.mount(api, path="/projects")
search_mcp.mount(api, path="/search")
# Page d'accueil (optionnel mais utile)
@api.get("/")
async def root():
return {
"service": "Mon Serveur MCP",
"version": "1.0.0",
"endpoints": {
"projects": "/projects/mcp",
"search": "/search/mcp",
},
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(api, host="0.0.0.0", port=8000)
Séparer les tools en modules
Chaque domaine fonctionnel a son propre fichier de tools :
# tools/project_tools.py
"""Tools MCP pour la gestion de projets."""
from mcp.server.fastmcp import FastMCP
from services.database import db
project_mcp = FastMCP(
"Project Manager",
description="Outils de gestion de projets et de tâches",
)
@project_mcp.tool()
async def create_project(name: str, description: str = "") -> str:
"""Crée un nouveau projet.
Args:
name: Nom du projet (2-100 caractères)
description: Description du projet (optionnel)
Returns:
JSON avec les détails du projet créé
"""
project = await db.projects.create(name=name, description=description)
return project.to_json()
@project_mcp.tool()
async def list_projects(status: str = "active") -> str:
"""Liste les projets par statut.
Args:
status: Filtrer par statut : active, archived, all (défaut: active)
Returns:
JSON avec la liste des projets
"""
projects = await db.projects.list(status=status)
return projects.to_json()
Gestion de la configuration
Centralisez la configuration dans un fichier dédié :
# config.py
"""Configuration du serveur MCP."""
import os
from dataclasses import dataclass
@dataclass
class Config:
api_token: str = os.getenv("MCP_API_TOKEN", "")
database_url: str = os.getenv("DATABASE_URL", "sqlite:///data.db")
debug: bool = os.getenv("DEBUG", "false").lower() == "true"
port: int = int(os.getenv("PORT", "8000"))
max_results: int = int(os.getenv("MAX_RESULTS", "50"))
config = Config()
Gestion des erreurs
Les tools MCP doivent retourner des erreurs exploitables par le modèle :
import json
def error_response(message: str, code: str = "error") -> str:
"""Formate un message d'erreur standardisé."""
return json.dumps({
"success": False,
"error": {"code": code, "message": message}
}, ensure_ascii=False)
@project_mcp.tool()
async def get_project(project_id: str) -> str:
"""Récupère les détails d'un projet par son identifiant."""
try:
project = await db.projects.get(project_id)
if not project:
return error_response(f"Projet {project_id} introuvable", "not_found")
return project.to_json()
except Exception as e:
return error_response(f"Erreur serveur : {str(e)}", "server_error")
Serveurs stateful vs stateless
Stateful (avec état)
Le serveur maintient un état entre les appels (base de données en mémoire, sessions utilisateur). C’est le cas le plus courant pour les serveurs de gestion.
Stateless (sans état)
Chaque requête est indépendante. FastMCP supporte le mode stateless avec le paramètre stateless_http=True. C’est recommandé pour les serveurs de calcul ou de transformation pure.
app = FastMCP("Stateless Server", stateless_http=True)
Points clés à retenir
- Séparez vos tools en modules thématiques dans un dossier
tools/ - Utilisez FastAPI comme base HTTP et montez les serveurs MCP sur des routes dédiées
- Centralisez la configuration via des variables d’environnement
- Standardisez le format des réponses d’erreur pour que le modèle les exploite
- Choisissez entre stateful (gestion de données) et stateless (calculs purs)
- Ajoutez une page d’accueil
/pour documenter vos endpoints MCP