Skip to main content
Tools are capabilities the model can call while executing a task. The Qoder Agent SDK supports two kinds of tools:
  • Built-in tools: Provided by Qoder CLI, such as reading files, searching, executing commands, and invoking subagents.
  • Custom tools: Defined by SDK users through tool() and createSdkMcpServer(), then exposed to the model.
This guide focuses on defining custom tools. For the complete built-in tool list, see Tools Reference - Built-in Tool List.

Built-in Tools

When using built-in tools, you do not implement the tools yourself. You only control which tools are available, which tools are pre-authorized, and which tools are denied for the current session through query() options.
Common built-in tools include Read, Edit, Write, Bash, Glob, Grep, WebFetch, WebSearch, and Agent. The complete list and names are defined by Tools Reference - Built-in Tool List. Input and output structures are documented in Built-in Tool Input and Output Types, such as FileReadInput / FileReadOutput, BashInput / BashOutput, and AgentInput / AgentOutput. If you need TypeScript-level unified representations, see ToolInputSchemas and ToolOutputSchemas.

Custom Tools

Define a custom tool when you want the model to call your own business capability, such as order lookup, internal knowledge base search, approval system calls, or read-only database access. Custom tools usually involve three steps:
  1. Create a tool with tool().
  2. Register the tool in an MCP server with createSdkMcpServer().
  3. Attach the server through mcpServers in query({ options }), and control calls with permission settings.

Custom Tool Integration Steps

First, here is a complete minimal example. The following sections then explain each step.

Step 1: Create a Tool with tool()

This step defines the tool itself: its name, description, input parameters, execution logic, and metadata.

tool() Arguments

tool() defines a tool. It has five arguments. See tool() for the complete type.

Configure Input Parameters

inputSchema takes a Zod raw shape, meaning a field object, not z.object(...). See AnyZodRawShape for the type and InferShape for handler parameter inference.
Common patterns:

Configure Tool Metadata

extras.annotations passes MCP tool annotations. The SDK keeps them on the tool definition and forwards them when registering the tool with the MCP server. See ToolExtras and ToolAnnotations for the complete fields. These fields do not replace permission configuration. Whether a tool call is allowed is still determined by tools, allowedTools, disallowedTools, permissionMode, canUseTool, and hooks. Current mcpServerStatus().tools[] does not echo annotations back to the host application. If your host UI needs to show this information, keep your own mapping next to the tool definition. Example:

Step 2: Register with an MCP Server

createSdkMcpServer() registers one or more tools as an in-process MCP server. The server name becomes part of the full tool name, so keep it short and stable.
See CreateSdkMcpServerOptions for the full option type and createSdkMcpServer() return value for the return value.

Step 3: Attach to query()

After you put the server in options.mcpServers, the CLI discovers its tools and calls back into your handler through the SDK when the model needs them.
The full custom tool name format is:
For example, if the server name is orders and the tool name is lookup_order, the full name is mcp__orders__lookup_order. Use this full name in allowedTools, disallowedTools, canUseTool, hook matchers, and subagent tools configuration.

Controlling Tool Permissions

When the model calls tools, the SDK provides multiple permission layers. You can decide:
  • Which tools are provided to the current session.
  • Which tools are allowed by default.
  • Which tools are explicitly denied.
  • Whether the host application should make a dynamic decision before each tool call.

Permission Control Overview

These methods can be combined. A common pattern is to use tools to narrow the visible set, allowedTools / disallowedTools for static rules, and canUseTool for argument-level decisions.

Method 1: tools, allowedTools, disallowedTools

tools controls the tools visible to this session. allowedTools and disallowedTools control permission rules. Custom MCP tools must use full names.
When the same tool matches both allow and deny rules, the deny rule takes precedence.

Method 2: permissionMode

permissionMode sets the default permission behavior for the whole session with one option.

Method 3: canUseTool

canUseTool runs before a tool call. You can allow or deny based on the tool name, arguments, and approval context.
Common return values: When using custom tools in a subagent, use the full tool name as well:

Method 4: hooks.PreToolUse

If you already use the hooks system, use PreToolUse to intercept or audit tool calls in one place.
For canUseTool parameter structure, see CanUseToolOptions. For return structure, see PermissionResult. For a more complete permission strategy, see Permissions.

How the SDK Handles Tool Errors

Tool handlers have two error paths.

Business Failure: Return isError: true

For expected business failures, return isError: true. The SDK passes this CallToolResult to the CLI. The model can see the failure content and may retry or choose another path.
Good cases for isError: true:
  • Arguments are valid, but no business result exists, such as an order not found.
  • A security policy rejects execution, such as only allowing SELECT queries.
  • An external service returns a business error that can be explained.

Unexpected Exception: Handler Throws

If a handler throws, the MCP layer converts the exception into an error result, and the agent loop does not crash just because a normal tool exception occurred. However, the model usually only sees the exception message, which is less controllable than explicitly returning isError: true.
Recommendation: use isError: true for predictable business failures, and throw only for truly unexpected exceptions.

Tool Return Values

Tool handlers return MCP CallToolResult. Text content is the most common:
You can also return structured JSON strings, which help the model understand and continue processing:
Common content blocks; see McpToolResultContent for the complete union type: See Tools Reference - CallToolResult for complete type definitions.

Common Pitfalls

  • When writing permission configuration for custom tools, use the full mcp__server__tool name.
  • Pass a Zod raw shape as the third argument to tool(), not z.object(...).
  • Tool descriptions should explain when to use the tool, what it does, and what it returns. Avoid vague descriptions like query or helper.
  • readOnlyHint is tool metadata and a scheduling hint, not a permission switch. Whether execution is allowed is still determined by permission configuration.
  • Avoid putting a huge all-purpose business entry point into one universal tool. A tool should complete one clear class of action.

Continue Reading

  • Tools Reference: Built-in tool list, tool(), createSdkMcpServer(), CallToolResult, and built-in tool input/output types.
  • MCP Integration: stdio, SSE, HTTP, OAuth, and other MCP server integration methods.
  • Permissions: permissionMode, allowedTools, canUseTool, and permission rule updates.
  • Subagent Guide: Let different agents use different tool sets.