Protocole · Tools / Resources / Prompts · débogage & déploiement · base de connaissances
Les développeurs backend / IA avec des bases Python ou TypeScript partagent un blocage : Claude et GPT sont puissants, mais n'accèdent ni à votre base, ni à vos API internes, ni à vos fichiers locaux — il manque un canal standardisé vers les outils externes. Le Model Context Protocol (MCP) d'Anthropic est un protocole ouvert : les clients IA (Cursor, Claude Desktop) dialoguent en JSON-RPC avec votre serveur. À la fin de cet article, vous saurez développer et déployer un MCP Server prêt pour la production : architecture → environnement → Hello World → Tools / Resources / Prompts → transport HTTP → débogage → Docker → projet base de connaissances → écosystème 2026.
Même les grands modèles ignorent vos clients CRM et les logs d'hier. La trajectoire est claire : Function Calling → Plugins → MCP. Les deux premiers restent souvent propriétaires ; MCP standardise la découverte et l'appel d'outils — écrire une fois, réutiliser sur plusieurs clients.
Douleur : Claude / GPT doit interroger DB, API et fichiers — chaque format diffère.
Scénario : lire vos notes Markdown dans Cursor, consulter GitHub Issues dans Claude Desktop.
Promesse : du dossier vide au serveur déployable — code complet et tableau de dépannage.
Anthropic a publié MCP en novembre 2024 pour standardiser la communication IA-outils et résoudre le problème N×M d'adaptateurs. Contexte dans notre article MCP et HTTP.
Modèle Client ↔ Server : le Client côté IA (Claude Desktop, Cursor) ; le Server expose les capacités en JSON-RPC :
Tools : fonctions appelables — recherche, calcul, requête DB.
Resources : données lisibles — fichiers, URLs, config.
Prompts : modèles de prompts paramétrables.
Base JSON-RPC 2.0. Transport : stdio (sous-processus local, défaut Cursor) ou HTTP + SSE / Streamable HTTP (distant). Cycle : poignée de main → initialize → requêtes → fermeture.
| Dimension | MCP | OpenAI Function Calling | LangChain Tools |
|---|---|---|---|
| Standard | Protocole ouvert | Propriétaire | Lié au framework |
| Transport | stdio / HTTP | HTTP | HTTP |
| Multi-modèle | Oui | Non | Partiel |
| Resources / Prompts | Natif | Non | Non |
| Écosystème 2026 | 10 000+ serveurs | Mature | Mature |
Python (mcp, FastMCP) pour débuter ; TypeScript (@modelcontextprotocol/sdk) pour frontend/full-stack. Cet article privilégie Python, TS en référence.
# Python python -m venv .venv && source .venv/bin/activate pip install mcp httpx pydantic # TypeScript (référence) npm init -y && npm install @modelcontextprotocol/sdk
my-mcp-server/ ├── server.py # point d'entrée ├── tools/ # calculator.py, web_search.py ├── resources/ # file_reader.py ├── prompts/ # templates.py ├── tests/test_tools.py ├── pyproject.toml └── README.md
MCP Inspector : npx @modelcontextprotocol/inspector python server.py
Claude Desktop : éditer claude_desktop_config.json.
Cursor : Settings → MCP → ajouter command + args.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-first-server")
@mcp.tool()
def say_hello(name: str) -> str:
"""Salue une personne"""
return f"Hello, {name}! Voici votre premier outil MCP."
if __name__ == "__main__":
mcp.run()Après python server.py, configurez Cursor avec {"command":"python","args":["/chemin/absolu/server.py"]} — say_hello doit apparaître dans la liste d'outils.
Chemins absolus vers server.py et le Python du venv.
Après modification, redémarrer la connexion MCP ou la fenêtre Cursor.
Demander explicitement l'appel d'outil dans le chat pour valider l'enregistrement.
La signature sert de documentation : types, retour et docstring guident le choix d'outil. Nommage : snake_case, verbe en tête (search_web). Retourner du JSON structuré plutôt que des exceptions brutes.
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(description="Terme de recherche")
max_results: int = Field(default=5, description="Nombre max de résultats")
language: str = Field(default="fr", description="Langue des résultats")
@mcp.tool()
def web_search(input: SearchInput) -> list[dict]:
"""Recherche web, retourne une liste de résultats"""
...| Outil | Usage | Attention |
|---|---|---|
| Calculatrice | Expressions math | ast.literal_eval, pas eval |
| Fichiers | Lecture/écriture locale | Liste blanche, normalisation de chemin |
| HTTP | APIs externes | Timeout, retry, limite de taille |
| Requête DB | SQL lecture seule | Paramètres, pas de DDL |
| Temps | Now, fuseaux | Retour ISO 8601 |
@mcp.tool()
async def fetch_url(url: str) -> str:
"""Récupère le contenu d'une URL"""
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.get(url)
return response.textRéseau/IO : timeout 15–30 s.
Ops sensibles : auth (clé API, chemins autorisés).
{"error": "...", "hint": "..."} pour retry du modèle.
Resource vs Tool : la Resource est un fournisseur de données (lecture) ; le Tool exécute une action. Adressage URI : file://, http://, custom://.
@mcp.resource("config://app-settings")
def get_app_settings() -> str:
"""Configuration applicative"""
return json.dumps({"version": "1.0", "env": "production"})
@mcp.resource("user://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
"""Profil utilisateur par ID"""
return json.dumps(db.query_user(user_id))Types : texte (text/plain, JSON), binaire (images, PDF), flux (données live). Cas pratique : serveur filesystem avec listing, lecture, watch optionnel.
Les Prompts MCP sont des fragments paramétrables pour harmoniser les prompts d'équipe.
from mcp.types import PromptMessage, TextContent
@mcp.prompt()
def code_review_prompt(language: str, code: str) -> list[PromptMessage]:
"""Modèle de revue de code"""
return [PromptMessage(
role="user",
content=TextContent(type="text", text=f"""Revoyez ce code {language} :
1. Qualité 2. Bugs & sécurité 3. Performance
```{language}
{code}
```""")
)]Modèles multi-tours (user + assistant) pour entretiens ou assistant debug. Le client appelle prompts/get.
| Caractéristique | stdio | HTTP + SSE |
|---|---|---|
| Déploiement | Local | Serveur distant |
| Latence | Très faible | Réseau |
| Multi-client | Non | Oui |
| Scénario | IDE local | SaaS / équipe |
mcp = FastMCP("remote-server", transport="streamable-http")
if __name__ == "__main__":
mcp.run(host="0.0.0.0", port=8000)Production : Bearer Token, CORS, rate limiting. Ne pas exposer un MCP HTTP non authentifié sur Internet.
Tester graphiquement tools/list, tools/call, logs JSON-RPC et scénarios d'erreur.
@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 | Chemin config incorrect | Vérifier chemin absolu |
| Échec JSON | Type non sérialisable | Convertir en str ou dict |
| Timeout | Exécution lente | Async + timeout |
| Permission refusée | Chemin / TCC | Whitelist / VNC pour dialogue |
FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . EXPOSE 8000 CMD ["python", "server.py"]
Railway / Render : projets personnels rapides.
Lambda / Cloud Run : serverless — cold start, limites stdio.
VPS + Nginx : reverse proxy, TLS, rate limit.
Logs structurés, métriques Prometheus, Sentry, /health. Déclarer la version MCP, étendre les outils de façon rétrocompatible.
Objectif : l'IA recherche vos notes Markdown locales, index sémantique, création de notes. Dans Cursor : « Qu'ai-je noté sur MCP la semaine dernière ? »
| Composant | Recommandation |
|---|---|
| Base vectorielle | ChromaDB / Qdrant (local) |
| Embeddings | text-embedding-3-small |
| Surveillance fichiers | watchfiles pour index incrémental |
index_notes : scanner le répertoire, index vectoriel.
semantic_search : recherche sémantique.
write_note : créer ou ajouter du Markdown.
Resource : notes://{path} pour une note.
semantic_search économise des tokens vs injecter toute la bibliothèque et améliore la précision.
mcp-server-filesystem — système de fichiers
mcp-server-github — GitHub
mcp-server-brave-search — recherche web
mcp-server-postgres — base de données
mcp-server-slack — Slack
En 2026, Cursor, Claude Desktop, OpenAI, Google Gemini et Microsoft supportent MCP ; marketplace et sécurité entreprise (OAuth 2.1, audit) mûrissent. Docs : modelcontextprotocol.io ; SDK Python : github.com/modelcontextprotocol/python-sdk.
Choisir l'hôte (Cursor / Claude Desktop), vérifier le support MCP en version 2026.
Développer en stdio local, valider tools/list avec Inspector.
Enregistrer dans Cursor MCP, smoke test Hello World.
Serveurs navigateur, trousseau, capture d'écran : session GUI macOS pour TCC (SSH insuffisant).
HTTP + Docker + auth en prod ; lier au guide Agent Skill et au MCP navigateur.
Python (mcp + FastMCP) le plus rapide ; TypeScript (@modelcontextprotocol/sdk) pour les équipes Node. Couche protocole identique.
IDE local : stdio. Multi-utilisateur / SaaS : HTTP + SSE / Streamable HTTP avec authentification.
Tools exécutent des actions ; Resources fournissent des données en lecture via des URI.
MCP navigateur, trousseau et capture d'écran déclenchent les dialogues TCC macOS. SSH ne peut pas cliquer « Toujours autoriser » — session VNC sur l'hôte requise.
MCP est le protocole standard du tooling IA — maîtriser la chaîne du Hello World à la production est une compétence clé en 2026. Quel outil allez-vous construire ensuite ?
Le coût caché est rarement le code, mais l'environnement d'exécution : Windows + Mac cloud + Cursor MCP exige dialogues TCC, venv et logs Inspector dans une même session bureau. Un Mac mini personnel ajoute veille, mises à jour et amortissement ; 8 Go de RAM suffisent mal avec index vectoriel et serveurs parallèles.
Pour valider MCP à l'heure avec GUI sur la même machine que Cursor, louez un Mac distant via VNCMac — bouton principal vers les tarifs, offres sur l'accueil.