# How the A2A Protocol Server Enables Agent-to-Agent Communication in OmniRoute

> Learn how the A2A protocol server enables agent-to-agent communication in OmniRoute. Discover its JSON-RPC 2.0 endpoint, real-time SSE updates, and stateful task management for orchestrated skills.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: deep-dive
- Published: 2026-07-12

---

**The A2A protocol server enables agent-to-agent communication by exposing a JSON-RPC 2.0 endpoint at `POST /a2a` that manages task lifecycles, streams real-time updates via Server-Sent Events, and orchestrates reusable skills through a stateful task manager.**

The **A2A protocol server** in the OmniRoute repository provides a standardized infrastructure for autonomous agents to exchange messages and coordinate workflows over HTTP. Built on JSON-RPC 2.0, it handles everything from task creation to skill execution, allowing agents to communicate synchronously or via real-time streaming. This article examines the server architecture, request flow, and implementation details based on the source code in `diegosouzapw/OmniRoute`.

## Core Architecture of the A2A Protocol Server

The server architecture revolves around five primary components that handle the complete lifecycle of agent interactions.

### Task Manager

Located in [`src/lib/a2a/taskManager.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskManager.ts), the **Task Manager** maintains a state machine (`submitted → working → completed/failed/canceled`) for each task. It persists task metadata in SQLite, handles TTL-based cleanup of stale tasks, and assigns UUIDs to track request state across the distributed system.

### Task Execution Engine

The [`src/lib/a2a/taskExecution.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskExecution.ts) module executes the actual logic for each request. It looks up the requested skill, validates input using **Zod** schemas, runs the skill in a sandboxed executor, and manages the transition from task creation to result delivery.

### Streaming Layer

Implemented in [`src/lib/a2a/streaming.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/streaming.ts), this component handles **Server-Sent Events (SSE)** for JSON-RPC streaming. It manages back-pressure, abort signals, and proper JSON-RPC framing for long-running agent interactions.

### Skills Registry

Reusable modules in `src/lib/a2a/skills/*.ts` encapsulate domain logic such as routing, quota management, and provider discovery. Each skill registers a JSON-RPC method name, input schema, and handler function that the execution engine can invoke.

### Routing Logger

The [`src/lib/a2a/routingLogger.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/routingLogger.ts) component records detailed logs of every inter-agent request, providing audit trails and debugging capabilities for production deployments.

## Agent-to-Agent Communication Workflow

When one agent communicates with another through the A2A protocol server, the request flows through five distinct stages:

1. **Request Validation**: The calling agent sends a JSON-RPC payload to `POST /a2a` (e.g., `message/send` or `message/stream`). The server validates the payload against Zod schemas defined in the skill modules.

2. **Task Creation**: `taskManager.createTask()` stores a new task row, assigns a UUID, and returns a task ID to track the operation.

3. **Skill Execution**: `taskExecution.runSkill()` looks up the skill implementation, runs it inside a sandboxed executor, and prepares results for delivery.

4. **Result Propagation**: For streaming calls (`message/stream`), the server pushes JSON-RPC `progress` or `result` messages over an SSE connection. For synchronous calls (`message/send`), the final JSON-RPC response is returned once the skill completes.

5. **Task Finalization**: The task state updates to `completed`, `failed`, or `canceled`. A background TTL cleanup job automatically removes stale tasks from SQLite.

## Practical Implementation Examples

### Synchronous Message Exchange

Agents can send single-request messages using the `message/send` method:

```http
POST /a2a HTTP/1.1
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "params": {
    "targetAgent": "router",
    "payload": { "query": "list available models" }
  },
  "id": "req-123"
}

```

Once the skill finishes, the server returns a standard JSON-RPC response:

```json
{
  "jsonrpc": "2.0",
  "result": {
    "models": ["gpt-4o", "claude-3.5-sonnet", "gemini-1.5-pro"]
  },
  "id": "req-123"
}

```

### Real-Time Streaming

For continuous interactions, use `message/stream` with Server-Sent Events:

```http
POST /a2a HTTP/1.1
Accept: text/event-stream
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "method": "message/stream",
  "params": {
    "targetAgent": "router",
    "payload": { "prompt": "Explain the A2A architecture" }
  },
  "id": "stream-456"
}

```

The server returns partial results as SSE data frames:

```http
data: {"jsonrpc":"2.0","method":"progress","params":{"chunk":"The A2A"}}
data: {"jsonrpc":"2.0","method":"progress","params":{"chunk":" protocol server"}}
data: {"jsonrpc":"2.0","result":{"answer":"The A2A protocol server ..."},"id":"stream-456"}

```

### Direct Skill Invocation

You can also invoke specific skills directly, such as the smart routing skill:

```http
POST /a2a HTTP/1.1
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "method": "smartRouting",
  "params": {
    "taskId": "req-789",
    "candidateProviders": ["openai", "anthropic", "gemini"]
  },
  "id": "req-789"
}

```

Response:

```json
{
  "jsonrpc": "2.0",
  "result": {
    "selectedProvider": "anthropic",
    "reason": "lowest estimated cost for 1k tokens"
  },
  "id": "req-789"
}

```

## Agent Discovery and Capability Negotiation

The A2A server exposes its capabilities via the [`.well-known/agent.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/.well-known/agent.json) endpoint. This public metadata describes available skills, endpoint URLs, and supported protocols, allowing other agents to discover and negotiate capabilities automatically without manual configuration.

## Summary

- **JSON-RPC 2.0 API**: The server exposes a single endpoint at `POST /a2a` supporting both synchronous and streaming communication patterns.
- **Stateful Task Management**: [`src/lib/a2a/taskManager.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskManager.ts) implements a robust state machine with SQLite persistence and automatic TTL cleanup.
- **Real-Time Streaming**: The [`src/lib/a2a/streaming.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/streaming.ts) module enables SSE-based communication for long-running agent workflows.
- **Modular Skill System**: Skills in `src/lib/a2a/skills/*.ts` provide reusable capabilities like routing and quota management that any agent can invoke.
- **Observable Communication**: [`src/lib/a2a/routingLogger.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/routingLogger.ts) captures detailed audit trails of all inter-agent requests.

## Frequently Asked Questions

### What protocol does the A2A server use for agent communication?

The A2A protocol server implements **JSON-RPC 2.0** over HTTP, providing a standardized request-response format. It supports both standard HTTP POST requests for synchronous calls and Server-Sent Events (SSE) for streaming interactions, as defined in the OmniRoute source code.

### How does the server handle real-time streaming between agents?

Real-time streaming uses the `message/stream` method implemented in [`src/lib/a2a/streaming.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/streaming.ts). The server maintains an open SSE connection and pushes JSON-RPC `progress` messages for partial results, followed by a final `result` message when the skill completes. The implementation handles back-pressure and abort signals to ensure reliable delivery.

### What is the purpose of the [`.well-known/agent.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/.well-known/agent.json) file?

The [`.well-known/agent.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/.well-known/agent.json) file serves as a public capability descriptor that allows other agents to discover the server's available skills, endpoint URLs, and supported protocols automatically. This enables dynamic agent networks where participants can negotiate capabilities without hard-coded configuration.

### How does the task manager handle failed or stale tasks?

The **Task Manager** in [`src/lib/a2a/taskManager.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskManager.ts) tracks task states through a defined lifecycle (`submitted → working → completed/failed/canceled`). For failed tasks, it updates the state to `failed` with error details. Stale tasks are automatically cleaned up via a TTL-based background job that removes old entries from the SQLite database.