A2A Support in the API Platform #2743
RakhithaRR
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
What problem are we solving, and why now?
Enterprises are deploying AI agents — their own and third-party — that increasingly call each other over the Agent2Agent (A2A) protocol to delegate tasks. Today a platform/API team has no consistent way to put these agent-to-agent interactions under governance: each agent re-implements its own auth, there is no central identity, authorization ("which agent may call which"), rate limiting, or cost control, and no end-to-end visibility across a multi-agent call chain. Teams want to govern A2A agents the way they already govern their other agent traffic, without modifying agent code.
A2A is now stable. A2A reached v1.0 under the Linux Foundation — its first stable release. The earlier 0.2.x/0.3.x versions changed rapidly and introduced breaking changes, making it risky to build durable gateway support against them; v1.0 provides a stable, vendor-neutral contract we can implement against with confidence. The AI Gateway governs enterprise agent traffic (LLM access, MCP tools), configured through AI Workspace; A2A is the agent-to-agent pillar and is currently the gap.
Who are we solving it for?
Primarily platform / API teams and agent developers in enterprises adopting multi-agent systems, and their security & compliance stakeholders who must audit and constrain agent interactions. Secondarily, the agents themselves (internal systems acting as callers) that need a stable, governed endpoint to reach other agents.
Solution
Introduce a new proxy type (
a2aproxy) in the gateway and the AI Workspace to onboard agents.flowchart LR subgraph CP["Control Plane — AI Workspace"] REG["A2A agent onboarding · policies<br/>security config · analytics"] end CLIENT["A2A clients /<br/>calling agents"] subgraph DP["Data Plane — AI Gateway"] GW["a2aproxy<br/>• Agent Card mediation<br/>• Transports: JSON-RPC / HTTP+JSON<br/>• Authentication<br/>• Rate limiting<br/>• Guardrails<br/>• Analytics & observability"] end UP["Upstream A2A agents<br/>(A2A v1.x)"] REG <-->|"config · sync"| GW CLIENT -- "A2A request<br/>(JSON-RPC / HTTP+JSON, SSE)" --> GW GW -- "forward request" --> UPThe platform will support the following capabilities:
securityRequirements, skills, etc. based on the user requirements.User Stories
As an agent developer, I want to publish a rewritten Agent Card at the gateway's own well-known URL, so that clients discover the gateway endpoint and all traffic flows through governance.
Acceptance Criteria
/.well-known/agent-card.jsonrelative to the base path of the A2A proxy created, with the URLs rewritten to the gateway address.As an A2A client developer, I want to call the agent over either the JSON-RPC or the HTTP+JSON binding, so that I can use whichever transport my A2A SDK supports.
Acceptance Criteria
/path as well as specific REST endpoints based on the transport protocol used.As an agent developer, I want the gateway to authenticate every caller against a declared scheme before forwarding, so that only authorized clients can reach an agent.
Acceptance Criteria
As an agent developer, I want the public Agent Card to expose only non-sensitive metadata, so that discovery does not leak internal endpoints or sensitive skills.
Acceptance Criteria
As a security & compliance officer, I want the gateway to verify and optionally re-sign Agent Card signatures, so that clients can trust the card was not tampered with.
Acceptance Criteria
As an agent developer, I want to apply rate limits, so that expensive A2A operations can be constrained independently of cheap ones.
Acceptance Criteria
SendMessagevstasks/get) and enforced independently.As an agent developer, I want end-to-end traces and per-agent metrics for A2A traffic, so that I can monitor and troubleshoot multi-agent interactions.
Acceptance Criteria
gen_ai.agent.idand the A2A operation.Challenges
allOforanyOfsort of scenarios. Need to check whether we can support such scenarios through our policy approach.Card Mediation: where the rewrite executes, and card curation for discovery
The gateway serves a rewritten Agent Card, not the upstream one —
supportedInterfaces[].urlrewritten to the gateway,securitySchemes/securityRequirementsderived from the attached frontend-auth policy, upstream security stripped, optionally re-signed with the gateway key + published JWKS. Two questions: where the rewrite runs, and who can curate the result.Runtime serving is settled
However the card is produced, the gateway serves it from a local, non-forwarding route at
/{context}/.well-known/agent-card.json— the same pattern used to synthesize MCP's OAuth Protected Resource Metadata. The gateway never proxies the well-known path upstream at request time (available even if upstream is down, consistent across replicas). Unlike the MCP tool list (proxied live + policy-filtered), a signed discovery card is curated config, so the synth pattern fits.Where the rewrite executes
Option A — control-plane only. platform-api rewrites and bakes the finished card into the deployed config; the gateway just serves it. Problem: gateway-only users must hand-author the whole
agentCardblock.Option B — gateway-controller, deploy-time (recommended). fetch + validate + rewrite in the controller transformer, once at deploy/reconcile. The user supplies only
agentCardUrl; the controller produces the served card. Works for both modes; AI Workspace layers editing on top of the same logic. Trade-off: one-time upstream fetch at deploy (retry / degraded status); an explicitspec.agentCardoverride remains available for air-gapped deployments.The controller derives everything the Option-A card spells out by hand — the rewritten
supportedInterfaces[].url(fromcontext+ gateway host), andsecuritySchemes/securityRequirements(from thejwt-authpolicy). NoagentCardblock needed in the common case.Card editing & devportal publishing (discovery)
Editing the card in AI Workspace is valuable beyond mediation: the controller-generated card is a baseline, and the workspace lets operators curate it — descriptions, tags, surfaced skills, public-vs-extended split, docs links. The curated card then has two destinations:
This directly addresses the registry gap noted above (A2A has no standardized registry yet, a2aproject/A2A#741) — the devportal becomes the discovery surface for governed A2A agents, exactly as it already is for REST/MCP/LLM APIs. Curation feeds both destinations from one edited card.
Consequences to design for
Proposal: card mediation = a deploy-time controller transform keyed off
agentCardUrl(with inlinespec.agentCardoverride), producing a baseline card served from a synth well-known route. AI Workspace adds a curation/editing layer on that card, and the curated result is published to both the gateway and the devportal — making the devportal the discovery catalog for A2A agents in the absence of a protocol-standard registry.Transports: JSON-RPC methods ↔ HTTP+JSON paths (v1.0)
Every A2A operation maps onto both bindings the gateway must support. In JSON-RPC everything hits
POST /and the operation is selected by themethodfield; in HTTP+JSON the operation is the HTTP verb + path. These are the routes the gateway classifies, authenticates, and rate-limits.POST /)SendMessagePOST /message:sendSendStreamingMessagePOST /message:streamSubscribeToTaskGETorPOST /tasks/{id}:subscribeGetTaskGET /tasks/{id}ListTasksGET /tasksCancelTaskPOST /tasks/{id}:cancelGetExtendedAgentCardGET /extendedAgentCardGET /.well-known/agent-card.json(The push-notification / webhook config operations —
CreateTaskPushNotificationConfigetc. /…/tasks/{id}/pushNotificationConfigs— are deferred along with the gateway-mediated webhook story and omitted here.)How the two bindings differ (same operations, different envelope):
POST /; the operation is chosen by themethodfield (PascalCase), andparamscarries the request message. Responses are wrapped in the JSON-RPC envelope ({"jsonrpc","id","result"}), withresultholding the typed payload (e.g.SendMessageResponse={"task": …}).POSTs the body is the bare request message (no JSON-RPC wrapper) and the response is the bare object.{id}is the task id.SendStreamingMessage,SubscribeToTask) returntext/event-stream(SSE) in both bindings; each frame is aStreamResponseenvelope ({"statusUpdate": …}/{"artifactUpdate": …}/{"task": …}), wrapped in a JSON-RPCresultfor JSON-RPC, or emitted bare for REST.Beta Was this translation helpful? Give feedback.
All reactions