qaqnuz MCP public API reference

call_tool#

call_tool invokes one tool by name with a JSON arguments object. Every call runs the full governed path — there is no MCP-only shortcut around authorization, approval, or sanitization.

What happens on a call#

In order:

  1. Entitlement gate. A non-entitled brand (not on Growth/Enterprise) gets a

permission error immediately — no further work.

  1. Rate limit. The per-api-key and per-brand limits are checked

(fail-closed). Over-limit returns a retryable error. See Rate limits.

  1. Reachability / scope pre-flight. The tool must pass the same filter as

list_tools: exposable, non-sensitive, and within the key's scopes. If not, you get a generic permission error — the server does not reveal whether the tool exists, is disabled, is sensitive, or is just out of scope.

  1. Governed execution. The call goes through tool lookup → policy evaluation

(default-deny, exact scope match) → approval gate → execution.

  1. Approval gate. If the tool requires approval, the call does not

execute. An approval request is queued and a permission error is returned that includes the approval request id (poll/await out-of-band).

  1. Result envelope. Success returns the tool payload; failure returns an

error_class and a sanitized_error (the only error text that ever crosses the boundary — never policy internals, provider errors, PII, or key material).

Request#

The standard MCP tools/call request:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_order_status",
    "arguments": { "order_id": "ord_12345" }
  }
}
  • name — the tool name from list_tools.
  • arguments — a JSON object validated against the tool's inputSchema. Invalid

input returns a validation error.

Response#

Success#

Over the MCP wire, a successful call returns a content array whose text is the JSON-encoded tool payload, with isError: false:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      { "type": "text", "text": "{\"order_id\":\"ord_12345\",\"status\":\"shipped\"}" }
    ],
    "isError": false
  }
}

The underlying result envelope also carries a truncated flag: when true, the payload was clipped to a size/row ceiling and should carry a cursor for pagination.

Error#

A failed call returns the sanitized message as text with isError: true:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      { "type": "text", "text": "Tool not found or not available with your current api key." }
    ],
    "isError": true
  }
}

Internally each failure also carries one of five error_class values (permission, validation, terminal, retryable, dependency) — see Errors & error classes for how to branch on them.

Examples#

TypeScript#

ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const transport = new StdioClientTransport({
  command: "qaqnuz-mcp",
  args: [],
  env: { QAQNUZ_API_KEY: process.env.QAQNUZ_API_KEY! },
});

const client = new Client({ name: "my-integration", version: "1.0.0" });
await client.connect(transport);

const res = await client.callTool({
  name: "get_order_status",
  arguments: { order_id: "ord_12345" },
});

if (res.isError) {
  // res.content[0].text is a sanitized, safe-to-log message.
  console.error("call_tool failed:", res.content[0]?.text);
} else {
  const payload = JSON.parse(res.content[0]?.text ?? "null");
  console.log("status:", payload.status);
}

await client.close();

Python#

python
import json
import os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

server = StdioServerParameters(
    command="qaqnuz-mcp",
    args=[],
    env={"QAQNUZ_API_KEY": os.environ["QAQNUZ_API_KEY"]},
)

async def main():
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool(
                "get_order_status",
                arguments={"order_id": "ord_12345"},
            )
            text = result.content[0].text if result.content else "null"
            if result.isError:
                print("call_tool failed:", text)
            else:
                payload = json.loads(text)
                print("status:", payload["status"])

Billing & attribution#

  • A billable call is one call_tool that reaches execution. list_tools and

any auth / permission / rate-limit rejection are not billable.

  • Every reachable call is attributed to your specific api key in the audit trail,

so usage is traceable per key.

Notes#

  • call_tool never throws at the protocol layer — all outcomes (including

auth, scope, and rate-limit failures) come back as an enveloped result with isError set appropriately.

  • Approval-gated tools (write / external with approval required) will not

execute synchronously; treat the returned approval id as the handle to track the decision.