Dans l'article précédent, on a construit un agent capable de raisonner et d'agir via des tools. Il recherchait sur le web, lisait des pages, et synthétisait les résultats. Mais tous ses tools étaient codés en dur dans le projet : web_search, read_url, chacun avec son schéma Zod, son implémentation, son wiring dans la boucle agentique.
Et si tu voulais que ce même agent accède aussi à tes fichiers ? À ton calendrier ? À ta base de données ? Il faudrait recoder chaque intégration à la main, dans chaque projet.
Le problème : N×M connecteurs
Sans protocole commun, 5 clients LLM (Claude, Cursor, ton app, ChatGPT, Gemini) et 10 sources de données (filesystem, PostgreSQL, GitHub, Slack...) donnent 50 connecteurs à écrire et maintenir.
1Sans standard :
2Claude ──custom──▶ GitHub
3Claude ──custom──▶ Slack
4Cursor ──custom──▶ GitHub (recodé depuis zéro)
5Cursor ──custom──▶ Slack (recodé depuis zéro)
6...MCP règle ce problème : chaque source de données est exposée par un serveur MCP, et chaque client parle le même protocole. Tu codes l'intégration une fois.
1Avec MCP :
2Claude ─┐
3Cursor ─┤─── MCP ───▶ Serveur GitHub
4Ton app ─┘ Serveur Slack
5 Serveur PostgreSQLN + M au lieu de N × M. Anthropic a publié MCP fin 2024, et en un an, OpenAI, Google et Microsoft l'ont adopté.
Comment ça marche
Model Context Protocol définit comment un client LLM communique avec un serveur qui expose des outils.
1┌────────────────┐ ┌────────────────┐ ┌──────────────┐
2│ Client LLM │──MCP──│ Serveur MCP │──────▶│ Backend │
3│ (Claude, │ │ (expose des │ │ (fichiers, │
4│ Cursor...) │ │ tools) │ │ API, DB…) │
5└────────────────┘ └────────────────┘ └──────────────┘Le client se connecte au serveur, découvre les tools disponibles avec leurs descriptions, et les utilise. Rien à configurer côté client.
Function calling vs MCP
Si tu as lu l'article 1, tu connais le function calling : tu définis des tools dans le prompt, le LLM les appelle, et ton code les exécute. MCP externalise ça dans un serveur séparé.
| Function calling | MCP | |
|---|---|---|
| Qui définit les tools ? | Toi, dans ton code | Le serveur MCP |
| Qui les exécute ? | Ton code | Le serveur MCP |
| Discovery | Manuelle (tu listes les tools) | Automatique |
| Réutilisabilité | Copier-coller entre projets | Un serveur sert tous les clients |
| Transport | Intégré à ton app | Protocole séparé (stdio ou HTTP) |
Sous le capot, MCP utilise le function calling : quand Claude est connecté à un serveur MCP, les tools du serveur apparaissent comme des functions dans son contexte. La vraie différence, c'est que ces tools viennent d'un processus externe et pas de ton code applicatif.
Le function calling, c'est du sur-mesure. MCP, c'est du réutilisable.
Les 3 primitives
Un serveur MCP peut exposer trois choses :
Tools : des fonctions que le LLM appelle. C'est le coeur du protocole : read_file, search_database, send_email. 90% des serveurs n'exposent que des tools.
Resources : des données en lecture seule que le client charge dans le contexte. Un schéma de base de données, un fichier de config. Contrairement à un tool, une resource est récupérée par le client (souvent à l'initiative de l'utilisateur), pas appelée par le LLM.
Prompts : des templates fournis par le serveur pour guider le LLM. Un serveur SQL pourrait fournir un prompt "Analyse cette table" qui structure la requête.
On se concentre sur les tools pour la suite.
Ton premier serveur MCP
Voici un serveur fonctionnel qui expose un tool get_weather :
1npm install @modelcontextprotocol/sdk zodNote : les exemples utilisent le SDK v1 (
@modelcontextprotocol/sdk), la version recommandée au moment de l'écriture. Le SDK v2 (@modelcontextprotocol/server) est en cours de stabilisation et change certaines API, notammentserver.tool()qui devientserver.registerTool(). Vérifie la doc officielle pour la version courante.
1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3import { z } from "zod";
4
5const server = new McpServer({
6 name: "weather-server",
7 version: "1.0.0",
8});
9
10server.tool(
11 "get_weather",
12 "Retourne la météo actuelle pour une ville donnée",
13 { city: z.string().describe("Nom de la ville") },
14 async ({ city }) => {
15 // En vrai, tu appellerais une API météo ici
16 const weather = {
17 city,
18 temperature: Math.round(Math.random() * 30),
19 condition: ["Ensoleillé", "Nuageux", "Pluvieux"][Math.floor(Math.random() * 3)],
20 };
21
22 return {
23 content: [{ type: "text" as const, text: JSON.stringify(weather, null, 2) }],
24 };
25 }
26);
27
28const transport = new StdioServerTransport();
29await server.connect(transport);Le SDK gère le protocole, la sérialisation JSON-RPC, la discovery. Tu définis le nom, la description, le schéma Zod et l'implémentation. C'est le même principe que le roll_dice de l'article 1, sauf que le tool vit dans son propre processus.
Tester avec Claude Desktop
Ajoute le serveur dans la config :
1// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
2// %APPDATA%/Claude/claude_desktop_config.json (Windows)
3{
4 "mcpServers": {
5 "weather": {
6 "command": "npx",
7 "args": ["tsx", "/chemin/vers/ton/server.ts"]
8 }
9 }
10}Relance Claude Desktop, demande "Quel temps fait-il à Lyon ?" :
1Toi : "Quel temps fait-il à Lyon ?"
2
3Claude : [appelle get_weather({ city: "Lyon" })]
4 → { city: "Lyon", temperature: 22, condition: "Ensoleillé" }
5
6Claude : "Il fait 22°C à Lyon et c'est ensoleillé."Ce serveur fonctionne aussi avec Cursor, Claude Code, ou tout client MCP compatible. Même code, zéro adaptation.
L'écosystème en 2026
Clients : Claude Desktop, Claude.ai (web et mobile), Claude Code, Cursor, ChatGPT (mars 2025), Gemini, Windsurf, Cline.
Serveurs : 10 000+ serveurs publics, des registries comme mcp.run et Smithery. Filesystem, bases de données, GitHub, Slack, Google Drive, Linear, Notion, Sentry...
Gouvernance : MCP a rejoint la Linux Foundation fin 2025 (Agentic AI Foundation, co-fondée par Anthropic, Block, OpenAI). Ce n'est plus le protocole d'un seul acteur.
Stdio vs HTTP
Notre serveur utilise stdio : Claude Desktop le lance comme un sous-processus et communique via stdin/stdout. Simple, parfait pour le dev local.
Sauf que stdio implique que le serveur tourne sur ta machine. Pour y accéder depuis le web, depuis ton téléphone, ou le partager avec une équipe, il faut le transport Streamable HTTP : un serveur déployé derrière une URL HTTPS, avec authentification OAuth.
1stdio → local, un seul client, dev/perso
2HTTP → distant, multi-clients, partageableOn explore le transport HTTP en détail dans la série MCP en pratique.
Ce qu'il faut retenir
Si tu as suivi cette série, tu as les bases complètes : les LLM génèrent du texte, le function calling leur permet d'agir (article 1), les agents les rendent autonomes (article 2), et MCP standardise leurs outils (cet article).
En résumé : un serveur MCP expose des tools, le client les découvre automatiquement, le SDK rend ça simple à construire, et l'écosystème est déjà large (tous les clients majeurs, milliers de serveurs, fondation Linux). Deux transports existent : stdio pour le local, Streamable HTTP pour le remote.
La suite de la série abordera l'évaluation des réponses LLM et la gestion des coûts. Pour le MCP remote et l'authentification OAuth, direction la série MCP en pratique.