Claude Code 的 Skills、Hooks 和 MCP,到底该怎么选?
在仓库工作里,有一种错误特别难察觉:你以为自己在做架构决策,其实只是在往不同的盒子里塞同一种东西。
"让 Claude 每次都按这个方式做 Code Review。"——你把它写进了 MCP server。
"提交前自动跑格式化。"——你用 Skill 来做的。
"从 GitHub 拉 PR 的 diff。"——你写了一个 Hook。
三件事,三种做法,但每一种都放错了地方。最后你得到的不是一个可靠的工作流,而是三个不同的失控点。
我在自己的仓库工作流里踩过类似的坑。Skills、Hooks、MCP 这三个东西并不难理解,但它们容易被一个模糊的概念统一吞掉——"扩展"。一旦被叫作扩展,人们就不再问"这件事真正的责任边界在哪里",而是问"哪个扩展更强大"。这是错误问题。
选择规则先放在这里:
Claude 需要复用一套做法时,用 Skill。某个生命周期事件必须触发受控动作时,用 Hook。需要连接外部工具或数据源时,用 MCP。三者可以组合,但不能在没有责任边界的情况下互相替代。
下面用一个发布工作流把这三件事说清楚。如果你还没有跑通过终端 Agent 的基础工作流,可以先看 Claude Code 新手指南。
用一个场景拉通
假设你在维护一个有标准发布流程的仓库。每次准备合并一个 Release PR,你需要:
- 按照固定的方式检查 Changelog、版本号、依赖更新,核对发布证据清单;
- 在 PR 提交前,自动对修改的文件跑格式化,并阻止对某些保护性文件的直接修改;
- 从 GitHub 拉取当前 PR 状态,从监控系统检查近期告警,决定是否继续发布。
这三件事对应的需求是:复用发布方法、事件控制执行、外部系统连接。它们不是同一件事,不应该交给同一个机制。
Skill:操作手册,用时取用
Skill 真正负责的是:把一套可复用的做法和判断封装起来,让 Claude 在相关任务中能够调用它。
Skill 的入口是 SKILL.md,里面可以包含流程说明、判断规则、输出格式要求,以及其他支持性资源文件——比如发布证据清单的模板、版本检查的参考规则。Skill 不只是一条 Prompt,它可以携带结构化的参考材料,让 Claude 在执行时有据可查。
在发布工作流里,Skill 是合适的:
skills/release-review/
├── SKILL.md # 发布审查的完整流程和判断规则
├── checklist.md # 发布证据清单
└── version-rules.md # 版本号规范参考
SKILL.md 里说明:审查时要核对哪些项目、证据不完整时应该返回什么结论、发布摘要的格式是什么。Claude 在执行发布审查任务时,可以调用这个 Skill;你也可以直接触发它。
关键特征: Skill 的内容在使用时载入,不是长期驻留在上下文里。这和把所有规则都堆进 CLAUDE.md 是不同的——CLAUDE.md 里的内容是项目级的常驻指令,Skill 是按需取用的方法书。如果这里的边界仍然不清楚,可以先判断 Coding Agent 的记忆应该保存什么。
判断空间: Skill 本质上是给 Claude 的指令,Claude 仍然有完整的模型判断在运行。Skill 让 Claude 知道"该怎么做",但执行中的具体判断还是模型在做。这是它和 Hook 最大的区别。
明显误用: 把格式化检查写成 Skill,期望它在每次提交时自动执行——这不是 Skill 该做的事。Skill 没有事件触发机制,它不会在提交发生时自动运行。
Hook:边界上的触发器,事件决定一切
Hook 真正负责的是:在 Claude Code 的特定生命周期事件发生时,执行一个受控动作。
这是三者里责任边界最清晰的一个。你不是在告诉 Claude 某件事应该怎么做,你是在说:当这个事件发生时,无论如何,运行这个命令。
在发布工作流里,Hook 是合适的:
- 在提交前,对修改的文件自动执行格式化脚本;
- 在 Claude 准备操作某个受保护文件时,检查是否有授权标记,没有就阻止;
- 在对话结束后,向内部状态记录系统写入操作日志。
这些动作有一个共同特征:它们不依赖 Claude 的判断——格式化要么跑,要么不跑;文件要么被保护,要么不被保护。
触发机制和判断空间: 这里有一个必须说清楚的区分。
Claude Code 支持不同类型的 Hook。Command Hook 在匹配的生命周期事件发生时直接执行一个 shell 命令——这是确定性的,事件触发就执行,不经过模型判断。Prompt-based 和 Agent-based Hook 则会引入模型判断,不能把它们等同于 command Hook 的确定性。
如果你需要的是"每次提交前,保证跑了格式化",那你需要的是 command Hook,而不是让模型来判断是否应该格式化。
安全边界: Hook 命令使用你的用户环境和权限执行。这意味着一个写错的 Hook 能做的事情,和你在终端里手动输入一条命令能做的事情,是同一个级别的。在审查 Hook 配置时,把它当成一段在你机器上运行的脚本来对待,不要因为它在 Claude Code 里就降低审查标准。
明显误用: 把"从 GitHub 拉 PR 状态"写成 Hook——Hook 不是用来连接外部系统的通道,它是本地生命周期上的门禁。把外部调用塞进 Hook 脚本,会让两个不同的责任在同一个地方混在一起,出问题时也更难追踪。
MCP:通向另一套系统的连接口
MCP 真正负责的是:把 Claude Code 连接到外部工具、数据源、数据库和 API。
在发布工作流里,MCP 是合适的:
- 从 GitHub API 拉取当前 PR 的状态、Review 评论、CI 结果;
- 从监控系统查询近期告警,判断发布窗口是否安全;
- 在获得授权后,向 issue tracker 更新发布状态。
这些都有一个共同特征:数据或操作的来源在 Claude Code 之外,需要通过协议连接。需要更完整的配置和集成介绍时,可以继续看 MCP Server 指南。
工具发现: 当前 Claude Code 在受支持的第一方配置中,MCP 工具可以按需发现——不是所有工具 schema 在启动时就全量载入。这意味着连接外部系统的成本在设计上是可控的,但实际表现取决于你使用的配置和服务端实现。
安全边界: MCP 的安全边界比 Hook 更复杂,因为涉及外部连接。第三方 MCP server 和通过 MCP 引入的外部内容,都需要认真做信任审查。外部内容有可能携带注入指令(Prompt Injection),MCP server 的权限范围也需要明确限制——不要因为"只是查询"就给它写入权限。
判断空间: MCP 工具本身是外部能力,Claude 决定什么时候调用哪个工具、如何使用返回的数据。这是 MCP 和 Hook 的另一个本质区别:Hook 的执行是事件触发的,MCP 工具的调用是模型在任务中做出的判断。
明显误用: 把发布审查的判断规则放进 MCP server,期望通过调用这个 server 来"标准化" Claude 的判断——这是 Skill 该做的事。本文不建议 MCP 承担主要判断方法。
三者的组合使用
在完整的发布工作流里,三者可以同时存在,各司其职:
| Skill | Hook | MCP | |
|---|---|---|---|
| 负责什么 | 复用做法和判断规则 | 生命周期事件上的受控动作 | 外部工具和数据的连接 |
| 谁触发 | Claude 按任务选用,或用户直接调用 | 特定生命周期事件 | Claude 在任务中按需调用 |
| 模型判断空间 | 大(Skill 是给 Claude 的指令) | Command Hook 无判断;Prompt/Agent Hook 有 | 中(Claude 决定调用时机和参数) |
| 外部连接 | 无 | 取决于命令可达范围 | 是 |
| 主要风险 | 指令设计不清导致误判 | Hook 命令权限未审查 | 第三方信任、Prompt Injection |
| 发布场景例子 | 发布审查流程、证据清单 | 提交前格式化、保护文件拦截 | 拉取 PR 状态、查询监控告警 |
| 明显误用 | 期望自动触发 | 用来调用外部 API | 用来封装判断规则 |
组合时的逻辑:
- Skill 告诉 Claude 发布审查的完整方法——要看什么、怎么判断、输出什么结论;
- MCP 提供实际数据——当前 PR 的状态、CI 结果、监控快照;
- Hook 保证在提交前,格式化一定跑了,保护文件一定检查了——不依赖 Claude 记得做。
这三件事在发布工作流里同时有意义,但它们的责任不重叠。Claude 通过 Skill 知道怎么做审查,通过 MCP 拿到外部数据,而格式化和文件保护的门禁则由 Hook 在事件上保证执行。
不清晰时的代价
把这三种东西混用,最终会出现三种典型的混乱:
把外部连接写进 Skill: Claude 每次运行 Skill 时,你期望它自动拉 PR 状态——但如果 Skill 只有静态说明,Claude 只能凭记忆或猜测。结果是不稳定的。
把判断规则写进 Hook: Hook 跑了,但结果取决于脚本本身的逻辑,而不是 Claude 对任务的理解。更糟糕的是,一个写成 Prompt-based Hook 的判断规则,你以为是确定性执行的,其实引入了模型判断。
把门禁依赖 MCP: 你通过 MCP server 做了一个"发布检查"工具,期望 Claude 在每次发布前都调用它——但 MCP 工具的调用是模型判断,Claude 在某次对话里可能跳过这一步。如果这个检查是门禁,它应该是 Hook。
区分这三种混乱的方式很简单:问一个问题——"如果 Claude 忘记了,这件事还会发生吗?"
- 如果答案必须是"是",你需要 Hook;
- 如果这件事本身需要从外面拿数据或改外部状态,你需要 MCP;
- 如果你只是需要 Claude 按照固定方法做某件事,你需要 Skill。
安全这件事不能带过
Hooks 和 MCP 都有值得单独说清楚的安全边界,不能含糊地写进"注意事项"里。
Hooks 的安全边界: Hook 命令以你的用户身份运行。这不是 Claude 在执行,这是你的系统在执行。审查 Hook 配置时,要问:这条命令如果被篡改或被注入了额外参数,能做什么?Hook 不是沙箱,也不是权限系统的替代品,它只是生命周期事件上的执行钩子。
MCP 的安全边界: 连接外部系统就意味着引入了外部内容。外部内容——包括 issue 描述、PR 评论、数据库字段——都可能携带注入指令。如果你的工作流里有 MCP 在读取用户可控的外部内容,要明确 Claude 不会无条件执行那些内容里的指令。第三方 MCP server 需要做信任审查,不要因为安装方便就跳过这一步。
一个可以马上执行的检查
从你当前的 Claude Code 配置里,各找出一条:
-
复用做法——某个你希望 Claude 每次都按照某种方式执行的流程或规则。检查它是否在 Skill 里,还是散落在
CLAUDE.md里,或者错误地依赖 Hook 脚本来模拟。 -
事件保证——某个你需要在特定时机一定发生的动作,比如提交前的验证、操作后的记录。检查它是否是一个 command Hook,还是你在依赖 Claude "记得"去触发某个工具。
-
外部连接——某个需要从外部系统获取数据或操作外部系统的步骤。检查它是否通过 MCP 连接,还是你在用 Skill 里的静态描述让 Claude 去"模拟"一个它实际上没有工具支持的操作。
如果这三件事都放在了正确的机制里,你的工作流是清晰的。如果有一件事放错了,你现在知道为什么它会在某次对话里失效。
当这套流程具体用于合并前 review 时,可以继续使用 AI Code Review 工作流,把需求、diff、检查结果和残余风险整理成一个有证据的合并结论。
如果你还想把这套选择放回完整的 Agent 学习路径,可以继续看 AI 编程 Agent 新手路线。
参考资料
以下为 Anthropic 官方文档,本文所有产品行为均以此为据: