Si votre Claude / GPT / Cursor ne peut discuter mais pas interroger une base de données, lire des fichiers ou appeler des API — vous n'avez pas besoin d'un prompt plus long, mais d'une couche d'outils réutilisable. Ce guide s'adresse aux développeurs backend et full-stack : du Hello World au MCP Server ChromaDB, en passant par Tools / Resources / Prompts, les transports stdio et HTTP+SSE, le débogage, les tests et le déploiement Docker en production. À la fin, vous aurez des outils personnalisés appelables depuis Cursor et une vision claire pour héberger le Server sur un Mac distant en 24/7 (pour le contexte protocolaire, commencez par notre article d'analyse du protocole MCP).
Les grands modèles ont une date limite d'entraînement et ne peuvent accéder à votre CRM, vos dépôts Git ou vos API internes. Avant 2024, vous écriviez du Function Calling pour Claude, des Plugins pour GPT et un autre format pour Cursor — changer de modèle = tout recommencer. Un MCP Server encapsule les capacités d'outils dans un processus indépendant : écrivez une fois, utilisez dans Claude Desktop, Cursor et Gemini.
Scénarios typiques : interroger Postgres depuis Claude Desktop ; faire lire la documentation projet et modifier le code par un Agent Cursor ; appeler votre système de tickets via HTTP MCP depuis GPT — le même Server sous-jacent.
Ce que ce guide livre : pas seulement du concept, mais un chemin de say_hello vers un Server de base de connaissances production avec recherche vectorielle. Public visé : développeurs avec bases Python ou TypeScript qui veulent étendre l'IA dans leur IDE ou application Desktop.
Verrouillage fournisseur : OpenAI Function Calling et Claude Tool Use utilisent des formats différents — chaque changement de fournisseur impose de réécrire la couche d'adaptation.
Outils non découvrables : les API REST reposent sur une documentation statique ; l'IA ne peut pas appeler tools/list à l'exécution pour découvrir les capacités seule.
Silos IDE : Cursor, extensions VS Code et plugins JetBrains définissent les outils séparément — vous maintenez N×M intégrations.
Contexte et données fragmentés : les LLM ne lisent pas fiabilément config, préférences utilisateur ou logs en direct — il faut des Resources en lecture seule standardisées.
Templates de prompt dispersés : code review, rapports d'incident, etc. n'ont pas de registre unifié ; chaque équipe copie-colle.
Chaos local vs distant : les sous-processus stdio conviennent au développement, mais les passerelles HTTP production, l'authentification et le monitoring manquent de patron commun (voir notre guide gouvernance sous-processus stdio).
« Connecter un MCP Server à l'IA, c'est comme installer des extensions IDE pour un développeur — la frontière des capacités passe du chat à l'action sur le monde réel. »
Évolution : Function Calling (2023) → ChatGPT Plugins → MCP (nov. 2024, open source Anthropic). Anthropic a conçu le MCP comme le « USB-C » entre l'IA et le monde extérieur : le Host (Cursor / Claude Desktop) intègre un Client MCP et ouvre une session 1:1 avec votre MCP Server.
La communication repose sur JSON-RPC 2.0 : initialize → tools/list / tools/call → resources/read. Deux cycles de vie au niveau transport :
Spécification complète sur modelcontextprotocol.io.
| Dimension | MCP | OpenAI Function Calling | Outils LangChain |
|---|---|---|---|
| Ouverture | Protocole ouvert multi-fournisseurs, gouvernance AAIF | Lié à l'API OpenAI | Abstraction framework, pas un standard de transport |
| Découverte | tools/list à l'exécution | Tableau functions inline dans la requête | Enregistrement en code, pas de découverte standard |
| Données lecture seule | Resources + schéma URI | Pas d'équivalent de premier ordre | Concept Retriever, pas protocolaire |
| Templates de prompt | Interface Prompts standard | Aucun | Classe PromptTemplate |
| Transport | stdio / HTTP+SSE / Streamable HTTP | API HTTPS intégrée | Dépend du runtime Agent |
| Réutilisabilité | Un Server sert Cursor + Claude + Gemini | Écosystème OpenAI seul | Réécriture inter-frameworks |
Deux voies principales : Python mcp + FastMCP (data/scripts) et TypeScript @modelcontextprotocol/sdk (intégration Web/API, typage strict). Dépôts SDK : python-sdk, typescript-sdk.
# Voie Python python -m venv .venv && source .venv/bin/activate pip install "mcp[cli]" httpx pydantic # Voie TypeScript npm init -y && npm install @modelcontextprotocol/sdk zod npm install -D typescript tsx @types/node
my-mcp-server/ ├── pyproject.toml # ou package.json ├── src/ │ ├── server.py # point d'entrée FastMCP │ ├── tools/ # modules d'outils │ ├── resources/ # fournisseurs Resource │ └── prompts/ # templates Prompt ├── tests/ │ └── test_tools.py # pytest + ClientSession ├── Dockerfile └── README.md
Choisir la stack : équipes data/ML → Python ; full-stack Node → TypeScript.
Créer un environnement virtuel et verrouiller les dépendances : pip freeze ou package-lock.json pour éviter la dérive de schéma.
Installer MCP Inspector : npx @modelcontextprotocol/inspector pour déboguer JSON-RPC visuellement.
Configurer Claude Desktop : éditer ~/Library/Application Support/Claude/claude_desktop_config.json et ajouter command/args du Server.
Configurer Cursor : Settings → MCP → Add Server ; pour stdio, python -m src.server ou chemin absolu.
Vérifier la connectivité Inspector : lancer le Server → connecter Inspector → confirmer que tools/list retourne une liste non vide.
// Exemple de config MCP Cursor / Claude Desktop
{
"mcpServers": {
"my-tools": {
"command": "python",
"args": ["-m", "src.server"],
"env": { "API_KEY": "your-key" }
}
}
}
Avec FastMCP, créez un outil say_hello et validez la chaîne complète : code → Inspector → Cursor.
# src/server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("hello-server")
@mcp.tool()
def say_hello(name: str = "World") -> str:
"""Saluer une personne ou entité"""
return f"Hello, {name}! MCP is working."
if __name__ == "__main__":
mcp.run() # transport stdio par défaut
# Déboguer avec Inspector npx @modelcontextprotocol/inspector python -m src.server # ou lancer stdio directement python -m src.server
Après avoir ajouté la même commande dans Cursor, demandez à l'Agent « utilise say_hello pour saluer NodeMini ». Si vous obtenez un résultat JSON, le handshake Client ↔ Server a réussi.
Astuce : FastMCP génère automatiquement le JSON Schema depuis les docstrings et annotations de type — pas besoin de décrire les paramètres manuellement.
Les Tools sont la capacité centrale du MCP : l'IA exécute des opérations avec effets de bord via tools/call. Chaque Tool expose un nom, une description et un inputSchema ; FastMCP utilise Pydantic pour la validation.
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(..., description="Mot-clé de recherche")
limit: int = Field(10, ge=1, le=100, description="Nombre de résultats")
@mcp.tool()
async def search_docs(params: SearchInput) -> str:
"""Rechercher dans la bibliothèque de documents"""
results = await index.search(params.query, params.limit)
return json.dumps(results, ensure_ascii=False)
ast.literal_eval ; jamais exec.import httpx
from datetime import datetime, timezone
@mcp.tool()
async def fetch_url(url: str) -> str:
"""HTTP GET du contenu URL (domaines en liste blanche)"""
allowed = ("api.github.com", "nodemini.com")
if not any(url.startswith(f"https://{d}") for d in allowed):
raise ValueError(f"Domain not allowed: {url}")
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(url)
resp.raise_for_status()
return resp.text[:8000]
@mcp.tool()
def get_current_time() -> str:
"""Retourner l'heure UTC actuelle"""
return datetime.now(timezone.utc).isoformat()
raise ValueError("message lisible") — le Client renvoie le message au LLM.retryable ; refus de permission = échec immédiat.idempotency_key pour éviter les données corrompues par appels Agent en double.Tool vs Resource : les Tools ont des effets de bord et sont invoqués par l'IA ; les Resources sont du contexte en lecture seule que le Host injecte avant la conversation ou que l'IA tire via resources/read. Schémas URI personnalisés — ex. config://, user://, file://.
@mcp.resource("config://app/settings")
def app_settings() -> str:
"""Configuration applicative statique (text/plain)"""
return open("config/settings.json").read()
@mcp.resource("user://{user_id}/profile")
def user_profile(user_id: str) -> str:
"""Profil utilisateur dynamique (application/json)"""
return json.dumps(get_user(user_id))
| Type MIME | Usage | Exemple |
|---|---|---|
| text/plain | Logs, README | file://logs/app.log |
| application/json | Config, réponses API | config://env |
| application/octet-stream | Binaire (base64) | Résumé PDF |
| text/event-stream | Souscription temps réel | Tail de logs, flux metrics |
Pattern Server Resource filesystem : implémenter resources/list pour scanner les répertoires, resources/read pour lire par URI, resources/subscribe pour surveiller les changements via watchfiles et pousser les mises à jour — idéal pour exposer la documentation du codebase à un Agent Cursor.
Un Prompt MCP est un squelette de conversation enregistré sur le Server. Le Client récupère une liste de messages via prompts/get, avec rôles user / assistant et placeholders de paramètres — l'équipe partage code review et workflows d'incident sans fichiers prompt individuels.
from mcp.types import PromptMessage, TextContent
@mcp.prompt()
def code_review_prompt(language: str = "python") -> list[PromptMessage]:
"""Template multi-tours Code Review standardisé"""
return [
PromptMessage(role="user", content=TextContent(
type="text",
text=f"Vous êtes un ingénieur {language} senior. Auditez le diff suivant selon sécurité, performance et lisibilité."
)),
PromptMessage(role="assistant", content=TextContent(
type="text",
text="Collez le diff ou indiquez le numéro de PR — je produirai un review structuré selon la CHECKLIST."
)),
]
Les templates multi-tours peuvent imbriquer des variables ({ticket_id}, {severity}). Le Server gère les versions ; quand le Client met à jour le Server, toute l'équipe obtient les standards de review à jour.
| Dimension | stdio | HTTP + SSE / Streamable HTTP |
|---|---|---|
| Déploiement | Sous-processus local, lancé par le Host | Service autonome, connexion par URL |
| Montée en charge | Machine unique, scaling horizontal difficile | Équilibrage de charge, réplicas multiples |
| Authentification | Variables d'environnement du Host | Bearer Token / API Key / mTLS |
| Débogage | Connexion directe Inspector | curl + client SSE |
| Idéal pour | Dev personnel, Cursor local | Partage d'équipe, intégration SaaS |
# Mode Streamable HTTP (FastMCP 2026)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("prod-server", host="0.0.0.0", port=8080)
# ... enregistrer les tools ...
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Indispensables en production : middleware de validation Bearer Token, liste blanche CORS (domaines Host uniquement), rate limit (ex. 100 req/min/IP), HTTPS terminé au reverse proxy. Détails ops passerelle distante dans notre guide gouvernance passerelle HTTP.
Attention : ne exposez jamais un MCP HTTP sur Internet sans authentification — en 2026, de nombreux Server sont encore trouvés sans protection. Ajoutez toujours auth et restrictions IP.
MCP Inspector est le débogueur visuel officiel : connectez via stdio ou URL, envoyez manuellement tools/list et tools/call, inspectez les allers-retours JSON-RPC — bien plus efficace que de deviner depuis les logs Cursor.
# tests/test_tools.py
import pytest
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
@pytest.mark.asyncio
async def test_say_hello():
params = StdioServerParameters(command="python", args=["-m", "src.server"])
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("say_hello", {"name": "MCP"})
assert "MCP" in result.content[0].text
| Symptôme | Cause | Correction |
|---|---|---|
| Server quitte immédiatement après le lancement | stdout pollué par print | Logs vers stderr ; jamais print sur stdout |
| tools/list vide | Décorateur non enregistré ou ordre d'import incorrect | Vérifier que @mcp.tool() s'exécute avant run() |
| Cursor affiche disconnected | Chemin command incorrect ou venv non actif | Chemins absolus ; chemin python complet dans la config |
| JSON-RPC parse error | Sortie non-JSON sur stdio | Désactiver bannières debug ; niveau log WARNING+ |
FROM python:3.12-slim WORKDIR /app COPY pyproject.toml . RUN pip install --no-cache-dir . COPY src/ src/ EXPOSE 8080 HEALTHCHECK CMD curl -f http://localhost:8080/health || exit 1 CMD ["python", "-m", "src.server", "--transport", "streamable-http"]
Choix de plateforme : Railway / Render pour validation rapide ; AWS ECS / GCP Cloud Run pour conformité entreprise ; VPS + Docker Compose coût minimal mais gestion des correctifs en interne.
protocolVersion à initialize — le Server doit déclarer sa plage de compatibilité./metrics (QPS appels outils, latence P99) ; Sentry pour exceptions non gérées ; /health pour liveness K8s.Vectorisez Wiki interne / docs Markdown et exposez les outils index_document, search_knowledge et write_note pour qu'un Agent Cursor puisse « consulter la base de connaissances avant d'écrire le code ».
Exigences : indexation incrémentale (watchfiles sur docs/), recherche sémantique Top-K, écriture scratchpad optionnelle.
import chromadb
from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction
client = chromadb.PersistentClient(path="./data/chroma")
collection = client.get_or_create_collection(
"wiki", embedding_function=SentenceTransformerEmbeddingFunction()
)
@mcp.tool()
def search_knowledge(query: str, top_k: int = 5) -> str:
"""Recherche sémantique dans la base de connaissances interne"""
hits = collection.query(query_texts=[query], n_results=top_k)
return json.dumps(hits["documents"][0], ensure_ascii=False)
@mcp.tool()
def index_document(path: str) -> str:
"""Indexer un fichier Markdown"""
text = open(path).read()
collection.upsert(ids=[path], documents=[text], metadatas=[{"path": path}])
return f"Indexed: {path}"
Requête démo Cursor : « Recherche dans la base de connaissances les docs sur le déploiement MCP HTTP, puis résume une checklist de mise en ligne en trois étapes » — l'Agent appelle d'abord search_knowledge, puis répond depuis le contexte retrouvé. Remplacez le store vectoriel par Qdrant (gRPC distant) à plus grande échelle.
Des Server officiels et communautaires sont prêts à l'emploi — pas besoin de tout reconstruire :
Tendances 2026 : marketplaces MCP, autorisation OAuth 2.1 des outils sur la roadmap spec, Streamable HTTP remplaçant progressivement le SSE pur. Checklist d'apprentissage : ① lire la spec → ② Hello World → ③ écrire 3 Tools → ④ ajouter une Resource → ⑤ pytest → ⑥ déployer Docker → ⑦ connecter Cursor.
De say_hello à la base ChromaDB, vous maîtrisez le MCP Server full-stack : exécution Tools, contexte Resources, templates Prompts, double transport, tests et ops production. Prochaine étape : forker un Server communautaire ou encapsuler vos API d'entreprise comme couche d'outils standard d'équipe.
Le stdio local convient aux expérimentations personnelles, mais plusieurs Server en parallèle, index vectoriels persistants et connexions HTTP longues poussent un portable 16 GB vers le swap fréquent. Les VPS Linux bon marché peinent avec les chaînes outils macOS exclusives. Les passerelles HTTP auto-construites sans affinité de session et authentification souffrent de fuites de connexion et d'exposition non autorisée — la stabilité long terme dépasse rarement les attentes.
Pour les équipes qui traitent le MCP comme infrastructure de production tout en exécutant Agents Cursor et CI iOS/macOS, héberger les MCP Server sur un Mac cloud exclusif en 24/7 est généralement plus prévisible qu'un portable local ou une VM générique. La location Mac Mini cloud NodeMini sert de couche d'exécution MCP + Agent : changez de LLM sous-jacent, les nœuds SSH et la config Server restent inchangés. Spécifications : tarifs de location ; prise en main : centre d'aide.
Python FastMCP est le chemin le plus rapide pour les outils data et scripts ; le SDK TypeScript offre typage strict et intégration Node native. Les deux sont entièrement compatibles au niveau protocole. Pour faire tourner plusieurs Server en 24/7, consultez les tarifs de location pour les configurations Mac distantes.
Function Calling est lié à OpenAI ; le MCP est un protocole ouvert transversal Claude, GPT, Gemini et Cursor, avec Resources et Prompts. Contexte dans notre article d'analyse du protocole MCP.
Le stdio léger peut tourner en local ; plusieurs Server + store vectoriel + connexions HTTP longues bénéficient d'un Mac distant exclusif. Étapes d'accès dans le centre d'aide ; ops dans notre guide gouvernance sous-processus stdio.