# How A2A Protocol Integration Works in Embabel for Agent-to-Agent Communication

> Discover how Embabel integrates the A2A protocol for seamless agent-to-agent communication. Learn about JSON-RPC endpoints, discovery, and bidirectional messaging.

- Repository: [Embabel/embabel-agent](https://github.com/embabel/embabel-agent)
- Tags: how-to-guide
- Published: 2026-08-08

---

**Embabel implements the Google A2A protocol via a Spring Boot auto-configuration module that registers JSON-RPC endpoints for agent discovery and bidirectional communication, supporting both synchronous requests and server-sent event streaming.**

The **A2A protocol integration in Embabel** provides a full-stack implementation of Google’s Agent-to-Agent specification within the `embel-agent` repository. When enabled, the framework exposes standardized HTTP endpoints that allow any A2A-compliant client to discover agent capabilities via an **AgentCard** and exchange messages through JSON-RPC. The architecture separates endpoint registration, request handling, and streaming concerns into distinct Spring components that activate automatically under the `a2a` profile.

## How the A2A Server Auto-Configures in Spring Boot

Activation begins with Spring’s profile system. Adding the `a2a` profile to your [`application.yml`](https://github.com/embabel/embabel-agent/blob/main/application.yml) triggers the `embabel-agent-a2a-autoconfigure` module, which imports `AgentA2AAutoConfiguration` into the application context.

```yaml

# application.yml

spring:
  profiles:
    active: a2a

```

Located at [`embabel-agent-autoconfigure/embabel-agent-a2a-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/a2a/AgentA2AAutoConfiguration.java`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-a2a-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/a2a/AgentA2AAutoConfiguration.java), this configuration class wires the core infrastructure beans: `A2AEndpointRegistrar`, `AutonomyA2ARequestHandler`, `A2AStreamingHandler`, and the Jackson converters required for JSON-RPC serialization. The auto-configuration runs only when the profile is present, ensuring zero overhead for applications that do not require A2A interoperability.

## Dynamic Endpoint Registration with A2AEndpointRegistrar

On `ApplicationReadyEvent`, the `A2AEndpointRegistrar` scans the Spring context for all beans implementing the `AgentCardHandler` interface. For each discovered handler, the registrar dynamically mounts two routes:

- `GET /<path>/.well-known/agent.json` — Returns the **AgentCard** JSON describing the agent’s capabilities, version, and supported methods.
- `POST /<path>` — Accepts JSON-RPC 2.0 requests for both streaming and non-streaming operations.

This registration logic resides in [`embabel-agent-a2a/src/main/kotlin/com/embabel/agent/a2a/server/support/A2AEndpointRegistrar.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-a2a/src/main/kotlin/com/embabel/agent/a2a/server/support/A2AEndpointRegistrar.kt) (lines 46–61). The registrar acts as a bridge between the Spring Web MVC infrastructure and the A2A protocol handlers, eliminating the need for manual route configuration while allowing multiple agents to coexist within a single application under distinct paths.

## Handling A2A JSON-RPC Requests

The `AutonomyA2ARequestHandler` class implements the `A2ARequestHandler` interface and serves as the primary entry point for A2A protocol logic. Located at [`embabel-agent-a2a/src/main/kotlin/com/embabel/agent/a2a/server/support/AutonomyA2ARequestHandler.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-a2a/src/main/kotlin/com/embabel/agent/a2a/server/support/AutonomyA2ARequestHandler.kt), this component distinguishes between synchronous and asynchronous operations:

**Non-streaming methods** (`sendMessage`, `getTask`, `cancelTask`) delegate to `handleJsonRpc`, returning standard JSON-RPC responses with a single result object.

**Streaming methods** (`sendStreamingMessage`, `TaskResubscriptionRequest`) invoke `handleJsonRpcStream`, which creates an `SseEmitter` to maintain a persistent connection. The handler converts incoming request maps using Jackson, routes them to the internal Autonomy service, and emits `TaskStatusUpdateEvent` objects until the final status flag (`"final": true`) terminates the stream.

Throughout the lifecycle, the handler fires `A2ARequestEvent` and `A2AResponseEvent` through the Spring application event publisher, allowing observability components to audit or log agent interactions without modifying core business logic.

## Streaming Architecture and SSE Implementation

Streaming support relies on the `A2AStreamingHandler`, defined in [`embabel-agent-a2a/src/main/kotlin/com/embabel/agent/a2a/server/support/A2AStreamingHandler.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-a2a/src/main/kotlin/com/embabel/agent/a2a/server/support/A2AStreamingHandler.kt). This component manages the lifecycle of server-sent events (SSE) by:

1. Creating an `SseEmitter` instance for each streaming request.
2. Periodically emitting `TaskStatusUpdateEvent` JSON objects representing incremental task progress.
3. Handling client disconnections and completion signals to prevent resource leaks.

The streaming endpoint returns `text/event-stream` content type, enabling A2A clients to receive real-time updates for long-running agent tasks such as content generation or complex data processing workflows.

## Practical Configuration and Usage Examples

Once the `a2a` profile is active, the endpoints become immediately accessible. Use the following examples to interact with an Embabel agent running on port 8080.

**Retrieve the AgentCard for discovery:**

```bash
curl http://localhost:8080/a2a/.well-known/agent.json

```

**Send a non-streaming message:**

```bash
curl -X POST http://localhost:8080/a2a \
  -H "Content-Type: application/json" \
  -d '{
        "jsonrpc": "2.0",
        "id": "msg-1",
        "method": "sendMessage",
        "params": {
          "message": {
            "taskId": "task-123",
            "contextId": "ctx-456",
            "parts": [{ "type": "text", "text": "Summarize the latest news" }]
          }
        }
      }'

```

**Initiate a streaming request:**

```bash
curl -N -X POST http://localhost:8080/a2a \
  -H "Content-Type: application/json" \
  -d '{
        "jsonrpc": "2.0",
        "id": "stream-1",
        "method": "sendStreamingMessage",
        "params": {
          "message": {
            "taskId": "task-789",
            "contextId": "ctx-789",
            "parts": [{ "type": "text", "text": "Generate a poem about AI" }]
          }
        }
      }'

```

The streaming response delivers incremental JSON events until the final status update completes the sequence.

## Summary

- **Auto-configuration**: The `a2a` Spring profile triggers `AgentA2AAutoConfiguration`, which wires all A2A infrastructure beans without manual setup.
- **Dynamic registration**: `A2AEndpointRegistrar` automatically exposes [`/.well-known/agent.json`](https://github.com/embabel/embabel-agent/blob/main//.well-known/agent.json) and JSON-RPC POST endpoints for every `AgentCardHandler` bean.
- **Protocol handling**: `AutonomyA2ARequestHandler` processes both synchronous JSON-RPC calls and asynchronous SSE streams, delegating to the core Autonomy service.
- **Observability**: The implementation fires `A2ARequestEvent` and `A2AResponseEvent` events for cross-cutting concerns like logging and monitoring.
- **Standards compliance**: The endpoints follow Google’s A2A specification exactly, enabling interoperability with any A2A-compatible client or agent framework.

## Frequently Asked Questions

### How do I enable A2A protocol support in an Embabel application?

Activate the `a2a` Spring profile in your [`application.yml`](https://github.com/embabel/embabel-agent/blob/main/application.yml) or via command-line argument (`--spring.profiles.active=a2a`). This imports the `embabel-agent-a2a-autoconfigure` module, which instantiates `AgentA2AAutoConfiguration` and registers the required endpoints automatically.

### What is the difference between streaming and non-streaming A2A requests?

Non-streaming requests (such as `sendMessage` or `getTask`) return a single JSON-RPC response immediately after processing. Streaming requests (such as `sendStreamingMessage`) open an SSE connection via `A2AStreamingHandler` and emit multiple `TaskStatusUpdateEvent` objects incrementally until the task reaches a final state.

### Where does Embabel store the AgentCard metadata used for discovery?

The `AgentCard` JSON is generated by beans implementing the `AgentCardHandler` interface. The `A2AEndpointRegistrar` maps these handlers to `GET /<path>/.well-known/agent.json` routes at startup, serving the metadata dynamically from the handler’s implementation rather than a static file.

### Can I monitor A2A request lifecycle events for auditing purposes?

Yes. `AutonomyA2ARequestHandler` publishes `A2ARequestEvent` before processing begins and `A2AResponseEvent` after completion. You can create Spring event listeners to capture these events for logging, metrics, or security auditing without modifying the core protocol handlers.