扩展点:MCP、Skills、插件与子 Agent
外部能力如何挂进 Harness,以及每种扩展点的边界与代价。
一句话理解:扩展点决定新能力从哪个口子进入 Agent 循环:MCP 把外部系统变成工具,Skills 把方法按需装进上下文,子 Agent 把一段工作隔离出去、只交回结论,Hooks 在事件上运行确定性代码,插件把这些打包分发。选对口子,能力才加得进来,代价也才可控。
一个 Coding Agent 团队用了两个月,需求清单越来越长:要能读工单系统里的 Bug 描述;提 PR 时按团队模板写说明;动手改代码前先在全仓库查一遍影响范围;每次编辑后自动跑格式化,而且绝不能碰 .env;最后,这套配置要在十几个仓库里复用。
最省事的做法是全部写进系统提示或项目说明文件。结果每一轮请求都背着几千 Token 的“说明书”,模型反而更容易忘掉关键规则。另一个极端是什么都做成 MCP Server,连一份 PR 模板都要起一个服务。两种做法的共同问题是:没有分清每种需求该从哪个扩展点接入。
这一课站在 Harness 的角度,看 MCP、Skills、插件、子 Agent 和 Hooks 各挂在循环的哪个环节、各自的边界与代价,以及怎么选。每种扩展的协议和写法在各自模块里有专门的课,这里只讲接入与取舍。
扩展点挂在循环的哪里
回忆 Harness 的核心循环:装配上下文 → 调用模型 → 调度工具 → 执行并回填结果。Claude Code 的官方文档把各种扩展描述为“插进 Agent 循环的不同部位”。按挂载位置,可以分成三类:
- 进入上下文的:Skills,以及上一课的 项目说明文件。它们改变模型“知道什么”。
- 注册为工具的:MCP Server 提供的工具,以及子 Agent(在 Claude Code 里通过一个专门的 Agent 工具来派发)。它们改变模型“能做什么”,由模型决定何时调用。
- 不经过模型的:Hooks。Harness 在生命周期事件上直接执行它们。
插件不属于任何一个环节,它是 分发单位:把以上几种打成一个可安装的包。
这张图里有一个容易忽略的事实:MCP 和子 Agent 在模型眼里都只是工具。模型看到的是工具名和描述,并不知道背后是一个远程服务还是另一个 Agent 循环。所以它们也继承了工具的全部问题:描述写不好就会调错,结果太大就会撑满上下文,权限太宽就有风险(见 工具运行时)。
扩展点对比表
| 扩展点 | 解决什么 | 加载时机 | 上下文代价 | 适用场景 |
|---|---|---|---|---|
| MCP | 连接外部系统:查询、写入、操作 | 会话开始时连接;Claude Code 默认先只给工具名,完整参数定义用到时再加载 | 平时较低;工具结果可能很大 | 工单系统、数据库、浏览器、企业 IM |
| Skills | 可复用的方法、资料与流程 | 描述在会话开始时装入,正文在被调用时装入 | 描述每轮都在;正文装入后一直留到上下文压缩 | 代码审查清单、发布流程、API 风格指南 |
| 子 Agent | 把一段工作隔离到独立上下文 | 被派发时启动全新的上下文 | 不占主上下文,只回传最终结论;但它自己的 Token 照样计费 | 大范围搜索、并行调研、只读审查 |
| Hooks | 在事件上执行确定性代码 | 事件触发时运行 | 为零,除非 Hook 返回补充信息 | 编辑后格式化、拦截危险命令、审计日志 |
| 插件 | 把以上几种打包、版本化、分发 | 启用后每个会话都加载 | 包内每个可被模型调用的 Skill、子 Agent 的描述每轮都在 | 多仓库共用一套配置、团队内分发 |
表格依据 Claude Code 官方的扩展功能总览整理。其他产品叫法不同,但分层相似:OpenAI Codex 的定制层同样包括 AGENTS.md、Skills、MCP 和子 Agent,并用插件打包 Skills 与 MCP Server。
“上下文代价”这一列值得单独画出来。同样是“加一个扩展”,有的每一轮都要付费,有的用到才付,有的根本不进主上下文:
五个扩展点逐个看
MCP:给循环接上外部系统
从 Harness 的角度,MCP Server 是一个“工具提供方”:连接与认证由 Server 处理,Harness 负责发现它的工具、注册进调度器、执行调用并回填结果。协议本身见 MCP 架构。
在 Claude Code 里接入一个远程 Server 只需一条命令,例如 claude mcp add --transport http <名字> <地址>;加上 --scope project 会写进仓库根目录的 .mcp.json,与团队共享。接入后工具名形如 mcp__<server>__<工具>,权限规则和 Hooks 都按这个名字匹配。
- 边界:MCP 只提供“能做什么”,不提供“怎么做才对”。工单系统接进来了,模型仍然不知道团队的分诊规则。
- 代价:一是工具定义。Claude Code 默认开启工具搜索,闲置工具只占很少上下文;关掉它或回退到预先加载时,每个 Server 的全部工具定义都会进入每一轮请求。二是工具结果:Claude Code 对单次 MCP 输出设有 Token 上限,超出时把结果存成文件、只把路径交给模型。三是安全:会抓取外部内容的 Server 会带来 Prompt 注入 风险,官方文档要求接入前确认信任该 Server。
Skills:按需装入的方法
Skill 是一个带 name 和 description 的 SKILL.md 文件,可以附带脚本和参考资料。Harness 在会话开始时只把描述放进上下文;模型判断任务相关、或者用户用 /名字 显式调用时,才装入正文,这正是 渐进式披露。发现与加载的细节见 Skill 如何被发现与加载。
- 边界:Skill 是给模型读的指令,不是强制。“发布前必须跑完测试”写在 Skill 里仍然可能被跳过,必须保证的事交给 Hook。
- 代价:描述每轮都在。描述写得含糊或彼此重叠,模型会装错或漏装。正文一旦装入,会一直留到上下文压缩。有副作用的流程(例如发布)可以设置
disable-model-invocation: true,只允许人手动触发,它的描述也不再占用上下文。 - 通用性:Claude Code 的 Skills 遵循 Agent Skills 开放标准;Codex 的 Skill 结构相同(
SKILL.md加可选的脚本、参考资料目录),放在.agents/skills下。Skill 与工具、子 Agent 的区别见 Skill、Tool、Workflow 与 Subagent。
子 Agent:把一段工作隔离出去
子 Agent 是一个有自己系统提示、工具集和模型设置的独立循环。在 Claude Code 里,它是 .claude/agents/ 下的一个 Markdown 文件,frontmatter 写 name、description,可选 tools、model 等;主 Agent 通过 Agent 工具把任务派给它。它从全新的上下文启动,看不到主对话的历史,只有最后一条消息回到主 Agent。协作模式见 Subagent 与上下文隔离。
- 边界:隔离是双向的。子 Agent 看不到主对话里的约定,派发时写进任务描述的信息就是它知道的全部;主 Agent 也只看到摘要,摘要里漏掉的证据就丢了。
- 代价:不占主上下文,但总 Token 往往更多,因为每个子 Agent 都要重新读文件、重新建立背景。在 Claude Agent SDK 中,子 Agent 的花费计入同一个预算上限。多一层委派,也就多一层延迟和一个可能出错的环节。
- Harness 设计:给子 Agent 收窄工具(只读审查员只给
Read、Grep、Glob),并用SubagentStart/SubagentStop这类 Hook 追踪它们。
Hooks:不经过模型的扩展
上一课 Hooks 与生命周期 已经详细讲过。放在扩展点里看,它的独特之处在于:这是唯一不需要模型“想起来”就会发生的扩展。Claude Code 的 Hook 除了执行脚本,还可以发 HTTP 请求、调用 MCP 工具,或者交给一段提示、一个子 Agent 去做判断。
- 边界:Hook 只在事件发生时运行,不能替模型做多步推理;复杂的业务逻辑应该做成独立服务。
- 代价:不进上下文,但同步 Hook 会拖慢每一次匹配到的工具调用;来自不同来源的 Hooks 会全部叠加生效。
插件:打包与分发
插件本身不增加新能力,它解决的是“同一套配置怎么在很多地方用”。一个 Claude Code 插件就是一个目录:.claude-plugin/plugin.json 声明名字与版本,skills/、agents/、hooks/、.mcp.json 分别放各类组件。插件里的 Skill 带命名空间,例如 /my-plugin:review,所以多个插件可以共存。插件通常从 marketplace(一个列出插件及其来源的目录)安装,并按用户、项目或本地三种范围启用。
- 边界:插件没有运行时角色,装进来的每个组件仍按各自的规则工作。
- 代价:官方文档特别提醒,启用的插件是每个会话的一部分,而不只在用到时:包里每个可被模型调用的 Skill、子 Agent 的名字和描述每轮都在上下文里;它的 MCP Server 随会话运行,Hooks 在事件上触发;它执行的一切都以你的身份运行。安装第三方插件前,要像审查代码依赖一样审查它。
怎么选:按顺序问五个问题
面对一个新需求,可以按下面的顺序问。它不是唯一答案(一个 Skill 也可以带脚本去调外部接口),但能挡住最常见的错配:
回到开场的团队,最后的装配是这样的:
| 需求 | 扩展点 | 理由 |
|---|---|---|
| 读取工单系统里的 Bug 描述 | MCP | 外部系统,需要认证和结构化查询 |
| 按团队模板写 PR 说明 | Skill | 一份方法,只在提 PR 时用到 |
| 动手前查全仓库的影响范围 | 子 Agent(只读工具) | 会读几十个文件,主 Agent 只需要结论 |
每次编辑后格式化、禁止改 .env |
Hook | 必须每次执行,不需要判断 |
| 构建与测试命令 | 项目说明文件 | 每一轮都要知道,而且很短 |
| 十几个仓库共用 | 插件(按项目范围启用) | 统一版本,一处更新 |
注意 Skill 和 MCP 经常成对出现:MCP 提供连接,Skill 告诉模型怎么用好这个连接,例如工单字段的含义和分诊规则。这是官方文档推荐的组合方式之一。
常见误区
- “能力不够就加一个 MCP Server。” 很多“能力不足”其实是“方法不足”。模型已经能读写文件、跑命令,缺的是团队的流程与标准,这应该写成 Skill;只有需要连接新系统时才需要 MCP。
- “写进 Skill 就等于立了规矩。” Skill 和项目说明文件一样是请求,不是保证。必须每次成立的规则,放进 Hook 或 权限规则。
- “子 Agent 能省钱。” 它省的是主上下文,不是总成本。任务本身很小,或者需要频繁共享背景时,派子 Agent 反而更贵、更慢。
- “插件装上不用就没影响。” 启用即常驻:描述占上下文,Server 占进程,Hook 照常触发。不用的插件应该禁用。
设计要点
- 为每个扩展写下三件事:挂在循环的哪个环节、每轮常驻多少上下文、失败时会发生什么。
- 必须保证的规则走 Hook 或权限;需要判断的方法走 Skill;需要新连接才走 MCP。
- 定期盘点上下文里的常驻部分:Skill 描述、MCP 工具名、插件描述,删掉长期不用的。
- 子 Agent 的任务描述要自包含,工具收到最小,并要求它返回结构化的结论和证据位置。
- 第三方 MCP Server 和插件按依赖包的标准审查:来源、权限、会不会抓取外部内容。
- 对同名覆盖心里有数:Claude Code 里 Skill、子 Agent、MCP Server 同名时按优先级只有一个生效,而 Hooks 会全部叠加。
练习
选一个场景,「每日 SEO 巡检 Agent」或「客服工单批处理 Agent」,列出至少 6 条能力需求,用 40 分钟完成:
- 按本课的五个问题,为每条需求选一个扩展点,并写一句理由。
- 估算每轮常驻的部分:有几个 Skill 描述、几个 MCP 工具名、多长的项目说明。
- 找出一条“写在 Skill 里、但其实必须保证”的规则,把它改写成 Hook:写出事件、匹配条件和拒绝原因。
延伸阅读
- Extend Claude Code:Claude Code 各扩展功能的定位、对比表与上下文代价。
- Plugins overview:插件的目录结构、marketplace、安装范围,以及启用插件对每个会话的影响。
- Connect Claude Code to tools via MCP:接入命令、作用范围、工具搜索与输出上限。
- Extend Claude with skills:
SKILL.md结构、调用控制与加载方式。 - Create custom subagents:子 Agent 的定义文件、启动时加载的内容与结果回传。
- Codex:Customization:Codex 的 AGENTS.md、Skills、MCP 与子 Agent 分层。
下一步
扩展点越多,可能出错的地方也越多:MCP Server 超时、子 Agent 半路失败、Hook 拒绝后模型反复重试。下一课「错误恢复与重试」讲 Harness 如何接住这些失败。