Agent-bridge tools
Discover and message A2A agents from an MCP client with agent_list, agent_info, agent_send, and agent_query — bridging MCP to the A2A gateway.
The four agent-bridge tools turn an MCP client into an A2A caller: it can list registered agents, read an agent's card, and send messages or forward JSON-RPC methods to an agent — all without leaving the Model Context Protocol.
Overview
The MCP connector exposes 15 tools. Eleven are core messaging tools that always
reach the broker directly. The remaining four — agent_list, agent_info,
agent_send, and agent_query — are bridge tools: they forward to the A2A
agent registry instead of to a messaging channel.
| Tool | Purpose | Required arguments | Optional arguments |
|---|---|---|---|
agent_list | List registered agents | (none) | skill_tags (array of strings) |
agent_info | Get an agent's details | agent_id | (none) |
agent_send | Send a message to an agent via A2A | agent_id, message | blocking (default true), timeout_seconds (default 60, max 300), context_id |
agent_query | Forward a JSON-RPC method to an agent | agent_id, method | params (object), timeout_seconds (default 60, max 300) |
The bridge tools appear in tools/list only when the A2A agent registry is
injected into the MCP connector. If the A2A connector is not running, an MCP
client sees only the 11 core tools. See Tools overview.
How it works
agent_send builds an A2A message/send JSON-RPC envelope and forwards it over a
Query to _AGENTS_.agents/<agent_id>, where the agent's
virtual subscriber delivers it as an HTTP POST. agent_query
forwards an arbitrary JSON-RPC method to the same destination. Both add the gateway
timeout buffer on top of the caller's timeout_seconds.
Bridge tools route discovery to the registry and messages to the agent's internal channel, which a virtual subscriber delivers over HTTP.
agent_list
Lists every registered agent. Pass skill_tags to filter agents whose
agent card advertises matching skill tags.
curl -X POST http://localhost:9090/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 13,
"method": "tools/call",
"params": {
"name": "agent_list",
"arguments": {}
}
}'url := os.Getenv("KUBEMQ_MCP_URL")
if url == "" {
url = "http://localhost:9090"
}
c, err := client.NewStreamableHttpClient(url + "/mcp")
if err != nil {
log.Fatal(err)
}
defer c.Close()
ctx := context.Background()
if err := c.Start(ctx); err != nil {
log.Fatal(err)
}
result, err := c.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "agent_list",
Arguments: map[string]any{},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Tool: agent_list")
fmt.Printf("Result: %+v\n", result)KUBEMQ_MCP_URL = os.environ.get("KUBEMQ_MCP_URL", "http://localhost:9090")
async with streamablehttp_client(f"{KUBEMQ_MCP_URL}/mcp") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
# List all agents (no filter)
result = await session.call_tool("agent_list", {})
print(f"Tool: agent_list")
print(f"IsError: {result.isError}")
for content in result.content:
print(f"Result: {content.text}")
# To filter by skill tags, use: {"skill_tags": ["echo"]}const KUBEMQ_MCP_URL = process.env.KUBEMQ_MCP_URL || "http://localhost:9090";
const transport = new StreamableHTTPClientTransport(
new URL(`${KUBEMQ_MCP_URL}/mcp`)
);
const client = new Client({ name: "kubemq-mcp-ts-example", version: "1.0.0" });
await client.connect(transport);
// List all agents (no filter)
const result = await client.callTool({
name: "agent_list",
arguments: {},
});
console.log(JSON.stringify(result, null, 2));
// To filter by skill tags: { skill_tags: ["echo"] }
await client.close();String url = System.getenv().getOrDefault("KUBEMQ_MCP_URL", "http://localhost:9090");
var transport = HttpClientStreamableHttpTransport.builder(url).endpoint("/mcp").build();
var client = McpClient.sync(transport).build();
client.initialize();
// List all agents (no filter)
var result = client.callTool(new CallToolRequest(
"agent_list",
Map.of()
));
System.out.println(result);
// To filter by skill tags: Map.of("skill_tags", List.of("echo"))
client.closeGracefully();var url = Environment.GetEnvironmentVariable("KUBEMQ_MCP_URL") ?? "http://localhost:9090";
var transport = new HttpClientTransport(new HttpClientTransportOptions { Endpoint = new Uri($"{url}/mcp") });
await using var client = await McpClientFactory.CreateAsync(transport);
var result = await client.CallToolAsync("agent_list", new Dictionary<string, object>());
Console.WriteLine($"Tool: agent_list");
Console.WriteLine($"Result: {result}");val url = System.getenv("KUBEMQ_MCP_URL") ?: "http://localhost:9090"
val httpClient = HttpClient { install(SSE) }
val transport = StreamableHttpClientTransport(client = httpClient, url = "$url/mcp")
val client = Client(clientInfo = Implementation(name = "kubemq-mcp-kotlin-example", version = "1.0.0"))
client.connect(transport)
val result = client.callTool("agent_list", emptyMap())
println("Tool: agent_list")
println("Result: $result")
client.close()
httpClient.close()url = ENV.fetch("KUBEMQ_MCP_URL", "http://localhost:9090")
client = MCP::Client.new(
transport: MCP::Transport::StreamableHTTP.new("#{url}/mcp"),
name: "kubemq-mcp-ruby-example",
version: "1.0.0"
)
client.initialize_handshake
result = client.call_tool("agent_list", {})
puts "Tool: agent_list"
puts "Result: #{result}"
client.closelet url = std::env::var("KUBEMQ_MCP_URL")
.unwrap_or_else(|_| "http://localhost:9090".to_string());
let transport = StreamableHttpClientTransport::from_uri(format!("{url}/mcp"))?;
let client = ().serve(transport).await?;
let result = client.call_tool("agent_list", json!({})).await?;
println!("Tool: agent_list");
println!("Result: {result:#?}");let url = ProcessInfo.processInfo.environment["KUBEMQ_MCP_URL"] ?? "http://localhost:9090"
let transport = HTTPClientTransport(endpoint: URL(string: "\(url)/mcp")!, streaming: true)
let client = Client(name: "kubemq-mcp-swift-example", version: "1.0.0")
try await client.connect(transport: transport)
let result = try await client.callTool("agent_list", arguments: [:])
print("Tool: agent_list")
print("Result: \(result)")The result text is a JSON array of agent summaries:
{
"jsonrpc": "2.0",
"id": 13,
"result": {
"content": [{ "type": "text", "text": "[{\"agent_id\":\"echo-01\",\"name\":\"Echo Agent 01\",\"skills\":[{\"id\":\"echo\",\"name\":\"Echo\",\"tags\":[\"test\",\"echo\"]}]}]" }],
"isError": false
}
}agent_info
Returns the full agent card for one agent — name, description, version, URL, and skills.
curl -X POST http://localhost:9090/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 14,
"method": "tools/call",
"params": {
"name": "agent_info",
"arguments": { "agent_id": "example-agent" }
}
}'result, err := c.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "agent_info",
Arguments: map[string]any{
"agent_id": "example-agent",
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Tool: agent_info")
fmt.Printf("Result: %+v\n", result)result = await session.call_tool("agent_info", {
"agent_id": "example-agent",
})
print(f"Tool: agent_info")
print(f"IsError: {result.isError}")
for content in result.content:
print(f"Result: {content.text}")const result = await client.callTool({
name: "agent_info",
arguments: {
agent_id: "example-agent",
},
});
console.log(JSON.stringify(result, null, 2));var result = client.callTool(new CallToolRequest(
"agent_info",
Map.of("agent_id", "example-agent")
));
System.out.println(result);var result = await client.CallToolAsync("agent_info", new Dictionary<string, object>
{
["agent_id"] = "example-agent",
});
Console.WriteLine($"Tool: agent_info");
Console.WriteLine($"Result: {result}");val result = client.callTool("agent_info", mapOf(
"agent_id" to "example-agent"
))
println("Tool: agent_info")
println("Result: $result")result = client.call_tool("agent_info", {
"agent_id" => "example-agent",
})
puts "Tool: agent_info"
puts "Result: #{result}"let result = client.call_tool("agent_info", json!({
"agent_id": "example-agent"
})).await?;
println!("Tool: agent_info");
println!("Result: {result:#?}");let result = try await client.callTool("agent_info", arguments: [
"agent_id": "example-agent",
])
print("Tool: agent_info")
print("Result: \(result)")A successful call returns the agent card as a JSON string; an unknown agent_id
returns isError: true with Agent 'example-agent' not found:
{
"jsonrpc": "2.0",
"id": 14,
"result": {
"content": [{ "type": "text", "text": "{\"agent_id\":\"example-agent\",\"name\":\"Example Agent\",\"description\":\"example agent\",\"version\":\"1.0.0\"}" }],
"isError": false
}
}agent_send
Sends a message to an agent. The bridge wraps it in an A2A message/send envelope.
By default the call is blocking — it waits up to timeout_seconds for the
agent's reply. Pass blocking: false for fire-and-forget, or context_id to thread
the message into an existing conversation.
curl -X POST http://localhost:9090/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 15,
"method": "tools/call",
"params": {
"name": "agent_send",
"arguments": { "agent_id": "example-agent", "message": "hello from MCP" }
}
}'result, err := c.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "agent_send",
Arguments: map[string]any{
"agent_id": "example-agent",
"message": "hello",
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Tool: agent_send")
fmt.Printf("Result: %+v\n", result)result = await session.call_tool("agent_send", {
"agent_id": "example-agent",
"message": "hello from MCP",
})
print(f"Tool: agent_send")
print(f"IsError: {result.isError}")
for content in result.content:
print(f"Result: {content.text}")const result = await client.callTool({
name: "agent_send",
arguments: {
agent_id: "example-agent",
message: "hello from MCP",
},
});
console.log(JSON.stringify(result, null, 2));var result = client.callTool(new CallToolRequest(
"agent_send",
Map.of(
"agent_id", "example-agent",
"message", "hello from MCP"
)
));
System.out.println(result);var result = await client.CallToolAsync("agent_send", new Dictionary<string, object>
{
["agent_id"] = "example-agent",
["message"] = "hello",
});
Console.WriteLine($"Tool: agent_send");
Console.WriteLine($"Result: {result}");val result = client.callTool("agent_send", mapOf(
"agent_id" to "example-agent",
"message" to "hello"
))
println("Tool: agent_send")
println("Result: $result")result = client.call_tool("agent_send", {
"agent_id" => "example-agent",
"message" => "hello from MCP",
})
puts "Tool: agent_send"
puts "Result: #{result}"let result = client.call_tool("agent_send", json!({
"agent_id": "example-agent",
"message": "hello from MCP"
})).await?;
println!("Tool: agent_send");
println!("Result: {result:#?}");let result = try await client.callTool("agent_send", arguments: [
"agent_id": "example-agent",
"message": "hello",
])
print("Tool: agent_send")
print("Result: \(result)")The agent's reply is returned in the content text. If the agent is not registered,
the call returns isError: true:
{
"jsonrpc": "2.0",
"id": 15,
"result": {
"content": [{ "type": "text", "text": "{\"echo\":{\"method\":\"message/send\",\"params\":{\"message\":\"hello from MCP\"}},\"received_headers\":{}}" }],
"isError": false
}
}agent_query
Forwards an arbitrary JSON-RPC method to an agent — useful for A2A methods beyond
message/send, such as tasks/get. Pass a params object to supply method
arguments.
curl -X POST http://localhost:9090/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 16,
"method": "tools/call",
"params": {
"name": "agent_query",
"arguments": { "agent_id": "example-agent", "method": "tasks/get" }
}
}'result, err := c.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "agent_query",
Arguments: map[string]any{
"agent_id": "example-agent",
"method": "tasks/get",
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Tool: agent_query")
fmt.Printf("Result: %+v\n", result)result = await session.call_tool("agent_query", {
"agent_id": "example-agent",
"method": "tasks/get",
})
print(f"Tool: agent_query")
print(f"IsError: {result.isError}")
for content in result.content:
print(f"Result: {content.text}")const result = await client.callTool({
name: "agent_query",
arguments: {
agent_id: "example-agent",
method: "tasks/get",
},
});
console.log(JSON.stringify(result, null, 2));var result = client.callTool(new CallToolRequest(
"agent_query",
Map.of(
"agent_id", "example-agent",
"method", "tasks/get"
)
));
System.out.println(result);var result = await client.CallToolAsync("agent_query", new Dictionary<string, object>
{
["agent_id"] = "example-agent",
["method"] = "tasks/get",
});
Console.WriteLine($"Tool: agent_query");
Console.WriteLine($"Result: {result}");val result = client.callTool("agent_query", mapOf(
"agent_id" to "example-agent",
"method" to "tasks/get"
))
println("Tool: agent_query")
println("Result: $result")result = client.call_tool("agent_query", {
"agent_id" => "example-agent",
"method" => "tasks/get",
})
puts "Tool: agent_query"
puts "Result: #{result}"let result = client.call_tool("agent_query", json!({
"agent_id": "example-agent",
"method": "tasks/get"
})).await?;
println!("Tool: agent_query");
println!("Result: {result:#?}");let result = try await client.callTool("agent_query", arguments: [
"agent_id": "example-agent",
"method": "tasks/get",
])
print("Tool: agent_query")
print("Result: \(result)"){
"jsonrpc": "2.0",
"id": 16,
"result": {
"content": [{ "type": "text", "text": "{\"echo\":{\"method\":\"tasks/get\",\"params\":{}},\"received_headers\":{}}" }],
"isError": false
}
}Errors
A missing or unknown agent_id returns a tool-level error — isError: true with the
message in the content block — not a JSON-RPC protocol error:
{
"jsonrpc": "2.0",
"id": 15,
"result": {
"content": [{ "type": "text", "text": "Agent 'example-agent' not found" }],
"isError": true
}
}The bridge applies the gateway timeout buffer on top of the caller's
timeout_seconds (default 60, max 300). See
Error handling for the three failure
layers and Error codes for the catalog.
Related
A2A connector
The agent gateway the bridge forwards to — registry, agent cards, and messaging.
Agent registry
How agents register and how agent_list and agent_info read them.
Tools overview
All 15 MCP tools and the shared tools/call response shape.
Tools reference
Full catalog: arguments, defaults, and response shapes for every tool.
Was this page helpful?
Channel Management Tools
Discover KubeMQ channels through MCP — list channels by type or pattern and inspect a single channel's live metadata with channel_list and channel_info.
Client Setup
Connect any MCP client to KubeMQ — Claude Desktop config, generic JSON-RPC over HTTP, session headers, and the official SDK in nine languages.