Aller au contenu
Guide

Sécurisez votre serveur MCP : une liste de contrôle pour les développeurs en 8 points

| 8 min read

43 frameworks d'agents livrés avec des vulnérabilités intégrées en 2026. Huit vérifications pour verrouiller votre serveur MCP avant qu'un agent IA ne trouve les lacunes.

Server room with colorful network cables representing MCP server infrastructure
Photo by Taylor Vick on Unsplash

En novembre 2026, Barracuda a signalé que 43 composants du framework d'agent étaient livrés avec des vulnérabilités intégrées. par le biais d’un compromis dans la chaîne d’approvisionnement. Les attaquants n'ont pas pénétré dans les serveurs. Ils ont empoisonné les outils que les agents d'IA appeler. Le Top 10 des applications agentiques de l'OWASP répertorie désormais les vulnérabilités de la chaîne d'approvisionnement et l'utilisation abusive des outils comme étant dédiées. catégories.

Les serveurs MCP (Model Context Protocol) exposent vos API comme des outils appelables pour les assistants IA : Claude Desktop, Curseur, VS Code Copilot, Windsurf. Chaque outil que vous enregistrez devient une surface d'attaque. Et la plupart des serveurs MCP livré sans authentification, sans validation d’entrée et sans journalisation.

Cet article est une liste de contrôle en 8 points pour sécuriser votre serveur MCP. Chaque élément comprend un code de travail que vous pouvez s'adapter. Les exemples utilisent le API Botoi pour la validation du schéma, le hachage, et décodage JWT, mais les modèles s'appliquent à n'importe quel serveur MCP.

Le problème de sécurité MCP dans une table

Risque Ce qui se produit Élément de la liste de contrôle
Aucune authentification sur le point de terminaison MCP N'importe quel client sur le réseau appelle n'importe quel outil #1 Ajouter une authentification
Tous les outils exposés à toutes les clés Un agent de surveillance en lecture seule déclenche des opérations destructrices #2 Outils de portée par clé
Aucune validation d'entrée Les agents envoient du JSON mal formé ; les outils plantent ou exécutent des opérations involontaires #3 Valider avec Zod
Annotations d'outils manquantes Les agents ne peuvent pas distinguer les outils en lecture seule des outils destructeurs #4 Définir des annotations
Aucune limite de taux Un agent de bouclage épuise votre quota d'API en quelques minutes #5 Limite de taux par agent
Aucune piste d'audit Vous ne pouvez pas déterminer quel agent a causé un problème de production #6 Journaliser les appels
Falsification du manifeste de l'outil L'attaquant modifie les définitions des outils pour rediriger les appels #7 Manifestes d'épingles et de hachage
Aucune confirmation pour les écritures L'agent crée, supprime ou modifie des données sans examen humain #8 Opérations destructrices du bac à sable

1. Ajoutez l'authentification à votre point de terminaison MCP

"C'est sur localhost" n'est pas un modèle de sécurité. Extensions de navigateur, processus locaux et tout code exécuté sur la même machine peut atteindre localhost:3000. Le MCP distant connaît une croissance rapide ; Claude Desktop, Curseur, et Windsurf prennent tous en charge la connexion à des serveurs MCP distants via HTTPS.

Exigez un jeton Bearer à chaque demande. Le serveur MCP de Botoi sur api.botoi.com/mcp accepte l'API clés via le Authorization en-tête. Sans clé valide, vous obtenez 5 requêtes par minute en rafale et 100 par jour ; avec un, les limites s'adaptent à votre plan.

Si vos agents transmettent des JWT au lieu de clés statiques, décodez-les pour en extraire les portées et l'identité. Voici comment pour inspecter un JWT à partir d'un en-tête de requête MCP :

curl -s -X POST https://api.botoi.com/v1/jwt/decode \\
  -H "Content-Type: application/json" \\
  -d '{
    "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZ2VudC1jdXJzb3ItNDIiLCJzY29wZSI6InJlYWQ6ZG5zIHJlYWQ6c3NsIiwiaWF0IjoxNzE3MDAwMDAwfQ.signature"
  }'
{
  "success": true,
  "data": {
    "header": { "alg": "RS256", "typ": "JWT" },
    "payload": {
      "sub": "agent-cursor-42",
      "scope": "read:dns read:ssl",
      "iat": 1717000000
    },
    "signature": "signature"
  }
}

La sub la revendication identifie l'agent. Le scope la revendication répertorie les outils qu'elle peut accès. Vérifiez la signature côté serveur avant de faire confiance à ces valeurs.

2. Outils de portée par clé API

Tous les agents n’ont pas besoin de tous les outils. Un agent de surveillance qui vérifie les enregistrements DNS ne doit jamais accéder à un point final de création de collage. Créez des listes autorisées qui mappent chaque clé API à un ensemble spécifique d'outils.

// Scope tools per API key using an allowlist
interface AgentPermissions {
  allowedTools: Set<string>;
  maxBurst: number;
  dailyLimit: number;
}

const AGENT_PERMISSIONS: Record<string, AgentPermissions> = {
  "key_readonly_monitor": {
    allowedTools: new Set(["lookup_dns", "lookup_ssl", "lookup_ip"]),
    maxBurst: 10,
    dailyLimit: 500,
  },
  "key_full_access": {
    allowedTools: new Set(["*"]),  // wildcard for all tools
    maxBurst: 30,
    dailyLimit: 5000,
  },
};

function canUseTool(apiKey: string, toolName: string): boolean {
  const perms = AGENT_PERMISSIONS[apiKey];
  if (!perms) return false;
  if (perms.allowedTools.has("*")) return true;
  return perms.allowedTools.has(toolName);
}

Le serveur MCP de Botoi expose 49 outils sélectionnés à partir de plus de 150 points de terminaison d'API. La curation elle-même est une forme de cadrage : seuls les outils pertinents pour les assistants IA sont enregistrés. Votre serveur devrait faire de même.

3. Validez les entrées de l'outil avec les schémas Zod

Les outils MCP acceptent le JSON arbitraire des agents. Un agent peut envoyer où tu attendez une chaîne ou incluez des champs que votre outil ne reconnaît pas. Validez chaque entrée avant de l’exécuter.

Le serveur MCP de Botoi convertit les définitions de chemin OpenAPI en schémas Zod au démarrage en utilisant schema-builder.ts. La buildZodSchema la fonction lit votre spécification OpenAPI, cartographie chaque type de propriété en un type Zod et marque les champs obligatoires :

import { z } from "zod";
import { buildZodSchema } from "./schema-builder";

// Build a Zod schema from your OpenAPI spec for each tool
const dnsSchema = z.object(buildZodSchema("/v1/dns/lookup", "post"));

function validateToolInput(toolName: string, input: unknown) {
  const schemas: Record<string, z.ZodTypeAny> = {
    lookup_dns: dnsSchema,
    // ... one schema per tool
  };

  const schema = schemas[toolName];
  if (!schema) {
    throw new Error(\`Unknown tool: \${toolName}\`);
  }

  const result = schema.safeParse(input);
  if (!result.success) {
    return {
      error: "Invalid input",
      issues: result.error.issues.map((i) => ({
        path: i.path.join("."),
        message: i.message,
      })),
    };
  }

  return { data: result.data };
}

Générer des schémas Zod à partir d'exemples d'entrées

Si vous n'avez pas de spécification OpenAPI, générez des schémas Zod à partir d'exemples d'entrées d'outils :

curl -s -X POST https://api.botoi.com/v1/schema/json-to-zod \\
  -H "Content-Type: application/json" \\
  -d '{
    "json": {
      "domain": "github.com",
      "check_mx": true,
      "timeout_ms": 5000
    }
  }'
{
  "success": true,
  "data": {
    "schema": "z.object({ domain: z.string(), check_mx: z.boolean(), timeout_ms: z.number() })"
  }
}

Valider les entrées par rapport au schéma JSON au moment de l'exécution

Pour la validation d'exécution sans Zod, utilisez le schéma JSON. Envoyer le schéma et les entrées de l'agent à /v1/schema/validate:

curl -s -X POST https://api.botoi.com/v1/schema/validate \\
  -H "Content-Type: application/json" \\
  -d '{
    "schema": {
      "type": "object",
      "required": ["domain"],
      "properties": {
        "domain": { "type": "string", "minLength": 1 },
        "record_type": { "type": "string", "enum": ["A", "AAAA", "MX", "TXT", "CNAME", "NS"] }
      },
      "additionalProperties": false
    },
    "data": { "domain": "stripe.com", "record_type": "MX" }
  }'

Une entrée valide renvoie :

{
  "success": true,
  "data": {
    "valid": true,
    "errors": []
  }
}

Si un agent passe "record_type": "INVALID", vous obtenez des erreurs exploitables avant l'exécution de votre outil :

{
  "success": true,
  "data": {
    "valid": false,
    "errors": [
      {
        "path": "/record_type",
        "message": "must be equal to one of the allowed values"
      }
    ]
  }
}

4. Définir les annotations des outils

Le protocole MCP définit quatre conseils d'annotation : readOnlyHint, destructiveHint, idempotentHint, et openWorldHint. Ceux-ci indiquent aux agents si un outil lit des données, modifie l'état, peut réessayer en toute sécurité ou contacte des services externes. La plupart des serveurs MCP les ignorent.

Le serveur MCP de Botoi annote les 49 outils. Voici à quoi cela ressemble en pratique :

// curated-tools.ts (from Botoi's MCP server)
export const CURATED_TOOLS: Record<string, CuratedTool> = {
  lookup_dns: {
    path: "/v1/dns/lookup",
    method: "post",
    title: "DNS Lookup",
    description: "Query DNS records for a domain.",
    annotations: {
      readOnlyHint: true,   // reads data, changes nothing
      openWorldHint: true,  // contacts external DNS servers
    },
  },
  storage_paste_create: {
    path: "/v1/paste/create",
    method: "post",
    title: "Create Paste",
    description: "Store text content and return a short URL.",
    annotations: {
      destructiveHint: true,  // creates new data
      idempotentHint: false,  // each call creates a new paste
    },
  },
};

Les agents qui respectent les annotations éviteront d'appeler des outils destructeurs sans confirmation et préféreront outils idempotents lors de la nouvelle tentative de requêtes ayant échoué. Placez-les sur chaque outil.

Annotation Signification Exemple
readOnlyHint: true L'outil lit les données, ne change rien Recherche DNS, vérification SSL, géolocalisation IP
destructiveHint: true L'outil crée, met à jour ou supprime des données Créer un collage, générer une URL courte, envoyer un webhook
idempotentHint: true Appelez plusieurs fois en toute sécurité avec la même entrée Génération de hachage, formatage JSON, conversion d'unités
openWorldHint: true L'outil contacte les services externes DNS sur HTTPS, WHOIS, extraction de métadonnées d'URL

5. Limite de débit par identité d'agent

Un agent malveillant coincé dans une boucle de nouvelle tentative ne devrait pas épuiser la totalité de votre quota d'API. Limitation de débit standard par adresse IP ne suffit pas ; plusieurs agents peuvent partager la même adresse IP et un seul agent peut alterner les adresses IP.

Extrayez l'identité de l'agent de la clé API ou du JWT, puis appliquez des limites par identité à l'aide d'une fenêtre coulissante ou un compartiment de jetons stocké dans KV :

// Hono middleware for per-agent rate limiting
import type { Context, Next } from "hono";

const BURST_LIMIT = 5;   // requests per minute
const DAILY_LIMIT = 100;  // requests per day

async function rateLimitAgent(c: Context, next: Next) {
  // Extract agent identity from API key or JWT
  const apiKey = c.req.header("Authorization")?.replace("Bearer ", "");
  const agentId = apiKey || c.req.header("X-Forwarded-For") || "anonymous";

  // Check burst limit (sliding window in KV)
  const burstKey = \`rate:\${agentId}:burst\

Le middleware d'authentification de Botoi applique deux couches : une limite de rafale (5 requêtes par minute) et un plafond quotidien. (100 requêtes par jour) pour un accès anonyme. Les clés authentifiées bénéficient de limites plus élevées en fonction de leur Niveau d'abonnement Stripe. Appliquez le même modèle à deux couches à votre serveur MCP.

6. Enregistrez chaque appel d'outil avec attribution d'agent

Lorsque quelque chose ne va pas dans la production, vous devez répondre à trois questions : quel agent a appelé quel outil, quand et avec quelle contribution. Sans journaux d'appel, vous déboguez à l'aveugle.

Hachez l'entrée au lieu de stocker les arguments bruts. Cela vous donne suffisamment de corrélation et de déduplication sans enregistrer de données sensibles :

// Log every tool invocation with agent identity
interface ToolInvocationLog {
  timestamp: string;
  agent_id: string;
  tool_name: string;
  input_hash: string;   // SHA-256 of the input (not the raw input)
  duration_ms: number;
  status: "success" | "error";
}

async function logToolInvocation(
  agentId: string,
  toolName: string,
  input: unknown,
  startTime: number,
  status: "success" | "error"
) {
  const inputStr = JSON.stringify(input);
  const inputHash = await crypto.subtle.digest(
    "SHA-256",
    new TextEncoder().encode(inputStr)
  );
  const hashHex = Array.from(new Uint8Array(inputHash))
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");

  const log: ToolInvocationLog = {
    timestamp: new Date().toISOString(),
    agent_id: agentId,
    tool_name: toolName,
    input_hash: hashHex,
    duration_ms: Date.now() - startTime,
    status,
  };

  // Send to your logging pipeline (Datadog, Loki, Cloudflare Logpush)
  console.log(JSON.stringify(log));
}

Envoyez ces journaux structurés à votre pipeline existant (Datadog, Grafana Loki, Cloudflare Logpush). Créez des alertes pour les modèles inhabituels : un seul agent effectuant 10 fois son volume d'appels normal, ou un message en lecture seule agent essayant d'appeler des outils destructeurs.

7. Épingler les définitions d’outils et vérifier l’intégrité

Le rapport Barracuda a révélé que des attaquants injectaient des définitions d'outils malveillants dans les infrastructures d'agents via dépendances compromises. Si quelqu'un modifie le manifeste de votre outil MCP (noms, descriptions ou paramètres schémas), les agents appelleront des outils avec un comportement différent de celui souhaité.

Hachez le manifeste de votre outil au moment de la construction. Au démarrage, recalculez le hachage et comparez :

import crypto from "node:crypto";
import Botoi from "@botoi/sdk";

const botoi = new Botoi();

// Your tool manifest (the source of truth)
const tools = [
  { name: "dns_lookup", path: "/v1/dns/lookup" },
  { name: "ip_lookup", path: "/v1/ip/lookup" },
  { name: "email_validate", path: "/v1/email/validate" },
  // ... all your tools
];

const manifest = JSON.stringify(tools);

// Hash it at build time and store the expected hash
const EXPECTED_HASH = "a3f2b8c1d4e5f6..."; // from your CI build

// At startup, verify integrity
function verifyManifestIntegrity() {
  const currentHash = crypto
    .createHash("sha256")
    .update(manifest)
    .digest("hex");

  if (currentHash !== EXPECTED_HASH) {
    throw new Error(
      \`Tool manifest tampered. Expected \${EXPECTED_HASH}, got \${currentHash}\`
    );
  }

  console.log("Tool manifest integrity verified.");
}

// Or use the Botoi API for environments without Node crypto
async function verifyWithApi() {
  const result = await botoi.hash.sha256({ input: manifest });
  if (result.data.hash !== EXPECTED_HASH) {
    throw new Error("Tool manifest tampered.");
  }
}

Générez le hachage avec l'API Botoi

Pour les environnements CI ou les environnements d'exécution Edge sans node:crypto:

curl -s -X POST https://api.botoi.com/v1/hash \\
  -H "Content-Type: application/json" \\
  -d '{
    "text": "[{\\"name\\":\\"dns_lookup\\",\\"path\\":\\"/v1/dns/lookup\\"},{\\"name\\":\\"ip_lookup\\",\\"path\\":\\"/v1/ip/lookup\\"}]",
    "algorithm": "sha256"
  }'
{
  "success": true,
  "data": {
    "hash": "a3f2b8c1d4e5f67890abcdef1234567890abcdef1234567890abcdef12345678",
    "algorithm": "sha256"
  }
}

Stockez le hachage attendu en tant que variable d'environnement. Comparez-le au moment du déploiement. Si les hachages divergent, bloquer le déploiement.

8. Opérations destructrices du bac à sable

Les outils qui écrivent des données, déclenchent des effets secondaires ou contactent des services externes nécessitent un flux de confirmation. Ne laissez pas un agent créer 1 000 collages ou lancer des webhooks sans examen humain.

// Confirmation flow for destructive MCP tools
interface ToolResult {
  content: Array<{ type: string; text: string }>;
  isError?: boolean;
}

function handleDestructiveTool(
  toolName: string,
  input: Record<string, unknown>,
  confirmed: boolean
): ToolResult {
  const destructiveTools = new Set([
    "paste_create",
    "short_url_create",
    "webhook_inbox_create",
  ]);

  if (!destructiveTools.has(toolName)) {
    // Non-destructive: execute immediately
    return executeTool(toolName, input);
  }

  if (!confirmed) {
    // Return a preview instead of executing
    return {
      content: [{
        type: "text",
        text: JSON.stringify({
          action: "confirmation_required",
          tool: toolName,
          input,
          message: \`This tool will create new data. Pass "confirmed": true to proceed.\`,
        }),
      }],
    };
  }

  // Confirmed: execute the destructive operation
  return executeTool(toolName, input);
}

Le schéma est simple : les outils destructeurs renvoient un aperçu au premier appel. L'agent montre l'aperçu à l'utilisateur. Ce n'est qu'après confirmation de l'utilisateur que l'agent envoie un deuxième appel avec "confirmed": true.

Pour les outils qui contactent des services externes (openWorldHint: true), pensez à ajouter un timeout et un disjoncteur. Si une API externe est lente ou en panne, votre serveur MCP ne devrait pas accrocher éternellement en attendant une réponse.

Comment le serveur MCP de Botoi applique ces vérifications

Le serveur MCP de Botoi sur api.botoi.com/mcp sert de référence de travail pour cela liste de contrôle. Voici comment chaque élément est mappé :

Élément de la liste de contrôle Comment Botoi fait
Authentification Clés API via Authorization en-tête ; accès anonyme avec des limites de débit strictes
Cadrage des outils 49 outils sélectionnés à partir de plus de 150 points de terminaison ; seuls les outils appropriés à l'agent sont enregistrés
Validation des entrées schema-builder.ts convertit les schémas OpenAPI en Zod ; valide avant exécution
Annotations d'outils Chaque outil dans curated-tools.ts a readOnlyHint, destructiveHint, etc.
Limitation du débit 5 req/min en rafale + 100 req/jour plafond anonyme via KV ; limites plus élevées par niveau de clé API
Enregistrement Journaux d'observabilité Cloudflare Workers pour chaque demande avec attribution d'agent
Intégrité manifeste Les définitions d'outils sont en TypeScript contrôlé en version ; déployé via CI sans mutation d'exécution
Bac à sable destructeur Les outils de stockage (coller, URL courte, webhook) sont distincts des outils de recherche en lecture seule ; les annotations signalent un risque

Vous pouvez vous connecter au serveur MCP de Botoi depuis Claude Desktop, Claude Code, Cursor, VS Code ou Windsurf. Le Page de configuration MCP a la configuration pour chaque client.

Liste de contrôle de sécurité de votre serveur MCP

Voici la liste de contrôle complète, condensée. Imprimez-le, épinglez-le ou collez-le dans le runbook de votre équipe :

  • Exiger une authentification sur chaque point de terminaison MCP (jeton Bearer, clé API ou JWT)
  • Mappez chaque clé API à une liste blanche d'outils autorisés
  • Validez chaque entrée d'outil avec les schémas Zod ou JSON avant l'exécution
  • Annotez chaque outil avec readOnlyHint, destructiveHint, idempotentHint, et openWorldHint
  • Limite de débit par identité d'agent, et non par IP ; utilisez à la fois des capsules éclatées et quotidiennes
  • Enregistrez chaque appel d'outil avec l'ID d'agent, le nom de l'outil, le hachage d'entrée, la durée et l'état.
  • Hachez le manifeste de votre outil au moment de la construction ; vérifier au démarrage et bloquer les déploiements falsifiés
  • Renvoyez les aperçus des outils destructeurs ; exiger une confirmation explicite avant d'exécuter

43 frameworks d'agents livrés avec des vulnérabilités intégrées en 2026. Les serveurs MCP sont la prochaine cible. Les huit vérifications ci-dessus ne rendront pas votre serveur invulnérable, mais elles combleront les lacunes que les attaquants peuvent exploiter. exploitez en premier : les points de terminaison ouverts, les entrées non validées et les invocations invisibles.

FAQ

Les serveurs MCP ont-ils besoin d'une authentification ?
Oui. La plupart des serveurs MCP sont livrés sans authentification, ce qui signifie que tout client qui atteint le point final peut appeler n'importe quel outil. À mesure que l'adoption du MCP à distance se développe, vous avez besoin d'une clé API ou d'une authentification basée sur JWT sur chaque point de terminaison. Localhost uniquement n'est pas une garantie de sécurité ; les processus locaux et les extensions de navigateur peuvent également atteindre localhost.
Que sont les annotations de l’outil MCP et pourquoi sont-elles importantes ?
Les annotations d'outils sont des indications de métadonnées définies dans le protocole MCP : readOnlyHint, destructiveHint, idempotentHint et openWorldHint. Ils indiquent aux agents IA si un outil lit des données, modifie son état, peut réessayer en toute sécurité ou contacte des services externes. Les agents utilisent ces conseils pour prendre des décisions plus sûres quant aux outils à appeler et dans quel ordre.
Comment puis-je limiter le débit des agents IA appelant mon serveur MCP ?
Attribuez à chaque agent (ou clé API) une identité et appliquez des limites de débit par identité. Utilisez un algorithme de compartiment à jetons ou de fenêtre coulissante. Suivez les demandes dans un magasin KV ou Redis. Le propre serveur MCP de Botoi applique 5 requêtes par minute et 100 requêtes par jour pour un accès anonyme, avec des limites plus élevées pour les clés authentifiées.
Puis-je valider les entrées de l'outil MCP avec Zod ?
Oui. Les outils MCP reçoivent du JSON arbitraire des agents. Définissez un schéma Zod pour la forme d'entrée attendue de chaque outil et validez avant de l'exécuter. Vous pouvez générer des schémas Zod à partir d'un exemple JSON à l'aide du point de terminaison Botoi /v1/schema/json-to-zod, ou convertir les définitions de chemin OpenAPI en objets Zod comme le fait schema-builder.ts de Botoi.
Comment puis-je détecter toute falsification du manifeste de mon outil MCP ?
Hachez votre manifeste d'outil avec SHA-256 et stockez le hachage. Avant chaque démarrage ou déploiement de serveur, recalculez le hachage et comparez. Si les hachages diffèrent, quelqu'un (ou quelque chose) a modifié les définitions de vos outils. Vous pouvez calculer les hachages SHA-256 via le point de terminaison Botoi /v1/hash ou avec des bibliothèques de chiffrement natives.

Commencez a construire avec botoi

150+ endpoints API pour la recherche, le traitement de texte, la generation d'images et les utilitaires pour developpeurs. Offre gratuite, sans carte bancaire.