list_tools#
list_tools returns the set of tools the current api key may invoke. It is purely a discovery/visibility procedure — it never executes anything and never throws. If nothing is callable, it returns an empty list.
Visibility filter#
A tool appears in list_tools only if all of the following hold (checked in this order — cheap, fail-fast checks first):
- The brand is entitled for MCP (Growth/Enterprise). If not, the result is
an empty list — no error.
- The tool is not
sensitive.sensitivetools are excluded structurally,
before any other flag is consulted, and can never be surfaced over MCP.
- The tool is enabled in the brand's tool registry.
- The tool is flagged MCP-exposable. This is an explicit, opt-in per-tool
flag that defaults to off. A tool is invisible over MCP until a brand enables it.
- The key's scopes include the tool's scope (exact match). Tools your key
cannot call are never listed — there is no enumeration of un-grantable tools.
Because call_tool re-applies this same filter before executing, a tool you cannot list is a tool you cannot call.
Request#
list_tools takes no arguments beyond the connection's resolved api-key context. Over the MCP protocol it is the standard tools/list request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}Response#
Over the MCP wire, the response is the standard MCP tool list — each tool carries name, description, and inputSchema (a JSON Schema object for the tool's arguments):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "get_order_status",
"description": "[stable] Look up the status of an order by its id.",
"inputSchema": {
"type": "object",
"properties": {
"order_id": { "type": "string", "description": "The order id." }
},
"required": ["order_id"]
}
}
]
}
}Stability tier#
Each tool's stability tier is surfaced as a prefix on its description: [stable], [beta], or [deprecated] (a tool with no prefix is treated as stable). Pin production integrations to stable tools; beta tools may change additively without a server-version bump.
Side-effect class#
Tools are classified by side effect: read, write, or external. (sensitive tools never appear here — they are excluded from the MCP surface entirely.) write and external tools may require approval before they execute; see call_tool.
Examples#
TypeScript#
Using the official MCP TypeScript SDK over the stdio transport:
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 { tools } = await client.listTools();
for (const tool of tools) {
console.log(tool.name, "—", tool.description);
}
await client.close();Python#
Using the official MCP Python SDK over the stdio transport:
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.list_tools()
for tool in result.tools:
print(tool.name, "—", tool.description)Notes#
- An empty list is normal for a non-entitled brand, a brand with no
MCP-exposable tools, or a key whose scopes match no exposable tool. These cases are indistinguishable by design.
list_toolscalls are not rate-limited or billed — onlycall_tool
invocations that reach execution count against quota.