来源:Claude Code 技术文档 - v2.1.88 源码分析
工具系统
3.1 Tool 接口定义
Tool<Input, Output, P> 是所有工具的核心合约。它是一个泛型接口,参数化了输入 Schema、输出类型和进度数据类型。
3.1.1 完整接口签名
type Tool<
Input extends z.ZodType,
Output,
P extends ToolProgressData = ToolProgressData
> = {
// ──── 标识 ────
readonly name: string // 唯一工具名称
aliases?: string[] // 别名列表
searchHint?: string // 搜索提示文本
readonly strict?: boolean // 严格模式
isMcp?: boolean // 是否 MCP 工具
isLsp?: boolean // 是否 LSP 工具
shouldDefer?: boolean // 是否延迟加载
alwaysLoad?: boolean // 是否始终加载
mcpInfo?: { // MCP 元信息
serverName: string
toolName: string
}
// ──── Schema ────
readonly inputSchema: Input // Zod 输入验证 Schema
readonly inputJSONSchema?: ToolInputJSONSchema // JSON Schema 表示
outputSchema?: z.ZodType<unknown> // 输出验证 Schema
// ──── 能力标志 ────
isEnabled(): boolean // 工具是否启用
isReadOnly(input): boolean // 是否只读操作
isDestructive?(input): boolean // 是否破坏性操作
isConcurrencySafe(input): boolean // 是否并发安全
isSearchOrReadCommand?(input): { // 搜索/读取分类
isSearch: boolean
isRead: boolean
isList?: boolean
}
isOpenWorld?(input): boolean // 是否开放世界操作
requiresUserInteraction?(): boolean // 是否需要用户交互
interruptBehavior?(): 'cancel' | 'block' // 中断行为
// ──── 核心执行 ────
call(
args: z.infer<Input>,
context: ToolUseContext,
canUseTool: CanUseToolFn,
parentMessage: AssistantMessage,
onProgress?: ToolCallProgress<P>
): Promise<ToolResult<Output>>
// ──── 权限 ────
checkPermissions(
input: z.infer<Input>,
context: ToolUseContext
): Promise<PermissionResult>
validateInput?(
input: z.infer<Input>,
context: ToolUseContext
): Promise<ValidationResult>
getPath?(input): string
preparePermissionMatcher?(input): Promise<(pattern: string) => boolean>
// ──── 描述与提示 ────
description(
input: z.infer<Input>,
options: {
isNonInteractiveSession: boolean
toolPermissionContext: ToolPermissionContext
tools: Tools
}
): Promise<string>
prompt(options: {
getToolPermissionContext: () => Promise<ToolPermissionContext>
tools: Tools
agents: AgentDefinition[]
allowedAgentTypes?: string[]
}): Promise<string>
// ──── UI 渲染 ────
userFacingName(input): string
userFacingNameBackgroundColor?(input): keyof Theme | undefined
getToolUseSummary?(input): string | null
getActivityDescription?(input): string | null
renderToolUseMessage(input, options): React.ReactNode
renderToolResultMessage?(content, progressMessages, options): React.ReactNode
renderToolUseProgressMessage?(progressMessages, options): React.ReactNode
renderToolUseQueuedMessage?(): React.ReactNode
renderToolUseRejectedMessage?(input, options): React.ReactNode
renderToolUseErrorMessage?(result, options): React.ReactNode
renderToolUseTag?(input): React.ReactNode
renderGroupedToolUse?(toolUses, options): React.ReactNode | null
// ──── 序列化 ────
toAutoClassifierInput(input): unknown
mapToolResultToToolResultBlockParam(content, toolUseID): ToolResultBlockParam
backfillObservableInput?(input): void
inputsEquivalent?(a, b): boolean
extractSearchText?(output): string
isResultTruncated?(output): boolean
maxResultSizeChars: number
isTransparentWrapper?(): boolean
}3.1.2 ToolUseContext(执行上下文)
每次工具调用都会收到完整的执行上下文:
type ToolUseContext = {
options: {
commands: Command[] // 可用命令列表
debug: boolean // 调试模式
mainLoopModel: string // 当前模型名称
tools: Tools // 可用工具集
verbose: boolean // 详细输出
thinkingConfig: ThinkingConfig // 思考配置
mcpClients: MCPServerConnection[]// MCP 连接
mcpResources: Record<string, ServerResource[]>
isNonInteractiveSession: boolean // 是否非交互式
agentDefinitions: AgentDefinitionsResult
maxBudgetUsd?: number // 预算限额
customSystemPrompt?: string // 自定义系统提示
appendSystemPrompt?: string // 追加系统提示
querySource?: QuerySource // 查询来源
refreshTools?: () => Tools // 工具刷新回调
}
abortController: AbortController // 中断控制器
readFileState: FileStateCache // 文件状态缓存
// 状态管理
getAppState(): AppState
setAppState(f: (prev: AppState) => AppState): void
setAppStateForTasks?: (f: (prev: AppState) => AppState) => void
// UI 交互
setToolJSX?: SetToolJSXFn // 设置工具 JSX 渲染
addNotification?: (notif) => void
appendSystemMessage?: (msg) => void
sendOSNotification?: (opts) => void
// MCP 交互
handleElicitation?: (
serverName: string,
params: ElicitRequestURLParams,
signal: AbortSignal
) => Promise<ElicitResult>
// 动态触发器
nestedMemoryAttachmentTriggers?: ...
dynamicSkillDirTriggers?: ...
// ... 20+ 更多字段
}3.1.3 ToolResult(返回值)
type ToolResult<T> = {
data: T // 工具输出数据
newMessages?: ( // 可选的新增消息
UserMessage | AssistantMessage |
AttachmentMessage | SystemMessage
)[]
contextModifier?: ( // 可选的上下文修改器
context: ToolUseContext
) => ToolUseContext
mcpMeta?: { // MCP 元数据
_meta?: Record<string, unknown>
structuredContent?: Record<string, unknown>
}
}3.2 buildTool 工厂函数
3.2.1 设计理念
buildTool() 应用默认值,避免每个工具重复实现样板代码:
const TOOL_DEFAULTS = {
isEnabled: () => true,
isConcurrencySafe: () => false,
isReadOnly: () => false,
isDestructive: () => false,
checkPermissions: () => Promise.resolve({ behavior: 'allow' }),
toAutoClassifierInput: () => '',
userFacingName: function() { return this.name },
// ... 更多默认值
}
function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D> {
return { ...TOOL_DEFAULTS, ...def }
}3.2.2 使用示例
const MyTool = buildTool({
name: 'my_tool',
inputSchema: z.object({ path: z.string() }),
async call(args, context) {
// 实现工具逻辑
return { data: result }
},
async description() {
return '工具描述'
},
async prompt() {
return '给 AI 的工具使用提示'
},
renderToolUseMessage(input, options) {
return <Text>Using: {input.path}</Text>
},
// 覆盖默认值
isReadOnly: () => true,
isConcurrencySafe: () => true,
maxResultSizeChars: 50000,
})3.3 内置工具清单
3.3.1 核心工具
工具名称
类型
并发安全
只读
描述
BashTool
执行
❌
❌
Shell 命令执行
FileReadTool
文件
✅
✅
文件读取
FileEditTool
文件
❌
❌
文件编辑(基于字符串替换)
FileWriteTool
文件
❌
❌
文件写入/创建
GlobTool
搜索
✅
✅
文件名模式搜索
GrepTool
搜索
✅
✅
文件内容搜索
WebFetchTool
网络
✅
✅
网页内容获取
WebSearchTool
网络
✅
✅
网络搜索
AgentTool
代理
❌
❌
子代理任务创建
SkillTool
技能
❌
❌
技能调用
3.3.2 条件编译工具
以下工具仅在对应 Feature Flag 启用时编译到产物中:
工具
Feature Flag
描述
OverlapTestTool
OVERLAP_TEST_TOOL
重叠测试
REPLTool
REPL
交互式 REPL
ContextCollapseTool
CONTEXT_COLLAPSE
上下文折叠
TerminalPanelTool
TERMINAL_PANEL
终端面板
MonitorMcpTool
MONITOR_TOOL
MCP 监控
CronTools
WORKFLOWS
定时任务
3.3.3 任务相关工具
工具
描述
TaskCreateTool
创建后台任务
TaskStopTool
停止任务
TaskGetTool
获取任务状态
TaskListTool
列出所有任务
SendMessageTool
向队友发送消息
3.3.4 特殊工具
工具
描述
BriefTool
简洁摘要输出
NotebookEditTool
Jupyter Notebook 编辑
LSPTool
Language Server Protocol 交互
TungstenTool
内部特殊集成工具
SleepTool
延迟等待
3.4 工具池组装流程
3.4.1 组装管线
getAllBaseTools()
│
├─ CLAUDE_CODE_SIMPLE 模式?
│ └─ YES → 返回 [BashTool, FileReadTool, FileEditTool]
│ (或含 REPL 替代)
│
├─ NO → 加载所有内置工具
│ ├─ 核心工具 (Bash, FileEdit, FileRead, FileWrite, ...)
│ ├─ 检查 feature() 标志加载条件工具
│ └─ 检查环境变量加载特殊工具
│
▼
filterToolsByDenyRules(tools, permissionContext)
│
├─ 检查 alwaysDenyRules
│ └─ 完全匹配的工具被过滤掉
│
▼
isEnabled() 过滤
│
├─ 每个工具的 isEnabled() 检查
│
▼
REPL 模式处理
│
├─ 如果 REPL 启用,隐藏 REPL_ONLY_TOOLS
│ (这些工具仅在 REPL 内部可用)
│
▼
getTools(permissionContext) → 内置工具集
│
▼
assembleToolPool(permissionContext, mcpTools)
│
├─ 合并: [...内置工具, ...MCP工具]
├─ 按名称排序 (保持 prompt 缓存稳定性)
└─ uniqBy(name) 去重 (内置优先)
│
▼
最终工具池 → Tools (readonly Tool[])3.4.2 关键函数
// 获取当前权限下的内置工具
function getTools(permissionContext: ToolPermissionContext): Tools
// 组装完整工具池(内置 + MCP)
function assembleToolPool(
permissionContext: ToolPermissionContext,
mcpTools: Tools
): Tools
// 合并工具(不去重,用于内部场景)
function getMergedTools(
permissionContext: ToolPermissionContext,
mcpTools: Tools
): Tools
// 获取默认预设的工具名称列表
function getToolsForDefaultPreset(): string[]3.5 工具权限检查
3.5.1 权限检查流程
工具调用请求
│
▼
tool.checkPermissions(input, context)
│
├─ 返回 PermissionResult:
│ ├─ { behavior: 'allow' } → 直接执行
│ ├─ { behavior: 'ask', ... } → 提示用户确认
│ ├─ { behavior: 'deny', ... } → 拒绝执行
│ └─ { behavior: 'passthrough' } → 使用默认行为
│
▼
wrappedCanUseTool(tool, input)
│
├─ 规则匹配优先级:
│ 1. alwaysDenyRules (最高)
│ 2. alwaysAllowRules
│ 3. alwaysAskRules
│ 4. PermissionMode 默认
│
├─ auto 模式:
│ └─ YoloClassifier 自动判断
│ ├─ shouldBlock: true → deny
│ └─ shouldBlock: false → allow
│
▼
执行/拒绝/等待用户确认3.5.2 工具分类器
type YoloClassifierResult = {
thinking?: string // 推理过程
shouldBlock: boolean // 是否阻止
reason: string // 原因
unavailable?: boolean // 分类器不可用
transcriptTooLong?: boolean // 上下文太长
model: string // 使用的模型
usage?: ClassifierUsage // Token 使用
durationMs?: number // 耗时
stage?: 'fast' | 'thinking' // 阶段
}3.6 代理工具限制
不同代理类型有不同的工具访问权限:
3.6.1 代理禁止工具集
ALL_AGENT_DISALLOWED_TOOLS = Set[
TASK_OUTPUT_TOOL_NAME,
EXIT_PLAN_MODE_V2_TOOL_NAME,
ENTER_PLAN_MODE_TOOL_NAME,
ASK_USER_QUESTION_TOOL_NAME,
// 条件工具...
]3.6.2 异步代理允许工具
ASYNC_AGENT_ALLOWED_TOOLS = Set[
FILE_READ_TOOL_NAME, // 文件读取
WEB_SEARCH_TOOL_NAME, // 网络搜索
GREP_TOOL_NAME, // 代码搜索
GLOB_TOOL_NAME, // 文件查找
WEB_FETCH_TOOL_NAME, // 网页获取
// 更多文件/Web 相关工具
]3.6.3 进程内队友工具
IN_PROCESS_TEAMMATE_ALLOWED_TOOLS = Set[
TASK_CREATE_TOOL_NAME,
TASK_GET_TOOL_NAME,
TASK_LIST_TOOL_NAME,
SEND_MESSAGE_TOOL_NAME,
// 条件工具...
]3.6.4 协调器模式工具
COORDINATOR_MODE_ALLOWED_TOOLS = Set[
AGENT_TOOL_NAME, // 创建子代理
TASK_STOP_TOOL_NAME, // 停止任务
SEND_MESSAGE_TOOL_NAME, // 发送消息
SYNTHETIC_OUTPUT_TOOL_NAME, // 合成输出
]3.7 MCP 工具集成
3.7.1 MCP 工具标识
// MCP 工具具有特殊属性标记
tool.isMcp = true
tool.mcpInfo = {
serverName: 'server-name', // MCP 服务器名称
toolName: 'tool-name' // MCP 内工具名称
}3.7.2 集成优先级
当 MCP 工具与内置工具同名时:
assembleToolPool()使用uniqBy(name)去重- 排序后的列表中,内置工具先出现
- 因此 内置工具优先于同名 MCP 工具
3.7.3 权限过滤
function filterToolsByDenyRules(tools, permissionContext) {
// MCP 工具也受 deny 规则约束
// 匹配条件: toolName (内置) 或 serverName:toolName (MCP)
return tools.filter(tool => {
if (tool.mcpInfo) {
// 检查 server:tool 格式的匹配
}
// 检查纯工具名匹配
})
}3.8 工具辅助函数
// 按名称或别名查找工具
function findToolByName(tools: Tools, name: string): Tool | undefined
// 检查工具名称匹配(含别名)
function toolMatchesName(
tool: { name: string; aliases?: string[] },
name: string
): boolean
// 过滤工具进度消息
function filterToolProgressMessages(
progressMessages: ProgressMessage[]
): ProgressMessage<ToolProgressData>[]
// 获取空权限上下文
function getEmptyToolPermissionContext(): ToolPermissionContext3.9 工具渲染模式
每个工具可以提供多种渲染方法来控制 UI 显示:
渲染方法
时机
描述
renderToolUseMessage
发送调用时
工具使用消息(必需)
renderToolResultMessage
收到结果时
结果展示(可选)
renderToolUseProgressMessage
执行中
进度动画/状态(可选)
renderToolUseQueuedMessage
排队等待时
排队提示(可选)
renderToolUseRejectedMessage
被拒绝时
拒绝原因展示(可选)
renderToolUseErrorMessage
出错时
错误详情展示(可选)
renderGroupedToolUse
分组展示时
合并多个同类调用(可选)
renderToolUseTag
标签展示
简短标签标识(可选)