人工智能工具 | MCP、Skills 与 Plugin 三者的层次与边界
使用人工智能工具一段时间后,MCP(Model Context Protocol)、Skills(Agent Skills)与 Plugin 这三个概念几乎不可避免地会同时出现在同一个仓库、同一份配置之中。也正因如此,它们常被误认为是三种并列的扩展手段,以至于选型时被当成一道三选一的题。
这一理解的偏差在于:三者并非同一层面的事物。MCP 是一套连接标准,Skills 是一种能力封装方式,Plugin 则是打包与分发的格式。它们是自下而上叠加的三个层次,而非彼此竞争的三个选项。
本文一起聊聊如何厘清三者的边界,以及在不同场景下应当如何取舍。
三者的层次定位
为便于把握整体关系,先给出一个简化的对照:
| MCP | 让模型触及外部的工具与数据 | 连接层 | AI 领域的 USB-C |
| Skills | 教模型某套流程,用时由其自行调出 | 能力层 | 按需查阅的操作手册 |
| Plugin | 将上述能力打包为可一键安装之物 | 分发层 | 应用商店中的安装包 |
可以用一句话概括三者关系:Plugin 是容器,其中可以装入 Skills、MCP 配置乃至命令;Skills 是供模型阅读的操作手册;MCP 则是将模型连接至外部世界的通道。三者各司其职,无法相互替代。
理清这一层次之后,再回看那些配置便不易混淆。以下逐层展开,并着重说明各自容易出错之处。
MCP:连接外部世界的通道
MCP 全称 Model Context Protocol,是 Anthropic 于 2024 年 11 月开源的一套协议,用以标准化「应用如何向大模型提供外部上下文与工具」这一问题。官方将其类比为 AI 领域的 USB-C,这一比喻相当贴切:在此之前,模型每接入一个数据源、对接一个内部系统,都需单独编写私有的适配代码;而统一接口出现之后,接入便从「重复造轮子」转变为「即插即用」。
其架构为 host / client / server 三段式,底层基于 JSON-RPC。开发者实际使用的 AI 应用(如 Claude Code)即 host,它在内部为每个 server 维持一条连接;server 则是对外暴露能力的进程,既可以自行编写,也可以采用社区的开源实现。
server 主要对外暴露三类原语:tools(模型可调用的动作,如查询数据库、发起请求、读取文件,使用最为频繁)、resources(可供读取的上下文数据)与 prompts(预置的提示模板)。多数场景下开发者主要与 tools 交互,另外两类相对少用。
传输方式上有一处需要注意。当前协议标准仅保留两种:本地子进程使用 stdio,远程 server 使用 Streamable HTTP。早期独立的 SSE 传输已被废弃,其能力并入了 Streamable HTTP 的流式通道。Claude Code 出于兼容性仍接受 sse,但新接入不宜再选用,以免徒增后续迁移成本。
在 Claude Code 中配置有两种途径:执行 claude mcp add,或直接编写 .mcp.json。其作用域分为三档——仅在本机当前项目生效的 local、随仓库提交并可供团队共享的 project,以及对当前用户所有项目均生效的 user。一份最简的远程配置如下:
{
"mcpServers": {
"my-api": { "type": "streamable-http", "url": "https://example.com/mcp" }
}
}
判断是否需要 MCP,关键在于是否要让模型触及其自身无法直接访问的资源——内部 API、数据库、私有文件服务等——并希望这一接入是标准化、可被其他 host 复用的。需要强调的是,MCP 只负责「建立连接」,并不负责「模型如何用好这条连接」,后者属于 Skills 的范畴。
Skills:模型按需调用的操作手册
一个 Skill 在结构上即一个文件夹,其中包含一个 SKILL.md,以及可选的脚本、模板与参考文档。SKILL.md 开头的 YAML 中,description 是最为关键的字段——它在很大程度上决定了该 Skill 的命运,因为模型正是依据这句描述来判断当前是否应当调用它。
—
name: pdf-form-filler
description: 需要填写、合并或拆分 PDF 表单时使用,处理 AcroForm 字段映射与批量填充。
—
# 步骤
1. 先用 scripts/inspect.py 读出字段……
Skills 与「命令」最本质的区别,在于由谁决定使用。slash command 需由开发者手动键入 /名 触发;而 Skill 默认由模型在阅读 description 后自行判断是否加载。换言之,开发者只需将任务描述清楚,模型便会在恰当时机主动调用相应手册。这既是 Skill 区别于传统命令之处,也是其价值所在。
不过有一处细节常被误读:在 Claude Code 中,Skill 并非「只能由模型自动调用、不可手动触发」。开发者同样可以通过 /skill-name 手动调用;反之,若希望某个 Skill 仅供手动调用、不被模型自行触发,只需在 frontmatter 中加入 disable-model-invocation: true。
Skill 之所以能容纳大量手册而不致撑爆上下文,依赖的是渐进式披露这一惰性加载机制:name 与 description 构成的元数据始终驻留在上下文中,成本极低,使模型知晓其存在;完整正文需待模型判定相关后才载入;附带的脚本与文档,则要到实际用到那一步才会打开。这是其设计中颇为巧妙的一处——相当于为模型配备了一座图书馆,书脊始终可见,但只有取出的那一本才占用空间。
此外有一项值得了解的演变:自定义命令已被并入 Skills 体系。如今 .claude/commands/deploy.md 与 .claude/skills/deploy/SKILL.md 都会注册出一个 /deploy。因此更准确的表述是,slash command 现已成为 Skill 的一种轻量写法,而非另一套独立机制。相较于纯命令,Skill 额外具备携带附件、被模型自动唤起,以及在子代理中执行等能力。
既提及子代理,不妨一并厘清这对易混淆的概念。子代理(subagent)是另行启动的一个 agent,拥有独立的上下文窗口、独立的工具集与系统提示,置于 agents/ 之下;而 Skill 是注入给当前 agent 的指令与知识,并不另起炉灶。前者相当于「另请一人协助」,后者则是「向当前这人递交一份说明书」。二者可以协同(Skill 可在 fork 出的子代理中执行),但不应混为一谈。
在可移植性方面,Skills 遵循一套开放标准(agentskills.io),同一份 SKILL.md 理论上可在 claude.ai、Claude Code 与 Agent SDK 之间通用。但有一前提需要说明:Claude Code 为 Skill 增加了若干平台专属扩展——手动调用控制、子代理执行、以 ! 动态注入命令输出等——一旦使用了这些扩展,该 Skill 便不再是可跨平台运行的纯标准实现。其存放位置有三处:个人级的 ~/.claude/skills/、项目级的 .claude/skills/,以及随插件分发的 skills/。
Plugin:能力的打包与分发格式
如果说 MCP 与 Skills 各自承载一类能力,那么 Plugin 所承载的并非「能力」本身,而是「如何将一组能力打包、发布并供他人一键安装」。它本质上是一个容器。
一个 Claude Code 插件可以同时纳入命令、技能、子代理、MCP server 配置与 hooks,范围更广时甚至可包含 LSP server、后台监控、bin/ 脚本与 settings.json。因此需要把握一点:插件本身不提供任何新的能力,它仅仅是上述各部件的打包与分发格式。
其目录结构大致如下:
my-plugin/
├── .claude-plugin/
│ └── plugin.json # 清单文件,仅此文件位于该目录内
├── commands/ # 其余部件均位于插件根目录
├── skills/
├── agents/
├── hooks/
└── .mcp.json
此处有一个几乎人人都会遇到的陷阱:清单文件位于 .claude-plugin/plugin.json(注意其中的连字符),而 commands/、skills/、agents/、.mcp.json 等部件目录位于插件根目录,并不在 .claude-plugin/ 之内。位置放错会导致插件无法被识别,且报错信息往往难以直接指向这一根因,是较为隐蔽的常见失败原因。
发布通过 marketplace 进行——即由一份 marketplace.json 描述的插件市场,用户借助 /plugin 命令完成浏览、安装与启停。本仓库中的 .agents/plugins/marketplace.json 与 plugins/ 目录,正是这一机制的本地实例。
至于何时需要 Plugin:当开发者已积累一组技能、命令与 MCP 配置,并希望将其整体交付给团队或社区、免去对方手动拼装配置之时。若仅是单个 Skill 或一条 MCP 配置,则无需为其额外套上插件外壳。
三层协同的实例
仅作概念阐述略显抽象,以下以一个同时用到三层的实例说明——为团队交付一套「查询内部监控并自动生成周报」的能力,其搭建自底向上如下。
最底层是 MCP。编写一个 server,对外暴露 query_metrics 与 list_dashboards 两个 tool,使模型得以读取内部监控数据。这一层只解决「能否触及」的问题。
中间层是 Skill。编写一个 weekly-report,在 SKILL.md 中规定流程:先调用 query_metrics 拉取本周指标,依模板与上周对比,再生成结构化周报;同时通过 frontmatter 中的 allowed-tools 将其可调用的工具限定在上述两者,以防越权调用。这一层解决「是否用得好」的问题。
最外层是 Plugin。将上述 .mcp.json 与 skills/weekly-report/ 一并打包为一个插件,发布至团队市场。同事通过 /plugin 一键安装,连接与能力即同时就位,无需各自手动配置。
由此可见三者的咬合关系:插件之中可同时打包 MCP 与技能,技能又反过来调用 MCP 暴露的 tool,并借助 allowed-tools 收束权限。三层各司其职,缺少任何一层,这件事都无法完整成立。
选型判断
当三者被各自归回所属层次后,选型其实并不需要纠结,因为它们解决的本就不是同一个问题。
需要让模型触及某个外部系统,应当选择 MCP,并无其他替代;需要教会模型一套流程并令其在恰当时机自行调用,则编写 Skill;若仅需一个手动触发的快捷命令,同样使用 Skill,采用其命令式的轻量写法即可;若要将一组能力打包并交付他人一键安装,方才轮到 Plugin。而当所需的是一个拥有独立上下文、独立工具、可单独运行的执行单元时,应使用子代理,而非以 Skill 勉强替代。
几类较为常见的误解亦一并列出:将 Skills 与 MCP 视为二选一,实则一者管「是否用得好」、一者管「能否触及」,常需并用;认为 Skill 只能由模型自动调用,而在 Claude Code 中其亦可手动触发,禁用自动调用需显式声明;将 slash command 与 Skill 视为两套机制,而二者实已合并;以为 MCP 仍在使用 SSE 传输,而该传输已废弃,新接入应走 Streamable HTTP;以及误将插件的部件目录置于 .claude-plugin/ 之内,而其中仅应存放 plugin.json。
结语
归结而言:MCP 是连接外部世界的通道,Skills 是模型按需调用的操作手册,Plugin 是将二者打包以便分发的容器。三者并非互斥的选项,而是自下而上叠加的三个层次。
当再次面对一段不明所属的配置时,只需辨明它所解决的究竟是「能否触及」「是否用得好」,还是「如何分发」,其归属自然清晰。


