Skip to main content
ai voice11 mars 202616 min de lecture

Les intégrations MCP Server expliquées : connecter les outils IA à vos données

Ce que sont les serveurs MCP (Model Context Protocol), comment ils fonctionnent et comment en construire un. Exemple réel de l'intégration de HeySeo avec Claude, Cursor et Windsurf.

Loic Bachellerie

Senior Product Engineer

Introduction

Imaginez ouvrir Claude et lui demander : "Quelles landing pages perdent le plus de trafic organique cette semaine ?" et obtenir une vraie réponse - avec des URL spécifiques, des pourcentages de baisse et les mots-clés responsables. Pas une réponse générique sur le SEO. Vos données réelles.

C'est ce que MCP permet. Le Model Context Protocol est la couche manquante entre les outils IA et les systèmes sur lesquels votre entreprise tourne réellement. J'ai construit le serveur MCP pour HeySeo, un SaaS d'analytics SEO, et cela a changé ma façon d'utiliser Claude, Cursor et Windsurf au quotidien.

Dans ce guide, je vais vous expliquer ce qu'est MCP, comment l'architecture fonctionne, et comment en construire un from scratch - avec le vrai code TypeScript que j'utilise en production.

Qu'est-ce que MCP ?

MCP, abréviation de Model Context Protocol, est un standard ouvert créé par Anthropic fin 2024. L'idée fondamentale est simple : donner aux assistants IA un moyen standardisé d'appeler des outils et de lire des données depuis des systèmes externes.

Avant MCP, chaque intégration d'outil était sur mesure. Vous écriviez un plugin Claude personnalisé, une extension Cursor ou une intégration Windsurf séparément. Chacun avait son propre contrat d'API, son propre schéma d'authentification, son propre format pour passer le contexte. C'était le même problème de duplication que les clients d'API REST avaient avant OpenAPI - et MCP le résout de la même manière : avec un protocole partagé.

Un serveur MCP expose des outils, des ressources et des prompts via une interface JSON-RPC standard. Un client IA (Claude Desktop, Cursor, Windsurf ou votre propre application) se connecte à ce serveur et utilise les capacités qu'il expose. Construisez le serveur une fois, connectez tous les clients.

Ce que vous pouvez exposer via MCP :

  • Tools - des fonctions appelables que l'IA peut invoquer (récupérer des analytics, chercher, exécuter des requêtes)
  • Resources - des sources de données lisibles auxquelles l'IA peut s'abonner (métriques en direct, documents)
  • Prompts - des templates de prompts pré-construits que vos utilisateurs peuvent invoquer par nom

Pourquoi MCP est important pour les développeurs

Si vous construisez un produit SaaS, un outil interne ou même une configuration de productivité personnelle, MCP est le moyen le plus pratique de connecter l'IA aux données que vous possédez.

Avant MCP, je copiais-collais les données dans la fenêtre de contexte de Claude. Un rapport de trafic mensuel ? Export en CSV, coller les premières lignes, poser des questions. Fastidieux, avec perte d'information, et limité à ce qui tient dans le contexte.

Après MCP, je pose la question directement à Claude. L'IA appelle mon serveur MCP, qui interroge les bonnes tables de la base de données, effectue l'analyse et renvoie des données structurées. Claude synthétise ensuite le tout en une réponse. La boucle entière prend quelques secondes.

Le changement est significatif sur trois plans :

  • Fraîcheur - l'IA voit des données en temps réel, pas un export obsolète de mardi dernier
  • Profondeur - l'IA peut poser des requêtes de suivi sans que je récupère manuellement plus de données
  • Cohérence - le même serveur fonctionne avec tous les outils IA que j'utilise

Pour HeySeo spécifiquement, cela signifiait que nos utilisateurs pouvaient connecter Claude ou Cursor aux analytics de leur propre site et obtenir des conseils SEO véritablement contextuels - pas des bonnes pratiques génériques.

Vue d'ensemble de l'architecture

Avant d'écrire du code, il est utile de comprendre comment les pièces s'assemblent.

Architecture MCP

Comment les clients IA se connectent à vos données via un protocole standard

Clients IA
Claude Desktop
Cursor
Windsurf
Slack (via bot)
Applications custom
Serveur MCP
Tools

Fonctions appelables

Resources

Flux de données lisibles

Prompts

Templates de prompts nommés

JSON-RPC 2.0
Vos données
PostgreSQL / Firestore
Google Search Console
API Analytics
API internes
Systèmes de fichiers
transport stdio
transport HTTP/SSE
transport WebSocket

Le protocole supporte deux modes de transport :

  • stdio - le client lance le serveur comme sous-processus et communique via stdin/stdout. Rapide, zéro surcharge réseau, idéal pour les outils de développement locaux comme Claude Desktop, Cursor et Windsurf.
  • HTTP avec SSE - le serveur tourne comme un service HTTP standard. Mieux adapté aux déploiements en production où plusieurs utilisateurs ont besoin d'accès concurrent, ou lorsque le serveur doit être hébergé séparément du client.

Pour HeySeo, nous utilisons stdio pour les développeurs se connectant via leur IDE et HTTP/SSE pour le serveur de production auquel notre bot Slack se connecte.

Construire un serveur MCP étape par étape

Le SDK officiel pour TypeScript est @modelcontextprotocol/sdk. Il gère le cadrage du protocole, le cycle de vie de la connexion et la sécurité des types, pour que vous puissiez vous concentrer sur votre logique métier.

Installer les dépendances

npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx

Initialiser le serveur

// src/server.ts
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: "heyseo",
  version: "1.0.0",
});

La classe McpServer est la fondation. Vous enregistrez des tools et des resources dessus, puis vous attachez un transport.

Enregistrer votre premier tool

Un tool est une fonction que l'IA peut appeler avec des paramètres typés. Voici un vrai tool de HeySeo qui récupère les mots-clés les plus performants pour un site :

// src/tools/top-keywords.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { getTopKeywords } from "../data/keywords.js";
 
export function registerTopKeywordsTool(server: McpServer) {
  server.tool(
    "get_top_keywords",
    "Fetch the top-ranking keywords for a site, with click and impression data from Google Search Console.",
    {
      siteUrl: z
        .string()
        .url()
        .describe("The verified site URL, e.g. https://example.com"),
      limit: z
        .number()
        .int()
        .min(1)
        .max(100)
        .default(20)
        .describe("Number of keywords to return"),
      dateRange: z
        .enum(["7d", "28d", "90d"])
        .default("28d")
        .describe("Date range for the data"),
    },
    async ({ siteUrl, limit, dateRange }) => {
      const keywords = await getTopKeywords({ siteUrl, limit, dateRange });
 
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(keywords, null, 2),
          },
        ],
      };
    }
  );
}

Le schéma Zod joue un double rôle : il valide les entrées au runtime et génère le JSON Schema que le client IA utilise pour comprendre quels paramètres le tool accepte. C'est un de ces détails qui comptent en pratique - si votre schéma est vague, l'IA appellera votre tool avec de mauvais arguments.

Enregistrer une resource

Les resources sont différentes des tools. Un tool est impératif (faire quelque chose). Une resource est déclarative (voici des données que vous pouvez lire). Pensez-y comme un flux RSS auquel l'IA peut s'abonner.

// src/resources/site-overview.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { getSiteOverview } from "../data/overview.js";
 
export function registerSiteOverviewResource(server: McpServer) {
  server.resource(
    "site-overview",
    "heyseo://sites/{siteUrl}/overview",
    async (uri) => {
      const siteUrl = extractSiteUrl(uri.href);
      const overview = await getSiteOverview(siteUrl);
 
      return {
        contents: [
          {
            uri: uri.href,
            mimeType: "application/json",
            text: JSON.stringify(overview, null, 2),
          },
        ],
      };
    }
  );
}
 
function extractSiteUrl(href: string): string {
  const match = href.match(/heyseo:\/\/sites\/([^/]+)\/overview/);
  if (!match) {
    throw new Error(`Invalid resource URI: ${href}`);
  }
  return decodeURIComponent(match[1]);
}

Connecter le transport et démarrer

// src/server.ts (continued)
import { registerTopKeywordsTool } from "./tools/top-keywords.js";
import { registerSiteOverviewResource } from "./resources/site-overview.js";
 
registerTopKeywordsTool(server);
registerSiteOverviewResource(server);
 
const transport = new StdioServerTransport();
await server.connect(transport);
 
// Keep alive - the server runs until the client disconnects

Pour les déploiements HTTP en production, changez le transport :

import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
 
const app = express();
const transport = new SSEServerTransport("/messages", res);
app.get("/sse", (req, res) => server.connect(new SSEServerTransport("/messages", res)));
app.post("/messages", express.json(), (req, res) => transport.handlePostMessage(req, res));
app.listen(3000);

Connexion à Claude Desktop

Claude Desktop a un support MCP natif. Vous configurez les serveurs dans ~/Library/Application Support/Claude/claude_desktop_config.json sur macOS :

{
  "mcpServers": {
    "heyseo": {
      "command": "node",
      "args": ["/path/to/heyseo-mcp/dist/server.js"],
      "env": {
        "HEYSEO_API_KEY": "your-api-key"
      }
    }
  }
}

Redémarrez Claude Desktop après modification. Vous verrez une petite icône d'outils dans la barre de saisie quand un serveur est connecté. À partir de ce moment, toute conversation peut appeler vos tools - Claude décide de manière autonome quand les invoquer en fonction du contexte.

En pratique, je pose des questions comme "Quelles pages se cannibalisent mutuellement pour le mot-clé 'best crm for startups' ?" et Claude appelle search_keyword_cannibalization sur mon serveur MCP, reçoit des données structurées et synthétise une recommandation claire. Aucun copier-coller nécessaire.

Connexion à Cursor

Cursor a ajouté le support MCP dans la version 0.43. La configuration se trouve dans ~/.cursor/mcp.json :

{
  "mcpServers": {
    "heyseo": {
      "command": "node",
      "args": ["/path/to/heyseo-mcp/dist/server.js"],
      "env": {
        "HEYSEO_API_KEY": "your-api-key"
      }
    }
  }
}

Dans Cursor, les tools MCP sont disponibles dans le Composer (Cmd+I) et les panneaux Chat (Cmd+L). La différence clé avec Claude Desktop est le contexte : quand vous travaillez sur du code dans Cursor, l'IA a aussi le contexte de vos fichiers. Vous pouvez donc demander "d'après les analytics de ce composant, lequel de ces mots-clés devrais-je cibler dans le texte ?" et l'IA peut raisonner à la fois sur le code à l'écran et sur les données en direct de votre serveur MCP simultanément.

Pour HeySeo, j'utilise cela quand je construis de nouvelles landing pages. Le serveur MCP m'indique les opportunités de mots-clés actuelles, et Cursor m'aide à implémenter la structure de contenu qui les cible.

Connexion à Windsurf

Windsurf (l'IDE agentique de Codeium) utilise le même format de configuration. Ouvrez les Paramètres, naviguez vers MCP et ajoutez votre entrée serveur. L'agent Cascade de Windsurf est particulièrement bon pour les tâches multi-étapes qui combinent des modifications de code avec des consultations de données externes - ce qui est exactement ce que MCP permet.

Une chose que j'ai remarquée avec Windsurf spécifiquement : son agent est plus agressif pour appeler automatiquement les tools MCP sans que vous le demandiez. Quand je travaille sur une page dont l'URL correspond à quelque chose dans notre sitemap, Cascade va proactivement récupérer les données de performance des mots-clés et les afficher dans le panneau de contexte. C'est un détail, mais cela signifie que les données sont là avant même que vous ne réalisiez que vous en avez besoin.

Exemple réel : le serveur MCP de HeySeo

HeySeo est un SaaS d'analytics SEO qui se connecte à Google Search Console et GA4. L'intégration MCP que nous avons construite expose les capacités analytiques fondamentales de la plateforme à tout outil IA que l'utilisateur préfère.

Voici les tools que nous proposons :

ToolCe qu'il fait
get_top_keywordsMots-clés principaux par clics, impressions, CTR
get_landing_pagesVentilation des performances par page
get_ranking_historyPosition du mot-clé dans le temps
search_serpDonnées SERP en direct pour n'importe quelle requête
get_opportunitiesLacunes de mots-clés et gains rapides
run_onpage_auditAudit SEO technique pour une URL
query_gscRequête GSC brute avec plage de dates et dimensions personnalisées

Voici le détecteur d'opportunités, qui est l'un des tools les plus utiles en pratique :

// src/tools/find-opportunities.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { findKeywordOpportunities } from "../data/opportunities.js";
 
export function registerFindOpportunitiesTool(server: McpServer) {
  server.tool(
    "find_opportunities",
    "Find keyword opportunities for a site: queries with high impressions but low CTR (position 4-20), indicating quick wins with content improvements.",
    {
      siteUrl: z.string().url().describe("Site URL to analyze"),
      minImpressions: z
        .number()
        .int()
        .min(10)
        .default(100)
        .describe("Minimum impression threshold"),
      maxPosition: z
        .number()
        .min(1)
        .max(50)
        .default(20)
        .describe("Maximum average position to include"),
    },
    async ({ siteUrl, minImpressions, maxPosition }) => {
      const opportunities = await findKeywordOpportunities({
        siteUrl,
        minImpressions,
        maxPosition,
      });
 
      const formatted = opportunities.map((kw) => ({
        query: kw.query,
        impressions: kw.impressions,
        clicks: kw.clicks,
        ctr: `${(kw.ctr * 100).toFixed(1)}%`,
        position: kw.position.toFixed(1),
        estimatedTrafficGain: kw.estimatedGain,
      }));
 
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(
              {
                total: formatted.length,
                opportunities: formatted.slice(0, 50),
              },
              null,
              2
            ),
          },
        ],
      };
    }
  );
}

La couche de données (findKeywordOpportunities) interroge notre base Firestore, qui se synchronise depuis Google Search Console chaque nuit. Le serveur MCP ne se soucie pas de la base de données - il appelle simplement des fonctions et renvoie des données structurées. Cette séparation garde le serveur simple et la logique métier testable.

L'intégration Slack

Pour le bot Slack, nous exécutons le serveur MCP de HeySeo via HTTP/SSE et l'appelons depuis un handler de commande slash Slack. Les utilisateurs tapent /heyseo opportunities site:example.com dans Slack, notre bot envoie un POST au serveur MCP, récupère les données et les formate en message Slack Block Kit.

Cela représentait environ 150 lignes de code au-dessus du serveur MCP existant. Le serveur lui-même n'a nécessité aucune modification - c'est la valeur de l'abstraction du protocole.

Considérations de sécurité

Exposer des données métier via une interface d'outil IA introduit une vraie surface d'attaque. Voici comment je l'aborde pour HeySeo.

Authentification. Pour les transports stdio (Claude Desktop, Cursor, Windsurf), le serveur tourne comme le processus de l'utilisateur. Les variables d'environnement pour les clés API sont acceptables ici - la clé ne quitte jamais la machine. Pour les transports HTTP, utilisez une authentification par bearer token sur chaque requête.

// src/middleware/auth.ts
export function requireApiKey(apiKey: string | undefined): void {
  const expectedKey = process.env.HEYSEO_API_KEY;
 
  if (!expectedKey) {
    throw new Error("HEYSEO_API_KEY environment variable is not set");
  }
 
  if (apiKey !== expectedKey) {
    throw new Error("Invalid API key");
  }
}

Limitation du périmètre. Les tools ne doivent exposer que ce qui est nécessaire. Si un utilisateur connecte son site personnel, le serveur ne doit renvoyer que les données de ce site - pas celles d'un autre site du système. Nous appliquons cela en liant chaque clé API à un siteUrl spécifique au niveau de la base de données.

Validation des entrées. Les schémas Zod dans vos définitions de tools sont votre première ligne de défense. Traitez toutes les entrées de tools comme non fiables et validez-les strictement. Ne passez jamais des entrées de chaînes brutes directement à une requête de base de données.

// Never do this
const results = await db.query(`SELECT * FROM keywords WHERE site = '${siteUrl}'`);
 
// Always do this
const results = await db.collection("keywords")
  .where("siteUrl", "==", siteUrl)
  .limit(100)
  .get();

Limitation de débit. Les outils IA peuvent appeler votre serveur MCP de manière agressive, surtout lors d'exécutions d'agents multi-étapes. Ajoutez une limitation de débit par clé pour protéger votre backend et vos quotas d'API.

// src/middleware/rate-limit.ts
const requestCounts = new Map<string, { count: number; resetAt: number }>();
 
export function checkRateLimit(apiKey: string, maxPerMinute = 30): void {
  const now = Date.now();
  const entry = requestCounts.get(apiKey);
 
  if (!entry || entry.resetAt < now) {
    requestCounts.set(apiKey, { count: 1, resetAt: now + 60_000 });
    return;
  }
 
  if (entry.count >= maxPerMinute) {
    throw new Error("Rate limit exceeded. Try again in a minute.");
  }
 
  requestCounts.set(apiKey, { ...entry, count: entry.count + 1 });
}

Messages d'erreur. Ne renvoyez pas de stack traces internes ou de messages d'erreur de base de données au client IA. Renvoyez des messages d'erreur compréhensibles qui expliquent ce qui s'est mal passé sans divulguer de détails d'implémentation.

Déploiement en production

Pour un serveur local (transport stdio), le déploiement consiste simplement à publier le package npm ou à livrer un binaire. Les utilisateurs l'installent et configurent leur client.

Pour un serveur hébergé (transport HTTP/SSE), j'exécute le serveur MCP de HeySeo sur Railway avec la configuration suivante :

FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

Quelques considérations de production à mentionner :

Arrêt propre. Les processus de serveur MCP doivent gérer SIGTERM proprement. Si un client est en pleine conversation et que votre serveur meurt sans déconnexion propre, le client peut se retrouver dans un état cassé.

process.on("SIGTERM", async () => {
  await server.close();
  process.exit(0);
});

Logging structuré. Pour les serveurs stdio, toute sortie vers stdout fait partie du protocole MCP. N'utilisez jamais console.log vers stdout dans un serveur stdio - utilisez console.error ou un logger structuré qui écrit dans un fichier ou vers stderr uniquement.

Health checks. Pour les déploiements HTTP, exposez un endpoint /health qui vérifie votre connexion à la base de données et toute dépendance API en amont. Railway et Fly.io l'utiliseront pour router le trafic et redémarrer les instances en mauvaise santé.

Versionnage. La version du serveur MCP que vous déclarez dans le constructeur compte. Les clients l'utilisent pour décider s'ils doivent re-cacher les schémas de tools. Incrémentez la version chaque fois que vous ajoutez, supprimez ou modifiez la signature d'un tool.

La suite pour MCP

MCP a atteint la version 1.0 début 2025 et l'écosystème a grandi rapidement. Quelques éléments que je surveille :

Composition multi-serveur. Aujourd'hui, chaque client se connecte aux serveurs indépendamment. Il y a un travail préliminaire sur des serveurs proxy qui agrègent plusieurs serveurs MCP derrière un seul endpoint - utile quand vous avez dix outils internes et ne voulez pas configurer chaque IDE séparément.

Sampling et streaming. Le protocole supporte déjà les réponses en streaming, mais la plupart des serveurs renvoient tout d'un coup. À mesure que les volumes de données augmentent, le streaming incrémental comptera davantage. Le SDK a les hooks nécessaires ; la plupart des serveurs ne les ont simplement pas encore implémentés.

Auth standardisé. La communauté converge vers OAuth 2.0 comme standard pour les serveurs MCP distants, ce qui rendra la connexion aux serveurs MCP tiers beaucoup plus simple que le partage de clés API brutes.

Panneaux IA natifs dans les IDE. Cursor et Windsurf développent tous deux des surfaces UI plus profondes pour les données MCP - pas seulement des réponses textuelles, mais des graphiques, des diffs et des vues structurées. HeySeo expérimente le renvoi de tableaux Markdown et de données de graphiques qui se rendent directement dans l'IDE.

La trajectoire est claire : MCP est en train de devenir la couche de plomberie standard entre les outils IA et les systèmes avec lesquels ils doivent interagir. Si vous construisez un produit SaaS en 2026, livrer un serveur MCP devient rapidement incontournable - de la même manière que livrer une API REST est devenu attendu en 2015.

FAQ

Q : Dois-je construire un serveur MCP pour utiliser MCP ? R : Non. Il existe des centaines de serveurs MCP pré-construits pour les outils courants (GitHub, Notion, PostgreSQL, Slack, et plus). Consultez le registre officiel sur modelcontextprotocol.io/servers. Vous n'avez besoin d'en construire un que lorsque vous avez des données custom ou des API propriétaires à exposer.

Q : MCP est-il uniquement pour Claude d'Anthropic ? R : Non. MCP est un standard ouvert et tout client IA peut l'implémenter. Cursor (qui utilise les modèles Claude et OpenAI), Windsurf (Codeium) et plusieurs autres le supportent déjà. OpenAI ne l'a pas encore adopté au moment où j'écris ces lignes, mais la pression de la communauté augmente.

Q : Mon serveur MCP peut-il gérer plusieurs utilisateurs ? R : Oui, avec le transport HTTP/SSE. Chaque connexion client obtient sa propre session. Vous authentifiez par connexion et limitez l'accès aux données aux permissions de cet utilisateur. Le transport stdio est intrinsèquement mono-utilisateur puisqu'il tourne comme le propre processus de l'utilisateur.

Q : Comment MCP se compare-t-il au function calling d'OpenAI ou à sa spécification de plugin ? R : Le function calling d'OpenAI est une fonctionnalité d'API par requête. MCP est un protocole de connexion longue durée. MCP fonctionne aussi avec plusieurs fournisseurs d'IA sans aucune modification de votre serveur, ce qui est le principal avantage pratique.

Q : Que se passe-t-il quand mon serveur MCP est en panne ? R : Le client IA échoue gracieusement et informe l'utilisateur que l'outil est indisponible. Claude Desktop, Cursor et Windsurf gèrent tous cela correctement. Intégrez des health checks et des redémarrages rapides pour minimiser les temps d'arrêt.


Construire le serveur MCP de HeySeo a pris un week-end et a immédiatement changé la façon dont l'équipe utilise les outils IA. Si votre produit a des données qui pourraient éclairer de meilleures décisions assistées par l'IA, analytics SEO, données CRM, métriques de code, données financières, l'investissement en vaut absolument la peine.

Si vous souhaitez discuter de votre intégration MCP, contactez-moi et construisons-la ensemble.

Share:

Recevez des perspectives d'ingénierie pratiques

Agents vocaux IA, workflows d'automatisation et livraison rapide. Pas de spam, désabonnement à tout moment.