Production-ready TypeScript reference implementation of the Agent-to-Agent (A2A) protocol — server framework, client SDK, and a bidirectional A2A ↔ MCP bridge, all in one monorepo.
The A2A protocol defines how AI agents discover each other, exchange messages, and manage task lifecycles. This project provides the canonical TypeScript implementation — battle-tested Zod schemas, pluggable server adapters, a type-safe client, and infrastructure for authentication, persistence, and observability.
It also includes a bidirectional A2A ↔ MCP bridge, allowing A2A agents to call MCP tools and MCP hosts to delegate work to A2A agents. If you're building interoperable agent systems, this is your starting point.
┌─────────────────────────────────────────────────────────────┐
│ A2A Server │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Express │ │ Hono │ │ AgentExecutor │ │
│ │ Adapter │ │ Adapter │ │ (your logic) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ A2A Client SDK │
│ (discovery, task lifecycle, streaming) │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────────┐
│ Auth │ │Persistence│ │ Observability │
└─────────┘ └──────────┘ └──────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ A2A ↔ MCP Bridge │
│ (bidirectional protocol adapter) │
└─────────────────────────────────────────────────────────────┘
Data flows: ARCHITECTURE.md covers sync JSON-RPC, SSE streaming, A2A → MCP tool calls, and the task state machine in depth.
- Canonical types & validation — Zod schemas derived directly from the A2A protocol specification (
proto/) - Typed error hierarchy —
A2AErrorsubclasses with error codes for every protocol-defined failure mode - JSON-RPC 2.0 transport — Request/response and streaming via Server-Sent Events (SSE)
- Dual HTTP adapters — Express 5 and Hono, with a shared transport-agnostic core
- Task lifecycle management — Full state machine:
submitted → working → input-required → completed/failed/canceled - Pluggable executors — Implement
AgentExecutorto define agent behavior; framework handles protocol wiring - Agent cards — Automatic
/.well-known/agent.jsondiscovery endpoint
- Type-safe discovery — Fetch and validate agent cards with Zod
- Task submission —
sendMessage(sync) andsendSubscribe(SSE streaming) - Streaming consumption —
for await...ofiterator over task events
- Pluggable auth strategies — OAuth2, JWT, and API key verification out of the box
- Custom strategy support — Implement
AuthStrategyfor bespoke auth schemes
- Task store abstraction — Consistent interface across backends
- Batteries included — In-memory store (dev/testing) and Redis-backed store (production)
- A2A → MCP — Expose A2A skills as MCP tools, forward tool calls to agent executors
- MCP → A2A — Discover MCP tools as agent skills, invoke them from within A2A tasks
- Zero-copy passthrough — Message parts flow directly between protocols
- Structured logging — Pino-based JSON logging with configurable levels
- Tracing hooks — Instrumentation points for request lifecycle, task transitions, and errors
- Metrics — Prometheus-compatible counters, histograms, and gauges
All packages are published under @reaatech:
# Core types and schemas
pnpm add @reaatech/a2a-reference-core
# Server framework
pnpm add @reaatech/a2a-reference-server
# Client SDK
pnpm add @reaatech/a2a-reference-client
# Authentication
pnpm add @reaatech/a2a-reference-auth
# Task persistence
pnpm add @reaatech/a2a-reference-persistence
# A2A ↔ MCP bridge
pnpm add @reaatech/a2a-reference-mcp-bridge
# Observability
pnpm add @reaatech/a2a-reference-observabilitygit clone https://github.com/reaatech/a2a-reference-ts.git
cd a2a-reference-ts
pnpm install # install all workspace dependencies
pnpm build # build all packages
pnpm test # run the full test suite
pnpm lint # lint and check formatting
pnpm typecheck # type-check without emittingimport { createA2AExpressApp } from "@reaatech/a2a-reference-server";
import type { AgentExecutor, ExecutionContext, ExecutionEventBus } from "@reaatech/a2a-reference-server";
const agentCard = {
name: "Hello Agent",
description: "A friendly agent that echoes your message back",
url: "http://localhost:3000",
version: "1.0.0",
protocolVersion: "0.3.0",
capabilities: { streaming: false, pushNotifications: false, stateTransitionHistory: false },
defaultInputModes: ["text/plain"],
defaultOutputModes: ["text/plain"],
skills: [{ id: "echo", name: "Echo", description: "Echo a message back", tags: ["echo"], examples: ["Hello!"] }],
supportedInterfaces: [{ url: "http://localhost:3000", protocolBinding: "a2a", protocolVersion: "0.3.0" }],
};
const executor: AgentExecutor = {
async execute(context: ExecutionContext, eventBus: ExecutionEventBus) {
const text = context.message.parts
.filter((p) => p.kind === "text")
.map((p) => p.text)
.join(" ");
eventBus.emitStatusUpdate({ kind: "status", status: { state: "working" } });
eventBus.emitArtifactUpdate({
kind: "artifact",
artifact: { name: "response", parts: [{ kind: "text", text: `Hello! You said: "${text}"` }] },
});
eventBus.emitStatusUpdate({ kind: "status", status: { state: "completed" } });
},
};
const app = createA2AExpressApp({ agentCard, executor });
app.listen(3000, () => console.log("Agent running at http://localhost:3000"));import { A2AClient } from "@reaatech/a2a-reference-client";
const client = new A2AClient({ baseUrl: "http://localhost:3000" });
// Sync request
const task = await client.sendMessage({
messageId: crypto.randomUUID(),
role: "user",
parts: [{ kind: "text", text: "Hello!" }],
});
console.log(task.artifacts?.[0]?.parts);
// Streaming (SSE)
for await (const event of client.sendSubscribe({
messageId: crypto.randomUUID(),
role: "user",
parts: [{ kind: "text", text: "Count to 5" }],
})) {
if (event.kind === "artifact") {
console.log(event.artifact.parts);
}
}| Package | Description | Dependencies |
|---|---|---|
core |
Canonical A2A types, Zod schemas, error classes | zod |
server |
A2A server framework (Express + Hono) | core, auth, persistence, observability |
client |
A2A client SDK | core |
auth |
Pluggable authentication strategies | jose |
persistence |
Task store abstractions (in-memory + Redis) | core, ioredis |
mcp-bridge |
A2A ↔ MCP bidirectional adapter | core, client, observability, @modelcontextprotocol/sdk |
observability |
Structured logging, tracing, and metrics | pino |
Runnable examples live in the examples/ directory:
| Example | Description |
|---|---|
01-hello-agent |
Minimal echo agent — the simplest possible A2A server |
02-task-streaming |
SSE streaming with progress updates and a client-side consumer |
03-multi-agent-workflow |
Orchestrator pattern — one agent delegates to specialist agents via the client SDK |
04-mcp-bridge |
A2A ↔ MCP bridge in both directions |
05-auth-workflow |
Auth-protected agent with API key and JWT strategies |
Each example has its own README.md with run instructions.
| Document | Content |
|---|---|
| ARCHITECTURE.md | System design, package boundaries, data flows, state machine |
| CONTRIBUTING.md | Development setup, conventional commits, PR process, releasing |
| AGENTS.md | Coding conventions, tooling, and conventions for AI agents |
| docs/deployment.md | Production deployment patterns |
| docs/authentication.md | Auth strategy deep dive |
| docs/protocol-compliance.md | A2A protocol compliance matrix |
| docs/bridge-deep-dive.md | A2A ↔ MCP bridge internals |
| Layer | Technology |
|---|---|
| Language | TypeScript 5.8 (strict mode) |
| Runtime | Node.js ≥ 18 |
| Package manager | pnpm 10 (workspaces) |
| Build | tsup + Turborepo |
| Lint & format | Biome |
| Testing | Vitest |
| Validation | Zod |
| Logging | Pino |
| Versioning | Changesets |
Contributions are welcome. See CONTRIBUTING.md for the full workflow:
- Fork the repo, create a feature branch
- Write code with tests (
vitest), lint withbiome - Run
pnpm lint && pnpm testbefore committing - Use Conventional Commits
- Open a PR
Coding conventions and project guidance live in AGENTS.md.