技能、插件和 MCP——Claude Code 如何变得无限强大
前面几篇拆了启动链路、工具系统、上下文管理。但如果你只看这些,会觉得 Claude Code 是一个封闭的系统——功能就这么多,用完就没了。

实际上不是。Claude Code 有三套独立的扩展机制,让它的能力边界可以无限延伸。
今天拆这套扩展体系。
三套机制,三个层次
先看全景:
|
|
|
|
|---|---|---|
| 技能系统(Skills) |
|
|
| 插件系统(Plugins) |
|
|
| MCP 协议 |
|
|
三者层层递进:技能是最轻量的扩展,插件是中等粒度的功能包,MCP 是最底层的协议级接入。
技能系统:用 Markdown 写”操作手册”
技能系统的设计非常克制。一个技能就是一个目录,里面一个 SKILL.md 文件:
.claude/skills/my-skill/└── SKILL.md
SKILL.md 里用 frontmatter 定义元数据,用 Markdown 写具体内容:
---name: my-skilldescription: 做某件事的专业指南---当用户需要做 X 的时候,按以下步骤操作:1. 先做 A2. 再做 B3. 最后做 C
就这么简单。没有代码,没有配置文件,就是一个 Markdown 文件。
技能的加载机制也反映了这种克制:
async function loadSkillsFromSkillsDir(basePath, source) { const entries = await fs.readdir(basePath) return Promise.all( entries.map(async (entry) => { const skillDirPath = join(basePath, entry.name) const skillFilePath = join(skillDirPath, 'SKILL.md') const content = await fs.readFile(skillFilePath, { encoding: 'utf-8' }) const { frontmatter, content: markdownContent } = parseFrontmatter(content) return createSkillCommand({ ...parseSkillFrontmatterFields(frontmatter, markdownContent, entry.name), skillName: entry.name, markdownContent, source, baseDir: skillDirPath, loadedFrom: 'skills', }) }), )}
扫描目录、读 Markdown、解析 frontmatter、创建技能对象。整个技能系统本质上就是一个 Markdown 文件管理器。
技能可以来自多个位置:
-
• 项目级: .claude/skills/ -
• 用户级: ~/.claude/skills/ -
• 内置:代码里打包的 bundled/目录 -
• 插件:随插件自动安装 -
• MCP:从外部 MCP 服务器获取
内置技能里有几个值得注意的:
export function initBundledSkills() { registerUpdateConfigSkill() // 配置管理 registerKeybindingsSkill() // 快捷键 registerVerifySkill() // 代码验证 registerDebugSkill() // 调试 registerSimplifySkill() // 代码简化 registerLoopSkill() // 循环任务 if (feature('BUILDING_CLAUDE_APPS')) { registerClaudeApiSkill() // Claude API 开发 }}
registerLoopSkill 就是你在 Claude Code 里用 /loop 命令时触发的东西——定时循环执行某个任务。registerSimplifySkill 是代码审查和简化。
技能还有一个条件触发机制:
// 条件技能:根据文件路径自动激活const paths = splitPathInFrontmatter(frontmatter.paths)activateConditionalSkillsForPaths(filePaths, cwd)
在 frontmatter 里声明 paths 字段,当 AI 操作匹配路径的文件时,技能会自动激活。不用手动调用,AI 自己知道什么时候该用。
这个设计让我想到一个理念:最好的扩展是用户感知不到的扩展。 技能不是让用户去”使用”的,而是让 AI 自动”遵循”的。
插件系统:带依赖管理的功能包
插件比技能复杂得多。一个插件可以包含多个技能、多个钩子、多个 MCP 服务器配置。
export interface BuiltinPluginDefinition { name: string description: string version: string defaultEnabled?: boolean isAvailable?: () => boolean skills?: BundledSkillDefinition[] hooks?: HooksSettings mcpServers?: MCP[]}
注意 isAvailable 字段——插件可以声明自己的运行条件。比如某个插件只在 macOS 上可用,或者只在某个 Feature Flag 开启时才激活。
插件加载有一套完整的生命周期:
export async function loadPlugins(): Promise<LoadedPlugin[]> { // 1. 从 marketplace 加载 const marketplacePlugins = await loadMarketplacePlugins() // 2. 从 --plugin-dir 加载 const sessionPlugins = await loadSessionPlugins() // 3. 构建依赖图 const pluginGraph = buildPluginDependencyGraph([ ...marketplacePlugins, ...sessionPlugins, ]) // 4. 拓扑排序 const sortedPlugins = topologicalSort(pluginGraph) // 5. 加载所有组件 return await loadAllPluginComponents(sortedPlugins)}
插件之间有依赖关系,需要拓扑排序确定加载顺序。这不是简单的”按字母排序”,而是真正的图算法——插件 A 依赖插件 B,那 B 必须先加载。
还有一个热重载机制:
export function startPluginHotReloader() { const watcher = chokidar.watch(pluginPaths, { ignored: /(^|[\/\\])\../, persistent: true }) watcher.on('change', async (filePath) => { clearPluginCaches() const updatedPlugins = await reloadPluginsForPath(filePath) notifyPluginsUpdated(updatedPlugins) })}
用 chokidar 监听文件变化,插件文件一改就自动重新加载。开发插件的时候不用重启 Claude Code,改完文件直接生效。
这个体验很重要。 做过插件开发的人都知道,每次改代码都要重启宿主应用有多烦。Claude Code 把这个痛点解决了。
MCP:让外部世界接入 AI
MCP(Model Context Protocol)是整个扩展体系里最底层、最强大的机制。
简单说,MCP 是一个标准协议,让 AI 工具能调用外部服务器提供的工具和资源。任何语言、任何平台都可以实现 MCP 服务器,只要遵循协议,Claude Code 就能调用它。
export class McpClient { private transport: Transport private client: Client private tools: Tool[] = [] async initialize(serverConfig) { // 1. 创建传输层(stdio、HTTP等) this.transport = await createTransport(serverConfig) // 2. 初始化 MCP 客户端 this.client = new Client({ name: 'claude-code', version: '1.0.0' }) this.client.connect(this.transport) // 3. 发现可用工具 this.tools = await this.client.listTools() // 4. 发现可用资源 this.resources = await this.client.listResources() }}
MCP 客户端做的事很清晰:连接服务器 → 发现工具和资源 → 调用工具。
关键的桥接在 MCPTool.ts 里。外部 MCP 服务器提供的工具会被自动注册到 Claude Code 的工具池里:
// 在 tools.ts 的工具组装过程中export function assembleToolPool(permissionContext, mcpTools) { const builtInTools = getTools(permissionContext) const allowedMcpTools = filterToolsByDenyRules(mcpTools, permissionContext) return uniqBy( [...builtInTools].sort(byName).concat(allowedMcpTools.sort(byName)), 'name', )}
内置工具和 MCP 工具合并,按名称去重,内置优先。对外部工具来说,它和内置工具在 AI 眼里没有区别。 AI 不需要知道一个工具是内置的还是 MCP 提供的,调用方式完全一样。
这意味着什么?意味着你可以用任何语言写一个 MCP 服务器,提供任意工具,Claude Code 就能直接使用。数据库查询、API 调用、数据分析、图像处理——只要你有 MCP 服务器,Claude Code 就有这个能力。
MCP 让 Claude Code 的能力边界从”Anthropic 提供了什么”变成”社区提供了什么”。
MCP 还支持会话过期检测和自动重连:
export function isMcpSessionExpiredError(error: Error): boolean { if (error.message.includes('Session not found')) return true return false}
外部服务器可能随时断开连接,Claude Code 会自动检测并尝试恢复。这种容错设计在生产环境中很必要——你不能指望外部服务永远稳定。
钩子系统:悄无声息的拦截器
除了上面三套机制,还有一个容易被忽略的系统——钩子(Hooks)。
钩子可以在特定事件发生时自动执行命令:
type HookEvent = | 'PermissionRequest' // 权限请求时 | 'PreToolUse' // 工具使用前 | 'PostToolUse' // 工具使用后 | 'PostToolUseFailure' // 工具使用失败后 | 'Stop' // 会话结束时 | 'Notification' // 通知时 | 'SessionStart' // 会话开始时
钩子可以阻止操作继续执行。比如 PreToolUse 钩子检查到某个危险操作,可以直接返回 deny,工具就不会被调用。
钩子可以来自多个地方:用户配置、项目 CLAUDE.md、插件。执行时按优先级排序,任一钩子返回 deny 就立即终止。
这套系统让用户可以在不修改任何代码的情况下,定制 Claude Code 的行为。比如”每次修改文件后自动跑测试”、”每次会话结束时自动提交 git”——都是通过钩子实现的。
三个系统如何协作
这三套机制不是孤立的,而是形成了一条链路:
用户写了一个 SKILL.md(技能) → 技能里引用了一个 MCP 工具 → MCP 工具由一个插件提供 → 插件通过钩子自动配置了环境
举个例子:你安装了一个数据库插件。插件提供了:
-
• 技能:告诉 AI 如何安全地执行 SQL 查询 -
• MCP 服务器:提供数据库连接和查询工具 -
• 钩子:在每次查询前检查 SQL 是否包含危险操作
三个系统各司其职,组合在一起就是一个完整的解决方案。
彩蛋:Buddy 宠物系统
buddy/ 目录里藏着一个彩蛋——电子宠物陪伴系统。
function rollRarity(rng): Rarity { const total = Object.values(RARITY_WEIGHTS).reduce((a, b) => a + b, 0) let roll = rng() * total for (const rarity of RARITIES) { roll -= RARITY_WEIGHTS[rarity] if (roll < 0) return rarity } return 'common'}
每个用户根据 userId 确定性地生成一个宠物——有稀有度、有属性值、有峰值和谷值。而且是确定性的:同一个用户每次生成的宠物都一样。
用确定性随机,意味着宠物不会每次打开都变。这不像其他应用里随机开箱的玩法,更像是”你的专属伙伴”。
在一个51万行代码的严肃工程项目里,有人花时间做了这个。我觉得挺好的。工程师文化不只是代码质量,还有在严肃中保留一点乐趣的能力。
对开发者的真正启发
看完整个扩展体系,三个启发:
第一,扩展能力应该分层设计。 不是所有扩展都需要同等重量级的机制。一个简单的操作指南用 Markdown 就够了(技能),一个完整的功能包才需要插件,一个外部系统集成才需要 MCP。按需选择扩展粒度,而不是一刀切。
第二,协议比平台更重要。 Anthropic 推出 MCP 协议,本质上是在做”AI 工具界的 USB 接口”。与其自己实现所有功能,不如定义好标准,让社区来填充生态。这个思路和 Google 推出 Android、Apple 推出 App Store 是一样的——平台的终局不是自己做什么,而是让别人能在你上面做什么。
第三,AI 时代的软件架构正在变化。 传统的软件扩展靠 API 和插件。AI 工具的扩展靠协议(MCP)、提示词(技能)和钩子(行为控制)。三种机制对应三种不同的扩展维度——能力扩展、知识扩展、行为扩展。这个框架未来很可能会成为 AI 应用的标准架构模式。
最后一篇,我会做整个系列的总结——读完这些代码,对程序员 AI 转型的真实启发。
上一篇:在你开口之前,AI已经知道了很多——Claude Code上下文管理拆解
下一篇:读完51万行代码后,我找到了程序员 AI 转型的三个关键信号
我是贾昆,14年全栈程序员,正在 AI 转型路上。如果你也在纠结往哪个方向走,欢迎看看这篇:一个14年程序员的清醒与行动
夜雨聆风