Command & Query Tools
Use the command_send and query_send MCP tools to make synchronous request/reply calls into KubeMQ from an AI model.
The command_send and query_send tools let an MCP client make synchronous
request/reply calls into KubeMQ. A command triggers an action and waits for an
acknowledgement; a query asks for data and waits for a response payload.
Overview
Both tools are part of the 11 core messaging tools —
they are always available at /mcp, no agent registry required. Each maps to one
KubeMQ Request/Reply operation:
command_send— sends a command to a channel and blocks until a responder acknowledges it (success or error). Use it for mutating actions where you only need to know whether the work was accepted.query_send— sends a query to a channel and blocks until a responder returns a payload. Use it for read operations that produce data the model needs back.
Both are synchronous: the connector holds the tools/call open until the responder
replies or the timeout elapses. They require an active subscriber on the target
channel — with no responder, the call times out and returns an error result.
How it works
The connector translates the tool call into a native KubeMQ command or query, routes
it to a responder over the Array, waits for the reply, and hands
the result back inside the tools/call response.
Both tools hold the tools/call open for the round trip; a query returns data, a command returns an acknowledgement.
Input schema
Both tools share the same core arguments. The only difference is the default timeout.
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
channel | string | yes | — | Target channel. Cannot start with the reserved _AGENTS_. prefix. |
body | string | yes | — | Request payload sent to the responder. |
metadata | string | no | — | Optional metadata string carried alongside the body. |
tags | object | no | — | Optional string key/value tags attached to the request. |
timeout_seconds | integer | no | 10 (command) · 30 (query) | Seconds to wait for a reply. Maximum 300. |
timeout_seconds is capped at 300 for both tools. The connector also adds a
small gateway buffer on top of the caller-specified timeout. See
Configuration for ToolTimeoutSeconds.
Output schema
Both tools return the standard tools/call result with a content array of text
blocks. command_send returns an acknowledgement string; query_send returns the
responder's payload (often JSON) as text.
A successful command:
{
"jsonrpc": "2.0",
"id": 9,
"result": {
"content": [{ "type": "text", "text": "Command executed successfully on channel 'example-commands'" }],
"isError": false
}
}A successful query:
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"content": [{ "type": "text", "text": "{\"data\":\"query response payload from subscriber\"}" }],
"isError": false
}
}When no responder is listening, the call returns isError: true with a timeout
message — the JSON-RPC envelope itself still succeeds:
{
"jsonrpc": "2.0",
"id": 9,
"result": {
"content": [{ "type": "text", "text": "Command timed out: no subscriber on channel 'example-commands' within 10s" }],
"isError": true
}
}A timeout is reported through isError, not as a JSON-RPC error. See
Error handling for the three failure
layers.
command_send
Send a command and wait for an acknowledgement.
curl -X POST http://localhost:9090/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 9,
"method": "tools/call",
"params": {
"name": "command_send",
"arguments": {
"channel": "example-commands",
"body": "do-work",
"timeout_seconds": 10,
"metadata": "cmd-meta",
"tags": { "action": "process" }
}
}
}'result, err := c.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "command_send",
Arguments: map[string]any{
"channel": "example-commands",
"body": "do-work",
"timeout_seconds": 10,
"metadata": "cmd-meta",
"tags": map[string]any{"action": "process"},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Tool: command_send")
fmt.Printf("Result: %+v\n", result)result = await session.call_tool("command_send", {
"channel": "example-commands",
"body": "do-work",
"timeout_seconds": 10,
"metadata": "cmd-meta",
"tags": {"action": "process"},
})
print(f"IsError: {result.isError}")
for content in result.content:
print(f"Result: {content.text}")const result = await client.callTool({
name: "command_send",
arguments: {
channel: "example-commands",
body: "do-work",
timeout_seconds: 10,
metadata: "cmd-meta",
tags: { action: "process" },
},
});
console.log(JSON.stringify(result, null, 2));var result = client.callTool(new CallToolRequest(
"command_send",
Map.of(
"channel", "example-commands",
"body", "do-work",
"timeout_seconds", 10,
"metadata", "cmd-meta",
"tags", Map.of("action", "process")
)
));
System.out.println(result);var result = await client.CallToolAsync("command_send", new Dictionary<string, object>
{
["channel"] = "example-commands",
["body"] = "do-work",
["timeout_seconds"] = 10,
["metadata"] = "cmd-meta",
["tags"] = new Dictionary<string, string> { ["action"] = "process" },
});
Console.WriteLine($"Result: {result}");val result = client.callTool("command_send", mapOf(
"channel" to "example-commands",
"body" to "do-work",
"timeout_seconds" to 10
))
println("Result: $result")result = client.call_tool("command_send", {
"channel" => "example-commands",
"body" => "do-work",
"timeout_seconds" => 10,
})
puts "Result: #{result}"let result = client.call_tool("command_send", json!({
"channel": "example-commands",
"body": "do-work",
"timeout_seconds": 10,
"metadata": "cmd-meta",
"tags": {"action": "process"}
})).await?;
println!("Result: {result:#?}");let result = try await client.callTool("command_send", arguments: [
"channel": "example-commands",
"body": "do-work",
"timeout_seconds": 10,
])
print("Result: \(result)")query_send
Send a query and wait for a response payload.
curl -X POST http://localhost:9090/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 10,
"method": "tools/call",
"params": {
"name": "query_send",
"arguments": {
"channel": "example-queries",
"body": "get-data",
"timeout_seconds": 30,
"metadata": "qry-meta",
"tags": { "action": "lookup" }
}
}
}'result, err := c.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "query_send",
Arguments: map[string]any{
"channel": "example-queries",
"body": "get-data",
"timeout_seconds": 30,
"metadata": "qry-meta",
"tags": map[string]any{"action": "lookup"},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Tool: query_send")
fmt.Printf("Result: %+v\n", result)result = await session.call_tool("query_send", {
"channel": "example-queries",
"body": "get-data",
"timeout_seconds": 30,
"metadata": "qry-meta",
"tags": {"action": "lookup"},
})
print(f"IsError: {result.isError}")
for content in result.content:
print(f"Result: {content.text}")const result = await client.callTool({
name: "query_send",
arguments: {
channel: "example-queries",
body: "get-data",
timeout_seconds: 30,
metadata: "qry-meta",
tags: { action: "lookup" },
},
});
console.log(JSON.stringify(result, null, 2));var result = client.callTool(new CallToolRequest(
"query_send",
Map.of(
"channel", "example-queries",
"body", "get-data",
"timeout_seconds", 30,
"metadata", "qry-meta",
"tags", Map.of("action", "lookup")
)
));
System.out.println(result);var result = await client.CallToolAsync("query_send", new Dictionary<string, object>
{
["channel"] = "example-queries",
["body"] = "get-data",
["timeout_seconds"] = 30,
["metadata"] = "qry-meta",
["tags"] = new Dictionary<string, string> { ["action"] = "lookup" },
});
Console.WriteLine($"Result: {result}");val result = client.callTool("query_send", mapOf(
"channel" to "example-queries",
"body" to "get-data",
"timeout_seconds" to 30
))
println("Result: $result")result = client.call_tool("query_send", {
"channel" => "example-queries",
"body" => "get-data",
"timeout_seconds" => 30,
})
puts "Result: #{result}"let result = client.call_tool("query_send", json!({
"channel": "example-queries",
"body": "get-data",
"timeout_seconds": 30,
"metadata": "qry-meta",
"tags": {"action": "lookup"}
})).await?;
println!("Result: {result:#?}");let result = try await client.callTool("query_send", arguments: [
"channel": "example-queries",
"body": "get-data",
"timeout_seconds": 30,
])
print("Result: \(result)")The snippets above assume an initialized MCP session (client / session). For the
full connect-and-initialize handshake in each language, see
Client setup.
Related
Tools overview
The full 15-tool map and the shared tools/call response shape.
Channel tools
Discover channels and responders before sending a command or query.
Tools reference
Full catalog: arguments, defaults, and response shapes for all 15 tools.
Error handling
Detect timeouts and the three MCP failure layers.
Was this page helpful?
Events Tools
Publish ephemeral and persistent events and read the events store as MCP tools — events_publish, events_store_publish, and events_store_read on KubeMQ.
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.