Créer un MCP Server from scratch : construire pas à pas la capacité d'appel d'outils IA
Un grand modèle, aussi performant soit-il, ne peut pas interroger une base de données, appeler une API ou lire des fichiers par lui-même. La capacité d'appel d'outils IA détermine si un agent peut atteindre le monde réel. Le MCP (Model Context Protocol), protocole standard open source d'Anthropic, permet à Claude, Cursor et d'autres clients de découvrir et d'invoquer vos serveurs de manière unifiée. Ce guide s'adresse aux développeurs backend et IA maîtrisant Python ou TypeScript : il couvre les principes du protocole, la mise en place de l'environnement, les trois capacités Tools / Resources / Prompts, le déploiement HTTP distant, le débogage et la mise en production.
À la fin de la lecture, vous saurez répondre à trois questions : ① en quoi MCP diffère fondamentalement de Function Calling et des LangChain Tools ; ② comment enregistrer outils, ressources et modèles de prompts avec le SDK officiel ; ③ comment encapsuler une base de connaissances personnelle en MCP Server prêt pour la production et interroger Cursor : « Quelles notes ai-je prises sur MCP la semaine dernière ? »
01 Qu'est-ce que MCP ? Principes, mécanismes et comparaison
L'appel d'outils a connu trois générations : Function Calling (formats propriétaires) → Plugins (liés à la plateforme) → MCP (standard ouvert). La motivation centrale d'Anthropic : unifier via JSON-RPC la façon dont les clients IA découvrent, décrivent et invoquent des capacités externes, et mettre fin au cauchemar N modèles × M outils.
- Problème adressé : les modèles n'accèdent pas aux outils externes ni aux données en temps réel — pas de requêtes BDD, d'appels API ou d'opérations fichiers.
- Cas d'usage : vous voulez que Claude / GPT interroge une base, appelle une REST API, lise et écrive du Markdown local — c'est précisément ce qu'expose un MCP Server.
- Promesse : à l'issue de cet article, vous pourrez développer et déployer un MCP Server prêt pour la production.
Architecturalement, le MCP Client (Claude Desktop, Cursor, etc.) et le MCP Server (votre code) communiquent en JSON-RPC bidirectionnel ; le serveur se connecte aux systèmes externes :
- Tools : fonctions invocables par l'IA (recherche, calcul, requête BDD)
- Resources : ressources lisibles par l'IA (fichiers, URL, flux de données)
- Prompts : modèles de prompts prédéfinis avec injection de paramètres
La communication repose sur JSON-RPC 2.0. Deux modes de transport : stdio (sous-processus local, latence minimale) et HTTP + SSE / Streamable HTTP (service distant, multi-clients). Cycle de vie : poignée de main d'initialisation → négociation des capacités → requêtes/réponses → fermeture.
| Dimension | MCP | OpenAI Function Calling | LangChain Tools |
|---|---|---|---|
| Standardisation | Protocole ouvert | Propriétaire éditeur | Lié au framework |
| Transport | stdio / HTTP | HTTP | HTTP |
| Multi-modèles | Oui | Non | Partiel |
| Ressources / prompts | Support natif | Non supporté | Non supporté |
| Écosystème | Croissance rapide (10 000+ serveurs) | Mature | Mature |
Pour aller plus loin : Pourquoi MCP devient le HTTP de l'ère IA ; spécification officielle sur modelcontextprotocol.io.
02 Environnement de développement : langage, dépendances et structure
Python (recommandé pour débuter) : SDK officiel mcp, décorateurs FastMCP concis et accessibles. TypeScript (recommandé frontend / full-stack) : SDK officiel @modelcontextprotocol/sdk. Cet article privilégie Python, avec TypeScript en contrepoint.
Environnement Python
python -m venv .venv
source .venv/bin/activate
pip install mcp
Environnement TypeScript (référence)
npm init -y
npm install @modelcontextprotocol/sdk
Structure de projet recommandée :
my-mcp-server/
├── server.py Point d'entrée principal
├── tools/
│ ├── __init__.py
│ ├── calculator.py
│ └── web_search.py
├── resources/
│ └── file_reader.py
├── prompts/
│ └── templates.py
├── tests/
│ └── test_tools.py
├── pyproject.toml
└── README.md
Trois outils de débogage essentiels :
- MCP Inspector : interface officielle pour tester visuellement Tools / Resources / Prompts
- Claude Desktop : éditer
claude_desktop_config.jsonpour l'intégration locale - Configuration MCP Cursor : Settings → MCP → ajouter une commande stdio
03 Hello World : MCP Server minimal et intégration Cursor
Avec FastMCP, dix lignes suffisent pour un premier serveur fonctionnel :
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-first-server")
@mcp.tool()
def say_hello(name: str) -> str:
"""Salue la personne indiquée"""
return f"Hello, {name}! Voici votre premier outil MCP."
if __name__ == "__main__":
mcp.run()
Exécution et vérification :
python server.py
Ou via MCP Inspector
npx @modelcontextprotocol/inspector python server.py
Intégration Cursor en six étapes :
- Confirmer le chemin Python : dans le venv,
which pythonet noter le chemin absolu. - Ouvrir les paramètres MCP Cursor : Settings → Features → MCP Servers.
- Ajouter un serveur stdio : command = chemin Python, args = chemin absolu de
server.py. - Redémarrer Cursor : pour appliquer la configuration MCP.
- Vérifier la liste d'outils : en mode Agent, confirmer la présence de
say_hello. - Déclencher un appel : demander à l'IA d'« utiliser say_hello pour saluer JEXCLOUD » et valider la réponse.
Même logique pour Claude Desktop : éditer ~/Library/Application Support/Claude/claude_desktop_config.json et enregistrer la même configuration sous mcpServers.
04 Développement Tools : types de paramètres, cinq outils pratiques et mode async
Contrat d'un outil : la signature de fonction fait office de documentation — types de paramètres, type de retour et docstring sont convertis par MCP en JSON Schema pour l'IA. Nommage en snake_case ; privilégier des erreurs structurées plutôt que des exceptions brutes.
Paramètres complexes modélisés avec Pydantic :
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(description="Mot-clé de recherche")
max_results: int = Field(default=5, description="Nombre maximal de résultats")
language: str = Field(default="fr", description="Langue des résultats")
@mcp.tool()
def web_search(input: SearchInput) -> list[dict]:
"""Effectue une recherche web et retourne la liste des résultats"""
...
Cinq outils pratiques comme checklist d'entraînement :
- Calculatrice : évaluation sécurisée d'expressions (
ast.literal_evalanti-injection) - Lecture/écriture fichiers : read / write limités à un répertoire autorisé
- Requêtes HTTP : GET / POST avec timeout et retry uniformes
- Requête base de données : SQL en lecture seule + paramétrage anti-injection
- Outils temporels : heure courante, conversion fuseau, format ISO 8601
Outils IO-intensifs en asynchrone :
import httpx
@mcp.tool()
async def fetch_url(url: str) -> str:
"""Récupère le contenu de l'URL indiquée"""
async with httpx.AsyncClient() as client:
response = await client.get(url, timeout=30.0)
return response.text
Bonnes pratiques d'erreurs : timeouts, contrôle d'accès (whitelist de chemins / clé API), retour structuré {"error": "...", "code": "..."} pour l'auto-correction de l'IA.
05 Resources : adressage URI, ressources statiques et dynamiques
Resource vs Tool : la Resource fournit des données (lecture seule), le Tool exécute des actions (écriture, effets de bord). Adressage par schéma URI : file://, http://, custom://.
Ressource statique
@mcp.resource("config://app-settings")
def get_app_settings() -> str:
return json.dumps({"version": "1.0", "env": "production"})
Ressource dynamique (paramétrée)
@mcp.resource("user://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
user = db.query_user(user_id)
return json.dumps(user)
Types de ressources couverts :
- Texte :
text/plain,application/json - Binaire : images, PDF (Base64 ou URI blob)
- Streaming : logs temps réel, flux de marché (abonnement ressource)
Serveur de ressources système de fichiers : lister un répertoire → lire un fichier par chemin → optionnellement watchfiles pour détecter les changements et notifier les mises à jour.
06 Prompts : modèles réutilisables et scénarios multi-tours
Un MCP Prompt est un fragment de prompt prédéfini que le client IA peut réutiliser directement, avec injection dynamique de paramètres pour la cohérence et la maintenabilité des prompts d'équipe.
from mcp.types import PromptMessage, TextContent
@mcp.prompt()
def code_review_prompt(language: str, code: str) -> list[PromptMessage]:
"""Modèle de prompt pour revue de code"""
return [
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"Veuillez examiner le code {language} suivant..."
)
)
]
Les modèles multi-tours mélangent les rôles user et assistant. Scénarios typiques : simulation d'entretien (assistant pose, user répond), assistant de débogage (assistant guide les étapes).
07 Transport HTTP : MCP Server distant et durcissement sécurité
| Caractéristique | stdio | HTTP + SSE |
|---|---|---|
| Déploiement | Processus local | Serveur distant |
| Latence | Très faible | Dépend du réseau |
| Multi-clients | Non supporté | Supporté |
| Cas d'usage | Outils locaux | SaaS / partage d'équipe |
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("remote-server", transport="streamable-http")
if __name__ == "__main__":
mcp.run(host="0.0.0.0", port=8000)
En production, ajouter : authentification Bearer Token, middleware clé API, whitelist CORS, limitation de débit (ex. slowapi). Les serveurs distants conviennent aux requêtes BDD partagées, passerelles API internes, etc.
08 Débogage et tests : MCP Inspector, tests unitaires, erreurs courantes
Workflow MCP Inspector : lancer Inspector → connecter la commande stdio → tester tools/call dans l'UI → consulter les logs JSON-RPC → simuler timeout et refus de permission.
import pytest
from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
@pytest.mark.asyncio
async def test_calculator_tool():
server_params = StdioServerParameters(command="python", args=["server.py"])
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("calculate", {"expression": "2 + 2"})
assert result.content[0].text == "4"
| Erreur | Cause | Solution |
|---|---|---|
| Outil absent dans l'IA | Chemin de configuration incorrect | Vérifier les chemins absolus command / args dans config.json |
| Échec sérialisation JSON | Type de retour non supporté | Convertir en chaîne ou dict |
| Timeout / déconnexion | Exécution trop lente | Passer en async + contrôle de timeout |
| Permission refusée | Chemin fichier restreint | Configurer une whitelist de répertoires autorisés |
09 Déploiement production : Docker, cloud et observabilité
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "server.py"]
Options de déploiement :
- Railway / Render : déploiement en un clic, adapté aux projets personnels
- AWS Lambda / Google Cloud Run : serverless, facturation à l'appel
- VPS dédié : reverse proxy Nginx + TLS avec Bearer Token
Trois piliers d'observabilité : logs structurés des requêtes, métriques Prometheus des appels d'outils, alertes Sentry ; endpoint /health. Gestion de version : déclarer la version du protocole MCP, upgrades d'outils rétrocompatibles, négociation des capacités pour éviter les crashs client.
- MCP Python SDK : github.com/modelcontextprotocol/python-sdk
- MCP TypeScript SDK : github.com/modelcontextprotocol/typescript-sdk
- MCP Inspector : github.com/modelcontextprotocol/inspector
10 Projet pratique : MCP Server de base de connaissances personnelle
Besoin : permettre à l'IA de rechercher des notes Markdown locales, effectuer une recherche sémantique, créer et mettre à jour des notes.
Stack technique :
- Base vectorielle : ChromaDB ou Qdrant (léger en local)
- Modèle d'embedding :
text-embedding-3-small(OpenAI) ou localnomic-embed-text - Surveillance fichiers :
watchfilespour reconstruire l'index de façon incrémentale
Modules clés :
- Outil
index_notes: scanner le répertoire, découper, embedder, écrire en base vectorielle - Outil
semantic_search: query → top-k fragments pertinents - Outil
write_note: créer / ajouter des fichiers Markdown - Ressource
notes://{path}: lire le texte intégral d'une note par URI
Démonstration : dans Cursor, demander « Qu'ai-je noté sur MCP la semaine dernière ? » → l'IA appelle semantic_search → retourne les fragments pertinents et synthétise la réponse. Le chemin le plus court pour brancher une connaissance privée dans un workflow agent.
11 Écosystème MCP, parcours d'apprentissage et hébergement production
Serveurs communautaires recommandés :
mcp-server-filesystem: opérations système de fichiersmcp-server-github: opérations sur dépôts GitHubmcp-server-brave-search: recherche webmcp-server-postgres: requêtes base de donnéesmcp-server-slack: messages Slack
Tendances écosystème 2026 : Cursor, Claude Desktop, VS Code, OpenAI et Google Gemini supportent ou prévoient MCP nativement ; MCP Marketplace accélère la distribution ; standards entreprise (OAuth 2.1, journaux d'audit) entrent dans la feuille de route.
Prochaines étapes : lire la spécification MCP → publier un premier serveur public → explorer MCP + orchestration d'agents → contribuer par PR à l'écosystème open source.
- Version du protocole : première publication 2024-11-05 ; dès 2025, Streamable HTTP remplace le SSE pur comme transport distant recommandé
- Taille de l'écosystème : plus de 10 000 serveurs MCP communautaires en 2026
- Maintenance SDK : open source Anthropic + gouvernance Linux Foundation AAIF ; SDK Python / TypeScript officiels mis à jour chaque semaine
MCP est le protocole standard de l'outillage IA — maîtriser le développement de serveurs, c'est donner à tout LLM l'accès à vos systèmes métier. Quel outil comptez-vous encapsuler ? Partagez votre cas d'usage en commentaire.
Le coût caché d'un MCP Server en production réside dans la stabilité de l'hôte : fermer un laptop tue le sous-processus STDIO ; une connexion domestique instable interrompt le HTTP longue durée ; un VPS partagé sans sandbox macOS ni permissions TCC. Pour indexer une base de connaissances 24/7, un MCP HTTP distant ou un CI avec Cursor Agent, le Mac bare metal multi-région JEXCLOUD offre Apple Silicon dédié, IP publique fixe, livraison en 120 secondes et location mensuelle flexible — plus adapté à la production qu'un bricolage local avec reconnexions permanentes. Nœuds et tarifs : page tarifs JEXCLOUD ; questions de déploiement : centre d'aide.