The EventMesh A2A (Agent-to-Agent) Protocol is a specialized, high-performance protocol plugin designed to enable asynchronous communication, collaboration, and task coordination between autonomous agents.
With the release of v2.0, A2A adopts the MCP (Model Context Protocol) architecture, transforming EventMesh into a robust Agent Collaboration Bus. It bridges the gap between synchronous LLM-based tool calls (JSON-RPC 2.0) and asynchronous Event-Driven Architectures (EDA), enabling scalable, distributed, and decoupled agent systems.
The architecture adheres to the principles outlined in the broader agent community (e.g., A2A Project, FIPA-ACL, and CloudEvents):
Traditional A2A implementations often rely on HTTP Webhooks (POST /inbox) for asynchronous callbacks. While functional, this Point-to-Point (P2P) model suffers from significant scaling issues:
EventMesh A2A solves this by introducing Native Pub/Sub capabilities:
graph LR Publisher[Publisher Agent] -->|1. Publish (Once)| Bus[EventMesh Bus] subgraph Fanout_Layer [EventMesh Fanout Layer] Queue[Topic Queue] end Bus --> Queue Queue -->|Push| Sub1[Subscriber 1] Queue -->|Push| Sub2[Subscriber 2] Queue -->|Push| Sub3[Subscriber 3] style Bus fill:#f9f,stroke:#333 style Fanout_Layer fill:#ccf,stroke:#333
graph TD Client[Client Agent / LLM] -- "JSON-RPC Request" --> EM[EventMesh Runtime] EM -- "CloudEvent (Request)" --> Server[Server Agent / Tool] Server -- "CloudEvent (Response)" --> EM EM -- "JSON-RPC Response" --> Client subgraph Runtime [EventMesh Runtime] Plugin[A2A Protocol Plugin] end style EM fill:#f9f,stroke:#333,stroke-width:4px style Plugin fill:#ccf,stroke:#333,stroke-width:2px
eventmesh-protocol-a2a)The core protocol logic resides in the eventmesh-protocol-plugin module.
EnhancedA2AProtocolAdaptor: The central brain of the protocol.CloudEvents or HTTP adaptors when necessary.A2AProtocolConstants: Defines standard operations like task/get, message/sendStream.JsonRpc* Models: Strictly typed POJOs for JSON-RPC 2.0 compliance.AgentCard / AgentSkill / AgentInterface: Agent capability discovery models.A2ATopicFactory: Topic naming and parsing utility for request/response/status topics.A2AClient: Java SDK for agent developers — AgentCard registration, task submission (sync/async), task status query, heartbeat, and transport-based request handling. Returns typed TaskResult objects.A2AMessageTransport: Transport-agnostic pub/sub interface (InMemory implementation for dev/testing).eventmesh-runtime)The Gateway runtime provides a standalone Netty HTTP server bridging external clients to the A2A event bus.
graph TD Client["Client / A2AClient SDK"] -- "HTTP REST" --> Server["A2AGatewayServer<br/>(Netty HTTP)"] Server --> Handler["A2AGatewayHttpHandler"] Handler --> GwService["A2AGatewayService"] GwService --> Registry["TaskRegistry<br/>(state machine + TTL)"] GwService --> Transport["InMemoryA2AMessageTransport"] GwService --> PubSub["A2APublishSubscribeService<br/>(AgentCard discovery)"] Transport -- "publish/subscribe" --> Agent["Target Agent"] Agent -- "response event" --> Transport Transport --> GwService style Server fill:#f9f,stroke:#333,stroke-width:2px style Registry fill:#cfc,stroke:#333 style Transport fill:#ccf,stroke:#333
| Component | Module | Responsibility |
|---|---|---|
A2AGatewayServer | runtime | Standalone Netty HTTP server entry point. Pre-registers mock agents, wires all components. |
A2AGatewayHttpHandler | runtime | HTTP request router. Maps REST endpoints to service calls. Supports SSE streaming. |
A2AGatewayService | runtime | Core orchestration: task submission, response handling, status subscription, SSE push. |
TaskRegistry | runtime | In-memory task lifecycle state machine with TTL auto-cleanup. |
A2APublishSubscribeService | runtime | AgentCard registration, discovery, and heartbeat management. |
InMemoryA2AMessageTransport | runtime | In-memory pub/sub (replaceable by EventMesh broker). |
A2ACardHttpHandler | runtime | AgentCard CRUD REST endpoints (/a2a/cards/*). |
A2AClient | protocol-a2a | Java SDK for agent developers (HTTP + transport). |
SUBMITTED → WORKING → COMPLETED
↘ FAILED
↘ CANCELLED
pendingTasks.put(taskId, future) is called before transport.publish() to ensure the future is registered before any synchronous delivery could trigger handleResponse().| Method | Path | Description |
|---|---|---|
POST | /a2a/tasks?mode=sync | Submit task synchronously (wait for result) |
POST | /a2a/tasks?mode=async | Submit task asynchronously (return taskId immediately) |
GET | /a2a/tasks/{taskId} | Get task status and result |
DELETE | /a2a/tasks/{taskId} | Cancel a task |
GET | /a2a/tasks/{taskId}/wait | Long-poll wait for task result |
GET | /a2a/tasks/{taskId}/stream | SSE stream of task status updates |
GET | /a2a/agents | List all registered agents |
POST | /a2a/heartbeat | Agent heartbeat |
GET | /a2a/cards/list | List all AgentCards |
POST | /a2a/cards/card/{org}/{unit}/{agent} | Register an AgentCard |
To support MCP on an Event Bus, synchronous RPC concepts are mapped to asynchronous events:
| Concept | MCP / JSON-RPC | CloudEvent Mapping |
|---|---|---|
| Action | method (e.g., tools/call) | Type: org.apache.eventmesh.a2a.tools.call.reqExtension: a2amethod |
| Correlation | id (e.g., req-123) | Extension: collaborationid (on Response)ID: Preserved on Request |
| Direction | Implicit (Request vs Result) | Extension: mcptype (request or response) |
| P2P Routing | params._agentId | Extension: targetagent |
| Pub/Sub Topic | params._topic | Subject: The topic value (e.g. market.btc) |
| Streaming Seq | params._seq | Extension: seq |
ProtocolTransportObject (byte array/string).jsonrpc: "2.0".method.message/sendStream, sets type suffix to .stream and extracts _seq._topic present, sets subject (Pub/Sub)._agentId present, sets targetagent (P2P).result/error. Sets collaborationid = id.List<CloudEvent>._agentId or _topic from JSON body to CloudEvent attributes.message/sendStream.stream event type and preserves sequence order via seq extension attribute.GET /a2a/tasks/{taskId}/streamtext/event-stream) pushes real-time task state transitions.DefaultHttpContent chunks directly to the Netty channel, returning null to skip the standard FullHttpResponse path.POST /a2a/heartbeat refreshes the last-seen timestamp.Raw Payload:
{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "weather_service", "arguments": { "city": "New York" } }, "id": "msg-101" }
Raw Payload:
{ "jsonrpc": "2.0", "method": "market/update", "params": { "symbol": "BTC", "price": 50000, "_topic": "market.crypto.btc" } }
Generated CloudEvent:
subject: market.crypto.btctargetagent: (Empty)The A2A Gateway provides a REST API for external clients and non-Java agents.
curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \ -H 'Content-Type: application/json' \ -d '{"targetAgent":"weather-agent","message":"Beijing"}'
Response:
{ "taskId": "task-a1b2c3d4", "state": "COMPLETED", "data": "The weather in Beijing is sunny, 25°C" }
curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \ -H 'Content-Type: application/json' \ -d '{"targetAgent":"weather-agent","message":"Shanghai"}'
curl -N http://localhost:10105/a2a/tasks/{taskId}/stream
Response (text/event-stream):
data: {"taskId":"task-a1b2c3d4","state":"SUBMITTED"}
data: {"taskId":"task-a1b2c3d4","state":"WORKING","data":"processing..."}
data: {"taskId":"task-a1b2c3d4","state":"completed","data":"result..."}
curl http://localhost:10105/a2a/agents
A2AClient client = A2AClient.builder() .gatewayUrl("http://localhost:10105") .namespace("global") .agentName("my-agent") .agentCard(card) .heartbeatInterval(30_000) .build(); client.start(); // Synchronous task (returns typed TaskResult) TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); // Asynchronous task (returns taskId immediately) String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null); // Poll status TaskResult status = client.getTaskStatus(taskId); // Cancel boolean cancelled = client.cancelTask(taskId); // List registered agents (typed List<String>) List<String> agents = client.listAgents(); client.shutdown();
InMemoryA2AMessageTransport with the real EventMesh broker for production deployment.methods/list.TaskRegistry state to a durable store for crash recovery.