跳转至

07. 工具、技能与 MCP

Claude Code 的动作能力分成三层:模型可见的工具规格、运行时内部的工具对象、本地真正执行的处理器。模型只看到工具名、描述和结构说明;运行时持有工具的校验、权限、渲染、并发和安全属性;处理器才会读取文件、运行命令、访问网络或调用 MCP 服务。模型请求工具不等于工具已经执行。

工具系统同时管理能力暴露、任务方法和实际执行。技能(skill,指可复用的任务说明和约束)改变模型的工作方式;MCP 将外部服务的工具、资源或提示接入工具池;真正的本地副作用仍然由工具处理器和权限系统控制。

flowchart TB Model[模型] -->|工具调用: 名称 + 输入| Router[工具查找与路由] Router --> Schema[输入结构校验] Schema --> Hooks[PreToolUse hook] Hooks --> Permission[权限决策] Permission -->|允许| Handler[本地处理器] Permission -->|拒绝/询问| Denied[拒绝或询问结果] Handler --> Post[PostToolUse hook] Post --> Result[工具结果] Denied --> Result Result --> Model

工具对象承载了比结构说明更多的信息。它会声明是否只读、是否有破坏性、是否并发安全、是否需要用户交互、是否应该延迟加载、是否来自 MCP、最大输出大小、如何把结果映射为工具结果、如何渲染给界面、如何做工具特定权限检查。查询循环只处理“有工具调用需要执行”这个事实,具体工具行为由工具对象封装。

内置工具的能力分层

公开可观察到的 Claude Code 内置工具大致可以分成几类:文件读写类(读取文件、写入文件、编辑文件、按行范围替换)、检索类(按路径匹配的 Glob、按内容匹配的正则搜索)、执行类(Bash 命令)、网络类(抓取网页、联网搜索)、任务管理类(维护结构化待办列表,向用户展示进度)以及派生类(把一部分任务派发给子智能体独立完成)。这个分层本身就对应权限和并发策略:读取和检索类工具通常标记为只读、并发安全;写入、编辑和执行类工具通常标记为有状态修改、需要走完整的权限确认路径;派生类工具则会开启一个独立的查询循环,拥有自己的上下文窗口和转录分支,执行结束后只把结果作为一次工具结果(或附件)带回父任务,不会把子任务内部的全部中间过程转发给父模型。

执行管线

执行时,运行时会先把本轮工具调用分批。连续的并发安全工具可以并行执行,不安全工具串行执行。并发批次的上下文修改会在批次结束后统一应用,避免多个工具同时修改共享状态造成顺序混乱。比如多个只读搜索可以并行,编辑文件或影响任务状态的工具更可能串行。

工具执行管线的第一步是校验。模型给出的输入必须通过 JSON 结构说明和工具自定义校验。校验失败不会进入处理器,而是直接生成错误工具结果。第二步是钩子。工具使用前钩子可以观察或改写输入,也可以要求阻止继续。第三步是权限判断。只有权限系统返回允许,处理器才会执行。处理器返回后,运行时会截断或持久化大输出,运行工具使用后钩子,把结果转换成模型能理解的工具结果。

官方 hooks 文档公开的生命周期事件里,PreToolUsePostToolUse 正好对应这条管线里“权限判断前”和“处理器执行后”两个切入点;两者都可以按工具名做匹配(matcher),只对特定工具生效,这也是项目里常见的“给 Bash 加一层自定义 lint 检查”“给 Write 加一层敏感路径拦截”之类扩展的实现方式。

MCP 工具的接入路径

MCP 工具是同一套工具系统的扩展。MCP 客户端提供远端工具名称、描述、结构说明和调用能力,运行时把它们包装成普通工具对象,放进工具池。对模型来说,MCP 工具和内置工具一样表现为工具结构说明;对运行时来说,它们仍然要经过校验、权限、钩子、输出处理和结果回填。MCP 的区别在于处理器调用的是外部服务,而不是本地内置函数。

MCP Server 的接入配置可以分层声明:项目级 .mcp.json、用户级配置、命令行临时指定,各层之间存在覆盖顺序,项目配置通常需要用户显式信任后才会生效,避免克隆一个陌生仓库就静默连接到仓库自带的 MCP Server。传输方式上,MCP 支持本地子进程(stdio)和远程服务(Streamable HTTP,2025-03 版起取代了早期 2024-11 版的 HTTP+SSE;WebSocket 并非 MCP 官方传输方式)两类,前者的生命周期和权限边界更接近本地工具,后者则额外引入网络可用性和身份认证问题——这两类工具在结构说明层面对模型是透明的,但在运行时的失败模式上并不相同(一个是进程崩溃,一个是连接超时),协议层的具体细节见 mcp-protocol-flow.md

技能:任务方法而非执行权限

技能和工具不同。技能更接近“可复用的任务提示和运行方式”,不是直接副作用能力。一个技能通常由 SKILL.md 或命令定义描述:什么时候使用、参数是什么、允许哪些工具、是否禁用模型调用、是否分叉、是否指定模型或推理强度、是否带钩子。模型可以通过技能工具请求某个技能,但技能本身通常会展开成提示词、上下文、允许工具或子智能体任务,再由后续查询循环使用普通工具完成实际动作。

Claude Code 公开的 Agent Skills 机制里,一个技能通常以 SKILL.md 文件加 YAML frontmatter 的形式声明,frontmatter 里包含名称、一句话描述(供模型判断是否要用它)、允许调用的工具子集等元数据;正文才是完整的任务说明。技能来源可以是个人级(用户目录)、项目级(随仓库提交)或插件打包分发。这个“先给一句话描述,命中后再展开正文”的两段式设计,和下一段要讲的工具搜索是同一个思路:先用最小信息量做筛选,再用最大信息量做执行,避免一次性把所有技能正文都塞进系统提示词。

flowchart LR SkillFile[SKILL.md / 命令] --> Command[技能命令] Command --> SkillTool[技能工具] SkillTool -->|内联| Prompt[展开提示词 / 允许工具] SkillTool -->|分叉| Agent[分叉智能体] Prompt --> Loop[查询循环] Agent --> Attachment[结果 attachment] Attachment --> Loop

技能的发现:静态与动态两条路径

技能的发现分静态和动态。静态来源包括内置技能、插件技能、用户目录、项目目录、额外目录和 MCP 提供的提示命令。动态来源来自路径触发:当工具读写某些文件后,运行时可以沿目录向上发现嵌套 .claude/skills,或激活 frontmatter 中带 paths 条件的技能。被发现的技能会进入后续上下文或工具可见面,但这不代表它自动获得更多权限;它只是改变模型可调用的任务模板和提示。

工具数量问题:搜索与延迟加载

工具搜索和延迟工具处理工具数量问题。当工具池很大时,全部结构说明都放进提示词会浪费上下文。运行时可以让模型先使用搜索工具定位相关能力,或者根据历史中的工具引用再加载具体结构说明。这一层影响“模型能看到哪些工具说明”,不改变本地权限判断。即使工具结构说明被加载,真正执行时仍然要走同一条校验、钩子、权限、处理器流程。

这个问题在接入大量 MCP Server 时尤其突出:如果同时连接十几个 MCP Server,每个都暴露十几个工具,全量结构说明会占用可观的上下文预算,还会提高模型选错工具的概率。延迟加载本质上是把“工具发现”和“工具执行”两个阶段的信息量解耦——发现阶段只需要模型知道“有这么个能力,名字和大致用途是什么”,执行阶段才需要完整的参数结构说明,这和技能的两段式设计是同一个工程思路在不同层面的复用。

能力边界小结

可以用一条检查线区分能力边界:模型能看到什么、运行时能执行什么、权限在哪层判断、结果如何回到模型。技能只改变模型上下文;工具规范只暴露动作接口;处理器才产生本地副作用;权限系统决定是否放行;工具结果再把外部世界的变化反馈给模型。下一章会展开这条链路上的权限和安全控制。