- Protocol
- A2A
- Type
- SDK
- Stars
- 92
- License
- MIT
- Last push
- Nov 1, 2026
About a2a-rs
a2a-rs is an open-source A2A SDK by EmilLindfors, written mainly in Rust. Independent Rust framework implementing A2A and MCP transports. It has 92 GitHub stars and uses the MIT license, and its code was last pushed on Nov 1, 2026.
New to A2A? Our A2A Protocol guide explains how it works and lists other projects built on it.
At a glance
- Protocol
- A2A
- Type
- SDK
- Language
- Rust
- License
- MIT
- GitHub stars
- 92
- Last push
- Nov 1, 2026
Listed from public GitHub data, checked 2026-11-08. Not scanned by AgenticMart.
Questions about a2a-rs
What is a2a-rs?
Independent Rust framework implementing A2A and MCP transports It is listed as a A2A SDK, maintained in the EmilLindfors/a2a-rs repository on GitHub.
How do I install a2a-rs?
The README in EmilLindfors/a2a-rs has the setup steps. Clone the repository with git clone https://github.com/EmilLindfors/a2a-rs.git and follow its instructions.
Is a2a-rs an official A2A project?
No. It is a community project built on A2A, not published by the organisation that runs the protocol.
What license does a2a-rs use?
It is published under the MIT license. Check the license file in the repository before using it commercially.
Is a2a-rs still maintained?
Its code was last pushed on Nov 1, 2026, and it had 92 GitHub stars when we checked on 2026-11-08. Look at recent issues and releases in the repository for a fuller picture.
README
a2a-rs
An MIT-licensed Rust framework for building multi-agent systems on the Agent2Agent (A2A) protocol.
- Up to spec with A2A 1.0: the types, a client, a server, and the storage behind them.
- The latest MCP: a bridge in both directions on MCP 2026-07-28, and 2025-11-25 for peers that still initialize.
- Three transports: the spec's JSON-RPC 2.0 and HTTP+JSON bindings for interop with the other A2A SDKs, and ConnectRPC as the default between two a2a-rs peers.
- LLM providers and agent payments: OpenAI-compatible endpoints, Gemini, decision models, and the Agent Payments Protocol (AP2).
The core is hexagonal: storage, streaming, push delivery and authentication are ports, and every adapter behind them can be swapped without touching the agent's own logic. Every crate is MIT licensed, so you can build a product or your own agent platform on top.
Project site: https://emillindfors.github.io/a2a-rs/
Crates
| Crate | Directory | What it is |
|---|---|---|
| a2a-rs | The protocol: domain types, ports, transports (ConnectRPC, JSON-RPC 2.0, HTTP+JSON), auth, in-memory and SQLx storage | |
| a2a-cli | Command-line client: card, send, get, list, cancel, stream | |
| a2a-mcp | A2A ↔ MCP bridge in both directions on MCP 2026-07-28 and 2025-11-25, built on rmcp | |
| a2a-llm | Provider-neutral chat completions (OpenAI-compatible, Gemini) and decision models | |
| a2a-ap2 | Agent Payments Protocol (AP2) types and A2A extension helpers | |
| a2a-client | Building blocks for web frontends to A2A agents (SSE with polling fallback, view models, Axum components) |
Two directories are named differently from the crate they hold; the crate name
is what goes in a [dependencies] table.
Quick start
Talk to an agent
cargo install a2acli # or take a prebuilt binary from the a2acli GitHub release
export A2A_URL=http://127.0.0.1:8080
a2acli card # what can this agent do?
a2acli send "hello" # send a message, wait for the reply
a2acli list --state input-required
a2acli negotiates the transport from the agent card (ConnectRPC first, JSON-RPC
as the interop fallback), so it talks to agents written with other SDKs too. For
an agent to point it at, run the quick start below.
Build an agent
[dependencies]
a2a-rs = { version = "0.10", features = ["http-server", "http-client"] }
An agent's business logic can be one Responder: given the message and the
task, return a reply and the state the task ends in.
ResponderMessageHandler does the rest — creating the task, appending history,
announcing every transition to streaming subscribers and push webhooks.
use a2a_rs::adapter::business::{Responder, ResponderMessageHandler};
use a2a_rs::adapter::{
ConnectRpcAdapter, HttpServer, InMemoryStreamingHandler, InMemoryTaskStorage,
SimpleAgentInfo,
};
use a2a_rs::domain::{A2AError, Message, Part, Role, Task, TaskState};
struct Shout;
#[async_trait::async_trait]
impl Responder for Shout {
async fn respond(
&self,
message: &Message,
task: &Task,
) -> Result<(Message, TaskState), A2AError> {
let text: Vec<&str> = message.parts.iter().filter_map(|p| p.get_text()).collect();
let reply = Message::builder()
.role(Role::Agent)
.parts(vec![Part::text(text.join(" ").to_uppercase())])
.message_id(uuid::Uuid::new_v4().to_string())
.task_id(task.id.clone())
.context_id(message.context_id.clone())
.build();
Ok((reply, TaskState::Completed))
}
}
// Inside an async fn:
let storage = InMemoryTaskStorage::new();
let streaming = InMemoryStreamingHandler::new();
let handler = ResponderMessageHandler::new(
storage.clone(),
streaming.clone(),
storage.push_notifier(),
Shout,
);
let card = SimpleAgentInfo::new("shout".to_string(), "http://127.0.0.1:8080".to_string())
.with_description("Repeats what you say, louder".to_string())
.with_streaming();
let processor = ConnectRpcAdapter::new(handler, storage.clone(), storage, card.clone())
.with_streaming_handler(streaming);
HttpServer::new(processor, card, "127.0.0.1:8080".to_string())
.start()
.await?;
And a client:
use a2a_rs::{HttpClient, Message, Transport};
use a2a_rs::domain::SendCompletion;
let client = HttpClient::new("http://127.0.0.1:8080".to_string());
let message = Message::user_text("hello, agent".to_string(), uuid::Uuid::new_v4().to_string());
// `WhenSettled` is the A2A default: the server answers once the task has
// finished, so the reply is already in `task.history`. `None` lets the server
// name the task.
let task = client
.send_task_message(None, &message, None, None, SendCompletion::WhenSettled)
.await?;
Both halves run together in
examples/quickstart.rs, which CI compiles:
cargo run -p a2a-rs --example quickstart --features http-server,http-client
An agent that acknowledges now and finishes later implements
AsyncMessageHandler directly instead of Responder. The other examples in
a2a-rs/examples cover bearer auth, the JSON-RPC server
and client, and SQLx storage.
Feature flags (a2a-rs)
Compile only what you use. The default is server + tracing.
| Feature | What it adds |
|---|---|
server (default) | Server ports, TaskService, in-memory storage and streaming |
tracing (default) | Structured logging via tracing |
client | Client ports, without a transport |
http-client | ConnectRPC client over reqwest (HttpClient) |
jsonrpc-client | Spec JSON-RPC 2.0 + SSE client (JsonRpcClient), for third-party agents |
http-server | ConnectRPC server on Axum (HttpServer) |
jsonrpc-server | Spec JSON-RPC 2.0 and HTTP+JSON routers (jsonrpc_router, rest_router) |
auth | JWT, OAuth2 and OpenID Connect authenticators |
sqlite / postgres | SQLx task storage; enable both and the backend is picked from the URL at runtime |
full | All of the above |
Each feature builds on its own; CI checks every one of them in isolation.
Protocol coverage
The A2A v1.0.0 surface, wire-compatible with the spec:
SendMessageandSendStreamingMessage, blocking or returning immediatelyGetTask,ListTasks(filtered and paged),CancelTask,SubscribeToTask- Push notification config: create, get, list, delete, with webhook delivery
GetExtendedAgentCard, agent card signatures, and the public card readable without credentials on a guarded server- Security schemes: HTTP bearer, API key, OAuth2, OpenID Connect, mTLS
- Every task state, including
input-requiredandauth-required, and artifacts that stay on the task
Beyond the spec, both opt-in and backward-compatible:
- ConnectRPC transport. The spec names
JSONRPC,GRPCandHTTP+JSON. a2a-rs adds ConnectRPC as the default between a2a-rs peers, advertised under the non-specCONNECTRPCbinding. Use the JSON-RPC transport for third-party interop. - Gap-free stream resumption via
Last-Event-ID(W3C SSE, not an A2A feature). Spec clients ignore it and get the standard reconnect-from-current-state behaviour; gap-free resume only applies a2a-rs ↔ a2a-rs.
The full list of divergences is in
a2a-rs → Spec compliance.
Architecture
Transports ConnectRPC · JSON-RPC 2.0 · HTTP+JSON (behind an auth guard)
│
v
Application TaskService
│
v
Ports AsyncMessageHandler AsyncStreamingHandler Authenticator
AsyncTaskLifecycle AsyncEventLog AsyncPushNotifier
AsyncTaskQuery AsyncNotificationManager
AsyncConversationStore AsyncContextStateStore
│
v
Adapters in-memory · SQLite · Postgres · streaming fan-out · JWT · OAuth2 · OIDC
Domain Message · Part · Task · Artifact · AgentCard · TaskState
Transports decode a request and hand it to TaskService, which talks only to
ports. The agent implements AsyncMessageHandler (or a Responder); everything
else has an adapter in-tree that can be replaced.
The ports are the surface a platform built on a2a-rs depends on, so a change to any of them is a breaking change downstream, even when nothing in this repo fails.
Development
The toolchain is Rust 1.96 (rust-version in the workspace manifest; CI has an
MSRV job that holds it to that).
cargo build --workspace
cargo test --workspace --all-targets
cargo clippy -p a2a-rs --all-targets --all-features -- -D warnings
cargo fmt --all -- --check
# The PostgreSQL backend needs a server; without A2A_TEST_POSTGRES_URL its
# tests skip. CI runs them against a postgres:17 service.
A2A_TEST_POSTGRES_URL=postgres://postgres:a2a@localhost:5432/a2a \
cargo test -p a2a-rs --features full --test postgres_storage_test
The suite has unit, integration, property-based and spec-compliance tests, and
a2acli doubles as a cross-SDK interop harness (see its
README).
Releases are cut by release-plz from
Conventional Commits: feat and fix
land in the changelog, and ! marks a breaking change.
- TODO.md — open work, and where help is welcome
- NOTES.md — the reasoning behind the current design
- CHANGELOG.md — what changed, per crate
License
MIT
More A2A projects
All 20 →A2A
Specification and documentation for the Agent2Agent protocol
A2A Python SDK
Python SDK for building A2A clients and servers
tRPC-Agent-Go
Go agent framework with A2A, AG-UI and MCP integration