核心机制

工具系统解析:Tool 抽象与 tools 注册表

Claude Code 的执行力来自工具,不只来自模型

很多人讨论 AI 编程工具时,容易把注意力全部放在模型上。
但从 Claude Code 源码来看,真正让它“能干活”的,是模型外面的工具系统。

如果没有工具,Claude Code 再强也只是会分析代码。
有了工具,它才能真正读文件、改文件、跑命令、接 MCP、问用户、开子任务。

加载图表中...

Tool.ts 负责定义统一协议

Tool.ts 不是某个具体工具实现,而是全系统的工具抽象层。

这里最重要的价值有两个:

  • 统一工具的输入、输出、上下文和权限语义
  • 给所有工具提供相同的运行契约

文件里能看到很多关键类型:

  • ToolInputJSONSchema
  • ToolUseContext
  • ToolPermissionContext
  • 各类进度与状态类型

这些类型说明 Claude Code 设计工具时,不是把工具当命令快捷方式,而是把它们当系统级能力对象。

对应源码片段

export type ToolInputJSONSchema = {
  [x: string]: unknown
  type: 'object'
  properties?: {
    [x: string]: unknown
  }
}

这段定义虽然短,但非常关键。
它说明 Claude Code 的工具不是随便塞一段文本描述,而是要求:

  • 输入结构明确
  • 参数可枚举
  • 工具契约可被系统理解

这正是工具化系统和随意 prompt 技巧的区别。

Tool.ts 真正定义的是一套执行契约

从这些类型可以反推出,Claude Code 对工具的预期非常清晰:

  • 工具要有明确输入 schema
  • 工具要能拿到统一上下文
  • 工具要能被权限系统约束
  • 工具执行过程要能反馈进度
  • 工具结果要能回到消息流里

这套契约是后面所有能力扩展的基础。

ToolUseContext 很能说明问题

ToolUseContext 里挂了大量运行时资源,例如:

  • 当前工具集合
  • 命令集合
  • MCP client 与 resource
  • AppState 读写方法
  • 通知能力
  • 中断控制
  • 消息历史
  • 文件读取限制
  • attribution / fileHistory 更新器

这意味着一个工具并不是孤立执行的,它是运行在完整会话上下文里的。

对应源码片段

export type ToolUseContext = {
  options: {
    commands: Command[]
    debug: boolean
    mainLoopModel: string
    tools: Tools
    verbose: boolean
    thinkingConfig: ThinkingConfig
    mcpClients: MCPServerConnection[]
    mcpResources: Record<string, ServerResource[]>
  }
  abortController: AbortController
  readFileState: FileStateCache
  getAppState(): AppState
  setAppState(f: (prev: AppState) => AppState): void
  messages: Message[]
}

这段类型直接说明:
一个工具执行时,实际上是被放进完整运行时里的,而不是孤立调用一个小函数。

加载图表中...

tools.ts 是系统的工具目录

如果说 Tool.ts 定义的是协议,那 tools.ts 定义的就是“这次系统到底有哪些工具”。

从注册表里能看到 Claude Code 的能力面相当宽:

  • 文件工具:读、写、编辑、Notebook
  • 终端工具:Bash、PowerShell
  • 搜索工具:Glob、Grep
  • 网络工具:WebFetch、WebSearch、WebBrowser
  • 交互工具:AskUserQuestion
  • 管理工具:Todo、Task、Plan、Worktree
  • 集成工具:MCP、LSP、ToolSearch
  • 智能体工具:Agent、Team、SendMessage

这已经明显不是“几个简单 function calling 工具”的规模了。

对应源码片段

export function getAllBaseTools(): Tools {
  return [
    AgentTool,
    TaskOutputTool,
    BashTool,
    ...(hasEmbeddedSearchTools() ? [] : [GlobTool, GrepTool]),
    ExitPlanModeV2Tool,
    FileReadTool,
    FileEditTool,
    FileWriteTool,
    WebFetchTool,
    TodoWriteTool,
    WebSearchTool,
    AskUserQuestionTool,
    SkillTool,
    EnterPlanModeTool,
    ...(isEnvTruthy(process.env.ENABLE_LSP_TOOL) ? [LSPTool] : []),
    ListMcpResourcesTool,
    ReadMcpResourceTool,
  ]
}

这里最值得注意的是两点:

  • Claude Code 的能力面非常宽,不止读写文件和 Bash
  • 工具集不是死的,会受环境变量和 feature 条件影响

这些工具大致可以分成 4 组

1. 基础执行工具

  • FileRead
  • FileEdit
  • FileWrite
  • Bash
  • Glob
  • Grep

2. 会话控制工具

  • AskUserQuestion
  • TodoWrite
  • EnterPlanMode
  • ExitPlanMode

3. 扩展接入工具

  • ListMcpResources
  • ReadMcpResource
  • LSPTool
  • ToolSearchTool

4. 协作与任务工具

  • AgentTool
  • SendMessageTool
  • TaskCreate / Get / Update / List
  • TeamCreate / TeamDelete

工具不是全量暴露,而是动态筛选

tools.ts 里能看到很多 feature gate、环境判断和权限过滤逻辑。

这说明工具系统有两个重要特征:

  1. 工具集是可配置、可裁剪的
  2. 模型看到的工具集不一定等于代码里存在的工具集

也就是说,Claude Code 在“给模型什么能力”这件事上非常克制。

对应源码片段

export function filterToolsByDenyRules<
  T extends {
    name: string
    mcpInfo?: { serverName: string; toolName: string }
  },
>(tools: readonly T[], permissionContext: ToolPermissionContext): T[] {
  return tools.filter(tool => !getDenyRuleForTool(permissionContext, tool))
}

这段代码很重要,因为它说明安全不是只在执行时介入。
有些工具会在模型看到它们之前,就先被权限规则过滤掉。

加载图表中...

这里体现了 Claude Code 的工程哲学

从工具系统设计上,你能读出几个非常明显的工程取向:

  • 能力统一封装:先抽象协议,再接入具体能力
  • 权限前置:不是执行时再补安全,而是能力暴露阶段就开始约束
  • 按环境启用:不同构建、不同平台、不同 feature 下工具集不同
  • 扩展优先:MCP、LSP、Team、Workflow 都能接进这套协议

这也是它后面能不断长出新能力的前提。

为什么统一工具协议特别重要

因为一旦协议稳定,新增能力的方式就会变得非常可预测:

  1. 新能力实现自己的 Tool
  2. 接入统一上下文和权限体系
  3. 注册到工具目录
  4. 在合适条件下暴露给模型

这比给模型单独塞一堆特例能力,要稳定得多。

小结

Claude Code 的工具系统可以概括成一句话:

用统一的 Tool 协议,把文件系统、终端、搜索、外部集成和智能体能力包装成模型可调用、可控、可扩展的执行层。

理解了这层,你就能明白它为什么不是“聊天 + 插件”的简单组合,而是一个真正可操作的工程代理。