DonnIA
Toutes les ressources
GuideClaude Skills & MCP18 min

Brancher son API métier

Exposer l'API interne de son entreprise à un agent via MCP : trois outils, en lecture seule, qui ne renvoient que l'utile.


Ton entreprise a déjà une API : le CRM, la facturation, le stock, le suivi de production. L'agent, lui, ne la voit pas. Il répond « je n'ai pas accès à ces informations » pendant que la réponse existe à deux appels HTTP de là.

Le réflexe naturel est de tout exposer d'un coup : cinquante endpoints, un serveur MCP généré depuis le schéma OpenAPI, et on verra bien. C'est le meilleur moyen d'obtenir un agent qui choisit mal ses outils, sature son contexte avec du JSON inutile, et finit par modifier une fiche client par erreur.

Ce guide fait l'inverse. Trois outils, en lecture seule, qui renvoient dix lignes chacun. On étend après, quand on sait ce qui sert vraiment.

Le périmètre minimal

Avant d'écrire une ligne, note les questions que les gens posent réellement à l'équipe qui a accès à l'outil. Pas les fonctions de l'API : les questions. « Où en est la commande de Dupont ? », « Combien de tickets ouverts sur le module paiement ? », « Ce client est-il à jour de ses factures ? »

Trois questions, trois outils. Un endpoint qui ne répond à aucune question formulée par un humain n'a rien à faire dans le serveur.

Un outil n'est pas un endpoint

GET /customers/{id} est un endpoint. statut_commande(numero) est un outil. Le second peut appeler trois endpoints et n'en restituer que le résultat utile. Traduire, c'est tout l'intérêt de la couche MCP.

Avant de commencer

  • Node.js 20 ou plus récent
  • Une API interne joignable, et un jeton de lecture
  • Trois questions métier écrites noir sur blanc

1Créer le serveur

mkdir mcp-metier && cd mcp-metier
npm init -y
npm install @modelcontextprotocol/server zod

Ajoute "type": "module" dans package.json. Le paquet @modelcontextprotocol/server est la version 2 du SDK TypeScript ; les exemples qui importent @modelcontextprotocol/sdk datent de la v1.

2Un outil, en lecture seule

import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import * as z from "zod/v4";

const BASE = process.env.API_BASE_URL;
const JETON = process.env.API_TOKEN;

serveStdio(() => {
  const server = new McpServer({ name: "metier", version: "1.0.0" });

  server.registerTool(
    "statut_commande",
    {
      description:
        "Renvoie l'etat d'avancement d'une commande a partir de son numero. " +
        "A utiliser des qu'on demande ou en est une commande.",
      inputSchema: z.object({
        numero: z.string().describe("Numero de commande, format CMD-12345"),
      }),
      annotations: { readOnlyHint: true },
    },
    async ({ numero }) => {
      const r = await fetch(`${BASE}/orders/${encodeURIComponent(numero)}`, {
        headers: { Authorization: `Bearer ${JETON}` },
      });

      if (r.status === 404) {
        return {
          content: [{ type: "text", text: `Commande introuvable : ${numero}` }],
          isError: true,
        };
      }

      const c = await r.json();

      return {
        content: [
          {
            type: "text",
            text: [
              `Commande ${c.reference}`,
              `Statut : ${c.status}`,
              `Expedition prevue : ${c.shipping_date ?? "non planifiee"}`,
              `Montant : ${c.total_amount} EUR`,
            ].join("\n"),
          },
        ],
      };
    }
  );

  return server;
});

Deux choses méritent d'être notées. annotations: { readOnlyHint: true } déclare que l'outil ne modifie rien : c'est une indication de comportement, pas une garantie technique, la vraie garantie vient du jeton de lecture seule. Et isError: true renvoie une erreur que le modèle peut lire et corriger, au lieu d'une exception qui le laisse deviner.

3Filtrer ce qui sort, pas ce qui entre

C'est le point que presque tout le monde rate. Un return JSON.stringify(c) sur une fiche client, c'est deux cents champs envoyés au modèle : identifiants internes, horodatages techniques, adresse, RIB, historique complet. Coût en jetons, bruit dans la réponse, et fuite de données qui n'avaient rien à faire là.

La règle : le serveur choisit les champs, un par un, explicitement. Si tu ne peux pas nommer les cinq champs utiles, c'est que l'outil n'est pas assez précis.

Le filtrage côté modèle n'existe pas

« Le modèle ne montrera que ce qui est pertinent » est faux : tout ce que l'outil renvoie entre dans le contexte, donc dans les journaux du fournisseur, et peut ressortir dans une réponse. Ce qui ne doit pas sortir de ton système ne doit pas sortir de ton serveur.

4Brancher sans mettre le jeton dans un prompt

Les identifiants passent par l'environnement du processus, jamais dans le texte de la conversation :

claude mcp add --env API_BASE_URL=https://api.interne.local \
  --env API_TOKEN=xxxxx \
  --transport stdio metier -- node /chemin/absolu/serveur.js

Vérifie ensuite :

claude mcp list

Le serveur doit apparaître comme connecté. Dans un fichier .mcp.json partagé avec l'équipe, référence les variables au lieu des valeurs, avec la syntaxe ${API_TOKEN} : chacun fournit son propre jeton, et le fichier reste commitable.

5Passer en écriture, plus tard, et jamais en silence

Quand un outil d'écriture devient nécessaire, trois règles.

  • Une action précise, pas une action générique. annuler_commande(numero, motif) plutôt que modifier_commande(numero, champs).
  • Un compte de service dédié, avec les seuls droits de cette action, distinct du compte de lecture.
  • Une trace, côté API : qui a appelé, quand, avec quels arguments. Les journaux du modèle ne suffisent pas.

Et tant que possible, garde l'écriture sur un environnement de test le temps de vérifier que le modèle appelle l'outil au bon moment.

Quelques prompts pour aller plus loin

ObjectifPrompt à adapter
Définir le périmètreVoici 30 questions posees a notre equipe support ce mois-ci. Regroupe-les et propose au maximum 5 outils qui couvriraient 80 % des cas. Pour chacun : nom, arguments, champs a renvoyer.
Traduire un endpointVoici la reponse JSON de [ENDPOINT]. Selectionne les 5 champs utiles pour repondre a « [QUESTION] » et ecris la mise en forme texte. Justifie chaque champ ecarte.
Écrire les descriptionsVoici mes 4 outils. Reecris chaque description pour qu'elle dise quand l'utiliser et quand ne pas l'utiliser, en une ou deux phrases.
Chasser les fuitesRelis ce serveur MCP. Pour chaque outil, liste les champs renvoyes au modele et signale ceux qui sont des donnees personnelles ou des identifiants internes.
Tester le déclenchementVoici la liste de mes outils avec leurs descriptions. Pour chacune de ces 10 questions, dis quel outil tu appellerais, ou aucun. Ne les appelle pas.

Tu as d’autres ressources comme ça ?

Ce que tu viens de lire est entièrement gratuit. Une nouvelle ressource part chaque semaine dans la newsletter : guides, modèles à copier et liens triés, sans compte à créer.

Cette page est en accès libre, n’hésite pas à la partager.