Connecter Claude Code aux outils internes : intégrer vos systèmes d'entreprise avec MCP

Connectez les systèmes internes de votre entreprise à Claude Code via MCP — d'un serveur fetch générique à l'écriture d'un MCP Server dédié, couvrant plateformes de déploiement, monitoring, tickets et principes de conception d'outils.


L'article précédent traitait de la connexion aux bases de données. Les bases de données s'appuient sur des protocoles standards, ce qui rend l'intégration relativement directe. Mais la plupart des équipes dépendent aussi au quotidien d'une multitude de systèmes internes : plateformes de déploiement, tableaux de bord de monitoring, systèmes de tickets, APIs internes, services de configuration centralisée.

Ces systèmes n'ont généralement pas de MCP Server prêt à l'emploi, mais ils exposent presque tous une API HTTP. Cet article explique comment utiliser MCP pour connecter ces outils internes à Claude Code, afin qu'il puisse directement consulter les métriques de monitoring, vérifier l'état des déploiements et gérer les tickets.

Deux approches

Il existe deux façons d'intégrer des outils internes :

Approche 1 : Utiliser un MCP Server HTTP générique
La communauté propose des MCP Servers génériques capables d'encapsuler n'importe quelle API REST en outil MCP. Vous rédigez un fichier de description de l'API, et le serveur le transforme en outils que Claude peut appeler. Idéal pour les APIs à structure simple, sans logique complexe.

Approche 2 : Écrire son propre MCP Server
Utilisez le SDK MCP en TypeScript ou Python pour créer un serveur dédié, avec un contrôle total sur la définition des outils, la validation des paramètres et la gestion des erreurs. Idéal lorsqu'il faut combiner plusieurs APIs, transformer des données ou ajouter de la logique métier.

Cet article couvre les deux approches, en commençant par la plus simple.

Approche 1 : Intégration rapide avec mcp-server-fetch

La solution la plus légère consiste à utiliser le package officiel @anthropic-ai/mcp-server-fetch, qui permet à Claude d'envoyer des requêtes HTTP directement. La configuration est minimale :

{
  "mcpServers": {
    "fetch": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-server-fetch"]
    }
  }
}

Une fois configuré, Claude peut appeler directement les APIs internes :

Vérifie l'état actuel du service sur la plateforme de déploiement https://deploy.internal.com/api/v1/services/user-service

Claude enverra une requête GET, récupérera la réponse et vous la présentera de manière lisible.

Mais cette approche a des limites évidentes :

  • Il faut à chaque fois indiquer à Claude l'URL complète et le format de la requête
  • Pas de validation des paramètres ; Claude pourrait se tromper de chemin
  • L'authentification doit être transmise à chaque fois ou inscrite dans le prompt (peu sécurisé)
  • Impossible de combiner plusieurs appels d'API

Utile pour un usage ponctuel, mais inadapté comme solution pérenne.

Approche 2 : Écrire un MCP Server dédié

Lorsque vous utilisez régulièrement un système interne, écrire un MCP Server dédié est la meilleure option. Voici une démonstration avec un cas concret : l'intégration d'une plateforme de déploiement d'entreprise.

Supposons que votre plateforme de déploiement expose les APIs suivantes :

  • GET /api/v1/services — lister tous les services
  • GET /api/v1/services/:name/status — consulter l'état d'un service
  • POST /api/v1/services/:name/deploy — déclencher un déploiement
  • GET /api/v1/services/:name/logs — consulter les logs de déploiement récents

Écrire le MCP Server en TypeScript

Commencez par initialiser le projet :

mkdir mcp-deploy && cd mcp-deploy
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
npx tsc --init

Code principal dans src/index.ts :

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

const API_BASE = process.env.DEPLOY_API_URL!;
const API_TOKEN = process.env.DEPLOY_API_TOKEN!;

async function api(path: string, method = "GET", body?: unknown) {
  const res = await fetch(`${API_BASE}${path}`, {
    method,
    headers: {
      Authorization: `Bearer ${API_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!res.ok) {
    throw new Error(`API error: ${res.status} ${await res.text()}`);
  }
  return res.json();
}

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

// Lister tous les services
server.tool("list_services", "列出部署平台上的所有服务及其状态", {}, async () => {
  const data = await api("/api/v1/services");
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
});

// Consulter l'état d'un service
server.tool(
  "service_status",
  "查看指定服务的当前部署状态、版本号和健康检查结果",
  { name: z.string().describe("服务名称,如 user-service") },
  async ({ name }) => {
    const data = await api(`/api/v1/services/${name}/status`);
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

// Consulter les logs de déploiement
server.tool(
  "deploy_logs",
  "查看指定服务最近的部署日志",
  {
    name: z.string().describe("服务名称"),
    limit: z.number().optional().default(10).describe("返回条数,默认 10"),
  },
  async ({ name, limit }) => {
    const data = await api(`/api/v1/services/${name}/logs?limit=${limit}`);
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

// Déclencher un déploiement
server.tool(
  "trigger_deploy",
  "触发指定服务的部署。这是一个写操作,会实际影响生产环境",
  {
    name: z.string().describe("服务名称"),
    version: z.string().describe("要部署的版本号或 git ref"),
  },
  async ({ name, version }) => {
    const data = await api(`/api/v1/services/${name}/deploy`, "POST", {
      version,
    });
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

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

Compiler :

npx tsc

Configurer Claude Code

{
  "mcpServers": {
    "deploy": {
      "command": "node",
      "args": ["/path/to/mcp-deploy/dist/index.js"],
      "env": {
        "DEPLOY_API_URL": "https://deploy.internal.com",
        "DEPLOY_API_TOKEN": "your-api-token"
      }
    }
  }
}

Placez le token dans .claude/settings.local.json (non commité dans git) et l'URL dans .claude/settings.json (commité, partagé avec l'équipe).

En pratique

Une fois la configuration terminée, la conversation devient naturelle :

Quel est l'état actuel de user-service ?

→ Claude appelle service_status("user-service")
→ Réponse : en cours d'exécution, version v2.3.1, dernier déploiement il y a 2 heures, health checks réussis
Est-ce que des déploiements récents ont échoué ?

→ Claude appelle deploy_logs("user-service", 20)
→ Analyse les logs et vous indique que le troisième déploiement a été annulé à cause d'un timeout sur le health check
Déploie user-service en version v2.3.2

→ Claude appelle trigger_deploy("user-service", "v2.3.2")
→ Comme la description de l'outil indique « opération d'écriture », Claude vous demandera confirmation au préalable

Faut-il intégrer les opérations d'écriture ?

C'est une question qui mérite réflexion.

Les opérations de lecture peuvent être intégrées sans hésitation. Consulter un état, lire des logs, rechercher des tickets — ces opérations sont sans effet de bord ; si Claude se trompe, il n'y a aucune conséquence.

Les opérations d'écriture se divisent en deux catégories :

Les opérations à faible risque peuvent être intégrées, à condition de le signaler clairement dans la description de l'outil. Claude demande automatiquement confirmation pour les opérations marquées comme ayant des effets de bord. Par exemple : créer un ticket, envoyer un message, mettre à jour une configuration.

Les opérations à haut risque ne devraient pas être intégrées. Supprimer des ressources, déclencher un rollback, modifier des permissions — les conséquences sont graves et irréversibles ; il est plus sûr de les effectuer manuellement.

Si vous décidez malgré tout d'intégrer des opérations d'écriture, faites au minimum deux choses :

  1. Indiquez clairement dans la description de l'outil « ceci est une opération d'écriture qui impacte l'environnement de production »
  2. Ajoutez les vérifications de sécurité nécessaires dans le MCP Server (par exemple, interdire les déploiements sur le namespace de production)

Pistes d'intégration pour les systèmes internes courants

Système Outils exposés Points d'attention
Plateforme de déploiement (K8s / Kamal) Consulter l'état des services, voir les logs, déclencher des déploiements Confirmer les opérations d'écriture
Monitoring (Grafana / Datadog) Consulter les métriques, voir l'historique des alertes Limiter la plage temporelle des requêtes pour éviter de charger trop de données
Tickets (Jira / Linear) Rechercher des tickets, en créer, mettre à jour les statuts Créer un ticket est une écriture, mais à faible risque
Documentation interne (Notion / Confluence) Rechercher des documents, lire le contenu des pages Attention à la pagination ; ne pas charger trop de données en une seule fois
Configuration centralisée (Consul / etcd) Lire les configurations, comparer les différences entre environnements Lecture seule ; ne pas intégrer l'écriture
CI/CD (GitHub Actions / Jenkins) Voir l'état des builds, déclencher des builds Déclencher un build est considéré comme une écriture à risque moyen

Principes de conception des outils

Concevoir des outils MCP, ce n'est pas la même chose que concevoir des APIs. Les APIs s'adressent aux développeurs ; les outils s'adressent à l'IA. Voici quelques principes à garder en tête :

Les noms doivent être explicites

✗ get_svc_stat     — Claude ne devinera pas forcément le sens de l'abréviation
✓ service_status   — immédiatement compréhensible

Les descriptions doivent être rédigées pour l'IA

La description d'un outil n'est pas une documentation destinée aux humains ; c'est ce que Claude utilise pour décider quand l'appeler. Elle doit préciser : ce que fait l'outil, ce qu'il renvoie, et quand il doit être utilisé.

✗ "Obtenir l'état du service"
✓ "Consulter l'état de déploiement actuel, le numéro de version et le résultat des health checks d'un service donné. À utiliser quand l'utilisateur demande si un service fonctionne correctement"

Définir les paramètres clairement avec zod

Les paramètres dotés d'un .describe() sont ceux que Claude comprend correctement. Sans description, Claude ne peut que deviner d'après le nom.

Renvoyer des données structurées

Les outils MCP renvoient du texte, mais privilégiez du JSON formaté. Claude traite les données structurées avec bien plus de précision que le texte brut.

Adopter la bonne granularité

N'entassez pas un flux complexe dans un seul outil. Ne découpez pas non plus une simple requête en trois outils. Le principe : un outil par opération indépendante et cohérente.

Où placer le MCP Server

Le code du MCP Server peut être hébergé à plusieurs endroits :

Dans le dépôt du projet (recommandé pour démarrer)

your-project/
├── .claude/settings.json
├── mcp-servers/
│   └── deploy/
│       ├── src/index.ts
│       ├── package.json
│       └── tsconfig.json
└── ...

L'avantage : le code et la configuration sont regroupés ; l'équipe n'a qu'à cloner le dépôt et installer les dépendances pour commencer.

Dépôt indépendant

Lorsque le MCP Server doit être utilisé sur plusieurs projets, placez-le dans un dépôt séparé et publiez-le comme package npm ou image Docker.

{
  "mcpServers": {
    "deploy": {
      "command": "npx",
      "args": ["-y", "@yourcompany/mcp-deploy-server"]
    }
  }
}

Installation globale

Pour les MCP Servers d'usage transversal dans l'entreprise (par exemple, authentification unifiée ou plateforme de logs centralisée), installez-les globalement et configurez-les dans ~/.claude/settings.json.

Conseils de débogage

Les problèmes les plus fréquents lors du développement d'un MCP Server sont « Claude n'appelle pas mon outil » ou « il l'appelle mais ça plante ».

Vérifier que le serveur a démarré

Après avoir redémarré Claude Code, tapez /mcp pour afficher la liste des MCP Servers connectés. Si votre serveur n'y figure pas, vérifiez que le command et les args sont corrects.

Tester le serveur de manière isolée

Les MCP Servers communiquent via stdio, ce qui permet de les tester directement dans le terminal :

echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js

Si la liste des outils est renvoyée, le serveur fonctionne correctement.

Consulter les logs d'appel de Claude

Claude Code affiche les entrées et sorties de chaque appel d'outil. Si les paramètres sont incorrects, c'est généralement parce que la description de l'outil ou la définition des paramètres n'était pas assez claire, et Claude a mal interprété.

Cas pratique : intégrer Sentry pour le suivi des erreurs

Illustrons le tout avec un cas concret. Supposons que l'on souhaite intégrer Sentry à Claude Code pour qu'il puisse consulter directement les erreurs en production.

server.tool(
  "search_errors",
  "在 Sentry 中搜索最近的错误。用于排查线上问题、查看错误趋势",
  {
    query: z.string().describe("搜索关键词,如错误信息、函数名"),
    hours: z.number().optional().default(24).describe("查看最近多少小时的错误"),
  },
  async ({ query, hours }) => {
    const since = new Date(Date.now() - hours * 3600000).toISOString();
    const data = await api(
      `/api/0/projects/${ORG}/${PROJECT}/issues/?query=${encodeURIComponent(query)}&start=${since}&sort=date`
    );
    const summary = data.map((issue: any) => ({
      title: issue.title,
      count: issue.count,
      firstSeen: issue.firstSeen,
      lastSeen: issue.lastSeen,
      link: issue.permalink,
    }));
    return {
      content: [{ type: "text", text: JSON.stringify(summary, null, 2) }],
    };
  }
);

server.tool(
  "error_details",
  "查看 Sentry 中某个错误的详细信息,包括堆栈和最近一次事件",
  { issueId: z.string().describe("Sentry issue ID") },
  async ({ issueId }) => {
    const [issue, latest] = await Promise.all([
      api(`/api/0/issues/${issueId}/`),
      api(`/api/0/issues/${issueId}/events/latest/`),
    ]);
    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(
            {
              title: issue.title,
              count: issue.count,
              users: issue.userCount,
              stacktrace: latest.entries?.find(
                (e: any) => e.type === "exception"
              ),
            },
            null,
            2
          ),
        },
      ],
    };
  }
);

Une fois l'intégration en place, le diagnostic des problèmes en production se déroule ainsi :

Y a-t-il eu de nouvelles erreurs 500 ces 4 dernières heures ?

→ Claude interroge Sentry
→ Découvre 3 nouvelles issues, la plus critique affectant 120 utilisateurs
→ Récupère automatiquement la stack trace et identifie une exception de pointeur nul
→ Localise l'emplacement correspondant dans le code et propose un correctif

De la détection du problème à la localisation dans le code, l'ensemble du processus se déroule en une seule conversation.

Prochaine étape

Cet article a montré comment utiliser MCP pour intégrer des outils internes. L'idée centrale : le système interne expose une API HTTP → vous écrivez un MCP Server qui l'encapsule → Claude peut l'utiliser directement.

Tous les exemples de cet article encapsulent des APIs existantes — la plateforme de déploiement comme Sentry disposent déjà de leurs propres interfaces, et le MCP Server ne fait qu'assurer la traduction et l'adaptation. Le prochain article abordera un scénario différent : que faire lorsque la fonctionnalité dont vous avez besoin ne dispose d'aucune API, et comment construire un MCP Server de zéro en implémentant la logique, en gérant l'état et en orchestrant des interactions complexes à plusieurs étapes.