Les agents de code comme GitHub Copilot, Claude Code ou Cursor se branchent sur des serveurs MCP (Model Context Protocol). Ces serveurs leur apportent des tools : chercher un ticket Jira, lire une page Confluence, ouvrir une pull request…
C’est très pratique. Mais pour une entreprise, une question arrive vite : qui décide de ce que l’agent a le droit de faire ?
Dans cet article, nous allons partir d’un cas concret : Jira, Confluence et Context7 placés derrière une gateway MCP. Nous verrons les trois besoins de gouvernance, puis les trois solutions possibles aujourd’hui, avec leurs limites.
📌 Les trois besoins de gouvernance
Côté entreprise, nous voulons trois choses.
A. Choisir les serveurs MCP autorisés. Pas n’importe quel serveur trouvé sur Internet, mais une liste validée. Elle est publiée par une registry MCP interne, ou imposée par des managed settings, c’est-à-dire des réglages déployés par l’entreprise sur les postes.
B. Préférer les serveurs MCP distants officiels. Un serveur remote hébergé par l’éditeur (GitHub, Atlassian…) apporte :
- rien à installer sur les postes : ni
docker run, ninpx; - des mises à jour gérées par l’éditeur ;
- une simple URL à déclarer.
C. Filtrer les tools proposés par ces serveurs. Un serveur d’éditeur expose souvent des dizaines de tools, dont beaucoup en écriture. Le serveur open source mcp-atlassian, que nous utilisons dans notre test, en expose 97, dont une quarantaine qui modifient des données : jira_create_issue, confluence_delete_page… Nous voulons n’en garder qu’une partie, par exemple la lecture seule.
A et B sont bien outillés aujourd’hui. C est le vrai problème.
Rappel : registry et managed settings pour le besoin A
Deux mécanismes permettent déjà de choisir les serveurs.
Côté Copilot, une politique d’organisation GitHub impose à VS Code une registry MCP interne qui liste les serveurs approuvés. C’est ce que nous faisons. Une entrée de registry ressemble à ceci :
{
"server": {
"name": "io.github.upstash/context7",
"remotes": [{ "type": "streamable-http", "url": "https://mcp.context7.com/mcp" }]
}
}Chaque entrée décrit un serveur et la façon de s’y connecter. Ici, Context7 est déclaré comme serveur distant, sans installation locale.
Côté Claude Code, nous faisons de même avec des managed settings. L’entreprise dépose un fichier de réglages, dans /Library/Application Support/ClaudeCode/ sur macOS (documentation) :
{
"allowedMcpServers": [
{ "serverUrl": "https://mcp.context7.com/*" },
{ "serverUrl": "https://mcp-gateway.example.com/*" }
],
"deniedMcpServers": [
{ "serverUrl": "https://untrusted.example.com/*" }
]
}La liste de refus est évaluée en premier. Ensuite, seuls les serveurs présents dans la liste d’autorisation peuvent être chargés.
À noter : ces deux mécanismes filtrent des serveurs, pas des tools. Une fois un serveur autorisé, tous ses tools arrivent chez l’agent.
1️⃣ Solution 1 : le filtrage proposé par l’éditeur
Certains éditeurs permettent de choisir les tools… dans la configuration du client.
Le serveur MCP distant de GitHub lit par exemple des en-têtes HTTP maison, décrits dans sa documentation :
{
"servers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"X-MCP-Toolsets": "repos,issues",
"X-MCP-Tools": "get_file_contents,issue_read",
"X-MCP-Readonly": "true"
}
}
}
}X-MCP-Toolsets et X-MCP-Tools limitent les tools exposés, et X-MCP-Readonly ne garde que les tools de lecture.
Autre exemple : quand nous installons nous-mêmes mcp-atlassian, nous le configurons par variables d’environnement :
docker run -i --rm \
-e READ_ONLY_MODE=true \
-e ENABLED_TOOLS=jira_search,confluence_search \
...image-mcp-atlassian...Pourquoi cette approche est fragile
- C’est de la configuration client. Le réglage vit dans le
mcp.jsonde chaque utilisateur. Il suffit de retirerX-MCP-ReadonlyouREAD_ONLY_MODEpour retrouver tous les tools. Ce n’est pas une barrière, c’est une préférence. - Le serveur accepte toujours tout. Avec le même token, un autre client, ou un simple
curl, obtient l’ensemble des tools. - Chaque éditeur a sa propre convention.
X-MCP-Toolschez GitHub, variables d’environnement chez mcp-atlassian, rien chez d’autres. Aucune règle commune n’est possible. - Cela ne fonctionne qu’avec les éditeurs qui l’ont prévu.
GitHub le précise d’ailleurs à propos de X-MCP-Lockdown : c’est un filtre « best-effort », pas une frontière de sécurité.
2️⃣ Solution 2 : une gateway MCP entre les agents et les serveurs
L’idée est simple : les agents ne parlent plus directement aux serveurs MCP. Ils passent par une gateway qui applique la politique de l’entreprise.

Tous les agents passent par la même gateway, qui applique la liste blanche des tools et journalise chaque appel.
Nous avons testé cette approche avec agentgateway, un projet open source de l’Agentic AI Foundation (AAIF), en version 1.5.0. Toute la politique tient dans un fichier de configuration :
routes:
- name: atlassian
matches:
- path: { pathPrefix: /atlassian/mcp }
policies:
mcpAuthorization:
rules:
# Liste blanche : seuls ces tools existent pour l'agent
- 'mcp.tool.name in ["jira_get_issue", "jira_get_all_projects", "confluence_search", "confluence_get_page"]'
backends:
- mcp:
targets:
- name: atlassian
mcp: { host: http://localhost:8000/mcp }Les règles mcpAuthorization sont des expressions CEL (Common Expression Language). Ici, un seul tableau suffit à décrire la liste blanche de la route Atlassian.
⚡️ Voici ce que nous avons constaté pendant le test :
- Les tools refusés disparaissent de la liste envoyée à l’agent (
tools/list). Le modèle ne sait même pas qu’ils existent. - Un appel direct à un tool refusé est rejeté, même forcé à la main avec
curl. - Le token de l’utilisateur est relayé tel quel. Atlassian voit toujours la vraie personne, avec ses propres droits.
- Chaque appel est journalisé : quel serveur, quel tool, quand. Nous obtenons des statistiques d’usage sans effort supplémentaire.
Voici un extrait réel des logs d’accès, simplifié :
{"route":"default/context7","http.status":200,"mcp.method.name":"tools/call",
"mcp_target":"context7","mcp_tool":"resolve-library-id","duration":"2274ms"}Enfin, côté poste, rien à installer. L’agent déclare simplement l’URL de la gateway :
{
"mcpServers": {
"atlassian": {
"url": "https://mcp-gateway.example.com/atlassian/mcp",
"headers": { "Authorization": "Basic <base64(email:token)>" }
}
}
}Les limites de la gateway
- Il faut héberger et maintenir un composant de plus, dans notre cas un service Cloud Run.
- Il faut tenir la liste blanche à jour quand l’éditeur ajoute ou renomme des tools.
- Il faut penser la sécurité réseau. Par exemple, ne jamais transmettre le token Atlassian d’un utilisateur à un autre serveur :
policies:
requestHeaderModifier:
remove: [authorization] # sur la route Context7- Le filtrage se fait au niveau du tool, pas de ses paramètres. Pour aller plus loin, par exemple réécrire un schéma ou limiter un projet Jira, agentgateway propose des MCP guardrails. Il faut alors développer un service externe.
💪 ProTip : gardez une route par serveur MCP plutôt qu’une route unique qui les agrège. Les noms de tools restent inchangés, et un token ne peut pas fuiter d’un serveur à l’autre.
C’est la seule solution où la règle est appliquée côté serveur, au même endroit pour tous les agents.
3️⃣ Solution 3 : choisir les tools dans chaque agent de code
Troisième voie : garder la connexion directe et restreindre les tools dans la configuration de l’agent.
Côté Copilot CLI, c’est simple : une liste blanche par serveur.
{
"mcpServers": {
"atlassian": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"tools": ["jira_get_issue", "confluence_search"]
}
}
}VS Code propose en plus un sélecteur de tools dans l’interface du chat. Mais c’est à chaque développeur de choisir les tools qu’il charge dans sa fenêtre de contexte : l’entreprise ne peut pas imposer ce choix.
Côté Claude Code, c’est plus pénible. Il n’existe pas de liste tools par serveur, il faut passer par les règles de permissions :
{
"permissions": {
"deny": [
"mcp__atlassian__jira_create_issue",
"mcp__atlassian__jira_update_issue",
"mcp__atlassian__jira_delete_issue",
"mcp__atlassian__confluence_create_page",
"mcp__atlassian__confluence_delete_page"
]
}
}Un tool refusé est bien retiré du contexte du modèle, et une règle posée dans les managed settings ne peut pas être contournée par l’utilisateur. Mais deux points compliquent la maintenance :
- une règle
denyl’emporte toujours sur une règleallow. Impossible d’écrire « tout refuser sauf ces quatre tools » avecdeny: mcp__atlassian__*puisallow: …. Il faut lister un par un tout ce que nous refusons, et revoir la liste à chaque nouveau tool de l’éditeur ; - les règles dépendent du nom local donné au serveur (
mcp__atlassian__…). Si l’utilisateur l’appellejira, la règle ne s’applique plus.
Surtout, chaque agent a sa propre syntaxe. Une entreprise qui autorise Copilot, Claude Code et Cursor doit écrire et maintenir trois politiques différentes, puis vérifier qu’elles disent la même chose.
⚖️ Comparatif des trois solutions
| 1. Filtrage éditeur (client) | 2. Gateway MCP | 3. Réglage par agent | |
|---|---|---|---|
| Où vit la règle | config client | serveur (gateway) | config de chaque agent |
| Contournable par l’utilisateur | oui | non | oui, sauf managed settings Claude Code |
| Marche avec tous les éditeurs | non | oui | oui |
| Marche avec tous les agents | oui | oui | une syntaxe par agent |
| Statistiques d’usage | non | oui | non |
| Coût | nul | un service à héberger | maintenance de N configurations |
🎯 Conclusion : il manque une brique dans la spec MCP
Aujourd’hui, la seule manière fiable de filtrer les tools des éditeurs est d’ajouter une gateway. Elle fonctionne bien, mais c’est une infrastructure de plus pour un besoin que toutes les entreprises partagent.
La dernière version de la spécification MCP (2026-07-28) fait déjà un pas vers les intermédiaires :
- chaque requête HTTP porte des en-têtes standard comme
Mcp-Method: tools/calletMcp-Name: jira_search, pour qu’une gateway puisse router sans lire le corps de la requête ; - un serveur peut demander au client de recopier certains paramètres dans des en-têtes
Mcp-Param-*, grâce à l’extensionx-mcp-header.
Mais rien de tout cela ne permet de dire au serveur « n’expose que ces tools » ou « lecture seule ». Chacun invente sa convention : X-MCP-Tools et X-MCP-Readonly chez GitHub, READ_ONLY_MODE et ENABLED_TOOLS chez mcp-atlassian.
Ce qui manque, c’est une généralisation de ces réglages dans la spécification. Par exemple, avec des en-têtes qui n’existent pas encore :
POST /mcp HTTP/1.1
Mcp-Method: tools/list
Mcp-Tools: jira_get_issue,confluence_search
Mcp-Read-Only: trueTrois règles simples suffiraient :
- Des en-têtes standard, compris par tous les serveurs, pour restreindre les tools et imposer la lecture seule.
- Ils ne peuvent que restreindre, jamais élargir ce que le serveur autorise déjà. GitHub applique déjà ce principe à son mode lockdown.
- Les intermédiaires doivent les propager, et peuvent les imposer. Une gateway ou un proxy d’entreprise pourrait alors ajouter
Mcp-Read-Only: trueà toutes les requêtes, sans maintenir de liste de tools, et chaque serveur l’appliquerait lui-même.
Avec cette brique, la gouvernance deviendrait simple :
- la registry choisit les serveurs (A) ;
- les serveurs distants officiels évitent toute installation sur les postes (B) ;
- un en-tête standard, posé par l’entreprise et impossible à retirer côté poste, filtre les tools (C).
En attendant, la gateway reste la solution la plus robuste. C’est aussi un excellent point d’observation pour mesurer ce que les agents font vraiment de ces serveurs.
👉 Et vous, comment filtrez-vous les tools MCP de vos agents de code ?
🎓 Aller plus loin avec MCP
Vous voulez comprendre MCP de l’intérieur ? En une journée, la formation Model Context Protocol (MCP) de TechTown couvre :
- l’architecture client-serveur ;
- les tools, les resources et les prompts ;
- le cycle de vie d’une requête ;
- la création de serveurs MCP en Python et en Java ;
- l’intégration avec des agents IA et le déploiement dans le Cloud.
La journée alterne théorie et ateliers pratiques.