【合集】Claude Code 源码分析(二):Tools 工具技术实现
目录
-
架构总览
-
核心 Tool 抽象层
-
工具注册与发现机制
-
权限与授权系统
-
工具执行编排
-
Hook 系统集成
-
MCP 协议集成
-
工具结果处理与缓存
-
UI 渲染体系
-
工具搜索与延迟加载
-
并发控制策略
-
完整工具清单
-
关键设计模式
-
性能参数与限制
1. 架构总览
Claude Code 的工具系统采用插件化架构,由以下核心模块组成

核心文件路径:
|
|
|
|---|---|
Tool.ts |
|
tools.ts |
|
services/tools/toolOrchestration.ts |
|
services/tools/toolExecution.ts |
|
services/tools/toolHooks.ts |
|
hooks/useCanUseTool.tsx |
|
tools/
|
|
2. 核心 Tool 抽象层
2.1 Tool 接口定义 (Tool.ts)
Tool 接口是整个工具系统的基石,定义了 30+ 个方法/属性:
exporttypeTool<
InputextendsAnyObject = AnyObject,
Output = unknown,
P extendsToolProgressData = ToolProgressData,
> = {
// ====== 标识 ======
name: string// 唯一标识符
aliases?: string[] // 向后兼容的别名
searchHint?: string// ToolSearch 关键词提示
// ====== 核心执行 ======
call(
args: z.infer<input>,
context: ToolUseContext,
canUseTool: CanUseToolFn,
parentMessage: AssistantMessage,
onProgress?: ToolCallProgress</code><p><code class="typescript">,
): Promise<toolresult<output>>
// ====== Schema 定义 ======
readonly inputSchema: Input // Zod schema,输入验证
readonly inputJSONSchema?: ToolInputJSONSchema // MCP 工具用 JSON Schema
outputSchema?: ZodType
// ====== 权限控制 ======
checkPermissions(input, context): Promise<permissionresult>
validateInput?(input, context): Promise<validationresult>
preparePermissionMatcher?(input): Promise<(pattern) => boolean>
// ====== 行为分类 ======
isConcurrencySafe(input): boolean // 是否可并发
isEnabled(): boolean // 是否启用
isReadOnly(input): boolean // 是否只读
isDestructive?(input): boolean // 是否破坏性
isOpenWorld?(input): boolean // 是否访问外部
requiresUserInteraction?(): boolean // 是否需要交互
// ====== 结果处理 ======
maxResultSizeChars: number // 结果持久化阈值
mapToolResultToToolResultBlockParam(content, toolUseID): ToolResultBlockParam
// ====== UI 渲染 (8+ 方法) ======
renderToolUseMessage(input, options): React.ReactNode
renderToolResultMessage?(content, progressMessages, options): React.ReactNode
renderToolUseProgressMessage?(progressMessages, options): React.ReactNode
renderToolUseErrorMessage?(result, options): React.ReactNode
renderToolUseRejectedMessage?(input, options): React.ReactNode
renderGroupedToolUse?(toolUses, options): React.ReactNode | null
// ====== 元信息 ======
isMcp?: boolean
isLsp?: boolean
shouldDefer?: boolean // 是否延迟加载
alwaysLoad?: boolean // 强制加载
strict?: boolean // API strict 模式
}
</validationresult></permissionresult></toolresult<output></code></p></pre><h3>2.2 ToolResult 返回类型</h3><pre class="typescript"><code class="typescript">export type ToolResult<t> = {
data: T // 工具输出数据
newMessages?: Message[] // 附加消息(注入对话)
contextModifier?: (context: ToolUseContext) => ToolUseContext // 上下文修改器
mcpMeta?: { // MCP 协议元数据
_meta?: Record<string, unknown="">
structuredContent?: Record<string, unknown="">
}
}
</string,></string,></t>
关键设计点:contextModifier 只对非并发安全的工具生效。它允许工具在执行后修改共享上下文(如 BashTool 的 cd 命令修改工作目录),在批次执行完成后统一应用,避免竞态条件。
2.3 ToolUseContext 执行上下文
ToolUseContext 是传递给每个工具的共享上下文,包含 40+ 个字段:
exporttypeToolUseContext = {
options: {
commands: Command[]
tools: Tools
mainLoopModel: string
mcpClients: MCPServerConnection[]
mcpResources: Record<string, serverresource[]="">
agentDefinitions: AgentDefinitionsResult
refreshTools?: () =>Tools// MCP 工具动态更新
customSystemPrompt?: string
}
// 状态管理
abortController: AbortController// 取消控制
readFileState: FileStateCache// 文件状态缓存
getAppState(): AppState
setAppState(f: (prev: AppState) =>AppState): void
// UI 回调
setToolJSX?: SetToolJSXFn
addNotification?: (notif: Notification) =>void
// 权限上下文
toolPermissionContext: ToolPermissionContext
// 执行上下文
agentId?: AgentId// 子代理 ID
messages: Message[] // 对话消息
contentReplacementState?: ContentReplacementState// 结果预算管理
// 文件/搜索限制
fileReadingLimits?: { maxTokens, maxSizeBytes }
globLimits?: { maxResults }
}
</string,>
2.4 ToolPermissionContext 权限上下文
exporttypeToolPermissionContext = DeepImmutable<{
mode: PermissionMode// default | plan | acceptEdits | bypassPermissions | auto
additionalWorkingDirectories: Map<string, additionalworkingdirectory="">
alwaysAllowRules: ToolPermissionRulesBySource
alwaysDenyRules: ToolPermissionRulesBySource
alwaysAskRules: ToolPermissionRulesBySource
isBypassPermissionsModeAvailable: boolean
isAutoModeAvailable?: boolean
shouldAvoidPermissionPrompts?: boolean// 后台代理
prePlanMode?: PermissionMode// Plan 模式前的模式
}>
</string,>
2.5 ValidationResult
exporttypeValidationResult =
| { result: true }
| { result: false; message: string; errorCode: number }
3. 工具注册与发现机制
3.1 注册策略 (tools.ts)
工具注册采用静态列表 + 条件特性门控模式:
exportfunctiongetAllBaseTools(): Tools {
return [
// 核心工具(始终加载)
AgentTool,
TaskOutputTool,
BashTool,
FileReadTool,
FileEditTool,
FileWriteTool,
NotebookEditTool,
WebFetchTool,
TodoWriteTool,
WebSearchTool,
// 条件工具(环境变量/特性开关)
...(hasEmbeddedSearchTools() ? [] : [GlobTool, GrepTool]),
...(process.env.USER_TYPE === 'ant' ? [ConfigTool, TungstenTool] : []),
...(isTodoV2Enabled() ? [TaskCreateTool, TaskGetTool, TaskUpdateTool, TaskListTool] : []),
...(isWorktreeModeEnabled() ? [EnterWorktreeTool, ExitWorktreeTool] : []),
...(feature('AGENT_TRIGGERS') ? cronTools : []),
// 延迟加载(打破循环依赖)
getSendMessageTool(),
...(isAgentSwarmsEnabled() ? [getTeamCreateTool(), getTeamDeleteTool()] : []),
]
}
条件加载方式:
|
|
|
|
|---|---|---|
process.env.USER_TYPE |
=== 'ant' |
|
feature() |
feature('PROACTIVE') |
|
isEnvTruthy() |
|
|
|
|
getTeamCreateTool() |
|
|
|
require()
|
|
3.2 工具池组装
// 组装完整工具池(内置 + MCP)
exportfunctionassembleToolPool(permissionContext: ToolPermissionContext,mcpTools: Tools,): Tools {
const builtInTools = getTools(permissionContext)
const allowedMcpTools = filterToolsByDenyRules(mcpTools, permissionContext)
// 分区排序 → prompt-cache 稳定性
// 内置工具作为连续前缀,MCP 工具追加其后
constbyName = (a: Tool, b: Tool) => a.name.localeCompare(b.name)
returnuniqBy(
[...builtInTools].sort(byName).concat(allowedMcpTools.sort(byName)),
'name', // 同名时内置工具优先
)
}
设计要点:
-
排序保持 prompt-cache 命中率(服务端缓存策略依赖工具顺序)
-
uniqBy确保内置工具在名称冲突时优先于 MCP 工具 -
拒绝规则(deny rules)在组装前过滤,避免被拒绝的工具出现在 prompt 中
3.3 工具过滤链
getAllBaseTools() // 全量工具(特性门控后)
↓
filterToolsByDenyRules() // 拒绝规则过滤
↓
REPL 模式过滤 // 隐藏被 REPL 包装的原始工具
↓
isEnabled() 过滤 // 工具自身启用检查
↓
assembleToolPool() // 合并 MCP 工具
↓
prompt-cache 排序 // 缓存稳定性排序
3.4 工具查找
// 名称或别名匹配
exportfunctiontoolMatchesName(tool: { name: string; aliases?: string[] },name: string,): boolean {
return tool.name === name || (tool.aliases?.includes(name) ?? false)
}
// 从工具列表中查找
exportfunctionfindToolByName(tools: Tools, name: string): Tool | undefined {
return tools.find(t =>toolMatchesName(t, name))
}
4. 权限与授权系统
4.1 权限模式
exporttypePermissionMode =
| 'default'// 默认:询问用户
| 'plan'// 计划模式:需要审批
| 'acceptEdits'// 自动批准编辑
| 'bypassPermissions'// 绕过所有权限(--dangerously-skip-permissions)
| 'dontAsk'// 自动拒绝所有
| 'auto'// ML 分类器驱动(内部专用)
4.2 权限检查流程
工具调用请求
↓
┌─────────────────────┐
│ validateInput() │ ← 输入格式验证
└──────────┬──────────┘
↓
┌─────────────────────┐
│ checkPermissions() │ ← 工具自身权限逻辑
└──────────┬──────────┘
↓
┌─────────────────────┐
│ 检查 deny 规则 │ ← 配置文件/CLI 参数
└──────────┬──────────┘
↓ (未拒绝)
┌─────────────────────┐
│ PreToolUse Hooks │ ← 可修改输入/阻止执行
└──────────┬──────────┘
↓
┌─────────────────────┐
│ 检查 allow 规则 │ ← 自动批准匹配
└──────────┬──────────┘
↓ (未匹配)
┌─────────────────────┐
│ 权限模式决策 │ ← default:询问 / auto:分类器
└──────────┬──────────┘
↓
allow / deny / ask
4.3 权限决策结果
exporttypePermissionResult = {
behavior: 'allow' | 'deny' | 'ask'
updatedInput?: Record<string, unknown=""> // Hooks 可修改输入
suggestions?: string[] // 建议操作
message?: string// 显示给用户
decisionReason?: {
type: 'hook' | 'classifier'
classifier?: 'auto-mode'
reason?: string
}
pendingClassifierCheck?: Promise<classifierresult> // 异步分类器
}
</classifierresult></string,>
4.4 权限规则来源
typePermissionRuleSource =
| 'settings'// ~/.claude/rules.json(持久化配置)
| 'cliArg'// CLI --allow/--deny 参数
| 'command'// CLAUDE.md 中的 hooks
| 'session'// 会话内 /permissions 命令
4.5 权限规则匹配
规则支持工具名称 + 输入内容的组合匹配:
// 示例规则
{ tool: "Bash", ruleContent: "npm test" } // 只允许特定命令
{ tool: "mcp__server" } // 按 MCP 服务器前缀匹配
{ tool: "FileWrite", ruleContent: "src/**" } // 路径 glob 匹配
5. 工具执行编排
5.1 执行管线
// 入口: query.ts → runTools()
exportasyncfunction* runTools(
toolUseMessages: ToolUseBlock[],
assistantMessages: AssistantMessage[],
canUseTool: CanUseToolFn,
toolUseContext: ToolUseContext,
): AsyncGenerator<messageupdate></messageupdate>
5.2 完整执行流程
Query 输入 (含 tool_use blocks)
↓
[runTools] 入口
↓
[partitionToolCalls] 按并发安全性分批
↓
对每个批次:
├─→ [runToolsConcurrently] 或 [runToolsSerially]
│ ├─→ [runToolUse] 单工具执行
│ │ ├─→ 输入验证: validateInput()
│ │ ├─→ Pre Hooks: executePreToolHooks()
│ │ ├─→ 权限检查: canUseTool()
│ │ ├─→ 执行: tool.call()
│ │ ├─→ Post Hooks: executePostToolHooks()
│ │ └─→ 结果映射: mapToolResultToToolResultBlockParam()
│ └─→ yield {message, newContext}
└─→ 应用 contextModifier 到下一批次
↓
Yield MessageUpdate 给 query loop
↓
API 处理 tool_result blocks
↓
下一轮 → 新的 assistant 响应
5.3 批次分区逻辑
functionpartitionToolCalls(toolUseMessages: ToolUseBlock[],context: ToolUseContext,): Batch[] {
// 连续的只读工具 → 并发批次
// 非只读工具 → 串行批次(单工具)
//
// 判断标准: tool.isConcurrencySafe(input)
// - FileReadTool: 始终 true(无副作用)
// - BashTool: 无 cd 且无输出重定向时 true
// - AgentTool: 始终 false(状态变更)
// - FileEditTool: false(文件写入)
}
5.4 执行阶段详解
|
|
|
|
|---|---|---|
|
|
validateInput() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6. Hook 系统集成
6.1 工具相关 Hook 事件
typeHookEvent =
| 'PreToolUse'// 工具执行前(权限检查前)
| 'PostToolUse'// 工具执行后(结果返回前)
| 'PostToolUseFailure'// 工具执行失败后
| 'PermissionRequest'// 权限提示时
| 'PermissionDenied'// 权限被拒绝时
6.2 Hook 输入/输出
// PreToolUse Hook
typePreToolUseHookInput = {
toolName: string
toolInput: Record<string, unknown="">
toolUseId: string
}
typePreToolUseHookOutput = {
continue?: boolean// false = 阻止执行
decision?: 'approve' | 'block'// 权限决策
updatedInput?: Record<string, unknown=""> // 修改输入
}
// PostToolUse Hook
typePostToolUseHookInput = {
toolName: string
toolInput: Record<string, unknown="">
toolOutput: unknown
toolUseId: string
}
</string,></string,></string,>
6.3 Hook 在执行管线中的位置

7. MCP 协议集成
7.1 MCP 工具注册
MCP (Model Context Protocol) 工具通过动态发现机制注册:
// MCP 客户端发现工具
classMCPClient {
asynclistTools(): Promise<tool[]>
// 转换: MCP tool schema → Tool[] 格式
// 命名: mcp__<servername>__<toolname>
}
</toolname></servername></tool[]>
7.2 MCPTool 包装器 (tools/MCPTool/MCPTool.ts)
exportconstMCPTool = buildTool({
isMcp: true,
maxResultSizeChars: 100_000,
asynccall(args, context) {
// 1. 转换参数 → MCP 请求
// 2. 调用 MCP 服务器 (JSON-RPC)
// 3. 处理 MCP 错误(认证失败、工具未找到)
// 4. 截断超大响应
return { data: result }
},
asynccheckPermissions(input, context) {
// 透传到通用权限系统
return { behavior: 'passthrough' }
},
})
7.3 MCP 工具生命周期

7.4 MCP 认证 (tools/McpAuthTool/)
支持 OAuth 2.0 流程的 MCP 服务器认证,处理 -32042 错误码的 URL 授权请求。
8. 工具结果处理与缓存
8.1 结果大小管理
// 每个工具定义结果大小阈值
maxResultSizeChars: number
// 超出阈值时:
// 1. 保存输出到 ~/.claude/tool-results/<hash>.txt
// 2. 发送 API 预览 + 文件路径引用
// 3. 用户可通过文件查看完整输出
</hash>
8.2 结果预算系统
// ContentReplacementState 管理每轮对话的结果预算
// 聚合 token 限制: ~128K tokens(可配置)
// 超出时: 截断/持久化最早的结果
8.3 结果块映射
// 每个工具必须实现
mapToolResultToToolResultBlockParam(content, toolUseID): ToolResultBlockParam {
return {
type: 'tool_result',
tool_use_id: toolUseID,
content: content, // string 或 ContentBlockParam[]
is_error?: boolean,
}
}
9. UI 渲染体系
9.1 渲染方法矩阵
每个工具实现 6-8 个 React 渲染方法,覆盖不同状态:
|
|
|
|
|---|---|---|
renderToolUseMessage |
|
|
renderToolResultMessage |
|
|
renderToolUseProgressMessage |
|
|
renderToolUseErrorMessage |
|
|
renderToolUseRejectedMessage |
|
|
renderGroupedToolUse |
|
|
9.2 搜索/折叠分类
// 用于 UI 折叠/展开优化
isSearchOrReadCommand?(input): { isSearch, isRead, isList }
getToolUseSummary?(input): string | null// "Listed 42 files in 12ms"
getActivityDescription?(input): string | null
10. 工具搜索与延迟加载
10.1 延迟加载机制
当工具数量超过阈值(约 50 个)时,启用工具搜索:
// 工具标记
shouldDefer?: boolean// 标记为可延迟
alwaysLoad?: boolean// 强制加载(覆盖延迟)
searchHint?: string// 搜索关键词提示
// 流程:
// 1. 延迟工具从初始 prompt 中隐藏
// 2. 模型调用 ToolSearch(keywords) 查找工具
// 3. ToolSearch 返回匹配工具的完整 schema
// 4. 模型即可调用发现的工具
10.2 ToolSearchTool
// ToolSearchTool 接受查询字符串
// 支持:
// - "select:Read,Edit,Grep" → 精确匹配
// - "notebook jupyter" → 关键词搜索
// - "+slack send" → 名称要求 + 排序
11. 并发控制策略
11.1 并发安全分类
// 各工具的 isConcurrencySafe 实现:
BashTool: input 中无 cd 且无输出重定向时 true
FileReadTool: 始终 true(纯读取)
FileEditTool: 始终 false(文件写入)
FileWriteTool: 始终 false(文件创建)
GlobTool: 始终 true(纯搜索)
GrepTool: 始终 true(纯搜索)
AgentTool: 始终 false(状态变更)
MCPTool: 始终 false(外部副作用未知)
11.2 最大并发数
MAX_TOOL_USE_CONCURRENCY = 10
// 可通过 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY 环境变量配置
11.3 并发批次调度

12. 完整工具清单
12.1 工具目录 (40 个子目录)
|
|
|
|
|---|---|---|
| AgentTool |
|
|
| AskUserQuestionTool |
|
|
| BashTool |
|
|
| BriefTool |
|
|
| ConfigTool |
|
|
| EnterPlanModeTool |
|
|
| EnterWorktreeTool |
|
|
| ExitPlanModeTool |
|
|
| ExitWorktreeTool |
|
|
| FileEditTool |
|
|
| FileReadTool |
|
|
| FileWriteTool |
|
|
| GlobTool |
|
|
| GrepTool |
|
|
| LSPTool |
|
|
| ListMcpResourcesTool |
|
|
| MCPTool |
|
|
| McpAuthTool |
|
|
| NotebookEditTool |
|
|
| PowerShellTool |
|
|
| REPLTool |
|
|
| ReadMcpResourceTool |
|
|
| RemoteTriggerTool |
|
|
| ScheduleCronTool |
|
|
| SendMessageTool |
|
|
| SkillTool |
|
|
| SleepTool |
|
|
| SyntheticOutputTool |
|
|
| TaskCreateTool |
|
|
| TaskGetTool |
|
|
| TaskListTool |
|
|
| TaskOutputTool |
|
|
| TaskStopTool |
|
|
| TaskUpdateTool |
|
|
| TeamCreateTool |
|
|
| TeamDeleteTool |
|
|
| TodoWriteTool |
|
|
| ToolSearchTool |
|
|
| WebFetchTool |
|
|
| WebSearchTool |
|
|
12.2 各工具目录结构
ToolName/
├── ToolName.ts[x] # 主实现
├── prompt.ts # LLM 指令 & 常量
├── UI.tsx # React 渲染方法
├── constants.ts # 工具名称 & 配置
├── utils.ts # 辅助函数
└── testing/ # 测试工具
13. 关键设计模式
13.1 Lazy Schema Loading
const inputSchema = lazySchema(() =>
z.strictObject({
command: z.string(),
timeout: semanticNumber(z.number().optional()),
})
)
// 避免循环导入 & 模块加载时的副作用
13.2 语义类型强制转换
// 处理 LLM 可能返回的非标准类型
semanticBoolean(z.boolean().optional())
// "true" / "1" / "yes" → true
semanticNumber(z.number().optional())
// "42" / "4.2" → 42 / 4.2
13.3 buildTool 工厂函数
exportfunction buildTool<d extends="" anytooldef="">(def: D): BuiltTool<d>
// 提供安全默认值:
constTOOL_DEFAULTS = {
isEnabled: () =>true,
isConcurrencySafe: () =>false, // 默认不安全(fail-closed)
isReadOnly: () =>false, // 默认假设有写操作
isDestructive: () =>false,
checkPermissions: () => ({ behavior: 'allow', updatedInput }),
userFacingName: () => name,
}
</d></d>
13.4 工具别名
// 工具重命名时的向后兼容
aliases?: string[]
// toolMatchesName() 同时检查 name 和 aliases
13.5 输入等价性
// 用于推测执行中的去重
inputsEquivalent?(a: Input, b: Input): boolean
13.6 透明包装器
// REPLTool 使用透明包装器模式
isTransparentWrapper?(): boolean
// 为 true 时:
// - 包装器工具自身不渲染
// - 内部工具(bash, read, edit)原生渲染
14. 性能参数与限制
14.1 并发参数
|
|
|
|
|---|---|---|
|
|
|
CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY |
14.2 结果存储
|
|
|
|---|---|
|
|
|
|
|
|
|
|
~/.claude/tool-results/<hash>.txt |
14.3 文件读取
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14.4 搜索限制
|
|
|
|---|---|
|
|
|
|
|
|
14.5 Bash 超时
|
|
|
|---|---|
|
|
|
|
|
|
以上就是 Claude Code 的 Tools 实现架构与核心细节了。
从源码层面来看,这套系统做了大量扎实的工程化工作,远不止是简单的”工具调用封装”。
总结下 Claude Code 的 Tools 核心设计理念:
-
权限优先 (Permission-First): 多层权限检查贯穿整个执行流,fail-closed 策略确保安全
-
插件化架构: 统一的 Tool 接口支持 40+ 内置工具 + 无限 MCP 扩展
-
智能并发: 自动分析工具安全性实现最优并行,兼顾性能与正确性
-
渐进式加载: 延迟加载 + 工具搜索优化大量工具时的 prompt 效率
-
Hook 生态: Pre/Post 执行钩子提供完整的扩展点
-
结果预算管理: 自动持久化大输出,维护上下文 token 预算
-
类型安全: Zod schema + TypeScript 泛型确保端到端类型安全
-
缓存友好: 工具排序策略优化服务端 prompt cache 命中率
这八条设计原则并非相互独立,它们共同构成了一套自洽的工程哲学。
对于希望深入理解 Code Agent 底层机制的开发者来说,Claude Code 的 Tools 系统是一个值得细读的工程范本。
它告诉我们,一个真正可用于生产环境的 AI Agent 工具层,需要在安全、性能、可扩展性和成本之间持续寻找最优解,而这背后所依赖的,正是严谨的软件工程基础。
夜雨聆风