KubeMQ
AiwayMCPTools

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.

ArgumentTypeRequiredDefaultDescription
channelstringyesTarget channel. Cannot start with the reserved _AGENTS_. prefix.
bodystringyesRequest payload sent to the responder.
metadatastringnoOptional metadata string carried alongside the body.
tagsobjectnoOptional string key/value tags attached to the request.
timeout_secondsintegerno10 (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.

Was this page helpful?

On this page