Problem 1
An agent calls whatever it finds
Exposing an API to an agent opens more than needed.
Flexway's answer: Only operations marked x-flexway-tool are offered, filtered by the token's scopes.
Agents: MCP and A2A
The operations you mark become MCP tools, called with the same identity, quota and audit as REST. Existing MCP servers plug in behind the gateway.
8 of the 9 shown delivered · since v0.1.0
What you expect from this domain


Problem 1
Exposing an API to an agent opens more than needed.
Flexway's answer: Only operations marked x-flexway-tool are offered, filtered by the token's scopes.
Problem 2
An agent reuses the token it received, everywhere.
Flexway's answer: A token is issued for the MCP surface and never relayed; an upstream that verifies tokens receives a token exchanged for it (RFC 8693).
Problem 3
Scattered MCP servers, each with its own authentication and no quota.
Flexway's answer: Federation puts them behind the gateway: same authorisation, quota and audit.
Every step is a decision readable in the trace and in the console.
Agents: MCP and A2A - Domain diagram: who calls, the decision steps, what is called, and where a request is refused.
out of scope: absent from tools/list, 403 on call
AI agents: they call MCP tools and models through Flexway, under the same identity, quota and audit as an API.
Routes through here
MCP clients (assistants, IDEs): they discover then call the tools Flexway exposes, after an OAuth 2.1 token.
Routes through here
The MCP client reads the OAuth metadata Flexway publishes (RFC 9728) to learn where to get its token.
Routes through here
Flexway requires an OAuth 2.1 token issued for its MCP surface, and checks it before any routing.
Routes through here
The contract's marked operations become MCP tools; an agent sees only those within its scopes.
Routes through here
An agent acts on a person's behalf for a bounded time and depth; the token is exchanged (RFC 8693), revocable in cascade.
Routes through here
A tool call counts in the same quota and the same audit as a REST call.
Routes through here
The agent's token is never relayed to the upstream; it is exchanged when the upstream checks tokens.
Routes through here
Your REST and gRPC services: they receive only the requests Flexway let through, under deadline and circuit breaker.
Routes through here
Your existing MCP servers, federated behind Flexway: their tools come under the same authorization, quota and audit.
Routes through here
The essentials of each topic, with its status in the published release; unfold a card for the full text.
An operation marked x-flexway-tool becomes an MCP tool, filtered by the caller's scopes and called under the same verdict and quota as over REST.
An operation becomes an agent tool when the contract marks it with x-flexway-tool: exposure is opt-in, and a write is never offered to an agent unless someone decided it. tools/list is derived from the OpenAPI - name (operationId or a declared name), description, input schema built from the declared parameters and body - and filtered by the caller's scopes. A tool that is not a declared operation does not exist.
tools/call builds the operation's request and runs it, in memory, through the same decision as a REST call: scopes, caller quota, validation, policies, budgets, metrics. An operation is therefore callable over REST and via MCP with the same verdict and the same quota bucket. An undeclared argument is refused; the result is returned as text, as structuredContent for a JSON object, with isError for a status of 400 or above, and capped at 1 MiB.
The transport is stateless Streamable HTTP: a session would live on one replica and die on reload. The stdio transport does not cross a network, so it stays outside a gateway's scope. An operation with a streamed response cannot be a tool.
The MCP surface is an OAuth 2.1 resource server: the client discovers where to get a token issued for it, and that token is never relayed upstream.
The MCP surface is a full OAuth 2.1 resource server. It publishes its protected resource metadata (RFC 9728) under /.well-known/oauth-protected-resource/<path> and answers 401 with resource_metadata, so the client discovers where to obtain a token rather than guessing. The token must be issued for this surface (RFC 8707): its audience is the public URL declared in agents.mcp.resources, never inferred from the request.
The agent's token is never relayed upstream, which closes the confused deputy path. An MCP token is refused on a REST route, and the surface accepts OAuth tokens only: an API key is not the identity of an agent acting on someone's behalf. The issuer is checked, and its keys validate only its own tokens.
The client is read from the token (client_id, otherwise azp); agents.mcp.clients restricts the surface to declared clients, by metadata document URL or by prefix. An unattended agent - a client acting for itself - is recognised, and x-flexway-tool: { unattended: false } hides and refuses a tool for it.
An upstream receives a token exchanged for it on the caller's behalf (RFC 8693), after the whole decision, with scopes that only narrow.
An upstream that declares token_exchange receives a token issued for it, on behalf of the caller, by the provider that signed the original token (RFC 8693); the gateway consumes identities, it does not issue them. The exchange happens after the whole decision - identity, scopes, quota, validation, policies - and before relaying: a refused call costs no exchange. An anonymous call has nothing to exchange, and the upstream receives no Authorization header.
The exchange only narrows: it requests at most the caller's scopes, and an extra scope granted yields 403 without calling the upstream. The subject (sub) remains the human, the actors (nested act) are the agents, read and traced. A provider refusal gives 403; an unreachable provider or a missing secret gives 503 with Retry-After. There is never a fallback to the original token.
The client secret is a reference re-read on every exchange, which allows rotation without a reload. An exchanged token is reused until its expiry minus 30 s, with a single exchange in flight per original token and audience.
The depth and age of an agent chain are capped, and revoking the human cuts the whole chain through introspection.
A real chain looks like "human -> agent A -> agent B -> service". agents.delegation bounds its depth (max_depth) and its age (max_age, counted from auth_time, otherwise iat); an operation can tighten these bounds with x-flexway-delegation, never widen them, and the lower of the two applies. Beyond them, the answer is 403; a delegated token whose age cannot be established is refused.
Revocation goes through RFC 7662 introspection at the issuer, with a short cache: a revoked token gives 401, an unverifiable one 503 with Retry-After. Revoking the human thus cuts the whole chain. These rules apply over REST, when connecting to the MCP surface, and for both projected and federated tools.
The trace carries delegation.depth and delegation.actors, the flexway.delegation.refused metric counts refusals by reason, and the decision audit line carries the full chain of actors. Knowing which human, which agents and which scopes stand behind a write helps you meet traceability requirements for agent actions.
Your existing MCP servers sit behind Flexway without rewriting, with a declared tool list, closed by default, under the same authorisation.
Existing MCP servers move behind Flexway without rewriting: an upstream with protocol: mcp and an agents.mcp.servers entry are enough. Exposure uses a declared list of tools, closed by default - a tool added on the server side does not appear without a decision - or "*", chosen explicitly. Tools keep their original names, which can be renamed; a collision on the same host refuses the load with a declared list, and with "*" the colliding tool is not served, and this is reported.
Discovery runs in the background (initialize, then tools/list), retried with increasing delay and refreshed at a regular interval; neither start-up nor /readyz waits for a server. Each call requires an identity and scopes (tool_scopes, otherwise scopes) and uses the caller's bucket; the rate class is declared, otherwise read for a tool announced as read-only, write otherwise. The server receives a token exchanged for it if it declares token_exchange, never the agent's token.
Each call benefits from the upstream's bulkhead, circuit breaker and budget, with results capped at 1 MiB. A single surface serves contract tools and federated tools in one list sorted by name.
Agent-to-agent (A2A) traffic governance is not delivered as a whole: the chosen approach relays it under the same decision, without terminating the protocol.
Governance of agent-to-agent traffic (A2A v1.0) is not delivered as a whole; its state in this release is shown below. The chosen approach: relay A2A under the same decision as everything else - route, authenticate, authorise, count, observe - without terminating the protocol, that is without holding task state or delivering push notifications. An agent is declared by its agent card, treated as a versioned contract, and the upstream agent always receives an exchanged token, never the caller's.
The approach provides for a tenant held equal to the identity's tenant, a rate class per method, a stream cap and a bounded task duration, push notification targets restricted to a list of declared hosts, and an audit without content. Verification of signed upstream cards, re-signing of the published card and agent-to-agent delegation are still to be done.
The mcp-tools example, as it ships with Flexway v1.6.3.
# Agent tools from the contract: one line per host declares the MCP surface, then x-flexway-tool
# per operation. A token must be issued for that URL (RFC 8707); it is never relayed upstream.
version: 1
contracts:
openapi: ./openapi.yaml
upstreams:
default:
url: http://orders.internal:8080
auth:
tenant_header: X-Tenant
issuers:
- name: customers
discovery: https://login.example.net/.well-known/openid-configuration
audience: api # REST tokens; MCP tokens carry the resource below
tenant_claim: org
agents:
mcp:
resources:
api.example.com: https://api.example.com/mcpopenapi: 3.1.0
info: { title: Orders, version: "1.0.0" }
components:
securitySchemes:
customers: { type: openIdConnect, openIdConnectUrl: https://login.example.net/.well-known/openid-configuration }
paths:
/orders/{id}:
get:
operationId: getOrder
summary: Read one order
x-flexway-tool: true # a tool named getOrder, described by the summary
security: [ { customers: [orders:read] } ]
parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
responses: { "200": { description: One order } }
/orders:
post:
operationId: createOrder
x-flexway-tool: { name: create_order, description: Place an order for the caller }
security: [ { customers: [orders:write] } ]
requestBody:
required: true
content:
application/json:
schema: { type: object, required: [sku], properties: { sku: { type: string } } }
responses: { "201": { description: Created } }
/orders/export:
get:
operationId: exportOrders # not marked: never offered to an agent
responses: { "200": { description: CSV } }What is delivered in the published release v1.6.3, and what is coming; a feature is never shown as delivered before its release.
| Feature | Status |
|---|---|
| MCP surface: the contract's operations offered as tools | Delivered · v0.1.0 |
| OAuth 2.1 resource server, RFC 9728 metadata | Delivered · v0.1.0 |
| RFC 8693 token exchange: human subject, agent actor | Delivered · v0.1.0 |
| Delegation bounded in time and depth, cascading revocation | Delivered · v0.1.0 |
| MCP federation: existing MCP servers under the same authorisation, quota and audit | Delivered · v0.1.0 |
| A2A governance: signed agent cards, traffic under quota and audit | In progress |
| Agents dashboard: tools called, cost, scopes | Delivered · v1.2.0 |
| Issuer validation and resource indicators (RFC 8707) | Delivered · v0.1.0 |
| Client ID Metadata Documents; the case of unattended agents | Delivered · v0.1.0 |
The other expectations of this domain
unattended: false; approval and task rights are missingPartly · next in 1.10redact); in prompts, nothing yet: deterministic detectors and maskingPlanned in 1.9Flexwiz is a young company: you talk directly with the person who founds it. Tell us what you want to run through Flexway. We talk about your infrastructure and your digital sovereignty requirements.
Online booking is coming soon; until then, an e-mail is enough.