# EventMesh A2A (Agent-to-Agent Communication Protocol) ## Overview 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. ## Core Features ### 1. MCP over CloudEvents - **Standard Compliance**: Fully supports standard methods defined by **MCP (Model Context Protocol)**, such as `tools/call`, `resources/read`. - **Event-Driven**: Maps synchronous RPC calls to asynchronous **Request/Response Event Streams**, leveraging EventMesh's high-concurrency processing capabilities. - **Transport Agnostic**: All MCP messages are encapsulated within standard **CloudEvents** envelopes, running over any transport layer supported by EventMesh (HTTP, TCP, gRPC, Kafka). ### 2. Dual-Mode Support (Hybrid Architecture) A2A Protocol features a unique **Dual-Mode** architecture that simultaneously supports: 1. **JSON-RPC 2.0 (MCP Mode)**: * **Target**: LLMs, Scripts (Python/JS), LangChain integration. * **Benefit**: Extremely low barrier to entry. Clients send simple JSON objects; the adaptor automatically wraps them in CloudEvents. 2. **Native CloudEvents (Power Mode)**: * **Target**: EventMesh native apps, Knative, Serverless functions. * **Benefit**: Full control over event metadata. Allows pass-through of custom or binary data. **Mechanism**: The `EnhancedA2AProtocolAdaptor` intelligently detects the payload format. If `jsonrpc: "2.0"` is present, it engages the MCP translation engine; otherwise, it treats the payload as a standard CloudEvent (delegating to the underlying CloudEvents adaptor). ### 3. Native Pub/Sub Semantics - **O(1) Broadcast**: Publishers send messages once to a Topic, and EventMesh efficiently fans out to all subscribers. - **Decoupling**: Solves the scalability issues of traditional P2P Webhook callbacks. - **Isolation**: Provides backpressure isolation between publishers and subscribers. ### 3. High Performance & Routing - **Batch Processing**: Natively supports JSON-RPC Batch requests. EventMesh automatically splits them into parallel event streams. - **Intelligent Routing**: Extracts routing hints (`_agentId` for P2P, `_topic` for Pub/Sub) from MCP parameters and injects them into CloudEvents attributes for zero-decoding routing. ### 4. Streaming Support - **Sequencing**: Preserves message order for streaming operations (`message/sendStream`) using sequence IDs. ## Architecture ### Core Components ``` ┌─────────────────────────────────────────────────────────────┐ │ EventMesh A2A Protocol v2.0 │ │ (MCP over CloudEvents Architecture) │ ├─────────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ MCP/JSON-RPC│ │ Native │ │ Protocol │ │ │ │ Handler │ │ Pub/Sub │ │ Delegator │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ ┌───────────────────────────────────────────────────────┐ │ │ │ Enhanced A2A Protocol Adaptor │ │ │ │ (Intelligent Parsing & CloudEvent Mapping) │ │ │ └───────────────────────────────────────────────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ EventMesh Protocol Infrastructure │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ CloudEvents │ │ HTTP │ │ gRPC │ │ │ │ Protocol │ │ Protocol │ │ Protocol │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ### Gateway Runtime Architecture ``` protocol-a2a module runtime module examples module ┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐ │ A2AMessageTransport(Iface) │ A2AGatewayServer │ │ A2AGatewayDemo│ │ A2AClient (SDK) │<──HTTP──>│ (main, Netty HTTP)│<──HTTP──>│ (client only) │ │ AgentCard/Topic │ │ InMemoryTransport │ └──────────────┘ └─────────────────┘ │ GatewayService │ │ TaskRegistry(TTL) │ └──────────────────┘ ``` #### Core Runtime Components | Component | Module | Responsibility | | :--- | :--- | :--- | | `A2AGatewayServer` | runtime | Netty HTTP server entry point, pre-registers mock agents | | `A2AGatewayHttpHandler` | runtime | HTTP request router, supports SSE streaming | | `A2AGatewayService` | runtime | Core orchestration: task submission, response handling, SSE push | | `TaskRegistry` | runtime | In-memory task state machine + TTL auto-cleanup (5 min) | | `A2APublishSubscribeService` | runtime | AgentCard registration, discovery, heartbeat | | `InMemoryA2AMessageTransport` | runtime | In-memory pub/sub (replaceable by EventMesh broker) | | `A2AClient` | protocol-a2a | Java SDK with typed API | ### Asynchronous RPC Pattern To support the MCP Request/Response model within an event-driven architecture, A2A defines the following mapping rules: | MCP Concept | CloudEvent Mapping | Description | | :--- | :--- | :--- | | **Request** (`tools/call`) | `type`: `org.apache.eventmesh.a2a.tools.call.req`
`mcptype`: `request` | Request event. | | **Response** (`result`) | `type`: `org.apache.eventmesh.a2a.common.response`
`mcptype`: `response` | Response event. | | **Correlation** (`id`) | `extension`: `collaborationid` / `id` | Links Response to Request. | | **P2P Target** | `extension`: `targetagent` | Routing target Agent ID. | | **Pub/Sub Topic** | `subject`: `` | Broadcast Topic. | ## Protocol Message Format ### 1. MCP Request (P2P) ```json { "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_weather", "_agentId": "weather-service" // P2P Routing }, "id": "req-123" } ``` ### 2. MCP Request (Pub/Sub) ```json { "jsonrpc": "2.0", "method": "market/update", "params": { "price": 50000, "_topic": "market.btc" // Pub/Sub Routing } } ``` ## Usage Guide ### 1. Initiate Call (Client) ```java // 1. Construct MCP Request JSON String mcpRequest = "{" + "\"jsonrpc\": \"2.0\"," + "\"method\": \"tools/call\"," + "\"params\": { \"name\": \"weather\", \"_agentId\": \"weather-agent\" }," + "\"id\": \"req-001\"" + "}"; // 2. Send via EventMesh SDK eventMeshProducer.publish(new A2AProtocolTransportObject(mcpRequest)); ``` ### 2. Handle Request (Server) Subscribe to the topic `org.apache.eventmesh.a2a.tools.call.req`, process logic, and send back response with matching `id`. ### 3. Gateway REST API The A2A Gateway provides a full REST API for external clients and non-Java agents: ```bash # Sync task curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \ -H 'Content-Type: application/json' \ -d '{"targetAgent":"weather-agent","message":"Beijing"}' # Async task curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \ -H 'Content-Type: application/json' \ -d '{"targetAgent":"weather-agent","message":"Shanghai"}' # Query status curl http://localhost:10105/a2a/tasks/{taskId} # SSE stream curl -N http://localhost:10105/a2a/tasks/{taskId}/stream # List agents curl http://localhost:10105/a2a/agents ``` #### REST API Endpoints | Method | Path | Description | |------|------|------| | POST | `/a2a/tasks?mode=sync` | Submit task synchronously (wait for result) | | POST | `/a2a/tasks?mode=async` | Submit task asynchronously (return taskId) | | GET | `/a2a/tasks/{taskId}` | Get task status | | DELETE | `/a2a/tasks/{taskId}` | Cancel task | | GET | `/a2a/tasks/{taskId}/wait` | Long-poll wait for result | | GET | `/a2a/tasks/{taskId}/stream` | SSE stream of task status updates | | GET | `/a2a/agents` | List registered agents | | POST | `/a2a/heartbeat` | Agent heartbeat | | GET | `/a2a/cards/list` | List all AgentCards | | POST | `/a2a/cards/card/{org}/{unit}/{agent}` | Register AgentCard | ### 4. A2AClient Java SDK ```java A2AClient client = A2AClient.builder() .gatewayUrl("http://localhost:10105") .namespace("global") .agentName("my-agent") .agentCard(card) .heartbeatInterval(30_000) .build(); client.start(); // Sync task (returns typed TaskResult) TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); // Async task (returns taskId) String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null); // Query status TaskResult status = client.getTaskStatus(taskId); // Cancel boolean cancelled = client.cancelTask(taskId); // List agents (returns List) List agents = client.listAgents(); client.shutdown(); ``` ## Version History - **v2.0.0**: Fully Embraced MCP (Model Context Protocol) - Introduced `EnhancedA2AProtocolAdaptor` supporting JSON-RPC 2.0. - Implemented Async RPC over CloudEvents pattern. - Added **Native Pub/Sub** support via `_topic` parameter. - Added **Streaming** support via `_seq` parameter. - **v2.1.0**: Gateway Runtime Architecture - Added `A2AGatewayServer` (Netty HTTP) standalone Gateway service. - Implemented `TaskRegistry` task state machine + TTL auto-cleanup (5 min). - Added SSE streaming response (`GET /a2a/tasks/{taskId}/stream`). - `A2AClient` SDK returns typed objects (`TaskResult`, `List`). - Fixed `pendingTasks` race condition (put-before-publish). - AgentCard registration, discovery, heartbeat management. - 73 test scenarios all passing. ## Contribution Welcome to contribute code and documentation! ## License Apache License 2.0 ## Contact - Project Homepage: https://eventmesh.apache.org - Issues: https://github.com/apache/eventmesh/issues - Mailing List: dev@eventmesh.apache.org