a2a-mcp-v0.3.0
Changed - Breaking
-
McpToA2ABridgetool-call wire format replaced. The bridge no longer
detects tool calls by scanningMessage.partsfor aTextpart starting
withTOOL_CALL: <name>. It now reads a typed [McpToolCall] envelope
fromMessage.metadataunder the keya2a_rs_tool_call(exported as
MCP_TOOL_CALL_METADATA_KEY). Thepartsvector is no longer inspected
for routing and is free for any display/logging payload.Migration: replace ad-hoc message construction with
create_tool_call_message(name, args)orattach_tool_call(&mut msg, name, args).
Messages built with the previousTOOL_CALL:text prefix are now treated as
ordinary text and forwarded to the innerAsyncMessageHandlerunchanged.// Before let msg = Message::builder() .role(Role::User) .parts(vec![ Part::Text { text: "TOOL_CALL: add".into(), metadata: None }, Part::Data { data: data_map, metadata: None }, ]) .message_id(id) .build(); // After let msg = a2a_mcp::create_tool_call_message("add", json!({"a": 5, "b": 7}));
-
AgentToMcpBridge::newsignature simplified. The redundant
agent_url: Stringparameter has been removed; the bridge now derives its
MCP tool-name namespace fromagent_card.url. For the rare cases where the
namespace should differ from the advertised URL (e.g. tunnels, reverse
proxies), use the newAgentToMcpBridge::with_namespace(client, card, namespace)
constructor.// Before let bridge = AgentToMcpBridge::new(client, card, "https://...".to_string()); // After let bridge = AgentToMcpBridge::new(client, card); // Or, with explicit namespace: let bridge = AgentToMcpBridge::with_namespace(client, card, "internal-alias".into());
Added
-
MCP prompts ↔ A2A skills mapping for
McpToA2ABridge:- Automatically query downstream MCP prompts via
list_promptsand expose them as A2A skills. - Route prompt calls using a typed
MCP_PROMPT_CALL_METADATA_KEY("a2a_rs_prompt_call") envelope inMessage.metadatatoself.mcp_peer.get_prompt. - Convert
PromptMessages back to A2A messages.
- Automatically query downstream MCP prompts via
-
Dynamic Auth Bridging:
- Parse
self.agent_card.security_schemesinAgentToMcpBridge::get_infoand advertise"io.modelcontextprotocol/oauth-client-credentials"extension capability if OAuth2 client credentials scheme is present.
- Parse
-
Bidirectional Task Cancellation:
- Added
cancel_taskto theBridgeBackendtrait and implemented it for HTTP and WebSocket backends. - Implemented
cancel_taskonAgentToMcpBridgeto support upstream cancellation. - Implemented
RequestCancelGuardinMcpToA2ABridgeto cancel downstream MCP tool/prompt requests if the wrapping A2A task is canceled/dropped.
- Added
-
McpToA2ABridgeProgress Streaming & Token Matching:- Dynamic matching of auto-generated client progress tokens returned by
rmcpto correctly route downstream progress updates to A2A clients viastreaming_handler.
- Dynamic matching of auto-generated client progress tokens returned by
-
Task streaming, progress reporting, and client sampling support for
AgentToMcpBridge:- Support streaming task status, progress updates, and artifacts from the agent back to MCP clients.
- Implement MCP progress notification support using
progress_token(retrieved fromRequestContext::meta). - Implement client-driven LLM sampling support: if the streaming task or polling loop transitions to
InputRequired, the bridge suspends execution, converts the task history and current prompt into sampling messages, requests input from the client peer viapeer.create_message, and resumes the task with the response. - Added polling fallback loop for backends that do not support status streams (e.g. HTTP backends).
-
Public
BridgeBackendtrait & WebSocket Backend:- Re-exported
BridgeBackendas a public trait to allow custom backend implementations. - Implemented
WebSocketBackendfor communication with WebSocket-based agents (enabled via the"ws-client"feature). - Added
AgentToMcpBridge::with_websocketandwith_websocket_and_namespaceconstructors.
- Re-exported
-
In-process backend for
AgentToMcpBridge. Two new constructors —
AgentToMcpBridge::with_handler(handler, card)and
with_handler_and_namespace(handler, card, namespace)— call an
in-processAsyncMessageHandlerdirectly instead of dialing the agent
over HTTP. When the bridge and the wrapped agent live in the same
process, this skips the loopback HTTP server entirely.// HTTP-backed (unchanged) — for agents in another process/host: let bridge = AgentToMcpBridge::new(HttpClient::new(url), card); // In-process — for agents living in the same process: let bridge = AgentToMcpBridge::with_handler(my_handler, card);
Covered by
tests/agent_to_mcp_integration.rs::test_in_process_backend_dispatches_to_handler. -
McpToolCallpublic struct ({ name, arguments }) representing the
tool-call envelope carried inMessage.metadata. -
MCP_TOOL_CALL_METADATA_KEYconstant ("a2a_rs_tool_call") — the metadata
key the bridge looks at. -
attach_tool_call(&mut Message, name, arguments)helper for adding a
tool-call envelope to an existing message without losing itsparts. -
AgentToMcpBridge::with_namespace(...)constructor for explicit
tool-name namespacing. -
Examples:
a2a_as_mcp_server.rs(A2A agent exposed as MCP tools),
a2a_with_mcp_tools.rs(A2A handler augmented with MCP tools), and
bidirectional_demo.rs(both bridges in one process: upstream MCP
client →AgentToMcpBridge→ A2A HTTP server →McpToA2ABridge→
downstream calculator MCP server).
Documentation
- The metadata tool-call envelope is now documented in the crate-level
rustdoc (lib.rs) and inMcpToA2ABridge's struct docs, including a
worked example of the on-wire JSON shape. - Crate-level rustdoc examples in
lib.rswere promoted from
rust,ignoreto compile-checkedno_rundoctests, rewritten against
the real public API (the previous snippets referenced a non-existent
A2AClient). Doctests are now part ofcargo test --doc -p a2a-mcp.