{"slug": "mit-licensed-rust-framework-for-multi-agent-systems-in-rust", "title": "MIT-licensed Rust framework for multi-agent systems in Rust", "summary": "A new MIT-licensed Rust framework, a2a-rs, implements the Agent2Agent (A2A) protocol end to end, letting developers write an agent as a single trait and serve it over ConnectRPC, JSON-RPC 2.0, and HTTP+JSON from the same agent. The framework supports MCP 2026-07-28 and 2025-11-25, exposes agents as MCP tools or hands them an MCP server's tools, and ships SQLite or PostgreSQL storage, JWT, OAuth2 and OpenID Connect auth, retries and tracing behind individual feature flags. Every crate is MIT licensed, and no adapter is load-bearing, so developers can embed it in a commercial product or build their own agent platform on top.", "body_md": "a2a-rs is a framework for agents that work together. Write an agent as one trait, serve it over the transport its peers speak, and reach MCP tools and LLMs through the same ports. It implements the Agent2Agent protocol end to end, and the MIT license means you can build your product on it.\n\n`cargo add a2a-rs`\nThe protocol, the bridges, and the plumbing a multi-agent system needs, with every piece of infrastructure behind a port you can replace.\n\nMessages, tasks, artifacts, push notifications, extended agent cards and card signatures, and every task state. The few divergences are opt-in, backward-compatible, and documented.\n\nMCP 2026-07-28, and 2025-11-25 for peers that still initialize. Expose an agent as MCP tools, or hand an agent an MCP server's tools. A slow call becomes an MCP task; a question asked mid-call reaches the agent.\n\nServe ConnectRPC, JSON-RPC 2.0 and HTTP+JSON from the same agent. Clients negotiate from the agent card, and the spec bindings are crossed against the official A2A Rust SDK in both directions.\n\nAgent cards to discover what a peer can do, contexts that carry a\n          conversation across tasks, `input-required` hand-offs,\n          streams that resume without gaps, and push webhooks.\n\nSQLite or PostgreSQL storage, JWT, OAuth2 and OpenID Connect auth, retries and tracing. Each sits behind its own feature flag, so you compile only what you use.\n\nEvery crate here is MIT licensed: embed it in a commercial product, fork it, or build your own agent platform on top. No adapter is load-bearing, so nothing locks you in.\n\n      Implement `Responder`: given the message and the task, return a\n      reply and the state the task ends in. `ResponderMessageHandler`\n      creates the task, keeps its history, and announces every transition to\n      stream subscribers and push webhooks.\n    \n\n```\nuse a2a_rs::adapter::business::Responder;\nuse a2a_rs::domain::{A2AError, Message, Part, Role, Task, TaskState};\n\n/// Reply with the message in capitals, and finish the task.\nstruct Shout;\n\n#[async_trait::async_trait]\nimpl Responder for Shout {\n    async fn respond(\n        &self,\n        message: &Message,\n        task: &Task,\n    ) -> Result<(Message, TaskState), A2AError> {\n        let text: Vec<&str> = message.parts.iter().filter_map(|p| p.get_text()).collect();\n        let reply = Message::builder()\n            .role(Role::Agent)\n            .parts(vec![Part::text(text.join(\" \").to_uppercase())])\n            .message_id(uuid::Uuid::new_v4().to_string())\n            .task_id(task.id.clone())\n            .context_id(message.context_id.clone())\n            .build();\n        Ok((reply, TaskState::Completed))\n    }\n}\nuse a2a_rs::adapter::business::ResponderMessageHandler;\nuse a2a_rs::adapter::{\n    ConnectRpcAdapter, HttpServer, InMemoryStreamingHandler, InMemoryTaskStorage,\n    SimpleAgentInfo,\n};\n\n// Storage, streaming and push delivery are ports; these are the in-memory adapters.\nlet storage = InMemoryTaskStorage::new();\nlet streaming = InMemoryStreamingHandler::new();\nlet handler = ResponderMessageHandler::new(\n    storage.clone(),\n    streaming.clone(),\n    storage.push_notifier(),\n    Shout,\n);\n\nlet card = SimpleAgentInfo::new(\"shout\".to_string(), \"http://127.0.0.1:8080\".to_string())\n    .with_description(\"Repeats what you say, louder\".to_string())\n    .with_streaming();\nlet processor = ConnectRpcAdapter::new(handler, storage.clone(), storage, card.clone())\n    .with_streaming_handler(streaming);\n\nHttpServer::new(processor, card, \"127.0.0.1:8080\".to_string())\n    .start()\n    .await?;\nuse a2a_rs::{HttpClient, Message, Transport};\nuse a2a_rs::domain::SendCompletion;\n\nlet client = HttpClient::new(\"http://127.0.0.1:8080\".to_string());\nlet message = Message::user_text(\"hello, agent\".to_string(), uuid::Uuid::new_v4().to_string());\n\n// `WhenSettled` is the A2A default: the server answers once the task has\n// finished, so the reply is already in `task.history`.\nlet task = client\n    .send_task_message(None, &message, None, None, SendCompletion::WhenSettled)\n    .await?;\n\nprintln!(\"task {} is {:?}\", task.id, task.status.state);\n// task 7725e89c-… is TASK_STATE_COMPLETED\ncargo install a2acli\n\nexport A2A_URL=http://127.0.0.1:8080\na2acli card                           # what can this agent do?\na2acli send \"hello, agent\"            # send, and wait for the reply\na2acli list --state input-required    # tasks waiting on you\na2acli stream t1 --resilient          # follow a task, reconnecting on drop\n[dependencies]\na2a-rs = { version = \"0.10\", features = [\"http-server\", \"http-client\"] }\n\n# Or pick other features:\n#   jsonrpc-server / jsonrpc-client   the spec's JSON-RPC 2.0 and HTTP+JSON bindings\n#   auth                              JWT, OAuth2, OpenID Connect\n#   sqlite / postgres                 SQLx task storage\n#   full                              all of the above\n```\n\n      All of it runs as one program:\n      `cargo run -p a2a-rs --example quickstart --features http-server,http-client`.\n      An agent that acknowledges now and finishes later implements\n      `AsyncMessageHandler` instead.\n    \n\nThe protocol crate stands alone; the others extend it. Each is published to crates.io and released independently.\n\nThe protocol: domain types, ports, the ConnectRPC, JSON-RPC 2.0 and HTTP+JSON transports, auth, and in-memory and SQLx storage.\n\nA command-line client that negotiates its transport from the agent card. Prebuilt for Linux, macOS and Windows; doubles as a cross-SDK interop harness.\n\nA2A ↔ MCP in both directions, on MCP 2026-07-28 and 2025-11-25: expose an agent as MCP tools, or route an agent's tool calls to an MCP server. A slow call becomes an MCP task; a mid-call question reaches the A2A side.\n\nProvider-neutral chat completions for OpenAI-compatible endpoints and Gemini, and decision models that answer typed questions with probabilities instead of text.\n\nThe Agent Payments Protocol: typed, validated mandates, payment requests and receipts, and helpers to carry them in A2A messages and agent cards.\n\n      The A2A v1.0 surface, and how it reaches the wire. The full list of\n      divergences is in the\n      [spec compliance notes](https://github.com/EmilLindfors/a2a-rs/tree/master/a2a-rs#spec-compliance).\n    \n\n`SendMessage` · `SendStreamingMessage` Blocking until the task settles, or returning immediately`GetTask` · `ListTasks` Filtered by state and context, and paged`CancelTask` · `SubscribeToTask` With gap-free resume between a2a-rs peers`GetExtendedAgentCard` Plus agent card signatures\n| Binding | Server | Client | \n|---|---|---|\n| JSON-RPC 2.0 (spec) | ✓ | ✓ | \n| HTTP+JSON (spec) | ✓ | — | \n| ConnectRPC (a2a-rs default) | ✓ | ✓ | \n| gRPC (spec) | — | — | \n\nClients negotiate from the agent card's supported interfaces: ConnectRPC when the agent offers it, JSON-RPC otherwise. Crossed against the official A2A Rust SDK's CLI and server over JSON-RPC and HTTP+JSON.\n\n      Transports decode a request and hand it to `TaskService`, which\n      only talks to ports. You implement the message handler; everything else\n      has an in-tree adapter you can keep or replace.\n    \n\na2a-rs is MIT licensed and published on crates.io, so it's free to use in commercial products and to build your own platform on. Issues and pull requests are welcome.", "url": "https://wpnews.pro/news/mit-licensed-rust-framework-for-multi-agent-systems-in-rust", "canonical_source": "https://emillindfors.github.io/a2a-rs/", "published_at": "2026-10-15 15:14:50+00:00", "updated_at": "2026-10-15 15:23:22.429996+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "developer-tools", "ai-tools", "artificial-intelligence"], "entities": ["a2a-rs", "Agent2Agent protocol", "MCP", "ConnectRPC", "JSON-RPC 2.0", "SQLite", "PostgreSQL", "Rust"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/mit-licensed-rust-framework-for-multi-agent-systems-in-rust", "markdown": "https://wpnews.pro/news/mit-licensed-rust-framework-for-multi-agent-systems-in-rust.md", "text": "https://wpnews.pro/news/mit-licensed-rust-framework-for-multi-agent-systems-in-rust.txt", "jsonld": "https://wpnews.pro/news/mit-licensed-rust-framework-for-multi-agent-systems-in-rust.jsonld"}}