Sécuriser ses clés API MCP dans Claude Code (et pourquoi c'est urgent)
- Publié le
- ·6 min de lecture
Ouvrez votre mcp.json. Regardez bien.
Il y a quelques jours, en rédigeant un article sur ma config Claude Code, je me suis arrêté net. J'avais sous les yeux mon ~/.claude/mcp.json, prêt à le coller dans un bloc de code pour l'article. Et là, mes clés API. En clair. Dans un fichier JSON qui traîne sur ma machine depuis des mois.
Genre, littéralement ça :
{
"mcpServers": {
"mon-serveur": {
"command": "npx",
"args": ["-y", "mon-mcp-server@latest"],
"env": {
"API_KEY": "sk-1234567890abcdef..."
}
}
}
}
Des clés API en clair. Pas chiffrées. Pas dans un vault. Juste... là.
J'ai failli publier ça.
Pourquoi c'est pas juste "bof, c'est local"
On pourrait se dire : c'est sur ma machine, c'est pas grave. Sauf que non. En février 2026, deux CVE sont tombées sur Claude Code (CVE-2025-59536 et CVE-2026-21852). La seconde, c'était vicieux : un repo malveillant pouvait overrider ANTHROPIC_BASE_URL dans les settings projet et rediriger tout le trafic API vers un serveur tiers. Vos clés, aspirées en silence. Corrigé depuis la v2.0.65, mais quand même - ça calme.
Et y a pas besoin d'une CVE pour se faire avoir. Un git add . un peu trop enthousiaste et votre mcp.json finit sur GitHub. Ou un collègue qui jette un oeil à votre config pour "s'inspirer". Ou un script npm douteux qui scanne ~/.claude/. Une clé API leakée, c'est parfois des centaines d'euros de conso frauduleuse avant que vous remarquiez quoi que ce soit. J'ai vu passer des threads sur Reddit avec des factures à 400$ parce qu'une clé OpenAI traînait dans un dotfile.
Bref. On va régler ça.
L'interpolation ${VAR} : la feature que personne utilise
Claude Code supporte une syntaxe toute simple dans mcp.json : les variables d'environnement entre ${}. Au lieu de coller la clé en dur, on met une référence :
{
"mcpServers": {
"mon-serveur": {
"command": "npx",
"args": ["-y", "mon-mcp-server@latest"],
"env": {
"API_KEY": "${MON_SERVEUR_API_KEY}"
}
}
}
}
Au lancement du serveur MCP, Claude Code remplace ${MON_SERVEUR_API_KEY} par la vraie valeur depuis l'environnement. Le fichier JSON reste propre. Pas de secret dedans.
C'est dispo depuis un moment, mais je l'avais jamais mis en place. La flemme, probablement. Quinze minutes de boulot et j'aurais pu dormir tranquille depuis des mois.
Comment j'ai fait (en 4 étapes)
Étape 1 : un fichier secrets avec les bonnes permissions
Toutes les clés dans un seul fichier, verrouillé :
# Créer le fichier
cat > ~/.env.claude << 'EOF'
# API keys pour MCP servers Claude Code
MON_SERVEUR_API_KEY="sk-1234567890abcdef"
AUTRE_SERVICE_TOKEN="token_ici"
SERVICE_EMAIL="mon@email.com"
EOF
# Permissions : lecture/écriture uniquement pour le propriétaire
chmod 600 ~/.env.claude
Le chmod 600, c'est pas optionnel. Sans ça, n'importe quel process sur votre machine peut lire le fichier. Avec, seul votre utilisateur y a accès.
Étape 2 : charger les variables au démarrage du shell
Les variables doivent exister dans l'environnement avant que Claude Code démarre. Du coup, on les source dans le profil shell.
Fish (dans ~/.config/fish/config.fish) :
# Load Claude MCP secrets
if test -f ~/.env.claude
for line in (grep -v '^#' ~/.env.claude | grep '=')
set -l key (echo $line | cut -d= -f1)
set -l val (echo $line | cut -d= -f2- | tr -d '"')
set -x $key $val
end
end
C'est un peu verbeux parce que fish gère pas le source de fichiers .env nativement (merci fish, comme d'habitude).
Bash/zsh (dans ~/.bashrc ou ~/.zshrc) :
# Load Claude MCP secrets
[ -f ~/.env.claude ] && set -a && source ~/.env.claude && set +a
Le set -a exporte automatiquement toutes les variables sourcées. Pas besoin de mettre export devant chaque ligne du fichier. Le set +a désactive ce comportement après, pour pas polluer le reste.
Étape 3 : nettoyer mcp.json
On remplace chaque valeur hardcodée par sa variable :
{
"mcpServers": {
"serveur-recherche": {
"command": "npx",
"args": ["-y", "mcp-recherche@latest"],
"env": {
"SEARCH_API_KEY": "${SEARCH_API_KEY}"
}
},
"serveur-gestion": {
"command": "npx",
"args": ["-y", "mcp-gestion@latest"],
"env": {
"GESTION_API_KEY": "${GESTION_API_KEY}",
"GESTION_TOKEN": "${GESTION_TOKEN}"
}
},
"serveur-ia": {
"command": "uvx",
"args": ["mcp-ia-server"],
"env": {
"IA_API_KEY": "${IA_API_KEY}"
}
}
}
}
Si quelqu'un ouvre ce fichier maintenant, il voit des noms de variables. C'est tout.
Étape 4 : deny rules pour la ceinture et les bretelles
Là c'est le truc que j'ai rajouté après coup, en mode paranoïa. Claude Code peut lire n'importe quel fichier de votre machine. Y compris ~/.env.claude. Ce serait dommage qu'une hallucination ou une prompt injection via un MCP douteux le pousse à aller fouiller dedans.
Dans ~/.claude/settings.json, on lui interdit explicitement :
{
"permissions": {
"deny": [
"Edit(~/.env.claude)",
"Read(~/.env.claude)",
"Edit(~/.ssh/**)",
"Edit(~/.aws/**)",
"Read(~/.ssh/id_*)",
"Read(~/.aws/credentials)"
]
}
}
Defense in depth. Même si tout le reste échoue, Claude se prend un mur en essayant de lire le fichier.
Est-ce que ça marche ?
Relancez votre shell (ou exec fish / source ~/.bashrc) et vérifiez :
# Les variables sont-elles chargées ?
echo $MON_SERVEUR_API_KEY
# Doit afficher la clé
# Le fichier secrets est-il bien protégé ?
ls -la ~/.env.claude
# Doit afficher -rw------- (600)
# Plus de secrets en dur dans mcp.json ?
grep -c "sk-\|token_\|AIza" ~/.claude/mcp.json
# Doit afficher 0
Lancez Claude Code, testez vos serveurs MCP. Si un serveur refuse de démarrer, c'est probablement que la variable est pas exportée dans l'environnement. Un env | grep MON_SERVEUR pour vérifier.
Chez moi ça a marché du premier coup. Miracle.
Quelques trucs en plus
Rotation des clés : maintenant, renouveler une clé c'est changer une ligne dans ~/.env.claude et relancer le shell. Avant, fallait aller éditer le JSON, se souvenir du bon champ, prier pour pas casser la syntaxe. Nettement mieux.
Plusieurs environnements : si vous jonglez entre projets perso et clients, rien empêche d'avoir ~/.env.claude.perso, ~/.env.claude.work, ~/.env.claude.client-x et de loader le bon via un alias ou une variable. J'ai pas encore eu besoin, mais le jour où ça arrive, la mécanique est là.
Le .gitignore : si vous avez un dossier .claude/ dans un projet versionné, ajoutez ça direct :
# Claude Code
.env.claude*
.claude/settings.local.json
HTTP Hooks : depuis début 2026, Claude Code gère les hooks HTTP ("type": "http"). Ces hooks interpolent aussi des variables d'environnement via allowedEnvVars. Même réflexe : jamais de token en dur dans la config du hook. Restreignez la liste des variables autorisées au strict nécessaire.
Quatre fichiers, quinze minutes
Récap rapide :
~/.env.claude- toutes les clés, chmod 600mcp.json- que des${VAR}, zéro secretsettings.json- deny rules sur le fichier secrets- Shell config - loader automatique au démarrage
Vu les CVE de février et le fait que les agents IA ont accès à de plus en plus de trucs sur nos machines, sécuriser ses clés MCP c'est pas de l'excès de zèle. C'est de l'hygiène de base. Et franchement, quinze minutes pour dormir tranquille, ça vaut le coup.
Article précédent
← Censure internet : les solutions techniques pour rester connecté