SLIMRPC over AGNTCY SLIM

A2A carried over the AGNTCY SLIM fabric, implementing the SLIMRPC custom protocol binding.

protocolBinding: https://a2a-protocol.org/bindings/experimental-slimrpc/v1
address:         slim://[node-host[:port]/]domain/namespace/service
service:         lf.a2a.v1.A2AService

Read this first

This is not part of the A2A specification. The upstream binding describes itself as "community contributed … not part of the core A2A specification", and the ratified v1.0 spec contains no occurrence of "slim" or "agntcy". Nothing here is required for A2A conformance, and the project's TCK conformance claims cover the three spec bindings (JSON-RPC, HTTP+JSON, gRPC) plus WebSocket, which §12 admits as a custom binding — four in all, and not this one.

It exists because the SLIM fabric is where some deployments already are.

The binding itself is complete against the A2A 1.0 surface of upstream's main: all eleven A2A methods, both streaming methods, plus multicast, driving the same RequestHandler the HTTP bindings drive.

There are two Rust implementations, and neither contains the other

The A2A project ships its own — a2a-slimrpc in a2aproject/a2a-rs. Both implement all eleven A2A methods and pin the same SLIM crates. They diverge in both directions:

this crateofficial a2a-slimrpc
Multicast — one request to N agents, per-agent outcomes back to the calleryesno
Collaborate — many-to-many channel, members see each other's traffic, attributed by slim-srcnoyes, at 0.2.7

Multicast's specification is on upstream main. Collaborate's never reached main: the branch that held it renamed the design twice — slimrpc-broadcast-live.md on 2026-09-02, then slimrpc-collaborative-task.md on 2026-09-11 — and it was that last form upstream merged to main on 2026-09-29, while the official crate still ships Collaborate against the withdrawn text. Upstream's main now also specifies SendLiveMessage, an A2A 1.1 method, which this crate does not implement because no released A2A specification defines it. The current design is not implemented here because it profiles an A2A extension whose timeline semantics are A2A 1.1's, which no released A2A specification defines, and because its native mode needs SLIM shared-responses group channels this crate does not have. The tracking item is B24 in the post-release review, and the binding's README carries the dated detail. Pick on which of the two shapes your deployment needs, not on which crate looks more complete — neither is.

Installation

[dependencies]
a2a-protocol-slimrpc = "0.6"
a2a-protocol-server  = "0.14"

Why two version numbers

a2a-protocol-slimrpc is versioned independently of the SDK — it is at 0.6 while the SDK is at 0.14. Numbering it to match would claim eight minor versions of API stability it has not earned, and would force a bump on every SDK release even when nothing here changed.

Independence applies to the numbers, not the schedule. SlimRpcServer::builder takes an Arc<RequestHandler> and agent_interface() returns an AgentInterface, so a2a-protocol-server and a2a-protocol-types are public dependencies: your RequestHandler must come from the same SDK version this crate was built against. That is why the requirement is a tight pin on one SDK minor — whichever minor the [dependencies] block above names — and not a range: allow two and cargo links both, and you get expected RequestHandler, found RequestHandler, which is among the least helpful errors in Rust.

Two consequences:

  • Every SDK minor bump requires a matching release of this crate.
  • If you only need the types the binding hands you, take them from the binding's own re-exports rather than a second dependency:
use a2a_protocol_slimrpc::{AgentExecutor, RequestHandler, RequestHandlerBuilder};

Server

use a2a_protocol_slimrpc::{SlimName, SlimRpcServer};

let name = SlimName::parse("slim://org/demo/echo_agent")?;
let server = SlimRpcServer::builder(handler, name)
    .with_shared_secret("echo_agent", std::env::var("SLIM_SECRET")?)?
    .build()?;

// Advertise it, or callers cannot discover the binding — §5 makes the card the
// only way a client learns where to connect.
card.supported_interfaces.push(server.agent_interface());

server.serve().await?;

Client

use a2a_protocol_client::ClientBuilder;
use a2a_protocol_slimrpc::{SlimName, SlimRpcTransport};

let agent = SlimName::parse("slim://org/demo/echo_agent")?;
let transport = SlimRpcTransport::builder(agent)
    .with_shared_secret("caller", std::env::var("SLIM_SECRET")?)?
    .connect()?;

let client = ClientBuilder::new("slim://org/demo/echo_agent")
    .with_custom_transport(transport)
    .build()?;

Retries, interceptors, auth and the typed method surface behave exactly as they do over JSON-RPC. Only the wire underneath changes.

Why the code blocks on this page are not compiled

Every other Rust block in this book is compiled as a doctest by the a2a-book-tests crate. These are not, and the reason is structural rather than neglect: a2a-protocol-slimrpc is deliberately outside the root workspace with its own Cargo.lock, because agntcy-slim-rpc pulls 359 transitive dependencies including aws-lc-sys, a native C crypto build. Against 206 for a2a-protocol-server at all features and 11 for a2a-protocol-types at its defaults — both counting normal edges only, as cargo tree --edges normal reports them; add build-dependencies and the server reading is 222 — none of that belongs in the published crates' audit surface, or in the book's test build.

The snippets above are kept in step with the crate's own README and its test suite, which do compile and run.

Traps worth knowing before you start

These each cost real debugging time. All present as something other than what they are.

  • SLIM names carry a fourth instance component (org/ns/agent/NULL_COMPONENT). Key on the full rendering and every multicast response files under a name no member matches: all agents answer, and all of them report as timeouts.
  • A client must announce its own name to the node — app.subscribe(&reply_to, Some(conn)). Channel routes outward only, so without it every call fails its session handshake. This is invisible in-process; only a remote-node topology catches it.
  • SpireIdentityManager must be built once and cloned for provider and verifier, because it holds an MLS signing key — and each app needs its own SPIFFE ID, since two apps sharing one cannot complete an MLS handshake. Both present as a session that never completes, not as an auth error.
  • SPIFFE federation is bundles-before-entries. A -federatesWith entry is rejected unless that domain's bundle is already imported.

What is verified, and what is not

Verified end-to-end across ten topologies, including a real OS process boundary between apps and node, mTLS, and three suites against a real SPIRE.

Not verified — stated plainly because a documented limitation is a work item, not a disclaimer:

GapStatus
Real-network conditions (loss, latency, MTU, NAT)Everything runs on one machine over loopback
Node restart mid-sessionUntested
Agent-card discovery over SLIMYou must know the agent's SLIM name out of band
Federation via bundle endpointManual bundle exchange only; https_spiffe/https_web profiles untouched
X.509 SVID rotation, node TLS cert rotation under a live connectionUntested; rotation coverage is JWT-SVIDs only
Push notification delivery over SLIMConfig methods speak SLIM; delivery is still an HTTP webhook
Static-token identity (with_identity)Supported, no test
Sustained loadRotation is checked with a handful of calls, not traffic
TCK coverageThe "TCK all bindings" job does not include this binding

The specification itself is vendored at spec/slimrpc_v1/, so the method inventory above is checked against the document this binding claims to implement rather than against the A2A proto as a stand-in, and scripts/check_slimrpc_spec.sh fails CI when upstream moves. That closes the one claim here that previously could only be verified by opening a browser — it does not make this binding TCK-conformant, which remains out of reach for the reason given above.

Further reading

The crate's own README goes deeper: the full method inventory, wire format, error mapping, multicast semantics, identity modes, security posture, how to run a node, and the test suite layout.