Changer le thème

Développement MCP Server : construisez votre premier service MCP

Easton editorial illustration: trace beacon network

Introduction : Quand vous codez dans Cursor, avez-vous déjà souhaité que l’IA vérifie directement la dernière version de vos dépendances ? Ou, en analysant des données dans Claude, vouloir qu’elle lise les infos de votre base de données ? Sans MCP, il faudrait écrire une couche d’adaptation pour chaque outil IA. Avec un MCP Server, vous ne codez qu’une fois — tous les clients compatibles MCP en profitent. Cet article vous guide from scratch pour écrire un MCP Server complet en TypeScript.

30 min
Temps de prise en main
De zéro à l’exécution
3
Capacités clés
Tools/Resources/Prompts
1000+
Serveurs MCP
Communauté open source GitHub
Source: Données officielles MCP (2025)

Qu’est-ce que MCP ? Comprendre les concepts en 3 minutes

L’histoire d’une interface USB

Ceux qui ont connu les gadgets numériques il y a quelques années se souviennent de cette époque gênante : souris en port rond, clavier en port carré, imprimante en port parallèle — chaque appareil exigeait sa prise. Puis USB est arrivé : une interface pour tout.

MCP (Model Context Protocol) devient le « standard USB » du monde des outils IA.

Sans MCP, pour qu’une IA accède à une source de données, vous écrivez une couche d’adaptation par outil : un plugin pour Claude, une extension pour Cursor, encore une pour Windsurf… La complexité est N × M (N sources × M outils IA).

Avec MCP, vous n’écrivez qu’un MCP Server ; tous les clients compatibles l’appellent directement. La complexité passe à N + M.

L’architecture à trois couches est simple :

+-------------+     +-------------+     +-------------+
|    Host     | ->  |   Client    | ->  |   Server    |
|  (Claude)   |     | (client MCP)|     | (votre svc) |
+-------------+     +-------------+     +-------------+
  • Host : l’application IA elle-même, ex. Claude Desktop, Cursor
  • Client : client MCP, communique avec le Host
  • Server : votre service, fournit les fonctionnalités concrètes

Les trois capacités d’un MCP Server

Un MCP Server peut offrir trois types de fonctionnalités :

CapacitéUsageExemple
Tools (outils)Exécuter des actionsMétéo, envoi de messages, lecture BDD
Resources (ressources)Fournir des donnéesContenu de fichiers, réponses API, config
Prompts (invites)Modèles prédéfinisRevue de code, génération de rapport quotidien

Considérez Tools comme des « fonctions » — l’IA les appelle pour agir ; Resources comme des « sources de données » — l’IA lit leur contenu ; Prompts comme des « modèles » — ils aident l’IA à comprendre la tâche plus vite.

Différence avec d’autres articles : d’autres tutoriels MCP utilisent Python et FastMCP. Ici, le SDK TypeScript natif convient mieux aux développeurs frontend et full-stack. Les deux approches sont équivalentes — choisissez le langage que vous maîtrisez.

"https://modelcontextprotocol.io"


Préparation de l’environnement de développement

Prérequis

Cet article suppose que vous :

  • avez installé Node.js 18+ ou Bun 1.0+
  • connaissez TypeScript (interface, async/await)
  • disposez de Claude Desktop ou d’un client MCP (Cursor, Windsurf, etc.)

Si vous n’avez jamais utilisé Bun, essayez-le — bien plus rapide que npm, avec TypeScript intégré, sans configurer ts-node.

Initialiser le projet

# Créer le répertoire du projet
mkdir mcp-weather-server && cd mcp-weather-server

# Initialiser (Bun ou npm)
bun init -y
# ou npm init -y

# Installer le SDK MCP TypeScript
bun add @modelcontextprotocol/sdk zod
# ou npm install @modelcontextprotocol/sdk zod

Deux dépendances :

  • @modelcontextprotocol/sdk : SDK TypeScript officiel MCP
  • zod : validation de types à l’exécution, pour définir le schéma des paramètres d’outils

Points clés de la config TypeScript

Avec bun init, tsconfig.json est déjà prêt. En configuration manuelle, notez ces options :

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "strict": true
  }
}

moduleResolution: "bundler" est important pour les modules ESM, sinon vous risquez l’erreur « xxx is not defined ».


Pratique : écrire un MCP Server météo

Ce tutoriel couvre un MCP Server complet qui :

  1. reçoit les appels de l’IA
  2. interroge l’API OpenWeatherMap pour la météo en temps réel
  3. renvoie un résultat formaté

Structure du projet

mcp-weather-server/
+-- src/
|   +-- index.ts      # Point d'entrée
|   +-- weather.ts    # Implémentation outil météo
|   +-- resources.ts  # Définition des ressources
+-- package.json
+-- tsconfig.json

Le code peut tout tenir dans index.ts (comme ici), mais le découpage en modules facilite la maintenance.

Étape 1 : créer le squelette du MCP Server

Commencez par un MCP Server qui démarre :

// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// Créer l'instance serveur
const server = new McpServer({
  name: "weather-service",
  version: "1.0.0",
});

// Enregistrer un outil (Tools)
server.tool(
  "get_weather",
  "Obtenir la météo actuelle d'une ville",
  {
    city: z.string().describe("Nom de la ville, ex. : Pékin, Shanghai"),
  },
  async ({ city }) => {
    // Implémentation détaillée à l'étape suivante
    return { content: [{ type: "text", text: `Requête météo pour ${city}...` }] };
  }
);

// Démarrer le serveur
const transport = new StdioServerTransport();
await server.connect(transport);

McpServer est la classe centrale du SDK ; passez name et version. tool() enregistre un outil : nom, description, schéma des paramètres, fonction d’exécution.

Étape 2 : implémenter l’outil météo (code principal)

Rendons l’outil opérationnel avec l’API gratuite OpenWeatherMap :

// src/weather.ts
import { z } from "zod";

// Type de réponse API OpenWeatherMap
interface WeatherResponse {
  name: string;
  main: { temp: number; feels_like: number; humidity: number };
  weather: [{ description: string }];
  wind: { speed: number };
}

// Implémentation de l'outil météo
server.tool(
  "get_weather",
  "Obtenir la météo actuelle d'une ville",
  {
    city: z.string().describe("Nom de la ville, ex. : Pékin, Shanghai"),
  },
  async ({ city }) => {
    const API_KEY = process.env.OPENWEATHER_API_KEY;
    const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric&lang=zh_cn`;

    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`Échec de la requête API : ${response.status}`);
      }

      const data: WeatherResponse = await response.json();

      // Retour formaté
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify({
              city: data.name,
              temperature: `${data.main.temp}°C`,
              feels_like: `${data.main.feels_like}°C`,
              description: data.weather[0].description,
              humidity: `${data.main.humidity}%`,
              wind_speed: `${data.wind.speed} m/s`,
            }, null, 2),
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `Échec de la requête : ${error instanceof Error ? error.message : 'Erreur inconnue'}`,
          },
        ],
        isError: true,
      };
    }
  }
);

Points importants :

  1. Clé API via variable d’environnement : ne jamais la coder en dur
  2. Gestion d’erreurs : isError: true signale l’échec au client
  3. Typage : l’interface WeatherResponse valide la structure des données

Inscrivez-vous gratuitement sur OpenWeatherMap, récupérez votre clé API, puis :

export OPENWEATHER_API_KEY=your_api_key_here

Étape 3 : ajouter des Resources (optionnel mais recommandé)

Les Resources permettent des données en lecture seule. Exemple : état du serveur :

// src/resources.ts

// Informations d'état du serveur
server.resource(
  "server-status",
  "status://server",
  async (uri) => ({
    contents: [
      {
        uri: uri.href,
        text: JSON.stringify({
          name: "Weather Service",
          version: "1.0.0",
          status: "running",
          timestamp: new Date().toISOString(),
        }, null, 2),
      },
    ],
  })
);

// Documentation API
server.resource(
  "api-docs",
  "docs://api",
  async (uri) => ({
    contents: [
      {
        uri: uri.href,
        text: `
# Weather MCP Server API

## Tools
- get_weather(city: string): météo d'une ville

## Resources
- status://server - État du serveur
- docs://api - Documentation API
        `.trim(),
      },
    ],
  })
);

Les deux premiers paramètres de resource() sont le nom et l’URI ; le troisième est la fonction de lecture. L’URI peut utiliser n’importe quel schéma (status://, docs://), tant qu’ils sont distincts.

Étape 4 : ajouter des Prompts (fonction avancée)

Les Prompts sont des modèles de dialogue prédéfinis. Exemple : modèle « rapport météo » avec nom de ville prérempli :

// Modèle de rapport météo prédéfini
server.prompt(
  "weather_report",
  "Générer un rapport météo formaté",
  {
    city: z.string().describe("Nom de la ville"),
    include_tips: z.boolean().optional().describe("Inclure des conseils vestimentaires"),
  },
  ({ city, include_tips }) => ({
    messages: [
      {
        role: "user",
        content: {
          type: "text",
          text: `Générez un rapport météo pour ${city}.${include_tips ? " Incluez des conseils vestimentaires." : ""}`,
        },
      },
    ],
  })
);

Le retour de prompt() est un tableau de messages avec role et content. L’IA reçoit ainsi un contexte prédéfini.

Étape 5 : finaliser le point d’entrée

Regroupez tout dans src/index.ts avec gestion d’erreurs :

// src/index.ts (version complète)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "weather-service",
  version: "1.0.0",
});

// Enregistrer outils, ressources et prompts
// ... (code ci-dessus)

// Gestion d'erreurs
process.stdin.on("error", (err) => {
  console.error("Erreur entrée standard :", err);
  process.exit(1);
});

process.stdout.on("error", (err) => {
  console.error("Erreur sortie standard :", err);
  process.exit(1);
});

// Arrêt propre
process.on("SIGINT", async () => {
  await server.close();
  process.exit(0);
});

// Démarrer le serveur
const transport = new StdioServerTransport();
await server.connect(transport);

console.error("MCP Weather Server démarré, en attente de connexion...");

StdioServerTransport communique via stdin/stdout — la gestion d’erreurs est essentielle. Le handler SIGINT permet un arrêt propre avec Ctrl+C.

Lancez avec bun run src/index.ts ; le message « démarré » confirme que tout fonctionne.


Configurer le client : connecter Claude à votre Server

Le Server est prêt ; configurons Claude Desktop ou Cursor.

Configuration Claude Desktop

Fichier de configuration :

  • macOS : ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows : %APPDATA%\Claude\claude_desktop_config.json

Ajoutez votre Server :

{
  "mcpServers": {
    "weather": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/mcp-weather-server/src/index.ts"],
      "env": {
        "OPENWEATHER_API_KEY": "votre clé API"
      }
    }
  }
}

Attention : le chemin dans args doit être absolu. Un chemin relatif fait échouer le démarrage.

Configuration Cursor / Windsurf

Cursor et Windsurf suivent un schéma similaire : paramètres IDE → configuration MCP → ajouter une entrée serveur (même format).

Fichier Cursor habituel :

  • macOS : ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb
  • ou dans l’IDE : Paramètres → IA → MCP → Ajouter un serveur

Tester votre Server

  1. Redémarrez Claude Desktop / Cursor
  2. Dans le chat : « Quel temps fait-il à Pékin ? »
  3. Claude devrait appeler automatiquement votre MCP Server

Sortie attendue en cas de succès :

{
  "city": "北京",
  "temperature": "18°C",
  "feels_like": "16°C",
  "description": "多云",
  "humidity": "65%",
  "wind_speed": "3.2 m/s"
}

Dépannage courant

ProblèmeCause probableSolution
Server non connectéChemin incorrectVérifier le chemin absolu dans args
Clé API invalideVariable d’env non transmiseConfirmer la config env
Pas de réponseErreur de compilation TypeScriptCompiler d’abord avec bun build ou tsc
Erreur de permissionsDroits du fichier de configS’assurer que le fichier est lisible

"https://github.com/modelcontextprotocol/typescript-sdk"


Extension et déploiement

Ajouter d’autres outils

La météo n’est qu’un début. Vous pouvez :

  • Historique météo : API de données passées
  • Comparaison multi-villes : plusieurs villes en une requête
  • Alertes météo : vérifier les alertes de conditions extrêmes

Même enregistrement que get_weather, logique différente.

Comparaison des options de déploiement

Pour partager en équipe, le transport stdio local ne suffit plus :

ModeCas d’usageAvantagesInconvénients
stdio localUsage perso, dev/testSimple, sécuriséNon partageable
HTTP/SSEÉquipe, multi-utilisateursAccès distantAuthentification requise
ServerlessProductionAuto-scalingLatence au cold start

Points de production

Authentification : en HTTP, implémentez l’auth. MCP supporte OAuth 2.1 ; une clé API simple suffit aussi :

// Vérifier la clé API dans les en-têtes
const apiKey = request.headers.get("Authorization");
if (apiKey !== `Bearer ${process.env.API_KEY}`) {
  return new Response("Unauthorized", { status: 401 });
}

Limitation de débit : évitez d’épuiser vos quotas API. Utilisez express-rate-limit ou le rate limiting Cloudflare Workers.

Logs : pino ou winston pour tracer les appels d’outils :

import pino from "pino";
const logger = pino();

server.tool("get_weather", /* ... */, async ({ city }) => {
  logger.info({ city }, "Requête météo");
  // ...
});

Monitoring : taux de succès et temps de réponse. Prometheus + Grafana est un duo courant.


Résumé

Cet article explique comment écrire un MCP Server en TypeScript from scratch :

  • Comprendre MCP et son architecture à trois couches
  • Créer un serveur avec le SDK MCP TypeScript
  • Implémenter l’outil météo (Tools)
  • Ajouter des ressources d’état serveur (Resources)
  • Définir un modèle de rapport météo (Prompts)
  • Configurer Claude Desktop / Cursor pour appeler le Server

Vous pouvez maintenant :

  1. Construire des wrappers MCP pour vos API (GitHub, Slack, Notion, etc.)
  2. Créer des interfaces MCP pour vos systèmes internes (CRM, bases de données)
  3. Explorer les serveurs MCP de la communauté

Ressources pour aller plus loin :

Pour approfondir le protocole MCP, consultez le guide des principes du protocole MCP.

FAQ

Quelles bases faut-il pour développer un MCP Server ?
Des bases JavaScript/TypeScript. Ce tutoriel utilise le SDK MCP TypeScript ; maîtriser async/await et le typage suffit pour démarrer.
Quelle différence entre MCP Server et FastMCP ?
FastMCP est un framework Python pour développeurs Python. Ici, le SDK TypeScript natif convient aux développeurs frontend/full-stack. Fonctionnalités équivalentes — le choix dépend de votre stack.
Comment tester qu'un MCP Server fonctionne ?
Après configuration de Claude Desktop, saisissez une requête en langage naturel (ex. « météo à Pékin »). Si Claude appelle l'outil et renvoie un résultat, le Server fonctionne.
Peut-on déployer un MCP Server sur un serveur distant ?
Oui. Le transport stdio convient au dev local. En production, utilisez HTTP/SSE avec OAuth et limitation de débit.

9 min de lecture · Publié le: 19 mars 2026 · Mis à jour le: 27 juil. 2026

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog