Dans un précédent article, nous avons comparé trois façons de choisir les tools MCP auxquels nos agents de code ont accès. La gateway MCP était la solution la plus fiable : la règle est appliquée côté serveur, au même endroit pour tous les agents.
Restait à voir comment la mettre en place. Bonne nouvelle : avec agentgateway, un fichier YAML et une image Docker suffisent.
Dans cet article, nous allons présenter le projet et son histoire, puis monter pas à pas une gateway qui donne accès à Context7 et filtre les tools d’un serveur MCP Atlassian.
🧩 Le use case
Nos agents de code (GitHub Copilot, Claude Code, Cursor) utilisent deux serveurs MCP (Model Context Protocol) :
- Context7 , un serveur distant qui fournit de la documentation à jour sur les librairies. Il expose deux tools, sans authentification.
-
Atlassian , via le serveur open source mcp-atlassian, pour Jira et Confluence. Il expose 97 tools, dont une quarantaine qui modifient des données :
jira_create_issue,confluence_delete_page…
Nous voulons trois choses :
- accéder à Context7 en passant par la gateway ;
- ne garder qu’une liste de tools Atlassian en lecture seule ;
- que chaque utilisateur garde son propre token Atlassian, sans aucun secret côté serveur.
Tous les agents passent par la même gateway, qui applique la liste blanche des tools et journalise chaque appel.
📌 agentgateway en bref
agentgateway est un proxy open source pensé pour le trafic des agents IA. Il couvre trois familles de trafic avec un seul binaire :
- LLM Gateway : router les appels vers OpenAI, Claude, Gemini ou un modèle auto-hébergé, avec la gestion des clés d’API et le basculement automatique (failover) d’un modèle à l’autre ;
- MCP et A2A : un support natif du Model Context Protocol et du protocole A2A (Agent-to-Agent), le trafic entre agents ;
- APIs et services : le trafic HTTP, gRPC et TCP classique, observable par défaut, avec mTLS et OIDC intégrés.
Notre use case n’utilise que le pilier MCP, mais la même gateway peut ensuite porter le trafic LLM et API de l’équipe, avec la même configuration et les mêmes logs.
GitHub : agentgateway/agentgateway, plus de 5 600 stars en octobre 2026
Documentation : agentgateway.dev/docs
Pour notre use case, quatre fonctionnalités nous intéressent :
- la fédération MCP : une route par serveur MCP, distant ou local ;
- le filtrage des tools avec des règles CEL (Common Expression Language), une syntaxe d’expressions simple ;
- la manipulation des en-têtes , pour décider quel token part vers quel serveur ;
- l’observabilité : logs JSON, métriques Prometheus, traces OpenTelemetry et une UI web.
Le projet est écrit en Rust et publié sous licence Apache 2.0.
ℹ️ Un peu d’histoire
Le projet est jeune, mais il a déjà fait du chemin :
- mars 2025 : Solo.io crée agentgateway, un proxy pensé dès le départ pour MCP et A2A ;
- 25 août 2025 : la Linux Foundation accueille le projet, annoncé à l’Open Source Summit Europe à Amsterdam ;
- fin 2025 : la Linux Foundation lance l’Agentic AI Foundation (AAIF) avec MCP d’Anthropic, goose de Block et le standard AGENTS.md ;
- 4 juin 2026 : agentgateway rejoint l’AAIF et devient son quatrième projet hébergé.
Selon Solo.io, le projet comptait en juin 2026 plus de 300 contributeurs actifs venant de plus de 60 organisations. C’est un point important pour une brique d’infrastructure : la gouvernance est neutre et le projet ne dépend pas d’un seul éditeur.
À noter : nos tests ont été faits avec la version 1.5.0 (août 2026). La version 1.6.0 est sortie le 2 octobre 2026.
⚙️ 1. Lancer la gateway avec Docker Compose
Commençons par le fichier docker-compose.yaml. Il démarre deux conteneurs : le serveur mcp-atlassian et la gateway.
services:
mcp-atlassian:
image: ghcr.io/sooperset/mcp-atlassian:latest
ports:
- "8080:8080" # gateway : routes MCP
- "4001:4001" # gateway : UI
environment:
TRANSPORT: streamable-http
HOST: 127.0.0.1
PORT: "8000"
STATELESS: "true"
JIRA_URL: https://votre-site.atlassian.net/
CONFLUENCE_URL: https://votre-site.atlassian.net/wiki
ATLASSIAN_EXTERNAL_AUTH_ENABLE: "true"
READ_ONLY_MODE: "true"
agentgateway:
image: cr.agentgateway.dev/agentgateway:v1.5.0
command: ["-f", "/config/config.yaml"]
network_mode: "service:mcp-atlassian"
volumes:
- ./config:/config:ro
Quelques points méritent une explication :
-
network_mode: "service:mcp-atlassian"place les deux conteneurs dans le même réseau. La gateway joint mcp-atlassian surlocalhost:8000, exactement comme un sidecar sur Cloud Run. La même config sert donc en local et dans le Cloud. -
HOST: 127.0.0.1: mcp-atlassian n’écoute que sur localhost. Seule la gateway peut l’appeler. -
ATLASSIAN_EXTERNAL_AUTH_ENABLE: "true"indique à mcp-atlassian que chaque requête apporte son propre token. Sans ce réglage, le serveur ne trouve aucun identifiant global et n’expose aucun tool. -
READ_ONLY_MODE: "true"ajoute une seconde barrière, en plus du filtrage de la gateway.
Il n’y a aucun secret dans ce fichier.
⚙️ 2. Exposer Context7 derrière la gateway
Passons au fichier config/config.yaml. Il déclare d’abord le port de la gateway et celui de l’UI :
gateways:
default:
port: 8080
ui:
port: 4001
ui:
gateways: [ui]
Ajoutons ensuite une première route, pour Context7 :
routes:
- name: context7
matches:
- path:
pathPrefix: /context7/mcp
policies:
mcpAuthorization:
rules:
- 'mcp.tool.name == "resolve-library-id"'
- 'mcp.tool.name == "query-docs"'
backends:
- mcp:
targets:
- name: context7
mcp:
host: https://mcp.context7.com/mcp
policies:
requestHeaderModifier:
remove: [authorization]
La route reçoit les requêtes MCP sur /context7/mcp et les relaie vers le serveur distant de Context7. Le bloc requestHeaderModifier retire l’en-tête Authorization : le token Atlassian d’un utilisateur ne doit jamais partir vers un service externe.
⚙️ 3. Filtrer les tools Atlassian
La seconde route suit le même modèle, avec une liste blanche plus longue :
- name: atlassian
matches:
- path:
pathPrefix: /atlassian/mcp
policies:
mcpAuthorization:
rules:
- 'mcp.tool.name in ["jira_get_issue", "jira_search", "jira_get_project_issues", "jira_get_transitions", "jira_get_all_projects", "jira_get_agile_boards", "jira_get_board_issues", "jira_get_sprints_from_board", "jira_get_sprint_issues", "jira_get_user_profile"]'
- 'mcp.tool.name in ["confluence_search", "confluence_get_page", "confluence_get_page_children", "confluence_get_space_page_tree", "confluence_get_comments", "confluence_get_labels"]'
backends:
- mcp:
targets:
- name: atlassian
mcp:
host: http://localhost:8000/mcp
Ici, pas de requestHeaderModifier : l’en-tête Authorization de l’utilisateur doit arriver intact jusqu’à mcp-atlassian.
Lançons la stack :
docker compose up -d
Voici ce que nous avons constaté :
-
tools/listne renvoie que les 16 tools de la liste blanche, sur les 97 du serveur ; - un appel direct à
jira_create_issueest rejeté par la gateway, même forcé à la main aveccurl; - une requête sans token reçoit une erreur 401 de mcp-atlassian ;
- avec un token valide,
jira_searchetconfluence_searchrenvoient bien les données de l’utilisateur.
La gateway filtre les tools sans rien savoir d’Atlassian. Elle lit simplement les messages MCP qui passent.
💪 ProTip : gardez une route par serveur MCP. agentgateway sait aussi regrouper plusieurs serveurs derrière une seule URL, mais les noms des tools reçoivent alors un préfixe (atlassian_jira_search) et il devient plus difficile de contrôler quel token part vers quel serveur.
💻 4. Brancher un agent de code
Côté poste, il n’y a plus rien à installer. Chaque utilisateur prépare son en-tête à partir de son email et de son token API Atlassian :
printf '%s:%s' 'prenom.nom@exemple.fr' 'VOTRE_TOKEN_API' | base64
Avec Claude Code, une seule commande suffit :
claude mcp add --transport http atlassian-gw http://localhost:8080/atlassian/mcp --header "Authorization: Basic <BASE64>"
Avec Cursor, dans ~/.cursor/mcp.json :
{
"mcpServers": {
"atlassian-gw": {
"url": "http://localhost:8080/atlassian/mcp",
"headers": { "Authorization": "Basic <BASE64>" }
},
"context7-gw": {
"url": "http://localhost:8080/context7/mcp"
}
}
}
L’agent voit alors les 16 tools autorisés. Si nous lui demandons de créer un ticket Jira, il répond qu’il n’a pas de tool pour ça.
⚡️ ProTip : utilisez un token API classique d’Atlassian. Les tokens « avec scopes » ne fonctionnent pas avec l’URL du site (votre-site.atlassian.net) : ils passent obligatoirement par https://api.atlassian.com/ex/{jira|confluence}/<cloudId>. Nous avons perdu un peu de temps sur ce 401 avant de comprendre.
🎯 Conclusion
En quelques dizaines de lignes de YAML, agentgateway nous donne une gateway MCP qui :
- expose Context7 et Atlassian derrière une seule URL ;
- filtre les tools côté serveur, pour tous les agents à la fois ;
- relaie le token de chaque utilisateur, sans secret à stocker.
Le projet est simple à démarrer et sa gouvernance est neutre depuis son arrivée à l’AAIF. Pour une équipe qui veut encadrer les serveurs MCP de ses agents de code, c’est une bonne première brique, en local avec Docker Compose puis sur Cloud Run.
Le code complet de ce test tient en deux fichiers : docker-compose.yaml et config/config.yaml.
🚀 Bonus : aller plus loin avec l’observabilité
Une gateway voit passer tous les appels de tools. C’est l’endroit idéal pour mesurer l’usage réel des serveurs MCP.
Ajoutons une politique de logs d’accès en tête de config/config.yaml :
config:
logging:
format: json
frontendPolicies:
accessLog:
filter: 'mcp.methodName == "tools/call"'
add:
mcp_target: 'mcp.tool.target'
mcp_tool: 'mcp.tool.name'
Chaque appel de tool produit maintenant une ligne JSON avec le serveur et le tool utilisés :
{"route":"default/context7","http.status":200,"mcp.method.name":"tools/call",
"mcp_target":"context7","mcp_tool":"resolve-library-id","duration":"2274ms"}
Un peu de jq suffit pour compter les appels par serveur et par tool. Voici le résultat après quelques tests :
MCP TOOL APPELS ERREURS
atlassian confluence_search 3 0
atlassian jira_create_issue 3 3
atlassian jira_get_issue 3 0
context7 resolve-library-id 3 0
Les trois erreurs sur jira_create_issue sont les appels refusés par la gateway.
En local, jq suffit. En production, trois options s’offrent à nous selon les outils de l’équipe :
-
Les logs, sans rien installer. Sur Cloud Run, tout ce que la gateway écrit arrive automatiquement dans Cloud Logging. Le même tableau peut alors se construire avec une requête SQL dans Log Analytics, sur les champs
mcp_targetetmcp_tool. -
Un compteur Prometheus. agentgateway publie le compteur
agentgateway_mcp_requests_total(nombre de requêtes MCP par serveur et par tool) sur le port 15020. Prometheus le collecte et Grafana en fait un tableau de bord. - Des traces OpenTelemetry. Elles suivent chaque appel de bout en bout, de l’agent jusqu’au serveur MCP, avec le temps passé à chaque étape.
À noter : la colonne ERREURS ne compte que les appels bloqués par la gateway, comme jira_create_issue ici. En version 1.5.0, si l’appel passe la gateway mais échoue chez Atlassian (un token invalide, par exemple), il est compté comme réussi.
🎓 Envie de maîtriser MCP ?
Pour comprendre MCP de l’intérieur, notre formation Model Context Protocol (MCP) couvre en une journée l’architecture client-serveur, les tools, resources et prompts, la création de serveurs MCP en Python et en Java, puis l’intégration avec des agents IA et le déploiement dans le Cloud. La journée alterne théorie et ateliers pratiques.
👉 Et vous, quels serveurs MCP mettriez-vous en premier derrière une gateway ?

Top comments (0)