Hooks、MCP 与能力扩展:让 Claude Code 成为你的开发平台

Hooks、MCP 与能力扩展:让 Claude Code 成为你的开发平台
Pei系列文章
本篇是 Claude Code 系列的第 6 篇。系列将从安装入门到高级实战,由浅入深地拆解这个终端原生 Coding Agent 的每一个能力。
入门篇
核心篇
3. 内置命令全解:从 /compact 到 /doctor 的实战指南
4. CLAUDE.md:项目上下文工程的艺术
进阶篇
5. 多文件重构与复杂任务实战
6. Hooks、MCP 与能力扩展(本文)
高级篇
7. Headless 模式与 CI/CD 集成
8. 多 Agent 协作:从 Claude Code 到 Codex
引言:从”能用”到”好用”的跨越
前五篇文章,我们从安装、日常使用、内置命令、上下文工程到多文件重构,已经把 Claude Code 的核心能力拆解得差不多了。但如果你真正把它用到日常开发中,一定会遇到这些问题:
- Claude 修改了代码,但没有自动跑 lint,你得手动检查一遍
- 你反复告诉它”我们的 Java 项目用 Spotless 格式化”,但它每次都忘
- 你想让它直接查 JIRA 看 issue 描述,但 Claude Code 只能读本地文件
- 你想让它连数据库验证 SQL 变更,但它没有数据库连接能力
这些问题的根源是一样的:Claude Code 的默认能力是有边界的。它是一个强大的 AI Agent,但它不了解你的团队规范、无法访问你的外部系统、也不能在特定时刻自动执行你定义的逻辑。
好消息是,Claude Code 提供了三个层次的扩展机制,让你可以把这些边界逐一打破:
- Hooks(生命周期钩子):在 Claude Code 的关键时刻自动触发脚本,实现”守门人”和”自动化”
- MCP(Model Context Protocol):通过开放协议接入外部工具和数据源,让 Claude 能”看到”和”操作”你的外部系统
- Skills(自定义技能):将可复用的工作流封装为可调用的指令,实现团队知识的标准化
这三个机制各有分工,但组合起来,就能把 Claude Code 从一个”智能代码编辑器”升级为一个真正的开发平台。
第一部分:Hooks——给 Claude Code 装上”守门人”
什么是 Hooks?
Hooks 是用户定义的脚本或 HTTP 端点,它们在 Claude Code 生命周期的特定时刻自动执行。你可以把它理解为 Git Hooks 的 AI 版本——就像 pre-commit 钩子在你提交代码前跑 lint 一样,Claude Code 的 Hooks 在 Agent 执行工具调用的前后、会话开始和结束时自动运行你定义的逻辑。
Hooks 的核心价值在于两个字:自动化。你不需要每次都提醒 Claude “记得跑格式化”,Hooks 会在它修改文件后自动触发。你不需要担心它执行危险命令,Hooks 会在它运行前检查。
Hook 事件:什么时候触发?
Claude Code 定义了丰富的生命周期事件,覆盖了从会话开始到结束的每一个关键时刻:
| 事件 | 触发时机 | 典型用途 |
|---|---|---|
SessionStart |
会话开始或恢复 | 初始化环境、加载配置 |
UserPromptSubmit |
用户提交 prompt 之前 | 输入过滤、日志记录 |
PreToolUse |
工具调用执行之前 | 安全检查、命令过滤 |
PostToolUse |
工具调用成功之后 | 自动 lint、格式化 |
PermissionRequest |
权限对话框出现时 | 自动授权或拒绝 |
Stop |
Claude 完成回答时 | 质量检查、结果验证 |
SubagentStart/Stop |
子 Agent 启动/结束 | 子任务监控 |
Notification |
Claude 发送通知时 | 桌面通知 |
FileChanged |
监视的文件变化时 | 热重载、自动构建 |
SessionEnd |
会话终止时 | 清理资源 |
这些事件按照频率分为三档:
- 每会话一次:
SessionStart、SessionEnd - 每轮对话一次:
UserPromptSubmit、Stop、StopFailure - 每次工具调用:
PreToolUse、PostToolUse、PostToolUseFailure
配置 Hooks:三层嵌套结构
Hooks 的配置采用三层嵌套结构:事件 → 匹配器 → 处理器。
1 | { |
第一层:事件(如 PostToolUse)——决定什么时候触发。
第二层:匹配器(matcher)——进一步过滤。匹配器的规则很灵活:
"*"或省略:匹配所有"Bash":精确匹配工具名"Edit|Write":匹配多个工具名(用|分隔)"mcp__memory__.*":正则表达式匹配 MCP 工具
第三层:处理器(hooks 数组)——定义具体执行什么。处理器有五种类型:
| 类型 | 说明 | 适用场景 |
|---|---|---|
command |
运行 Shell 命令 | 脚本、lint、格式化 |
http |
发送 HTTP POST 请求 | 远程验证服务 |
mcp_tool |
调用已连接的 MCP 工具 | 安全扫描、数据库检查 |
prompt |
发送给 Claude 模型单轮评估 | 智能判断 |
agent |
启动子 Agent 进行多步验证 | 复杂条件检查 |
配置文件的存放位置
Hooks 可以定义在多个位置,作用域不同:
| 位置 | 作用域 | 是否可共享 |
|---|---|---|
~/.claude/settings.json |
你所有项目 | 否,本地 |
.claude/settings.json |
当前项目 | 是,可提交到 Git |
.claude/settings.local.json |
当前项目 | 否,被 gitignore |
插件的 hooks.json |
插件启用时 | 是,随插件分发 |
| Skill/Agent 的 frontmatter | 组件活跃期间 | 是 |
项目级的 .claude/settings.json 是团队协作的首选——你可以把 Hooks 配置提交到仓库,让整个团队共享同一套自动化规则。
实战:阻止危险命令
最经典的 Hook 用例是安全守门。假设你想禁止 Claude 执行 rm -rf:
1 | { |
对应的脚本 .claude/hooks/block-rm.sh:
1 |
|
这里的 if 字段是一个权限规则语法,Bash(rm *) 表示只在 Bash 工具的命令匹配 rm * 时才运行脚本。这比无条件运行脚本更高效——如果 Claude 执行的是 npm test,脚本根本不会启动。
实战:文件修改后自动格式化
另一个高频场景:Claude 修改了 Java 文件后,自动运行 Spotless 格式化:
1 | { |
注意这里用的是 PostToolUse(工具调用之后),而不是 PreToolUse。PostToolUse 不能阻止操作(工具已经执行了),但它可以运行后续处理,并通过 additionalContext 字段把格式化结果告知 Claude。
Hook 的输入输出:JSON 的双向通信
Hook 通过 JSON 进行双向通信。输入端,Claude Code 在 stdin 中发送事件上下文:
1 | { |
输出端,Hook 通过退出码和 stdout 返回决策:
- 退出码 0:成功,继续正常流程(可以附加 JSON 输出做精细控制)
- 退出码 2:阻塞错误——对于
PreToolUse会阻止工具调用,对于UserPromptSubmit会拒绝 prompt - 其他退出码:非阻塞错误,记录日志但继续执行
JSON 输出中最强大的字段是 additionalContext,它可以向 Claude 注入上下文信息:
1 | { |
这段文字会作为系统提醒注入 Claude 的上下文,Claude 可以据此调整后续行为。这比你每次手动告诉它”注意这是 staging 环境”要可靠得多。
Hook 的作用域模型
理解 Hook 的作用域对于团队协作至关重要。优先级从高到低:
1 | 托管策略设置(管理员级别) |
管理员可以通过 allowManagedHooksOnly 策略禁止用户和项目级 Hooks,只允许企业级配置。这在大型团队中很有用——安全团队可以强制执行”所有 Bash 命令必须经过安全检查”的策略,开发者无法绕过。
第二部分:MCP——给 Claude Code 接上”外部世界”
什么是 MCP?
MCP(Model Context Protocol)是 Anthropic 推出的开放标准,用于 AI 模型与外部工具、数据源之间的集成。如果说 Hooks 是”在 Claude Code 内部自动化”,那 MCP 就是”让 Claude Code 连接外部世界”。
没有 MCP 之前,Claude Code 只能操作本地文件系统和终端。有了 MCP,它可以:
- 读取 JIRA issue 描述并据此实现功能
- 查询 PostgreSQL 数据库验证数据变更
- 检查 Sentry 错误日志定位线上问题
- 操作 GitHub 创建 PR、查看 CI 状态
MCP 的架构模型是 Client-Server:Claude Code 作为 MCP Client,连接到各种 MCP Server。每个 Server 暴露一组 Tools(工具),Claude 可以像调用内置工具一样调用它们。
安装 MCP Server:四种方式
Claude Code 支持四种 MCP 传输协议:
1. HTTP(推荐):连接远程 MCP 服务,支持 OAuth 认证。
1 | # 连接 Notion |
2. SSE:旧版远程协议,已被 HTTP 取代,但部分服务仍然使用。
1 | claude mcp add --transport sse asana https://mcp.asana.com/sse |
3. Stdio:本地进程,适合需要直接系统访问的工具。
1 | # 添加 Airtable MCP Server |
注意 --(双横线)的作用——它分隔了 Claude 自身的选项和服务器的命令参数。没有它,Claude 会尝试把服务器的 --port 等参数解析为自己的选项。
4. WebSocket:持久双向连接,适合需要推送事件的远程服务。
1 | claude mcp add-json events-server \ |
安装范围:local、project、user
MCP Server 的配置可以存储在三个级别:
| 范围 | 存储位置 | 共享给团队 | 适用场景 |
|---|---|---|---|
local(默认) |
~/.claude.json |
否 | 个人开发服务器 |
project |
.mcp.json(项目根目录) |
是(通过 Git) | 团队共享的工具 |
user |
~/.claude.json |
否 | 跨项目的个人工具 |
Project 范围是团队协作的关键。在项目根目录创建 .mcp.json 文件并提交到 Git:
1 | { |
环境变量支持 ${VAR} 和 ${VAR:-default} 语法,这样每个开发者可以用自己的数据库连接字符串,无需修改 .mcp.json。
管理 MCP Server
1 | # 列出所有已配置的服务器 |
在 Claude Code 会话内,使用 /mcp 命令查看所有已连接的服务器状态,包括每个服务器暴露的工具数量。
MCP 工具的命名规则
MCP 工具在 Claude Code 中以特定格式命名:mcp__<server>__<tool>。例如:
mcp__memory__create_entities:Memory 服务器的创建实体工具mcp__filesystem__read_file:文件系统服务器的读文件工具mcp__github__search_repositories:GitHub 服务器的搜索工具
在 Hooks 中匹配 MCP 工具时,可以用正则表达式:mcp__memory__.* 匹配 Memory 服务器的所有工具,mcp__.*__write.* 匹配所有服务器中名字以 write 开头的工具。
实战:让 Claude 直接操作 GitHub
以 GitHub MCP Server 为例,安装后 Claude 可以:
1 | # 安装 GitHub MCP Server |
之后你可以直接对 Claude 说:
“查看 issue #42 的描述,按要求实现功能,然后创建一个 PR。”
Claude 会调用 mcp__github__get_issue 读取 issue,用内置工具编写代码,最后调用 mcp__github__create_pull_request 提交 PR。整个过程在一个会话中完成,无需你手动复制粘贴 issue 描述。
实战:数据库查询验证
安装 PostgreSQL MCP Server 后,Claude 可以直接查询数据库:
1 | claude mcp add --env DATABASE_URL=postgresql://localhost:5432/mydb \ |
然后:
“我刚改了 user 表的索引,帮我看下新索引对查询计划的影响。”
Claude 会调用 mcp__postgres__query 执行 EXPLAIN ANALYZE,分析结果并给出优化建议。这种”写完代码立刻验证”的工作流,比你自己复制 SQL 到终端再回来粘贴结果要高效得多。
MCP 安全考量
MCP 服务器可以访问外部系统,安全是绕不开的话题。Claude Code 内置了多层防护:
- Project 范围需要审批:首次使用
.mcp.json中的服务器时,Claude Code 会提示你确认 - 工具搜索(Tool Search):默认启用,Claude 不会一次性加载所有 MCP 工具,而是按需搜索
- OAuth 认证:远程 HTTP 服务器支持标准 OAuth 2.0 流程
- 输出限制:MCP 工具输出超过 10,000 tokens 时会显示警告
关键原则:在连接任何 MCP 服务器之前,确认你信任该服务器。获取外部内容的服务器可能暴露注入攻击风险。
第三部分:Skills——把团队知识变成可调用的指令
从 CLAUDE.md 到 Skills
在第 4 篇文章中,我们深入讨论了 CLAUDE.md——它存储的是”事实”:项目规范、代码风格、架构决策。但有些东西不是事实,而是流程:”如何部署到 staging”、”如何创建新的微服务”、”如何运行完整的集成测试”。
当 CLAUDE.md 中的某个章节变成了一个流程描述,那就是它应该被提取为 Skill 的信号。
Skills 和 CLAUDE.md 的核心区别:
- CLAUDE.md:始终在上下文中,适合不变的事实和规范
- Skills:按需加载,适合可复用的流程和指令
创建你的第一个 Skill
Skill 的结构很简单——一个目录,一个 SKILL.md 文件:
1 | .claude/skills/deploy-staging/ |
SKILL.md 的内容包含两部分:YAML frontmatter 和 Markdown 指令。
1 | --- |
Skill 的存放位置
| 位置 | 路径 | 适用范围 |
|---|---|---|
| 个人 | ~/.claude/skills/<name>/SKILL.md |
你所有项目 |
| 项目 | .claude/skills/<name>/SKILL.md |
当前项目 |
| 插件 | <plugin>/skills/<name>/SKILL.md |
插件启用时 |
项目级 Skills 是团队协作的利器——你可以把”如何部署”、”如何运行测试”、”如何创建新模块”等流程标准化,提交到 Git,让整个团队共享。
自定义命令 vs Skills
Claude Code 的自定义命令(.claude/commands/)已经合并到 Skills 中。一个文件放在 .claude/commands/deploy.md 和 .claude/skills/deploy/SKILL.md 效果相同,都会创建 /deploy 命令。但 Skills 额外支持:
- 目录结构(可包含模板、脚本、示例等支撑文件)
- Frontmatter 配置(控制是否允许模型自动触发、工具权限等)
- 动态上下文注入(运行命令并将输出内联到指令中)
动态上下文注入:让 Skill 感知实时状态
Skills 最强大的特性之一是动态上下文注入。在 SKILL.md 中使用 !`command` 语法,Claude Code 会在加载 Skill 时运行该命令,并将输出替换到指令中:
1 | --- |
当 Claude 加载这个 Skill 时,git diff HEAD --stat 的实际输出会被注入到指令中。这意味着 Claude 看到的不是你写 Skill 时的代码状态,而是当前的实时状态。
Skill 的触发方式
Skill 有两种触发方式:
- 手动调用:输入
/skill-name直接触发 - 自动触发:Claude 根据 Skill 的
description判断是否与当前任务相关
如果你想让某个 Skill 只能手动调用(避免 Claude 误触发),在 frontmatter 中设置:
1 | disable-model-invocation: true |
Skill 的生命周期成本
Skill 加载后,其内容会在后续每一轮对话中持续占用上下文窗口。因此,保持 Skill 内容精简很重要。写”做什么”而不是”为什么做”,避免冗长的背景说明。
第四部分:三者协作——构建完整的开发平台
Hooks、MCP、Skills 不是孤立的特性,它们可以组合使用,构建出强大的自动化工作流。
组合场景 1:安全的代码审查流
1 | 用户: "帮我重构 UserService 的认证逻辑" |
组合场景 2:全链路数据库变更
1 | 用户: "给 orders 表添加 status 索引" |
组合场景 3:自定义命令 + MCP 的”一键”工作流
创建一个 Skill,封装复杂的多步骤操作:
1 | --- |
为什么这样设计?背后的架构哲学
Hooks 的设计:事件驱动 + 组合模式
Claude Code 的 Hooks 采用了经典的事件驱动架构。每个生命周期事件就像一个”发布者”,Hook 处理器是”订阅者”。这种设计的好处是:
- 解耦:Hook 逻辑独立于 Claude Code 核心,可以独立开发、测试、部署
- 可组合:同一个事件可以有多个 Hook,按匹配器过滤后并行执行
- 渐进增强:你可以从一个简单的 PostToolUse Hook 开始,逐步添加更多自动化
MCP 的设计:协议标准化
MCP 选择成为开放标准而不是私有 API,这是一个战略级的决策。对 Java 开发者来说,这类似于 JDBC 的价值——你不需要为每个数据库写不同的连接代码,MCP Server 的作者也不需要为每个 AI 工具适配。一次实现,到处可用。
MCP 的四种传输协议也体现了务实的设计:
- HTTP:通用性最强,支持 OAuth,推荐默认使用
- Stdio:性能最好,适合本地工具,无需网络
- SSE:旧版兼容,逐步迁移到 HTTP
- WebSocket:需要推送能力时的特殊选择
Skills 的设计:关注点分离
Skills 的设计哲学是”按需加载“。CLAUDE.md 始终在上下文中,每一轮对话都要为其付出 token 成本。但你可能有 20 个流程文档,每个对话只需要其中 1-2 个。Skills 让你把不常用的内容从常驻上下文中移出,在需要时才加载。
生产实践:需要注意的坑
坑 1:Hook 超时导致阻塞
Hook 默认超时 600 秒。如果你的格式化脚本因为网络问题卡住了,Claude Code 会等 10 分钟才超时。建议对可能卡住的 Hook 设置合理的超时:
1 | { |
坑 2:退出码语义不同
Unix 约定退出码 1 表示失败,但 Claude Code 的 Hook 系统中,只有退出码 2 才是阻塞错误。退出码 1 只是非阻塞错误,Claude 会继续执行。如果你的 Hook 旨在阻止某个操作,必须用退出码 2。
坑 3:MCP Server 连接顺序
SessionStart 和 Setup 事件通常在 MCP Server 完成连接之前触发。如果你的 Hook 在这些事件中调用 MCP 工具,会收到”未连接”错误。对于需要 MCP 的 Hook,应该使用 PostToolUse 或 Stop 等后期事件。
坑 4:环境变量在 Shell Form vs Exec Form 中的差异
Hook 的 command 字段支持两种执行模式:
- Shell Form(无
args):通过sh -c执行,支持管道、重定向,但需要转义特殊字符 - Exec Form(有
args):直接 spawn 进程,不需要转义,路径中带空格也没问题
推荐使用 Exec Form + ${CLAUDE_PROJECT_DIR} 占位符,避免路径中特殊字符的问题。
坑 5:MCP 工具输出过大
MCP 工具输出超过 10,000 tokens 时会显示警告。如果你的数据库查询返回了大量结果,可能会撑爆上下文。通过 MAX_MCP_OUTPUT_TOKENS 环境变量调整限制,或者在 MCP Server 端实现分页。
与 Java 生态的集成建议
作为 Java 开发者,以下是一些实用的集成思路:
1. Gradle/Maven Hooks
1 | { |
2. 本地 SonarQube MCP Server
如果有内部 SonarQube 实例,可以构建 MCP Server 让 Claude 在修改代码后自动检查代码质量。
3. Spring Boot Actuator MCP
将 Spring Boot 的 Actuator 端点封装为 MCP Server,Claude 就可以直接查看应用的健康状态、指标、日志。
总结
Hooks、MCP、Skills 是 Claude Code 扩展能力的三根支柱:
- Hooks 解决”自动化”——在 Agent 生命周期的每个关键时刻自动执行你定义的逻辑
- MCP 解决”连接”——让 Agent 能访问和操作外部系统
- Skills 解决”标准化”——将团队的工作流程封装为可复用、可共享的指令
这三者组合使用,Claude Code 就不再是一个孤立的 AI 工具,而是一个可以深度集成到你的开发流程中的平台。
在下一篇中,我们将进入 Headless 模式——当 Claude Code 不需要你坐在终端前时,如何在 CI/CD 管道中让它自动执行任务。
本文基于 Claude Code 2026 年最新文档编写。Hooks 和 MCP 的具体 API 可能随版本更新,请以官方文档为准。



