关键词:Skills / Plugins / MCP / MiniAgent / 最小实现 / Agent 平台化 / Claude Code
Agent 一旦要长大,就必须插件化:Skills、MCP 和最小实现
如果一个 Agent 的所有能力都写死在主程序里,它很快就会撞墙。
原因很简单:
- 新功能只能改主仓库;
- 新工作流只能改主提示;
- 外部系统接入只能继续硬编码;
- 能力越来越多,主循环越来越重。
Claude Code 在第七章和第八章做的事,就是把这条路堵死,换成另一条路线:把 Agent 做成平台,把能力做成可插拔。
一、Claude Code 的扩展层不是一层,而是三层
它把扩展拆成:
SkillsPluginsMCP
这三者经常被混用,但它们负责的事情完全不同。
| 层 | 本质 | 解决的问题 |
|---|---|---|
| Skills | 提示词级能力单元 | 把常用动作固化成可复用操作手册 |
| Plugins | 有生命周期的功能包 | 把 Skills、Hooks、MCP 组合成一个可管理单元 |
| MCP | 外部工具协议 | 把主程序之外的能力标准化接进来 |
这个分层非常有价值,因为它让系统不需要只有一种扩展方式。
二、Skill 的本质不是命令,而是“给模型看的工作手册”
一个 Skill 文件本质上就是 Markdown + frontmatter:
---
description: 提交当前改动并生成规范 commit message
allowed-tools: [Bash]
when_to_use: 当用户想提交当前修改时
context: fork
model: sonnet
effort: medium
---
真正关键的字段其实不是 description,而是 when_to_use。
因为这个字段不是给人读的,而是给模型判断“什么时候该调这个 Skill”的。
也就是说,Skill 不是文档,而是操作策略。
Claude Code 还会从多个来源发现 Skill:
- 内置 Bundled Skills;
- 用户级 Skills;
- 项目级 Skills;
- 插件提供的 Skills;
- MCP 动态提供的 Skills。
这意味着 Skill 已经不是一个目录约定,而是整个系统里的能力注册机制。
三、Plugin 和 Skill 的差别,不在内容,而在生命周期
Plugin 不是“更多 Skill”,而是一个有状态的功能单元。
一个插件定义大概会包含:
name / description / versiondefaultEnabledisAvailable()skillshooksmcpServers
这说明 Plugin 关心的不只是功能,还关心:
- 默认开不开;
- 当前环境能不能用;
- 要不要带后台 MCP 服务器;
- 生命周期事件要不要挂 Hook。
所以 Plugin 和 Skill 的区别是:
- Skill 更像一张可复用卡片;
- Plugin 更像一个功能包。
四、MCP 解决的不是“远程调用”,而是“外部世界怎么标准化接进来”
Claude Code 对 MCP 的实现,是它走向平台化的关键。
MCP 定义的原语主要有三类:
ToolsResourcesPrompts
也就是说,外部系统不只可以暴露工具,还可以暴露:
- 只读资源;
- 预定义提示模板。
Claude Code 的客户端会连接外部 MCP Server,然后把远端工具重新注册回本地工具池。
它支持四种传输
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
import { WebSocketTransport } from '../../utils/mcpWebSocketTransport.js'
对应四种接入方式:
stdio:本地子进程;SSE:远程 HTTP 长连接;Streamable HTTP:新版规范;WebSocket:双向实时通信。
graph LR
A["Claude Code"] --> B["stdio 本地子进程"]
A --> C["SSE 远程服务"]
A --> D["Streamable HTTP"]
A --> E["WebSocket 服务"]
这说明 Claude Code 没把“工具”理解为进程内对象,而是理解成一种协议终点。
五、MCP 工具怎么变回 Claude Code 工具
连接成功后,Claude Code 会:
- 调
list_tools - 拿到远端工具列表
- 给每个远端工具造一个本地
MCPTool实例 - 把它们注册进当前工具池
这个本地骨架大概长这样:
export const MCPTool = buildTool({
isMcp: true,
name: 'mcp',
maxResultSizeChars: 100_000,
get inputSchema(): InputSchema {
return inputSchema()
},
async call() {
return { data: '' }
},
async checkPermissions(): Promise<PermissionResult> {
return {
behavior: 'passthrough',
message: 'MCPTool requires permission.',
}
},
})
然后在 client.ts 里覆盖真正的 name / description / call。
这是一种典型的模板化接入方式。
六、Claude Code 连 MCP 认证和循环依赖都按平台级问题处理
MCP 一旦接远程服务,认证问题就绕不过去。
Claude Code 专门实现了 OAuth 处理、401 自动刷新、认证失败缓存等逻辑。
还有一个很典型的大项目问题:循环依赖。
MCP Skills 的构建依赖 loadSkillsDir.ts,但 client.ts 又要反过来拿这些构建器。Claude Code 的解法是注册表注入:
let builders: MCPSkillBuilders | null = null
export function registerMCPSkillBuilders(b: MCPSkillBuilders): void {
builders = b
}
export function getMCPSkillBuilders(): MCPSkillBuilders {
if (!builders) {
throw new Error('MCP skill builders not registered')
}
return builders
}
这其实就是用依赖注入打断模块循环。
很工程化,也很实用。
七、为什么最后一定要回到 MiniAgent
只读源码,最容易出现一种错觉:我懂了。
Claude Code 第八章最重要的价值,是它没有停在分析,而是落回了一个最小可运行实现:MiniAgent。
最小目录结构大概是这样:
mini-agent/
src/
index.ts
types.ts
tools/
ReadFileTool.ts
WriteFileTool.ts
BashTool.ts
GrepTool.ts
ToolRegistry.ts
ContextManager.ts
AgentLoop.ts
CLI.ts
这一步非常关键,因为一旦你自己把它搭一遍,就会立刻理解 Claude Code 前面那些设计为什么不是“过度工程”。
八、MiniAgent 里最值得抄的,不是代码量,而是取舍方式
它没有试图一口气复刻 Claude Code 全部能力,而是把核心骨架缩到最小:
1. Tool 接口先收缩到核心契约
export interface Tool {
name: string;
description: string;
inputSchema: JSONSchema;
call(input: Record<string, unknown>): Promise<string>;
}
这比 Claude Code 的完整 Tool 协议轻很多,但保留了最关键的三件事:
- 工具名;
- 模型可见描述;
- 结构化输入输出。
2. 工具先挑最有代表性的四个
ReadFileToolWriteFileToolBashToolGrepTool
这四个足够覆盖:
- 文件读取;
- 文件写入;
- 命令执行;
- 代码搜索。
一个 Code Agent 的最小工作集,基本就浓缩在这四类能力里。
3. 连 MiniAgent 也必须做基础安全限制
例如 BashTool 不是裸跑命令,而是先黑名单过滤:
const DANGEROUS_PATTERNS = [
/rm\s+-rf\s+[\/~]/,
/:\s*\(\s*\)\s*\{/,
/dd\s+if=/,
/mkfs/,
]
ReadFileTool 和 GrepTool 也要控制返回大小,避免一个大文件或一大段 grep 结果直接淹没上下文。
这一步非常说明问题:
就算是最小实现,也不能跳过预算和安全边界。
因为这些不是高级特性,而是 Agent 的基本生存条件。
九、第七章和第八章合起来,本质上是在回答两个问题
问题一:系统怎么继续长
答案是 Skills、Plugins、MCP,把能力做成不同层级的可插拔单元。
问题二:开发者怎么真正学会
答案是把这些结构缩回一个能自己搭起来的最小实现。
如果没有前者,系统会越来越重;
如果没有后者,读者只会停在“看懂别人怎么做”的阶段。
最后
Claude Code 在最后两章里最值得抄的,不是某个具体实现,而是它对“成长路径”的处理:
- 小能力,用 Skill;
- 一组能力和生命周期,用 Plugin;
- 外部世界接入,用 MCP;
- 真正吸收这些设计,再自己做一个 MiniAgent。
这是一条很完整的路线:
从单体 Agent,到平台化 Agent;
从读懂系统,到重新实现系统。
一个 Code Agent 要想走得远,最后一定得走这条路。