flexway
FRENParler à un expert

Agents et MCP

GuideExploitationDepuis la version 0.1.0

Markdown

Sur cette page

Guide d'exploitation : configurer, déployer et observer la passerelle. Ce que fait la capacité côté produit : guide produit ; l'appeler : guide développeur.

Objectif : rendre vos API et vos serveurs MCP existants appelables par des agents IA, derrière une autorisation, un quota et des métriques communs - sans écrire de serveur MCP.

Trois modes, une surface

%%{init: {'theme':'base','themeVariables':{'fontSize':'13px','lineColor':'#94a3b8'}}}%%
graph LR
  A["Agent IA<br/>client MCP"]:::ext
  subgraph FW["Flexway - surface /mcp d'un hôte"]
    S["Jeton émis pour la surface<br/>tools/list filtré par portées<br/>quota de l'appelant"]:::hub
    P["Mode 1 - outil projeté<br/>une opération du contrat"]:::hub
    F["Mode 2 - outil fédéré<br/>un serveur MCP existant"]:::hub
  end
  R["Service REST"]:::spoke
  M["Serveur MCP existant"]:::spoke
  I["Fournisseur d'identité"]:::secret

  A -->|"MCP"| S
  S --> P -->|"la décision REST, rejouée"| R
  S --> F -->|"MCP"| M
  P -->|"jeton échangé, si l'amont l'exige"| I
  F -->|"jeton échangé, si l'amont l'exige"| I

  classDef hub    fill:#4f46e5,stroke:#3730a3,color:#fff,font-weight:bold
  classDef spoke  fill:#0891b2,stroke:#155e75,color:#fff,font-weight:bold
  classDef secret fill:#a855f7,stroke:#7e22ce,color:#fff,font-weight:bold
  classDef ext    fill:#64748b,stroke:#334155,color:#fff,font-weight:bold

L'échange de jeton n'a lieu que si l'amont l'exige (token_exchange). Tout ce schéma est construit (0.1.0).

Vous avez Mode Ce que vous écrivez Exemple
Des services REST décrits en OpenAPI 1 - outils projetés du contrat x-flexway-tool sur chaque opération à offrir Outils pour agents (MCP)
Des serveurs MCP qui tournent déjà 2 - fédération un amont protocol: mcp et agents.mcp.servers Serveur MCP existant, liste déclarée, Serveur MCP existant, tout ce qu'il annonce
Les deux 3 - mixte les deux, sur la même surface Outils projetés et fédérés ensemble
Des agents qui se parlent en A2A A2A (pas MCP : hors de la surface /mcp) une carte déclarée et un amont protocol: a2a Agents A2A, Agent A2A derrière la passerelle

Commun aux trois, une fois par hôte : l'URL publique de la surface, qui est l'audience qu'un jeton d'agent doit porter (RFC 8707). Elle est déclarée, jamais devinée depuis la requête - un jeton émis pour un autre serveur MCP ne doit pas ouvrir celui-ci.

agents:
  mcp:
    resources:
      api.example.com: https://api.example.com/mcp

Mode 1 - outils projetés du contrat

Rien à développer : une opération déjà servie en REST devient un outil.

      x-flexway-tool: true                           # ou { name: get_order, description: "…" }
Étape Ce que fait la passerelle
tools/list Nom (operationId, ou name), description (summary), schéma d'entrée tiré des paramètres et du corps déclarés
tools/call Construit la requête REST de l'opération et la fait passer, en mémoire, par la même décision qu'un appel REST : portées du contrat, quota, validation du schéma, politiques, délais, coupe-circuit, métriques
Résultat Le corps de la réponse ; isError pour un statut >= 400, avec le problème RFC 9457 ; borné à 1 Mio

Une opération non marquée n'est jamais offerte. Une opération à réponse en flux ne peut pas être un outil : elle est refusée au chargement.

Mode 2 - serveurs MCP existants (fédération)

Rien à changer chez le serveur ni chez ses agents : la passerelle se place devant lui.

upstreams:
  orders-mcp:
    url: http://order-service:8080/mcp               # son endpoint MCP
    protocol: mcp
agents:
  mcp:
    servers:
      orders:
        upstream: orders-mcp
        tools: [get_order, create_order]             # ou "*"
Réglage Effet
tools: [...] Liste déclarée - le défaut, fermé : un outil ajouté côté serveur n'apparaît pas sans décision
tools: "*" Tout ce que le serveur annonce - un choix explicite
rename Un autre nom sur la surface, par exemple contre une collision
scopes, tool_scopes Portées exigées de chaque outil, ou d'un outil ; vide : un appelant authentifié - jamais anonyme
rate_classes Classe de débit d'un outil ; sinon read si le serveur l'annonce en lecture seule (readOnlyHint), autrement write
hosts Les surfaces qui le servent ; défaut : toutes
discovery.issuer Le serveur exige un jeton même pour lister : la passerelle en demande un pour elle-même (client_credentials)
discovery.refresh Intervalle de redécouverte ; défaut 5 min
Fonctionnement Règle
Découverte En arrière-plan : tools/list du serveur, retenté, rafraîchi. Le démarrage n'attend jamais un serveur ; injoignable, ses outils sont absents, puis apparaissent quand il répond
Noms D'origine. Une collision est refusée au chargement pour une liste déclarée ; pour "*", l'outil en collision n'est pas servi, et c'est dit (/config, journal)
Appel Identité exigée, portées, quota de l'appelant, cloisonnement et coupe-circuit de l'amont, délai de l'amont, résultat borné
État /config (port d'administration), mcp_federation : découvert ou injoignable, outils servis, outils non servis et pourquoi

Les politiques de transformation (en-têtes, chemin) ne s'appliquent pas aux outils fédérés : ce sont des appels MCP, pas des requêtes REST du contrat. Seule la politique rate-limit (niveaux global et hôte) s'applique.

Mode 3 - mixte

Les deux modes sur la même surface : l'agent voit une liste, triée par nom. Les noms doivent être uniques sur un hôte - vérifié au chargement pour les outils déclarés.

Le jeton que reçoit l'amont

Le jeton de l'agent n'est jamais relayé : il a été émis pour la surface, pas pour l'amont, et la spécification MCP l'interdit. Ce que l'amont reçoit dépend de ce qu'il attend :

L'amont Configuration Il reçoit
Fait confiance à la passerelle (réseau privé, maillage) Rien Aucun Authorization ; le tenant par l'en-tête que pose la passerelle (outils projetés)
Vérifie lui-même les jetons token_exchange: { audience } sur l'amont, client sur l'émetteur Un jeton émis pour lui, au nom de l'appelant, par le fournisseur de l'appelant (RFC 8693) - Jeton échangé vers l'amont
upstreams:
  orders-mcp:
    token_exchange: { audience: order-service }      # le jeton que le serveur attend
auth:
  issuers:
    - name: customers
      client: { id: flexway, secret: "file:/etc/flexway/secrets/client" }   # une référence, relue à chaque échange

Si le fournisseur refuse l'échange, l'appel est refusé ; s'il est injoignable, l'appel échoue - jamais de repli sur le jeton de l'agent.

Chaîne d'agents bornée

Une chaîne réelle est humain -> agent A -> agent B -> service. Le fournisseur d'identité l'écrit dans le jeton, en revendications act imbriquées (RFC 8693) : sub reste l'humain, chaque act nomme un agent. La passerelle la lit et la borne :

agents:
  delegation:
    max_depth: 2               # agents au plus ; 0 : aucun jeton délégué accepté
    max_age: 15m               # depuis l'authentification de l'humain (auth_time, sinon iat)
    introspection:
      cache: 10s               # délai maximal pour voir une révocation
# contrat - une opération sensible resserre, jamais n'élargit
      x-flexway-delegation: { max_depth: 1, max_age: 5m }
Règle Comportement
Jeton direct (sans act) Pas une délégation : ni borne, ni introspection
Profondeur, âge Au-delà de la borne -> 403. La borne d'une opération est le minimum de la configuration et de la sienne
Révocation Un jeton délégué est vérifié auprès de son émetteur (introspection RFC 7662, avec le client de l'émetteur) ; révoqué -> 401 dans le délai cache ; émetteur injoignable -> 503, jamais un passage sans vérification
Rétrécissement Un échange de jeton (Le jeton que reçoit l'amont) demande au plus les portées de l'appelant ; un fournisseur qui en accorde davantage -> 403, l'amont n'est pas appelé
Partout REST, connexion à la surface MCP, outils projetés (bornes de l'opération) et fédérés
Traces delegation.depth, delegation.actors - les agents, jamais l'humain

Exemple complet : Chaîne d'agents bornée.

Autorisation, quota, observabilité

Sujet Règle
Jeton de l'agent Émis pour l'URL de la surface (indicateur de ressource resource= à la demande du jeton) ; un 401 donne resource_metadata, et GET /.well-known/oauth-protected-resource/mcp dit où l'obtenir
tools/list Ne montre que ce que l'appelant peut appeler
Outil projeté Les exigences du contrat (security), comme en REST
Outil fédéré scopes / tool_scopes ; une identité toujours
Quota Le même seau par appelant, quelle que soit la porte - REST, outil projeté, outil fédéré
Métriques flexway_mcp_calls_total (outil, issue, client, tenant, surveillé, cause de refus), flexway_mcp_connections_refused_total (motif), flexway_mcp_federated_duration_seconds (outil), flexway_mcp_discoveries_total (serveur, issue), flexway_token_exchanges_total (amont, issue), flexway_delegation_refused_total (raison : depth, age, revoked, widened, unverifiable)
/config mcp_tools (outils projetés par hôte), mcp_federation (état de chaque serveur, en direct) ; agents.mcp.clients et tool_unattended

Quels clients, et avec ou sans humain (1.0.0) - la surface admet par défaut tout client dont le jeton est valide. agents.mcp.clients la ferme aux clients déclarés, nommés par l'URL de leur document de métadonnées (révision MCP 2026-07-28) ; un outil peut être retiré aux agents non surveillés - un client qui agit pour lui-même, dont le jeton a pour sujet le client :

agents:
  mcp:
    clients: ["https://agents.example.com/*", "https://partner.example/agent.json"]
      x-flexway-tool: { name: create_order, unattended: false }   # caché et refusé sans humain

Un fournisseur qui donne au compte de service un sujet à lui (Keycloak : un identifiant d'utilisateur) se déclare : service_accounts: { claim: preferred_username, prefix: service-account- } sur l'émetteur.

Déclarer agents.mcp.clients est aussi ce qui rend chaque agent visible dans la console : sans liste, tous les clients comptent sous _undeclared.

Vérifier

  • GET /.well-known/oauth-protected-resource/mcp renvoie la ressource et son serveur d'autorisation ;
  • un client MCP sans jeton reçoit 401 avec resource_metadata ;
  • avec un jeton émis pour l'URL de la surface, tools/list montre les outils permis - projetés et fédérés ;
  • un appel compte dans le même quota que l'appel REST ;
  • /config montre mcp_tools et mcp_federation ;
  • flexway_mcp_calls_total porte le client de l'agent et, sur un refus, sa cause.

vers l'amont ; la chaîne d'agents bornée. Les clés d'API arrivent avec le change suivant ; les ressources et les invites MCP d'un serveur fédéré ne sont pas relayées.*

Étapes suivantes