ITSkillsCenter
Intelligence Artificielle

MCP server custom métier : tutoriel complet 2026

8 دقائق للقراءة

Le Model Context Protocol (MCP) est devenu en 2026 le standard de l’industrie pour connecter des sources de données et des outils métier aux LLM. Lancé par Anthropic et adopté par Cursor, Continue, Cline et de nombreux autres clients IA, MCP permet d’écrire UN serveur réutilisable qui expose vos APIs métier — votre CRM, votre ERP, votre base produits, vos tickets — et de le brancher à n’importe quel agent compatible. Voici le tutoriel complet pour créer votre propre MCP server custom et l’utiliser depuis Claude Agent SDK ou Claude Code.

Ce tutoriel s’inscrit dans notre série Claude Agent SDK. Pour les bases, voir notre guide complet Claude Agent SDK 2026.

Pourquoi MCP plutôt que des outils inline ?

  • Réutilisabilité : un MCP server peut servir plusieurs agents (assistant interne, agent client, agent dev) sans dupliquer le code
  • Compatibilité multi-clients : votre serveur fonctionne avec Claude Code, Cursor, Continue, Cline, et tout futur client MCP
  • Séparation propre : la logique métier vit dans son repo, son cycle de vie, ses tests, indépendamment des prompts
  • Versionnage : vous pouvez déployer une nouvelle version du MCP sans toucher aux agents qui l’utilisent
  • Sécurité : un MCP server peut tourner avec ses propres credentials (API keys, DB) sans les exposer à chaque agent
  • Langage au choix : MCP server en TypeScript, Python, Go, Rust, n’importe quel langage qui peut parler stdio ou HTTP

Architecture MCP en bref

Un MCP server expose trois types de capacités :

  • Tools : fonctions appelables (similaire aux tools du SDK)
  • Resources : données lisibles (fichiers, configurations, URI)
  • Prompts : templates de prompts prêts à l’emploi

La communication se fait soit via stdio (standard input/output, pour les serveurs locaux), soit via HTTP/SSE (pour les serveurs distants ou hébergés). Stdio est plus simple à démarrer ; HTTP/SSE est nécessaire pour les serveurs partagés ou en cloud.

Cas d’usage : MCP CRM

Pour ce tutoriel, on construit un MCP server qui expose les opérations courantes d’un CRM : lister clients, lire un client, créer une note, lister les opportunités. Une fois le serveur prêt, n’importe quel agent peut l’utiliser pour rédiger des emails de suivi, générer des rapports, ou analyser des données.

Prérequis

  • Node.js 20+ ou Bun
  • Connaissance TypeScript intermédiaire
  • Notion d’API REST
  • Niveau attendu : intermédiaire
  • Temps : 2-3 heures

Étape 1 — Setup

mkdir mcp-crm && cd mcp-crm
bun init -y
bun add @modelcontextprotocol/sdk zod

Étape 2 — Squelette du serveur

// src/server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";

const server = new Server(
  { name: "mcp-crm", version: "1.0.0" },
  { capabilities: { tools: {} } },
);

// Lister les outils disponibles
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "list_clients",
      description: "Liste les clients du CRM",
      inputSchema: {
        type: "object",
        properties: {
          search: { type: "string", description: "Mot-clé de recherche optionnel" },
          limit: { type: "number", description: "Nombre max de résultats", default: 20 },
        },
      },
    },
    {
      name: "get_client",
      description: "Récupère les détails d'un client par ID",
      inputSchema: {
        type: "object",
        properties: { id: { type: "string" } },
        required: ["id"],
      },
    },
    {
      name: "create_note",
      description: "Crée une note interne sur un client",
      inputSchema: {
        type: "object",
        properties: {
          clientId: { type: "string" },
          content: { type: "string" },
        },
        required: ["clientId", "content"],
      },
    },
  ],
}));

const transport = new StdioServerTransport();
await server.connect(transport);

Étape 3 — Implémenter les tools

// src/server.ts (suite)
import { listClients, getClient, createNote } from "./crm-api";

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    if (name === "list_clients") {
      const result = await listClients({
        search: args?.search as string,
        limit: (args?.limit as number) ?? 20,
      });
      return {
        content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
      };
    }

    if (name === "get_client") {
      const result = await getClient(args?.id as string);
      return {
        content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
      };
    }

    if (name === "create_note") {
      const result = await createNote({
        clientId: args?.clientId as string,
        content: args?.content as string,
      });
      return {
        content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
      };
    }

    return {
      content: [{ type: "text", text: `Unknown tool: ${name}` }],
      isError: true,
    };
  } catch (error: any) {
    return {
      content: [{ type: "text", text: `Error: ${error.message}` }],
      isError: true,
    };
  }
});

Étape 4 — Le module CRM API

// src/crm-api.ts
const CRM_BASE_URL = process.env.CRM_BASE_URL ?? "https://crm.exemple.sn/api/v1";
const CRM_TOKEN = process.env.CRM_TOKEN!;

async function fetchCRM(path: string, init: RequestInit = {}) {
  const res = await fetch(`${CRM_BASE_URL}${path}`, {
    ...init,
    headers: {
      "Authorization": `Bearer ${CRM_TOKEN}`,
      "Content-Type": "application/json",
      ...init.headers,
    },
  });
  if (!res.ok) throw new Error(`CRM ${res.status}: ${await res.text()}`);
  return res.json();
}

export async function listClients({ search, limit }: { search?: string; limit: number }) {
  const params = new URLSearchParams();
  if (search) params.set("search", search);
  params.set("limit", String(limit));
  return fetchCRM(`/clients?${params}`);
}

export async function getClient(id: string) {
  return fetchCRM(`/clients/${id}`);
}

export async function createNote({ clientId, content }: { clientId: string; content: string }) {
  return fetchCRM(`/clients/${clientId}/notes`, {
    method: "POST",
    body: JSON.stringify({ content, createdBy: "agent-mcp" }),
  });
}

Étape 5 — Tester le serveur localement

# Démarrer en mode dev
bun run --watch src/server.ts

# Tester avec MCP inspector (outil officiel)
npx @modelcontextprotocol/inspector bun run src/server.ts

L’inspector ouvre une UI web où vous voyez les tools exposés et pouvez les appeler avec des paramètres pour vérifier les réponses. Très pratique pour debugger avant de brancher un agent.

Étape 6 — Brancher à Claude Code

Dans le fichier ~/.claude/settings.json ou en CLI :

{
  "mcpServers": {
    "crm": {
      "command": "bun",
      "args": ["run", "/chemin/absolu/vers/mcp-crm/src/server.ts"],
      "env": {
        "CRM_TOKEN": "secret-token-prod",
        "CRM_BASE_URL": "https://crm.exemple.sn/api/v1"
      }
    }
  }
}

Lancez claude. L’agent voit maintenant les outils list_clients, get_client, create_note. Demandez : « Liste les 5 derniers clients ajoutés et résume leur activité. » L’agent va appeler list_clients, puis get_client pour chacun, et synthétiser.

Étape 7 — Brancher au Claude Agent SDK

// Dans votre code Agent SDK
import { query } from "@anthropic-ai/claude-agent-sdk";

const result = query({
  prompt: "Donne-moi un point sur le compte client ID 42",
  options: {
    mcpServers: {
      crm: {
        command: "bun",
        args: ["run", "/chemin/vers/mcp-crm/src/server.ts"],
        env: {
          CRM_TOKEN: process.env.CRM_TOKEN!,
        },
      },
    },
  },
});

Étape 8 — Déployer en HTTP/SSE

Pour partager le MCP server entre plusieurs machines (équipe distante, CI, agent en cloud), utilisez le transport HTTP/SSE plutôt que stdio :

// src/server-http.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";

const app = express();
const server = new Server(/* config */);

// Auth basique pour limiter l'accès
app.use((req, res, next) => {
  if (req.headers["authorization"] !== `Bearer ${process.env.MCP_TOKEN}`) {
    return res.status(401).end();
  }
  next();
});

app.get("/sse", async (req, res) => {
  const transport = new SSEServerTransport("/messages", res);
  await server.connect(transport);
});

app.listen(3001);

Le serveur peut alors être hébergé sur Coolify (voir notre guide Coolify) avec HTTPS automatique. Les agents s’y connectent en pointant l’URL.

Étape 9 — Bonnes pratiques production

  • Logging structuré : chaque tool call dans une base d’audit avec timestamp, agent appelant, paramètres, résultat
  • Rate limiting : protéger les APIs métier en aval (limite par agent et par tool)
  • Validation stricte avec Zod côté serveur, ne jamais faire confiance aux paramètres reçus
  • Permissions par tool : certains tools écrivent (create_note, update_client), d’autres lisent uniquement. Différenciez les credentials et les permissions
  • Versionnage : tag SemVer dans name: "mcp-crm@1.2.0", versioning d’API stable
  • Health check : un tool ping qui retourne OK si tout va bien, pour superviser depuis Uptime Kuma
  • Documentation des tools : description claire et inputSchema précis. C’est ce qui aide le LLM à utiliser correctement votre serveur

MCP servers populaires existants

Avant d’écrire le vôtre, vérifiez s’il existe déjà :

  • GitHub, GitLab, Linear, Notion, Slack — officiels Anthropic ou communauté
  • PostgreSQL, MySQL, MongoDB — accès en lecture aux DB
  • Filesystem, Git, Memory, Playwright — utilitaires
  • Stripe, Jira, Trello — services SaaS

Catalogue communautaire sur github.com/modelcontextprotocol/servers.

Adaptation Afrique de l’Ouest

Pour les PME ouest-africaines, créer un MCP server custom autour de votre stack métier (Odoo, ERPNext, votre propre application interne, votre catalogue Excel converti en API) débloque tout un écosystème d’agents IA productifs : assistant facturation, agent SEO, agent support. Hébergez le MCP en local sur un VPS Hetzner ou un serveur national, branchez-y un agent Claude, et vous avez un automate qui comprend votre métier.

Erreurs fréquentes

ErreurCauseSolution
Tools non listés dans Claude CodePath absolu manquant ou mal écritUtiliser chemin absolu, tester avec MCP inspector d’abord
JSON parsing failedRéponse non JSON valideToujours envelopper dans content: [{ type: « text », text: … }]
Server crash silencieuxException non catchéetry/catch global dans le handler, logger l’erreur
Token expiréPas de refresh logicImplémenter refresh automatique du token CRM
Données sensibles fuitentLogs trop verbeuxMasquer mots de passe, tokens, PII dans les logs

Pour aller plus loin

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité