- 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()andcreateSdkMcpServer(), then exposed to the model.
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 throughquery() options.
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:- Create a tool with
tool(). - Register the tool in an MCP server with
createSdkMcpServer(). - Attach the server through
mcpServersinquery({ 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.
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.
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.
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.
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.
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.
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
SELECTqueries. - 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 returningisError: true.
isError: true for predictable business failures, and throw only for truly unexpected exceptions.
Tool Return Values
Tool handlers return MCPCallToolResult. Text content is the most common:
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__toolname. - Pass a Zod raw shape as the third argument to
tool(), notz.object(...). - Tool descriptions should explain when to use the tool, what it does, and what it returns. Avoid vague descriptions like
queryorhelper. readOnlyHintis 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.