合并自 ARCHITECTURE.md + eventmesh-a2a-design.md + README.md + README_EN.md + IMPLEMENTATION_SUMMARY.md + IMPLEMENTATION_SUMMARY_EN.md + TEST_RESULTS.md(2026-08-13)。
- 1. Overview
- 2. Core Philosophy
- 3. Architecture
- 4. Protocol Specification
- 5. Implementation Summary
- 6. Test Results
- 7. 中文使用指南
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):
- JSON-RPC 2.0 as Lingua Franca: Uses standard JSON-RPC for payload semantics, ensuring compatibility with modern LLM ecosystems (LangChain, AutoGen).
- Transport Agnostic: Encapsulates all messages within CloudEvents, allowing transport over any EventMesh-supported protocol (HTTP, TCP, gRPC, Kafka).
- Async by Default: Maps synchronous Request/Response patterns to asynchronous Event streams using correlation IDs.
- Native Pub/Sub Semantics: Supports O(1) broadcast complexity, temporal decoupling (Late Join), and backpressure isolation, solving the scalability limits of traditional P2P webhook callbacks.
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:
-
Insufficient Fan-Out: A publisher must send
$N$ requests to reach$N$ subscribers, leading to$O(N)$ complexity. - Temporal Coupling: Consumers must be online at the exact moment of publication.
- Backpressure Propagation: A slow subscriber can block the publisher.
EventMesh A2A solves this by introducing Native Pub/Sub capabilities:
flowchart LR
Publisher["Publisher Agent"] -->|1. Publish (Once)| Bus["EventMesh Bus"]
subgraph FanoutLayer ["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 FanoutLayer fill:#ccf,stroke:#333
A2A Protocol introduces a unique Hybrid Architecture that bridges the gap between the AI ecosystem (which prefers simple JSON) and the Cloud Native ecosystem (which prefers structured CloudEvents).
| Feature | JSON-RPC 2.0 Mode | Native CloudEvents Mode |
|---|---|---|
| Primary Audience | LLMs, Scripts (Python/JS), LangChain | EventMesh Apps, Knative, Java SDK |
| Philosophy | "Battery Included" | "Power User" |
| Usage | Send raw JSON ({"method":...}) |
Send CloudEvent object |
| Complexity | Low (No SDK required) | Medium (Requires CE SDK) |
| Mechanism | Adaptor automatically wraps JSON in CE | Adaptor passes through the event |
Benefits:
- Zero-Barrier Entry: Developers can interact with the mesh using just
curlor simple JSON libraries. - Full Flexibility: Advanced users retain full control over CloudEvent attributes (Source, Type, Extensions) for complex routing or tracing scenarios.
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
The core protocol logic resides in the eventmesh-protocol-plugin module.
EnhancedA2AProtocolAdaptor: The central brain of the protocol.- Intelligent Parsing: Automatically detects message format (MCP vs. Raw CloudEvent).
- Protocol Delegation: Delegates to
CloudEventsorHTTPadaptors when necessary. - Semantic Mapping: Transforms JSON-RPC methods and IDs into CloudEvent attributes.
A2AProtocolConstants: Defines standard operations liketask/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 (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 typedTaskResultobjects.A2AMessageTransport: Transport-agnostic pub/sub interface (InMemory implementation for dev/testing).
The Gateway runtime provides a standalone HTTP server that bridges 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 implementation (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
- TaskRegistry TTL Cleanup: Terminal-state tasks (COMPLETED/FAILED/CANCELLED) are automatically removed after a configurable TTL (default: 5 minutes). A daemon
ScheduledExecutorServiceruns cleanup every 60 seconds, preventing memory leaks from accumulated historical tasks. - Race Condition Prevention: In
A2AGatewayService.submitTask(), the pending future is registered (pendingTasks.put()) beforetransport.publish(). This ordering is critical becauseInMemoryTransportdelivers messages synchronously — if publish happened first,handleResponse()could execute beforeput()and the future would never complete.
| Method | Path | Description |
|---|---|---|
POST |
/a2a/tasks?mode=sync |
Submit task synchronously (wait for result, 30s timeout) |
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 (configurable timeout) |
GET |
/a2a/tasks/{taskId}/stream |
SSE stream of task status updates (text/event-stream) |
GET |
/a2a/agents |
List all registered agents |
POST |
/a2a/heartbeat |
Agent heartbeat (keeps AgentCard alive) |
GET |
/a2a/cards/list |
List all AgentCards |
POST |
/a2a/cards/card/{org}/{unit}/{agent} |
Register an AgentCard |
The GET /a2a/tasks/{taskId}/stream endpoint provides real-time task status updates via Server-Sent Events:
- Client opens an HTTP connection with
Accept: text/event-stream. - Server sends initial state immediately.
- As task transitions (WORKING → COMPLETED/FAILED/CANCELLED), server pushes
data:events. - On terminal state, server sends final event and closes the connection.
The handler writes directly to the Netty channel (returns null to skip the default writeAndFlush path), using DefaultHttpContent chunks with text/event-stream content type.
The A2AClient provides a typed Java API for agent developers:
A2AClient client = A2AClient.builder()
.gatewayUrl("http://localhost:10105")
.namespace("global")
.agentName("my-agent")
.agentCard(card)
.heartbeatInterval(30_000)
.build();
client.start();
// Typed return: TaskResult instead of raw JSON
TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null);
String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null);
TaskResult status = client.getTaskStatus(taskId);
List<String> agents = client.listAgents(); // typed List<String>
boolean ok = client.cancelTask(taskId);TaskResult uses @JsonAlias("result") to handle the server's result field name while exposing a data property to callers.
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 |
- Ingestion: The adaptor receives a
ProtocolTransportObject(byte array/string). - Detection: Checks for
jsonrpc: "2.0". - Transformation (MCP Mode):
- Request: Parses
method.- If
message/sendStream, sets type suffix to.streamand extracts_seq. - If
_topicpresent, setssubject(Pub/Sub). - If
_agentIdpresent, setstargetagent(P2P).
- If
- Response: Parses
result/error. Setscollaborationid=id.
- Request: Parses
- Batch Processing: Splits JSON Array into a
List<CloudEvent>.
- Mechanism: Promotes
_agentIdor_topicfrom JSON body to CloudEvent attributes. - Benefit: Enables EventMesh Router to perform content-based routing (CBR) efficiently.
- Benefit: Significantly increases throughput for high-frequency interactions.
- Operation:
message/sendStream - Mechanism: Maps to
.streamevent type and preserves sequence order viaseqextension attribute.
- Endpoint:
GET /a2a/tasks/{taskId}/stream - Mechanism: Server-Sent Events (
text/event-stream) pushes real-time task state transitions to the client. - Flow: Initial state → WORKING updates → terminal state (COMPLETED/FAILED/CANCELLED) → connection close.
- Implementation: Handler writes
DefaultHttpContentchunks directly to the Netty channel, bypassing the standardFullHttpResponsepath.
- Problem: Completed/failed tasks accumulate in
TaskRegistryindefinitely, causing memory leaks. - Solution: A daemon
ScheduledExecutorService(a2a-task-ttl-cleanupthread) runs every 60 seconds, removing terminal-state tasks older than the TTL (default: 5 minutes). - Configuration:
TaskRegistry(taskTtlMs, cleanupIntervalMs)constructor allows custom tuning.
- Registration:
POST /a2a/cards/card/{org}/{unit}/{agent}registers anAgentCard. - Heartbeat:
POST /a2a/heartbeatrefreshes the agent's last-seen timestamp. Cards expire after 60 seconds without heartbeat. - Discovery:
GET /a2a/agentsreturns all live agent cards.
This mode is ideal for LLMs, scripts, and simple integrations where you want to send raw JSON without worrying about CloudEvent headers.
Client Sends (Raw JSON):
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "weather",
"city": "Shanghai",
"_agentId": "weather-agent"
},
"id": "req-101"
}EventMesh Converts to:
- Type:
org.apache.eventmesh.a2a.tools.call.req - Extension (targetagent):
weather-agent - Extension (mcptype):
request
Client Sends (Raw JSON):
{
"jsonrpc": "2.0",
"method": "notifications/alert",
"params": {
"message": "System Maintenance in 10 mins",
"_topic": "system.alerts"
}
}EventMesh Converts to:
- Type:
org.apache.eventmesh.a2a.notifications.alert - Subject:
system.alerts - Extension (mcptype):
notification
// See eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpCaller.java
Map<String, Object> request = new HashMap<>();
request.put("jsonrpc", "2.0");
request.put("method", "tools/call");
request.put("params", Map.of("name", "weather", "_agentId", "weather-agent"));
request.put("id", UUID.randomUUID().toString());
CloudEvent event = CloudEventBuilder.v1()
.withType("org.apache.eventmesh.a2a.tools.call.req")
.withData(JsonUtils.toJSONString(request).getBytes())
.withExtension("protocol", "A2A") // Critical to trigger A2A adaptor
.build();
producer.publish(event);This mode provides full control over all CloudEvent attributes and is recommended for robust, typed applications using the EventMesh SDK.
Client Sends (CloudEvent):
{
"specversion": "1.0",
"type": "com.example.rpc.request",
"source": "my-app",
"id": "evt-123",
"data": "...",
"protocol": "A2A",
"targetagent": "target-agent-001"
}Java SDK Example:
// See eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsCaller.java
CloudEvent event = CloudEventBuilder.v1()
.withId(UUID.randomUUID().toString())
.withSource(URI.create("ce-client"))
.withType("com.example.rpc.request")
.withData("application/text", "RPC Payload".getBytes())
.withExtension("protocol", "A2A")
.withExtension("targetagent", "target-agent-001") // Explicit routing
.build();
producer.publish(event);Client Sends (CloudEvent):
{
"specversion": "1.0",
"type": "com.example.notification",
"source": "my-app",
"subject": "broadcast.topic",
"protocol": "A2A"
}Client Sends (CloudEvent):
{
"specversion": "1.0",
"type": "com.example.stream",
"source": "my-app",
"subject": "stream-topic",
"protocol": "A2A",
"sessionid": "session-555",
"seq": "1"
}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"}'Response (HTTP 202):
{
"taskId": "task-e5f6g7h8",
"status": "accepted",
"message": "Task submitted. Use GET /a2a/tasks/task-e5f6g7h8 to check status."
}curl -N http://localhost:10105/a2a/tasks/task-a1b2c3d4/streamResponse (text/event-stream):
data: {"taskId":"task-a1b2c3d4","state":"SUBMITTED"}
data: {"taskId":"task-a1b2c3d4","state":"WORKING","data":"processing..."}
data: {"taskId":"task-a1b2c3d4","state":"completed","data":"The weather in Beijing is sunny, 25°C"}
curl http://localhost:10105/a2a/agentsA2AClient 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();- EventMesh Broker Integration: Replace
InMemoryA2AMessageTransportwith the real EventMesh broker for production deployment. - Schema Registry: Implement dynamic discovery of Agent capabilities via
methods/list. - Sidecar Injection: Fully integrate the adaptor into the EventMesh Sidecar for non-Java agents (Python, Node.js).
- WebSocket Streaming: Extend SSE to bidirectional WebSocket for real-time agent-to-agent dialogue.
- Task Persistence: Persist
TaskRegistrystate to a durable store (Redis/DB) for crash recovery. - Authentication: Add API key / JWT authentication to the Gateway REST API.
A2A 协议已成功重构为采用 MCP (Model Context Protocol) 架构,将 EventMesh 定位为现代化的 智能体协作总线 (Agent Collaboration Bus)。
- 混合引擎 (JSON-RPC & CloudEvents): 实现了智能解析引擎,支持:
- MCP/JSON-RPC 2.0: 面向 LLM 和脚本的低门槛接入,自动封装 CloudEvent。
- 原生 CloudEvents: 面向 EventMesh 原生应用的灵活接入,支持自定义元数据和透传。
- 适配器根据
jsonrpc字段自动分发处理逻辑。
- 异步 RPC 映射: 建立了同步 RPC 语义与异步事件驱动架构 (EDA) 之间的桥梁。
- 请求 (Requests) 映射为
*.req事件,属性mcptype=request。 - 响应 (Responses) 映射为
*.resp事件,属性mcptype=response。 - 关联 (Correlation) 通过将 JSON-RPC
id映射到 CloudEventcollaborationid来处理。
- 请求 (Requests) 映射为
- 路由优化: 实现了"深度内容路由提取":
params._agentId-> CloudEvent 扩展属性targetagent(P2P)。params._topic-> CloudEvent Subject (Pub/Sub)。
- Pub/Sub: 通过将
_topic映射到 CloudEvent Subject,支持 O(1) 广播复杂度。 - 流式 (Streaming): 支持
message/sendStream操作,映射为.stream事件类型,并通过_seq->seq扩展属性保证顺序。
- 数据模型: 定义了符合 JSON-RPC 2.0 规范的
JsonRpcRequest、JsonRpcResponse、JsonRpcErrorPOJO 对象。 - 方法定义: 引入了
McpMethods常量,支持标准操作如tools/call、resources/read。 - AgentCard 模型: 实现了
AgentCard、AgentSkill、AgentInterface、AgentCapabilities等完整的 Agent 能力描述模型。
完整的独立 HTTP Gateway 服务,桥接外部客户端到 A2A 事件总线。
| 组件 | 职责 |
|---|---|
A2AGatewayServer |
Netty HTTP 服务器入口,预注册 mock agent,组装所有组件 |
A2AGatewayHttpHandler |
HTTP 请求路由,支持 SSE 流式响应 |
A2AGatewayService |
核心编排:任务提交、响应处理、状态订阅、SSE 推送 |
TaskRegistry |
内存任务状态机 + TTL 自动清理 |
A2APublishSubscribeService |
AgentCard 注册、发现、心跳管理 |
InMemoryA2AMessageTransport |
内存 pub/sub 实现(可替换为 EventMesh broker) |
A2ACardHttpHandler |
AgentCard CRUD REST 端点 |
A2AClient |
Java SDK,提供类型化 API |
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/a2a/tasks?mode=sync |
同步提交任务 |
POST |
/a2a/tasks?mode=async |
异步提交任务 |
GET |
/a2a/tasks/{taskId} |
查询任务状态 |
DELETE |
/a2a/tasks/{taskId} |
取消任务 |
GET |
/a2a/tasks/{taskId}/wait |
长轮询等待结果 |
GET |
/a2a/tasks/{taskId}/stream |
SSE 流式推送状态更新 |
GET |
/a2a/agents |
列出已注册 agents |
POST |
/a2a/heartbeat |
Agent 心跳 |
GET |
/a2a/cards/list |
列出所有 AgentCard |
POST |
/a2a/cards/card/{org}/{unit}/{agent} |
注册 AgentCard |
- 问题: 终态任务(COMPLETED/FAILED/CANCELLED)无限累积导致内存泄漏。
- 方案: 守护线程
ScheduledExecutorService每 60 秒扫描一次,清理超过 TTL(默认 5 分钟)的终态任务。 - 配置:
TaskRegistry(taskTtlMs, cleanupIntervalMs)构造函数支持自定义调优。
- 问题:
InMemoryTransport同步投递消息,若transport.publish()在pendingTasks.put()之前执行,handleResponse()会先于put()运行,导致 future 永不完成。 - 方案: 严格保证
pendingTasks.put(taskId, future)在transport.publish()之前执行,并添加注释说明顺序重要性。
- 改进:
getTaskStatus()返回TaskResult对象(而非原始 JSON 字符串),listAgents()返回List<String>(而非原始 JSON)。 - 兼容:
TaskResult.data字段使用@JsonAlias("result")注解,兼容服务端result字段名。
- 端点:
GET /a2a/tasks/{taskId}/stream - 实现: Handler 直接写入 Netty channel(
DefaultHttpContentchunks),返回null跳过标准FullHttpResponse路径。通过StatusSubscriber回调实时推送状态变更。
- 新建
eventmesh-examples/.../demo/README.md,包含架构图、API 表、curl 示例、SDK 用法、运行方式。
- 协议层单元测试:
EnhancedA2AProtocolAdaptorTest覆盖请求/响应循环、错误处理、通知和批处理。 - Topic 工具测试:
A2ATopicFactoryTest覆盖 topic 生成与解析。 - Gateway 运行时测试:
TaskRegistryTest— 任务状态机 + TTL 清理验证InMemoryA2AMessageTransportTest— 内存传输投递A2AGatewayServiceTest— Gateway 服务层A2AGatewayEndToEndTest— 进程内全链路A2AClientServerIntegrationTest— 真实 HTTP 客户端-服务端集成测试
- 集成演示:
McpIntegrationDemoTest、McpPatternsIntegrationTest、McpComprehensiveDemoTest、CloudEventsComprehensiveDemoTest - 总计: 73 个测试场景,全部通过。
- EventMesh Broker 集成: 用真实 EventMesh broker 替换
InMemoryA2AMessageTransport,实现生产级部署。 - 路由集成: 更新 EventMesh Runtime Router,利用
targetagent和a2amethod扩展属性实现高级路由规则。 - Schema 注册中心: 实现"注册中心智能体 (Registry Agent)",允许智能体动态发布 MCP 能力 (
methods/list)。 - Sidecar 支持: 将 A2A 适配器逻辑暴露在 Sidecar 代理中,允许非 Java 智能体通过 HTTP/JSON 交互。
- WebSocket 流式: 将 SSE 扩展为双向 WebSocket,支持实时 agent 对话。
- 任务持久化: 将
TaskRegistry状态持久化到 Redis/DB,支持崩溃恢复。 - 认证授权: 为 Gateway REST API 添加 API Key / JWT 认证。
Date: 2026-06-19 Version: v2.0.0 (MCP Edition + Gateway Runtime) Status: ✅ PASS
The test suite provides comprehensive coverage across two layers: the Protocol Adaptor (JSON-RPC 2.0 & Native CloudEvents) and the Gateway Runtime (HTTP REST API, Task lifecycle, SSE streaming, AgentCard discovery).
| Test Class | Scenarios | Result | Description |
|---|---|---|---|
EnhancedA2AProtocolAdaptorTest |
12 | PASS | Unit tests covering core protocol logic, MCP parsing, Batching, Error handling, and A2A Standard Ops. |
McpIntegrationDemoTest |
1 | PASS | End-to-end RPC demo using MCP (JSON-RPC). |
McpPatternsIntegrationTest |
2 | PASS | End-to-end Pub/Sub and Streaming demos using MCP (JSON-RPC). |
McpComprehensiveDemoTest |
3 | PASS | Validation of all 3 patterns in MCP mode. |
CloudEventsComprehensiveDemoTest |
3 | PASS | Validation of all 3 patterns in Native CloudEvents mode. |
A2ATopicFactoryTest |
8 | PASS | Topic naming and parsing (request/response/status topics). |
| Test Class | Scenarios | Result | Description |
|---|---|---|---|
TaskRegistryTest |
6 | PASS | Task state machine transitions, parent-child relationships, TTL auto-cleanup. |
InMemoryA2AMessageTransportTest |
4 | PASS | In-memory pub/sub delivery, subscribe/unsubscribe, wildcard topics. |
A2AGatewayServiceTest |
8 | PASS | Gateway service layer: task submission (sync/async), response handling, cancel, status subscription. |
A2AGatewayEndToEndTest |
6 | PASS | In-process end-to-end: client → gateway → transport → agent → response → client. |
A2AClientServerIntegrationTest |
20 | PASS | Real HTTP client-server integration: AgentCard registration, sync/async tasks, status query, cancel, list agents, SSE streaming. |
Total Scenarios: 73 (All Passed)
- MCP Core: Validated Request/Response/Notification mapping.
- Error Handling: Validated JSON-RPC Error object mapping.
- Batching: Validated JSON Array splitting.
- Legacy Removal: Confirmed legacy A2A format is no longer processed.
- A2A Ops: Verified
task/get,message/sendStreammappings.
- Validated topic generation for request, response, and status topics.
- Validated topic parsing (extracting namespace, agent name, task ID, topic type).
- Verified wildcard topic patterns for gateway subscriptions.
- State Machine: SUBMITTED → WORKING → COMPLETED/FAILED/CANCELLED transitions.
- Parent-Child: Task hierarchy tracking and child task listing.
- TTL Cleanup: Verified that terminal-state tasks are removed after TTL expires.
- Concurrency: Thread-safe state transitions under concurrent access.
- Publish/subscribe message delivery.
- Multiple subscribers on the same topic.
- Unsubscribe behavior.
- Wildcard topic matching.
- Sync Task: submitTask → publish → handleResponse → future.complete.
- Async Task: submitTask returns immediately, status queried separately.
- Cancel: cancelTask transitions state and completes future with CANCELLED.
- Race Condition: Verified put-before-publish ordering prevents lost responses.
- Status Subscription: StatusSubscriber receives state transition callbacks.
- Full flow: A2AClient → Gateway HTTP → GatewayService → Transport → Agent → Response → Client.
- Verified task ID correlation across all components.
- Multiple concurrent tasks.
- Error scenarios (unknown agent, task not found).
- Real HTTP: Uses Apache HttpClient to hit the real Netty server.
- AgentCard: Registration and heartbeat via REST API.
- Sync Task:
POST /a2a/tasks?mode=syncreturns completed result. - Async Task:
POST /a2a/tasks?mode=asyncreturns taskId, thenGET /a2a/tasks/{taskId}polls status. - Cancel:
DELETE /a2a/tasks/{taskId}cancels the task. - List Agents:
GET /a2a/agentsreturns registered agent list. - Typed Returns:
A2AClient.getTaskStatus()returnsTaskResult,listAgents()returnsList<String>. - SSE Stream:
GET /a2a/tasks/{taskId}/streamreceives real-time state updates viatext/event-stream.
- Simulated Client → EventMesh → Server flow.
- Verified correlation ID linking (
req-id<->collaborationid).
- Pub/Sub: Verified
_topic->subjectmapping for Broadcast. - Streaming: Verified
_seq->seqmapping for ordered chunks.
- RPC: Request/Response flow verification.
- Pub/Sub: Broadcast to Topic routing verification.
- Streaming: Sequence ID preservation verification.
- RPC: Verified manual construction of
.req/.respCloudEvents works. - Pub/Sub: Verified manual setting of
subjectworks. - Streaming: Verified manual setting of
seqextension works.
- JDK: Java 8 (Source/Target 1.8), Compatible with Java 21 Runtime
- Build System: Gradle 7.x+
- Dependencies: Jackson 2.18+, CloudEvents SDK 3.0+, Netty 4.1+, Apache HttpClient
The A2A Protocol v2.0 implementation is stable, functionally complete, and ready for production deployment. It successfully supports:
- Hybrid Architecture (MCP & CloudEvents) with all three interaction patterns (RPC, Pub/Sub, Streaming)
- Gateway Runtime with full REST API, SSE streaming, task lifecycle management, TTL auto-cleanup, and typed Java SDK
- 73 test scenarios across protocol and runtime layers, all passing
您只需要发送标准的 JSON-RPC 格式消息到 EventMesh:
// 1. 构造 MCP Request JSON
String mcpRequest = "{"
"jsonrpc": "2.0",
"method": "tools/call",
"params": { "name": "weather", "_agentId": "weather-agent" },
"id": "req-001"
"}";
// 2. 通过 EventMesh SDK 发送
eventMeshProducer.publish(new A2AProtocolTransportObject(mcpRequest));订阅相应的主题,处理业务逻辑,并发送回响应:
// 1. 订阅 MCP Request 主题
eventMeshConsumer.subscribe("org.apache.eventmesh.a2a.tools.call.req");
// 2. 收到消息后处理...
public void handle(CloudEvent event) {
// 解包 Request
String reqJson = new String(event.getData().toBytes());
// ... 执行业务逻辑 ...
// 3. 构造 Response
String mcpResponse = "{"
"jsonrpc": "2.0",
"result": { "text": "Sunny" },
"id": """ + event.getId() + """
"}";
// 4. 发送回 EventMesh
eventMeshProducer.publish(new A2AProtocolTransportObject(mcpResponse));
}A2A Gateway 提供完整的 REST API,支持非 Java 客户端通过 HTTP 交互:
# 同步提交 task
curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \
-H 'Content-Type: application/json' \
-d '{"targetAgent":"weather-agent","message":"Beijing"}'
# 异步提交 task
curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \
-H 'Content-Type: application/json' \
-d '{"targetAgent":"weather-agent","message":"Shanghai"}'
# 查询状态
curl http://localhost:10105/a2a/tasks/{taskId}
# 列出 tasks(支持 state/limit/offset)
curl 'http://localhost:10105/a2a/tasks?state=COMPLETED&limit=20&offset=0'
# SSE 流式推送(含 heartbeat 保活)
curl -N http://localhost:10105/a2a/tasks/{taskId}/stream
# 健康检查
curl http://localhost:10105/a2a/health
# 列出 agents
curl http://localhost:10105/a2a/agents| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /a2a/tasks?mode=sync |
同步提交 task(等待结果) |
| POST | /a2a/tasks?mode=async |
异步提交 task(立即返回 taskId) |
| GET | /a2a/tasks?state=&limit=&offset= |
分页列出 tasks,可按状态过滤 |
| GET | /a2a/tasks/{taskId} |
查询 task 状态 |
| DELETE | /a2a/tasks/{taskId} |
取消 task |
| GET | /a2a/tasks/{taskId}/wait |
长轮询等待 task 结果 |
| GET | /a2a/tasks/{taskId}/stream |
SSE 流式推送 task 状态更新 |
| GET | /a2a/agents |
列出所有已注册 agents |
| POST | /a2a/heartbeat |
Agent 心跳 |
| GET | /a2a/cards/list |
列出所有 AgentCard |
| POST | /a2a/cards/card/{org}/{unit}/{agent} |
注册 AgentCard |
A2AClient client = A2AClient.builder()
.gatewayUrl("http://localhost:10105")
.namespace("global")
.agentName("my-agent")
.agentCard(card)
.heartbeatInterval(30_000)
.build();
client.start();
// 同步 task(返回类型化 TaskResult)
TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null);
// 异步 task(返回 taskId)
String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null);
// 查询状态
TaskResult status = client.getTaskStatus(taskId);
// 取消
boolean cancelled = client.cancelTask(taskId);
// 列出 agents(返回 List<String>)
List<String> agents = client.listAgents();
client.shutdown();A2A 协议不限制 method 的名称。您可以定义自己的业务方法,例如 agents/negotiate 或 tasks/submit。EventMesh 会自动将其映射为 CloudEvent 类型 org.apache.eventmesh.a2a.agents.negotiate.req。
由于 A2A 兼容标准的 JSON-RPC 2.0,您可以轻松编写适配器,将 LangChain 的 Tool 调用转换为 EventMesh 消息,从而让您的 LLM 应用具备分布式、异步的通信能力。
-
v2.0.0: 全面拥抱 MCP (Model Context Protocol)
- 引入
EnhancedA2AProtocolAdaptor,支持 JSON-RPC 2.0。 - 实现异步 RPC over CloudEvents 模式。
- 支持 Request/Response 自动识别与语义映射。
- 保留对 Legacy A2A 协议的完全兼容。
- 引入
-
v2.1.0: Gateway 运行时架构
- 新增
A2AGatewayServer(Netty HTTP) 独立 Gateway 服务。 - 实现
TaskRegistry任务状态机 + TTL 自动清理(5 分钟)。 - 支持 SSE 流式响应 (
GET /a2a/tasks/{taskId}/stream)。 A2AClientSDK 返回类型化对象 (TaskResult,List<String>)。- 修复
pendingTasks竞态条件(put-before-publish)。 - AgentCard 注册、发现、心跳管理。
- 73 个测试场景全部通过。
- 新增
欢迎贡献代码和文档!请参考以下步骤:
- Fork项目仓库
- 创建功能分支
- 提交代码更改
- 创建Pull Request
Apache License 2.0