基于 Claude Code CLI v2.1.88 源码分析
Claude Code 的工具系统是其核心架构之一,负责将 LLM 的意图转化为实际的文件操作、命令执行、搜索查询等具体行为。整个系统围绕 Tool 类型定义、工具注册表和权限模型三大支柱构建。
Tool 类型是整个工具系统的核心抽象,定义在 src/Tool.ts 中。以下是关键类型及其职责。
每个工具通过 JSON Schema 声明其输入参数的类型和约束:
type ToolInputJSONSchema = {
type: "object";
properties: Record<string, JSONSchemaProperty>;
required?: string[];
additionalProperties?: boolean;
};该 schema 在工具调用前用于校验 LLM 生成的参数是否合法,防止无效输入进入执行阶段。
描述工具执行时的权限环境:
interface ToolPermissionContext {
permissionMode: "default" | "auto" | "bypass";
rules: ToolPermissionRulesBySource;
additionalWorkingDirs?: string[];
}default— 默认模式,敏感操作需用户确认auto— 自动模式,大部分操作自动批准(适合 CI/CD 场景)bypass— 绕过模式,跳过所有权限检查
权限规则按来源组织(ToolPermissionRulesBySource),每条规则可设为 alwaysAllow、deny 或 ask,实现细粒度的权限控制。
工具执行时传入的运行时上下文,包含当前会话、文件系统状态、配置信息等:
interface ToolUseContext {
// 当前工作目录、会话信息、配置等
cwd: string;
session: Session;
config: Config;
// ... 其他运行时状态
}工具实现函数通过该上下文获取执行所需的一切环境信息。
允许工具注册自定义的 React 组件用于 UI 渲染:
type SetToolJSXFn = (jsx: React.ReactNode) => void;工具可以通过此函数在终端 UI(基于 Ink)中展示富文本输出,例如文件 diff、搜索结果高亮等。
工具在执行前可对输入进行自定义校验:
type ValidationResult =
| { valid: true }
| { valid: false; reason: string };除了 JSON Schema 的静态校验外,工具还可实现 validateInput 方法进行业务逻辑层面的校验(如文件路径是否存在、参数组合是否合理等)。
用于追踪嵌套的代理(Agent)调用链:
interface QueryChainTracking {
depth: number;
parentToolUseId?: string;
// ...
}当 AgentTool 创建子代理时,系统通过此机制追踪调用层级,防止无限递归并提供调试信息。
tools.ts 是工具注册的中枢,负责根据运行时环境条件加载 40 多个工具。
以下工具在所有环境下均可用:
| 工具名称 | 分类 | 说明 |
|---|---|---|
AgentTool |
代理 | 创建子代理执行复杂任务 |
BashTool |
命令执行 | 执行 shell 命令 |
FileEditTool |
文件操作 | 编辑文件(基于字符串替换) |
FileReadTool |
文件操作 | 读取文件内容 |
FileWriteTool |
文件操作 | 写入/创建文件 |
GlobTool |
搜索 | 文件名模式匹配搜索 |
GrepTool |
搜索 | 文件内容正则搜索(基于 ripgrep) |
NotebookEditTool |
文件操作 | 编辑 Jupyter Notebook |
WebFetchTool |
网络 | 抓取网页内容 |
WebSearchTool |
网络 | 网络搜索 |
SkillTool |
扩展 | 调用已注册的技能 |
AskUserQuestionTool |
交互 | 向用户提问 |
LSPTool |
开发 | 与语言服务器交互 |
TodoWriteTool |
任务管理 | 管理待办事项 |
TaskCreate/Get/Update/List/Stop/Output |
任务管理 | 后台任务的完整生命周期管理 |
EnterPlanMode / ExitPlanMode |
模式切换 | 进入/退出计划模式 |
EnterWorktree / ExitWorktree |
模式切换 | 进入/退出 git worktree |
ConfigTool |
配置 | 读写配置 |
ToolSearchTool |
元工具 | 搜索可用工具的 schema |
ListMcpResources / ReadMcpResource |
MCP | 操作 MCP 资源 |
BriefTool |
输出控制 | 控制输出详细程度 |
SendMessageTool |
通信 | 发送消息 |
TeamCreate / TeamDelete |
团队 | 团队管理 |
部分工具仅在特定特性标志(feature flag)开启时加载:
| 工具名称 | 加载条件 | 说明 |
|---|---|---|
REPLTool |
USER_TYPE === 'ant' |
REPL 执行环境(仅 Anthropic 内部) |
SleepTool |
PROACTIVE || KAIROS |
等待/休眠(主动式代理场景) |
CronCreate/Delete/List |
AGENT_TRIGGERS |
定时任务管理 |
RemoteTriggerTool |
AGENT_TRIGGERS_REMOTE |
远程触发器 |
MonitorTool |
MONITOR_TOOL |
系统监控 |
SendUserFileTool |
KAIROS |
向用户发送文件 |
PushNotificationTool |
KAIROS || KAIROS_PUSH_NOTIFICATION |
推送通知 |
SubscribePRTool |
KAIROS_GITHUB_WEBHOOKS |
订阅 GitHub PR 事件 |
VerifyPlanExecutionTool |
环境变量 CLAUDE_CODE_VERIFY_PLAN |
验证计划执行结果 |
工具的条件加载采用 require() + feature() 的模式:
const SleepTool = feature('PROACTIVE') || feature('KAIROS')
? require('./tools/SleepTool/SleepTool.js').SleepTool
: null;这种模式的设计意图:
- 按需加载 — 未启用的工具不会被
require(),减少启动时间和内存占用 - 编译时死代码消除 — 打包工具可在编译期移除不可达的
require()分支 - 运行时灵活性 — 通过
feature()函数在运行时决定加载哪些工具
最终,注册表将所有非 null 的工具收集到数组中:
export function getTools(): Tool[] {
return [
AgentTool,
BashTool,
FileEditTool,
// ... 始终加载的工具
SleepTool, // 可能为 null
REPLTool, // 可能为 null
// ... 其他条件工具
].filter(Boolean); // 过滤掉 null 值
}工具的权限控制是 Claude Code 安全架构的关键组成部分。
权限规则按来源分层组织(ToolPermissionRulesBySource),优先级从高到低:
- 命令行参数 — 启动时通过
--allow/--deny指定 - 项目配置 —
.claude/settings.json中的规则 - 用户配置 —
~/.claude/settings.json中的全局规则 - 默认规则 — 工具自身定义的默认行为
用户/LLM 请求调用工具
│
▼
检查 permissionMode
│
┌────┼────┐
│ │ │
bypass auto default
│ │ │
│ │ ▼
│ │ 遍历规则来源
│ │ │
│ │ ┌─┴──────────┐
│ │ │ alwaysAllow │→ 直接执行
│ │ │ deny │→ 拒绝执行
│ │ │ ask │→ 提示用户确认
│ │ └─────────────┘
│ │
│ ▼
│ 自动批准大部分操作
│ (危险操作仍需确认)
│
▼
跳过所有检查,直接执行
每个工具可实现 isReadOnly() 和 needsPermission() 方法:
// BashTool 示例:根据命令内容判断是否需要权限
needsPermission(input: BashInput, context: ToolPermissionContext): boolean {
// 只读命令(如 ls, cat)不需要额外权限
if (isReadOnlyCommand(input.command)) return false;
// 写入/删除操作需要权限确认
return true;
}Claude Code 通过 Model Context Protocol (MCP) 支持外部工具服务器的集成。
MCP 工具在运行时动态发现并注册,与内置工具共存于同一工具列表中:
ListMcpResources— 列出 MCP 服务器提供的资源ReadMcpResource— 读取特定 MCP 资源
MCP 工具的权限同样受工具权限模型管控,外部工具默认需要用户确认。
MCP 服务器在项目或用户配置中声明:
{
"mcpServers": {
"figma": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-figma"],
"env": {}
}
}
}每个工具以独立目录的形式组织在 src/tools/ 下。
src/tools/
├── AgentTool/
│ └── AgentTool.ts
├── BashTool/
│ ├── BashTool.ts
│ └── bashHelpers.ts
├── FileEditTool/
│ └── FileEditTool.ts
├── GrepTool/
│ └── GrepTool.ts
└── ...
每个工具导出一个符合 Tool 接口的对象:
// src/tools/GrepTool/GrepTool.ts
export const GrepTool: Tool = {
name: "Grep",
description: "基于 ripgrep 的强力搜索工具...",
// JSON Schema 定义输入参数
inputSchema: {
type: "object",
properties: {
pattern: { type: "string", description: "正则表达式模式" },
path: { type: "string", description: "搜索路径" },
glob: { type: "string", description: "文件名过滤" },
},
required: ["pattern"],
},
// 输入校验(可选)
validateInput(input): ValidationResult {
if (!input.pattern) {
return { valid: false, reason: "必须提供搜索模式" };
}
return { valid: true };
},
// 是否只读(影响权限判定)
isReadOnly(): boolean {
return true;
},
// 核心执行逻辑
async call(input, context: ToolUseContext): Promise<ToolResult> {
// 1. 解析参数
// 2. 执行 ripgrep
// 3. 格式化并返回结果
},
// 自定义 UI 渲染(可选)
renderToolUse(input, setJSX: SetToolJSXFn) {
setJSX(<GrepResultView results={...} />);
},
};一个工具调用的完整生命周期如下:
- Schema 校验 — 根据
inputSchema校验 LLM 生成的参数 - 自定义校验 — 调用
validateInput()进行业务逻辑校验 - 权限检查 — 根据
needsPermission()和权限规则决定是否放行 - 执行 — 调用
call()方法执行实际操作 - 渲染 — 通过
renderToolUse()在终端 UI 中展示结果 - 结果返回 — 将执行结果返回给 LLM 作为后续推理的输入
Claude Code 的工具系统通过以下设计实现了高度的灵活性和安全性:
- 类型安全 — 完整的 TypeScript 类型定义确保工具接口的一致性
- 条件加载 — 基于特性标志的按需加载减少不必要的资源消耗
- 分层权限 — 多来源、多级别的权限规则实现细粒度访问控制
- 可扩展性 — MCP 协议支持无限扩展外部工具
- 独立封装 — 每个工具独立目录,职责清晰,易于维护和测试