Le Model Context Protocol (MCP), créé par Anthropic et désormais sous l’égide de la Linux Foundation et de l’AAIF, est devenu le standard de facto pour connecter les agents IA à des outils externes. Un serveur MCP expose des capacités — requêtes SQL, appels API, lecture/écriture de fichiers, exécution de code — qu’un agent LLM peut invoquer de manière autonome. En développement, cette flexibilité est un accélérateur. En production, c’est une surface d’attaque.
L’attaque AgentJacking de juin 2026 a démontré qu’un agent IA compromis par injection de prompt pouvait pivoter via MCP vers des systèmes internes Sentry, affectant 2 388 organisations. L’incident Amazon Q Developer (CVE-2026-12957) a montré comment un serveur MCP mal configuré permettait le vol de credentials cloud. La sécurisation n’est plus optionnelle — c’est un prérequis de mise en production.
Ce guide détaille les 7 étapes que nous appliquons systématiquement chez D-Open lors du déploiement de serveurs MCP en production pour nos clients. Chaque étape est illustrée par du code fonctionnel et des configurations prêtes à l’emploi. Si vous cherchez un guide plus introductif, consultez d’abord notre article Sécuriser vos intégrations MCP contre les injections en 6 étapes.
Architecture de sécurité MCP en production — les 7 couches
Étape 1 : Activer l’authentification et l’autorisation OAuth 2.1
La spécification MCP 2025-06-18 intègre un framework d’authentification basé sur OAuth 2.1. En production, tout serveur MCP doit refuser les connexions non authentifiées. Cela signifie : chaque agent (ou application cliente) doit obtenir un token d’accès avant de pouvoir invoquer un outil.
La configuration repose sur trois composants : un serveur d’autorisation (Keycloak, Authelia, ou votre propre impleméntation), le serveur MCP configuré pour valider les tokens, et des scopes granulaires qui limitent les outils accessibles par chaque client.
# Configuration du serveur MCP avec authentification OAuth 2.1
# mcp-server-config.json
{
"auth": {
"type": "oauth2",
"discovery_url": "https://auth.example.com/.well-known/oauth-authorization-server",
"required_scopes": ["mcp:tools:read", "mcp:tools:execute"],
"token_validation": {
"issuer": "https://auth.example.com",
"audience": "mcp-production-server",
"algorithms": ["RS256"],
"max_token_age_seconds": 3600
},
"client_credentials": {
"allowed_grant_types": ["client_credentials", "authorization_code"],
"require_pkce": true
}
}
}Trois règles critiques : 1) Les tokens doivent avoir une durée de vie courte (1 heure maximum) avec refresh token rotatif. 2) Chaque outil MCP doit être protégé par un scope spécifique — l’outil database_query ne doit pas être accessible avec un scope file_read. 3) Implémentez la révocation immédiate : si un agent est compromis, vous devez pouvoir couper son accès en secondes, pas en heures.
Pour les équipes qui utilisent Keycloak (le choix open source le plus répandu), créez un realm dédié « mcp-production » avec des client scopes granulaires. Chaque agent LLM reçoit un client ID et un secret avec les seuls scopes dont il a besoin. Aucun client ne doit avoir le scope mcp:admin par défaut.
Étape 2 : Isoler le serveur MCP dans un sandbox
Même avec une authentification robuste, un agent légitime peut être compromis par injection de prompt — comme l’a démontré l’incident AgentJacking. Le sandbox garantit que même si un outil est invoqué de manière malveillante, les dégâts restent confinés.
La stratégie de sandboxing pour un serveur MCP repose sur trois niveaux : isolation réseau (le serveur MCP n’accède qu’aux systèmes qu’il doit atteindre), isolation de processus (Docker avec gVisor ou Kata Containers), et isolation de système de fichiers (montages read-only sauf les répertoires de travail explicitement autorisés).
# docker-compose.yml - Serveur MCP sandboxé
version: '3.8'
services:
mcp-server:
image: your-org/mcp-server:latest
runtime: runsc # gVisor pour isolation kernel
security_opt:
- seccomp:mcp-seccomp-profile.json
- apparmor:mcp-apparmor-profile
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:size=100M,noexec,nosuid
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Seule capacité nécessaire
networks:
- mcp-internal
deploy:
resources:
limits:
cpus: '2'
memory: 512M
environment:
- MCP_AUTH_DISCOVERY_URL=https://auth.internal/.well-known/oauth-authorization-server
- MCP_LOG_LEVEL=info
networks:
mcp-internal:
driver: bridge
internal: true # Pas d'accès Internet directLe point clé est internal: true sur le réseau Docker. Le serveur MCP ne doit jamais avoir d’accès Internet direct. S’il doit appeler une API externe, passez par un proxy avec une allow-list stricte de domaines autorisés. Cela empêche un outil compromis d’exfiltrer des données vers un serveur C2.
L’utilisation de gVisor (runtime: runsc) ajoute une couche d’isolation kernel — les appels système du conteneur sont interceptés par un kernel utilisateur-espace, ce qui protège contre les évasions de conteneur comme GhostLock (CVE-2026-43499).
Étape 3 : Valider et assainir toutes les entrées
Dans un serveur MCP, chaque invocation d’outil transporte des arguments fournis par l’agent LLM. Ces arguments sont du contenu non fiable — un agent victime d’injection de prompt peut transmettre des commandes malveillantes déguisées en paramètres légitimes. La validation stricte est la défense principale contre ce vecteur.
Utilisez Zod (TypeScript) ou JSON Schema pour définir le contrat de chaque outil. Rejetez tout ce qui ne correspond pas au schéma — pas de coercion, pas de valeurs par défaut silencieuses, pas de champs supplémentaires ignorés.
// Validation Zod pour un outil MCP de requête SQL
import { z } from 'zod';
const DatabaseQueryInput = z.object({
// Seul SELECT autorisé - pas de DDL, pas de DML
query: z.string()
.max(2000)
.regex(
/^SELECT\s/i,
"Seules les requêtes SELECT sont autorisées"
)
.refine(
(q) => !/(DROP|DELETE|INSERT|UPDATE|ALTER|CREATE|TRUNCATE|EXEC|UNION)/i.test(q),
"Opérations de modification interdites"
)
.refine(
(q) => !/(--|;|xp_|sp_|0x)/i.test(q),
"Patterns d'injection SQL détectés"
),
// Table autorisée via allow-list
table: z.enum([
'products', 'categories', 'public_stats'
]),
// Limite obligatoire pour éviter les scans complets
limit: z.number().int().min(1).max(100).default(20),
}).strict(); // .strict() rejette tout champ non déclaré
// Dans le handler de l'outil MCP
async function handleDatabaseQuery(rawInput: unknown) {
const result = DatabaseQueryInput.safeParse(rawInput);
if (!result.success) {
logger.warn('Validation failed', {
errors: result.error.issues,
rawInput: JSON.stringify(rawInput).slice(0, 500),
});
return { error: "Paramètres invalides" };
}
// result.data est maintenant typé et validé
return await executeQuery(result.data);
}Quatre règles de validation pour les outils MCP en production : 1) Utilisez .strict() pour rejeter les champs non déclarés — un champ supplémentaire est souvent le signe d’une injection. 2) Préférez les enum aux chaînes libres partout où c’est possible — une allow-list de tables vaut mieux qu’une regex. 3) Limitez la taille des entrées — un paramètre de 50 000 caractères est probablement une tentative d’injection. 4) Loggez les rejets de validation — ils sont souvent les premiers signaux d’une attaque.
Étape 4 : Chiffrer les transports et les données au repos
Le protocole MCP supporte deux modes de transport : stdio (pour les intégrations locales) et Streamable HTTP (pour les déploiements réseau). En production, seul le transport HTTP sur TLS 1.3 est acceptable. Le mode stdio ne doit jamais être exposé en réseau.
Configurez mTLS (mutual TLS) pour que le serveur vérifie également le certificat du client. Cela garantit que seuls les agents autorisés peuvent se connecter, même si un attaquant a obtenu l’URL du serveur.
# Configuration Caddy comme reverse proxy mTLS devant le serveur MCP
# Caddyfile
mcp.internal.example.com {
tls {
client_auth {
mode require_and_verify
trusted_ca_file /etc/caddy/ca/client-ca.pem
}
protocols tls1.3 tls1.3
ciphers TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256
}
reverse_proxy mcp-server:8080 {
header_up X-Client-CN {tls_client_subject}
header_up X-Request-ID {uuid}
}
log {
output file /var/log/caddy/mcp-access.log {
roll_size 100mb
roll_keep 30
}
format json
}
}Pour les données au repos, chiffrez les logs et les résultats d’outils stockés temporairement. Utilisez LUKS pour les volumes Docker ou le chiffrement natif du fournisseur cloud. Les données sensibles retournées par les outils MCP (résultats de requêtes, contenus de fichiers) ne doivent jamais transiter ou être stockées en clair.
Étape 5 : Appliquer le principe du moindre privilège aux outils
Chaque outil MCP doit avoir exactement les permissions nécessaires pour accomplir sa tâche — pas plus. Ce principe, trivial en théorie, est systématiquement négligé dans les déploiements MCP que nous auditons. Le schéma typique : un outil database_query qui a les droits d’écriture sur toute la base, un outil file_read qui peut lire n’importe quel chemin du système.
La solution est une policy-as-code qui définit explicitement ce que chaque outil peut et ne peut pas faire. Nous utilisons un fichier de politique JSON qui est chargé au démarrage du serveur MCP et appliqué avant chaque invocation d’outil.
// mcp-tool-policies.json
{
"tools": {
"database_query": {
"allowed_operations": ["SELECT"],
"allowed_tables": ["products", "categories", "public_stats"],
"max_rows": 100,
"timeout_ms": 5000,
"db_user": "mcp_readonly" // Utilisateur DB read-only dédié
},
"file_read": {
"allowed_paths": ["/app/data/public/", "/app/config/"],
"denied_patterns": ["*.env", "*.key", "*.pem", "*.secret"],
"max_file_size_bytes": 1048576 // 1 MB
},
"api_call": {
"allowed_domains": ["api.internal.example.com"],
"allowed_methods": ["GET"],
"rate_limit": { "requests_per_minute": 30 },
"timeout_ms": 10000
}
},
"default_policy": "deny" // Tout outil non listé est interdit
}Le "default_policy": "deny" est la règle la plus importante. Si un nouvel outil est ajouté au serveur MCP sans politique explicite, il est bloqué par défaut. C’est le contraire du comportement par défaut de la plupart des frameworks MCP, qui autorisent tout outil déclaré. Ce renversement de la politique par défaut est la leçon directe de l’incident Amazon Q Developer.
Étape 6 : Mettre en place le monitoring et l’audit
Un serveur MCP en production sans monitoring est un angle mort. Chaque invocation d’outil doit être loggée avec un contexte suffisant pour reconstruire une attaque a posteriori : l’identité de l’agent appelant, l’outil invoqué, les arguments (tronqués pour éviter de logger des données sensibles), le résultat, et la durée d’exécution.
// Middleware de logging pour serveur MCP
function mcpAuditMiddleware(toolName: string, input: unknown, context: AuthContext) {
const startTime = performance.now();
const requestId = crypto.randomUUID();
// Log structuré de l'invocation
logger.info({
event: 'mcp.tool.invocation',
requestId,
tool: toolName,
clientId: context.clientId,
scopes: context.scopes,
inputSummary: summarizeInput(input, 200), // Tronquer à 200 chars
timestamp: new Date().toISOString(),
});
return {
requestId,
onComplete: (result: unknown, error?: Error) => {
const duration = performance.now() - startTime;
logger.info({
event: error ? 'mcp.tool.error' : 'mcp.tool.success',
requestId,
tool: toolName,
durationMs: Math.round(duration),
resultSize: JSON.stringify(result ?? '').length,
error: error?.message,
});
// Alertes automatiques
if (duration > 10000) alertSlack(`MCP tool ${toolName} slow: ${duration}ms`);
if (error) metrics.increment('mcp.tool.errors', { tool: toolName });
},
};
}Exposez les métriques vers Prometheus et créez des alertes Grafana pour les anomalies. Cinq métriques essentielles à surveiller : 1) Taux d’échec de validation (pic = probable injection). 2) Nombre d’invocations par client par minute (détection de bruteforce). 3) Durée d’exécution des outils (latence anormale = charge ou exploitation). 4) Taille des réponses (exfiltration massive). 5) Requêtes refusées par le middleware d’autorisation.
Pour les équipes françaises soumises à NIS2, ces logs constituent les preuves d’audit nécessaires en cas de notification d’incident. Conservez-les au minimum 12 mois, chiffrés au repos, avec contrôle d’accès strict.
Pipeline de monitoring MCP — De l’invocation à l’alerte
Étape 7 : Planifier les mises à jour et la réponse aux incidents
Un serveur MCP sécurisé n’est pas un état — c’est un processus. Le protocole MCP évolue rapidement (la spécification a reçu trois mises à jour majeures au premier semestre 2026), les CVE affectant les dépendances du serveur sont fréquentes, et les techniques d’injection de prompt se perfectionnent continuellement.
Mettez en place trois processus récurrents :
- Patch Tuesday MCP : chaque mardi, vérifiez les mises à jour du SDK MCP, des dépendances du serveur et des images Docker. Appliquez les patches dans un environnement de staging, testez les outils, puis déployez en production.
- Rotation des secrets : tous les 30 jours, faites tourner les clés de chiffrement, les certificats mTLS, les identifiants de base de données du serveur MCP et les tokens d’accès des clients. Automatisez avec HashiCorp Vault ou AWS Secrets Manager.
- Plan de réponse aux incidents MCP : documentez la procédure en cas de compromission d’un agent, d’injection de prompt réussie ou de fuite de données via un outil. Le plan doit inclure : révocation immédiate du token de l’agent, kill switch pour désactiver l’outil compromis, notification ANSSI si applicable (NIS2).
# Script de rotation automatique des secrets MCP
#!/bin/bash
set -euo pipefail
echo "=== Rotation des secrets MCP - $(date -I) ==="
# 1. Générer nouveaux certificats mTLS
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-384 \
-keyout /etc/mcp/tls/new-server.key \
-out /etc/mcp/tls/new-server.crt \
-days 30 -nodes -subj "/CN=mcp.internal"
# 2. Mettre à jour le secret Kubernetes
kubectl create secret tls mcp-tls \
--cert=/etc/mcp/tls/new-server.crt \
--key=/etc/mcp/tls/new-server.key \
--dry-run=client -o yaml | kubectl apply -f -
# 3. Redémarrer le serveur MCP (rolling restart)
kubectl rollout restart deployment/mcp-server -n production
# 4. Révoquer les anciens tokens OAuth
curl -X POST https://auth.internal/admin/realms/mcp-production/clients \
-H "Authorization: Bearer ${KEYCLOAK_ADMIN_TOKEN}" \
-d '{"action": "revoke-all-sessions"}'
# 5. Vérifier la santé post-rotation
sleep 30
kubectl get pods -n production -l app=mcp-server
curl -sf https://mcp.internal/health || echo "ERREUR: santé MCP KO"
echo "=== Rotation terminée ==="
Le kill switch mérite une attention particulière. Implémentez un endpoint d’administration /admin/tools/disable qui permet de désactiver un outil spécifique en temps réel, sans redémarrer le serveur. En cas d’injection de prompt active, vous devez pouvoir couper l’outil exploité en secondes. C’est la différence entre un incident contenu et une brèche complète.
Conclusion : la sécurité MCP est un avantage compétitif
Ces 7 étapes construisent une architecture de sécurité MCP qui résiste aux attaques documentées de 2026 : injection de prompt via AgentJacking, vol de credentials via Amazon Q Developer, et pivotement latéral via outils mal isolés. Le coût d’implémentation est de 2 à 3 jours. Le coût d’un incident MCP non contenu se mesure en semaines de remédiation et en confiance client perdue.
Pour les équipes qui déploient des agents IA en production, la sécurité du serveur MCP n’est pas un coût supplémentaire — c’est un avantage compétitif. Les clients (et les régulateurs) demandent des garanties. NIS2 exige la documentation de la chaîne de traitement. Le cadre CISA sur la sécurité open source recommande explicitement le sandboxing des composants tiers. Ces 7 étapes transforment votre déploiement MCP en référence auditable.
Pour aller plus loin, consultez notre guide sur la sécurisation des intégrations MCP contre les injections, notre analyse de l’incident AgentJacking sur Sentry, et notre article sur la contribution aux serveurs MCP open source.
Déployez votre serveur MCP en production en toute sécurité
Nos architectes sécurité configurent l’ensemble du stack MCP en production : authentification OAuth 2.1, sandboxing gVisor, validation Zod, mTLS, monitoring Prometheus/Grafana, plan de réponse aux incidents.
Sécuriser mon serveur MCPQuestions fréquentes
Qu’est-ce que le protocole MCP et pourquoi le sécuriser ?
Le Model Context Protocol (MCP), créé par Anthropic et désormais sous la Linux Foundation, est un standard ouvert qui permet aux agents IA d’interagir avec des outils externes : bases de données, API, systèmes de fichiers, registres de conteneurs. En production, un serveur MCP expose des capacités critiques à des agents dont le comportement n’est pas entièrement prévisible (en raison des injections de prompt). Sans sécurisation, un attaquant peut exploiter un agent pour exécuter des commandes arbitraires, exfiltrer des données sensibles, ou pivoter latéralement dans l’infrastructure.
Le MCP supporte-t-il nativement l’authentification ?
Oui. La spécification MCP 2025-06-18 intègre un framework d’authentification complet basé sur OAuth 2.1. Les serveurs MCP exposent un endpoint de découverte /.well-known/oauth-authorization-server pour la négociation automatique entre client et serveur. En production, il faut configurer des scopes granulaires (un scope par outil), des tokens à durée de vie courte (1 heure max), PKCE obligatoire pour les clients publics, et un mécanisme de révocation immédiate. Les implémentations open source comme @modelcontextprotocol/sdk intègrent ce framework nativement.
Comment protéger un serveur MCP contre les injections de prompt ?
Trois défenses complémentaires : 1) Validez les entrées avec des schémas Zod ou JSON Schema stricts — rejetez tout ce qui ne correspond pas au type attendu, et utilisez .strict() pour bloquer les champs non déclarés. 2) Sandboxez les outils dans des conteneurs gVisor pour que même en cas d’injection réussie, l’impact soit confiné au conteneur. 3) Loggez toutes les invocations et créez des alertes sur les anomalies (pics de rejets de validation, patterns d’entrées inhabituels). L’attaque AgentJacking de juin 2026 a démontré qu’un agent compromis pouvait pivoter via MCP vers des systèmes internes Sentry — le sandboxing aurait limité l’impact.
Quel est le coût de mise en place de ces 7 étapes ?
Comptez 2 à 3 jours pour un développeur sécurité expérimenté. Les étapes 1 (authentification OAuth) et 2 (sandboxing) représentent environ 60 % du travail initial. Les étapes 3 à 5 (validation, chiffrement, moindre privilège) prennent une demi-journée chacune. Les étapes 6 et 7 (monitoring et processus de mise à jour) nécessitent 2-3 heures de configuration initiale. Tous les outils sont gratuits et open source : Keycloak ou Authelia pour l’auth, Docker/gVisor pour le sandboxing, Prometheus/Grafana pour le monitoring. Le coût opérationnel est minimal — 10 à 15 minutes de maintenance par semaine une fois la configuration en place.
Articles similaires
AgentJacking : attaque via MCP sur Sentry
Comment un agent IA compromis a pivoté vers 2 388 organisations via le protocole MCP.
Sécuriser les intégrations MCP
6 étapes pour protéger vos intégrations MCP contre les injections de prompt.
Contribuer à un serveur MCP open source
Guide en 7 étapes pour contribuer efficacement aux serveurs MCP de la communauté.
Sources
- • MCP Specification 2025-06-18 — Model Context Protocol, Authentication Framework
- • Linux Foundation — Agentic AI Foundation (AAIF), MCP governance (mai 2026)
- • Sygnia — AgentJacking : exploitation d’agents IA via MCP (juin 2026)
- • Amazon Web Services — CVE-2026-12957 Amazon Q Developer, credential theft via MCP
- • ANSSI — Recommandations de sécurité pour les systèmes d’IA en production (2026)
- • CISA — Open Source Security Principles & Practices (août 2026)
- • gVisor — Documentation officielle, sandboxing de conteneurs
- • Keycloak — OAuth 2.1, PKCE, token revocation