Quickstart
This page is the shortest path from cargo add to a working server you
can drive from another MCP client. The full tutorials live in
Write a server and
Write a client; the snippets
here are the front door.
Hello, server
Add the crate, then drop this into src/main.rs:
use protocol_droid::prelude::*;
/// A greeter: one tool, no state.struct Greeter;
#[protocol_droid::server(name = "greeter")]impl Greeter { /// Greets someone by name. #[protocol_droid::tool] async fn greet(name: String) -> String { format!("hello, {name}") }}
#[tokio::main]async fn main() -> std::io::Result<()> { Greeter.into_server()?.serve_stdio().await}#[protocol_droid::server] generates one method that matters — into_server. The marks inside it
(#[tool], #[resource], #[prompt]) register as the macro expands:
each parameter becomes a property in the tool’s inputSchema, the
doc comment becomes the description a peer reads, and the function
body is wired to the JSON-RPC router without further plumbing. A
#[tool] handler is async even when it awaits nothing, because the
call the macro generates has to produce a future.
Hello, client
Connecting to the server you just built, with the one-call entry point:
use protocol_droid::adapters::secondary::stdio::ChildSpec;use protocol_droid::application::client::Client;
let spec = ChildSpec::new("./target/debug/greeter")?;let client = Client::connect_stdio(&spec).await?;let tools = client.list_tools().await?;Client::connect_stdio is the consumer-side entry point; the spawn,
the handshake, the session bind, and the capability exchange are all
hidden behind one call. The result tools is the typed list the
server registered.
Hello, A2A server
For the A* protocols, the same shape but with the A2A route table mounted on a single axum router. The minimal example is 180 lines and the full reference is 200+; the entry point looks like this:
use std::sync::Arc;use protocol_droid::adapters::primary::a2a::serve_agent::serve_a2a_agent;
let app = serve_a2a_agent( "/a2a", Arc::new(my_agent), // implements A2aRequestHandler Arc::new(my_agent), // implements A2aStreamingRequestHandler Arc::new(my_card),);
let listener = tokio::net::TcpListener::bind("127.0.0.1:8080").await?;axum::serve(listener, app).await?;The streaming path is derived as {jsonrpc_path}/stream and the
well-known path is fixed at /.well-known/agent-card.json per A2A
v1.0 §8. The full walk-through is in
Write an A2A server.
Where to next
- The architecture overview for the one-IR, per-revision codec, runtime feature gating model.
- The CLI reference for
bridge,probe,inspect,record,replay, andconformance. - The security model for the trust boundary between the library and the consumer.