A2A
Purpose
A2A (Agent2Agent) is the platform's second AI-facing protocol surface, alongside MCP. Where MCP governs discrete tool calls, A2A governs agent-to-agent conversations. The platform exposes the same published capabilities — Mapping toolsets and any other capability contributor — through both surfaces, under the same tenant/client scoping, governance authorization, credential brokering, and audit pipeline.
Functionally, A2A is the component that lets another agent (an orchestrator, a third-party AI system) discover and invoke ApiMapper's governed tools as A2A skills, without ApiMapper forking any of its existing tool catalog, authorization, or invocation logic to do it.
What A2A Does
A2A supports two roles. Every registered agent is one of two kinds, deciding what actually executes when a caller reaches it:
- Remote agent (concentrator): a governed proxy for agent-to-agent traffic between other systems. The platform keeps a directory of remote agents it can call out to on a caller's behalf, with the same credential custody and audit trail it already gives downstream HTTP/SOAP APIs. A remote agent's own Agent Card is fetched, cached and served back to callers at the agent's own address. Registering agents, granting access policies and publishing an agent are all done in the Agent Directory admin page. Task status transitions can be pushed to a caller-registered webhook — see A2A Push Notifications.
- Hosted agent (LLM-backed): an agent the platform executes itself, reasoning with an LLM instead of proxying to a remote peer. An admin defines one or more Skills on a hosted agent — a name, a prompt, and an explicit, curated subset of individual tools drawn from the tenant's MCP toolsets and ESRA exposures marked available to Hosted Agents — and a caller's message is handed to that skill's LLM turn, built on Microsoft Agent Framework. The LLM decides which tool to call and with what arguments (every call still goes through the exact same governed tool invocation pipeline a deterministic call uses), or, if the request is incomplete, asks a clarifying question instead of failing outright. See A2A Hosted Agent Mode.
Main Flow
Every A2A message is addressed to a specific agent. There is no tenant-wide skill catalog and no way to reach a Mapping tool by speaking A2A — an agent that cannot speak MCP does not get to call a tool by speaking A2A instead. What differs between the two kinds of agent is what happens after the message is accepted.
- A caller identifies a tenant, a client application and the agent it wants to talk to.
- The caller requests that agent's Agent Card (
GET /.well-known/agent-card.jsonat the agent's route, or the authenticated extended card via JSON-RPCGetExtendedAgentCard). The card'sskills[]are the agent's own skills, filtered to the ones this caller is authorized for. - The caller sends a
SendMessage. The message is A2A's own — a role, one or more parts, and the sender'smessageId,contextId,taskIdandmetadata, all carried through. It names no skill:skillIdwas never an A2A field, and what to do with a message is the agent's decision. - The platform authorizes the caller against the agent's access policies, and refuses outright if it cannot — an unauthorized caller is not given a task id.
- It then answers with a
TaskinTASK_STATE_SUBMITTED, and does the work afterwards.- A hosted agent runs an LLM turn over the union of the tools its caller's authorized skills grant.
Every tool call goes through the same governance → credential resolution → downstream invocation →
audit pipeline
tools/calluses. The task moves toTASK_STATE_WORKINGand then to a terminal state, or pauses atinput-required/auth-requiredwhen the agent needs something from the caller. - A remote agent relays the message to its peer; the task tracks that outbound call.
- A hosted agent runs an LLM turn over the union of the tools its caller's authorized skills grant.
Every tool call goes through the same governance → credential resolution → downstream invocation →
audit pipeline
- The task is persisted at every transition, so
GetTaskcan be polled,SubscribeToTaskcan follow it live, and a push notification fires when it finishes or pauses.SendStreamingMessagereports the same sequence over SSE, starting with the task's real id. See A2A Task Lifecycle.
Functional Capabilities
- A2A Agent Card Discovery
- A2A Task Lifecycle
- A2A Concentrator Mode
- A2A Push Notifications
- A2A Hosted Agent Mode
This is the full capability set for A2A protocol support — server mode (both deterministic Mapping-tool skills and LLM-backed Hosted Agent skills), streaming/task store, concentrator mode, push notifications/monitoring, and the gRPC/REST transport bindings below are all implemented. Further work (Agent Card signing, SDK client support, auto-bridging between MCP and A2A catalogs) is filed as a follow-up plan, not scheduled.
Protocol Version and Wire Shape
A2A 1.0.0, served over three transports, all mounted under the same agent host and dispatching into the identical handler classes — no business logic is duplicated per transport:
JSON-RPC 2.0 (
POST /on the agent's own host) — the original transport; also carries the two inherently-streaming methods (SendStreamingMessage,SubscribeToTask) as an SSE upgrade.gRPC (
A2aGrpcServiceImpl,src/Runtime/CodedProjects.AI.ApiMapper.Runtime.A2a/Grpc/) —lf.a2a.v1.A2AService, generated from the A2A specification's owna2a.proto, vendored into this repository byte for byte. It exposes the full specified method set as unary/server-streaming RPCs:SendMessage,SendStreamingMessage,GetTask,ListTasks,CancelTask,SubscribeToTask, the four push-notification-config RPCs andGetExtendedAgentCard. Registered viaservices.AddGrpc()and mapped withMapGrpcService<A2aGrpcServiceImpl>()on the agent's host.The proto is the address. A gRPC method's URL is derived mechanically from the proto —
/<package>.<service>/<method>at the authority root, with no base path to mount a tenant or an agent under. That is the whole reason A2A needed per-agent hosts: identity has to live in the authority. It is also why the vendored copy is pinned byte-identical by an architecture test — an edit to the package or service name silently moves the address, and nothing else in the build would notice.Because gRPC needs HTTP/2 without TLS (h2c) in local development and a single Kestrel endpoint can't multiplex HTTP/1.1 and HTTP/2 without ALPN,
Runtime.HostandGateway.Hosteach expose a second, dedicated HTTP/2-only endpoint for it.REST/JSON (
A2aRestTransportEndpointRouteBuilderExtensions) — the spec's REST path table (POST /message:send,POST /message:streamas SSE,GET /tasks/{id},POST /tasks/{id}:cancel,POST /tasks/{id}:subscribeas SSE, the push-notification-config CRUD routes,GET /extendedAgentCard) via plainSystem.Text.Jsonbody binding — no protobuf involved.
Every transport is subject to the same transport guard and the same rate-limit policies, so there is no
separate security posture per transport. Method names are PascalCase (SendMessage, GetTask, GetExtendedAgentCard),
matching the unified naming the A2A 1.0 specification uses across its JSON-RPC, gRPC, and REST bindings —
not the slash-style names (message/send) found in pre-1.0 drafts of the specification.
Governance and Audit
A2A reuses every control MCP already has, applied to the new surface: the same inbound authentication,
the same authorization decisions, and the same audit trail. A2A audit records are
written under the same runtime category MCP uses, so a mixed MCP/A2A execution trace renders
as one coherent call in the Call Flow Dashboard with no additional wiring. The Call Flow Dashboard and its
underlying call-list recognize every A2A action with its own icon, label, and call-type badge — the same
way it already recognizes MCP's own tools/call/tools/list-style actions — rather than showing A2A
traffic with a generic fallback.
Supported Integrations
The server direction uses the same integrations Runtime already has for MCP — same trusted identity providers, same Azure Key Vault-backed secret resolution, same downstream HTTP/SOAP target systems. Concentrator mode adds registered remote agents as a further kind of governed outbound integration, reusing the platform's existing target-system and authentication-profile configuration rather than a parallel connection or credential model for agents. Push notifications add one more outbound integration point — a caller-registered webhook per task — governed by the same outbound allowlist and credential-custody rules as every other outbound call this platform makes, never a special case. See A2A Push Notifications.
