上周有个做后端的哥们儿在群里问,他想让手里的 agent 能查公司内部接口文档,顺带按团队规范生成代码。有人让他写 MCP,有人说写个 Skill 就够了,还有人直接甩了篇 Plugin 开发教程过来。三份文档他都看了,结果比看之前更懵——因为这三样东西压根不在同一个层面上打架。硬要比个高低,相当于问"螺丝刀、说明书和机器人手臂哪个更好用",答案是看你要拧螺丝、要教人干活,还是要造一条产线。
这篇就把 MCP、Skill、Plugin 这三样东西按层拆开讲清楚:它们各自解决什么问题、由谁来维护、什么时候会失效、以及在一个真实项目里怎么叠着用。刚接触 agent 开发不久的人可以拿它当选型清单,已经踩过坑的人可以对照着检查自己的架构是不是把三层混成了一层。
1. 别急着选型,先看清这三种扩展分别长在哪一层
很多人一上来就问"MCP 和 Skill 哪个强",这个问题本身问偏了。MCP 处理的是进程之间怎么对话,Skill 处理的是这件事该怎么做,Plugin 处理的是宿主程序怎么被改造。三者的作用位置完全不同,一个是通信协议,一个是自然语言资产,一个是跑在宿主里的代码。
我见过最典型的翻车,是有人把一套"我们公司的代码评审规范"硬塞进 MCP server 里,让 server 每次返回一大段规范文本。能跑,但非常别扭:规范会变,改一次就要发一次版本、重启一次服务,而且模型拿到这段文本的时机也不对——它不是工具,它是一份知识。
1.1 一句话判断法:谁在跑代码,谁在写文字,谁必须待在宿主里
判断该用哪个,我自己习惯走这三步:
- 有没有一段必须由真实程序执行的逻辑,比如查数据库、调内部 HTTP 接口、读本地文件、算一个复杂指标。有,那核心就落在 MCP 或者 Plugin 上。
- 有没有一套"应该怎么做"的判断标准,比如什么情况该拆表、命名要遵循什么前缀、遇到冲突先改哪边。有,那这部分就该写成 Skill。
- 这件事是不是必须改动我正在用的那个软件本身,比如加一个右键菜单、拦住保存动作、在侧边栏挂一个面板。是,那只有 Plugin 能做到。
三步走完,你大概率会发现答案不是"选一个",而是"分三段"。
1.2 用"给 agent 装能力"倒推一遍
举个具体点的例子。你想让 agent 能读公司内网的接口文档站,然后按规范生成调用代码。
- 文档站在内网、需要鉴权、内容是分页的——这是数据获取问题,交给 MCP server 最合适,因为鉴权逻辑、分页逻辑都是代码,写完就能复用。
- 拿到文档之后,怎么判断哪些字段必填、生成代码时用哪个 HTTP 客户端、异常怎么包——这是规范判断问题,交给 Skill,写成一份 Markdown 文档,改起来不用发版。
- 你还想让 agent 在你按下快捷键时自动读取当前光标所在的接口名——这是宿主行为问题,必须写 Plugin,因为 MCP server 根本感知不到你的光标在哪。
你看,一个需求自然裂成了三块。这也是为什么我常说,讨论"MCP 和 Skill 的区别"时,最好先讨论"我的需求里有几块"。
1.3 三种扩展的维度对照
| 维度 | MCP | Skill | Plugin |
|---|---|---|---|
| 本质 | 通信协议 | 写给模型看的文档资产 | 宿主程序的扩展代码 |
| 跑的进程 | 独立进程,通过 stdio 或 HTTP 通信 | 不跑代码,内容被加载进上下文 | 跑在宿主进程内 |
| 谁维护 | 后端或平台工程师 | 业务专家、技术负责人 | 宿主生态的插件开发者 |
| 改动成本 | 中,需要发版和重启 | 极低,改 Markdown 即可 | 高,依赖宿主 API 和版本 |
| 跨模型通用性 | 高,协议层通用 | 高,纯文本 | 低,绑定宿主 |
| 最容易出问题的点 | 工具描述质量、上下文占用 | 触发时机、内容过长 | 版本漂移、宿主 API 变更 |
注意:这张表不是用来比高低的,是用来判断"我这块需求到底落在哪一格"。落在同一格里的东西才值得比较,跨格比较没有意义。
2. MCP:把外部世界翻译成模型能看懂的接口
MCP 全称 Model Context Protocol,直译过来就是"模型上下文协议"。名字里最关键的词是"协议"两个字。它不是插件系统,不是工具库,也不是某个厂商的私有格式,而是一份约定:一个外部程序用什么样的格式声明自己能干什么、用什么样的格式接收调用、用什么样的格式把结果还回去。
这一点想通了,很多困惑会自动消失。比如"为什么我换了一个 agent 应用,同一个 MCP server 还能用"——因为它遵守的是同一份约定,就像换了个浏览器还能打开同一个网站。
2.1 Host、Client、Server 三个角色别搞混
刚接触时最容易把这三个词弄反。按我的理解方式:
- Host(宿主):你实际在用的那个 agent 应用本身,它负责跟模型对话、管理会话、决定要不要调用工具。
- Client(客户端):Host 内部的一个连接器组件,一个 Client 负责连一个 Server。你在配置里加一条 MCP 配置,Host 就起一个 Client 去连它。
- Server(服务端):你自己写的那个进程,里面注册了一堆工具、资源或者提示模板,等着被调用。
经常有人问"我该在哪里写鉴权",答案是:在 Server 里。Host 和 Client 是别人的代码,你改不了,也不该改。你要做的就是把 Server 写好,让它在收到调用时自己去处理 token、cookie、签名这些事。
2.2 一次工具调用从提问到返回,中间走了哪些路
这条链路值得完整走一遍,因为绝大多数"agent 不调用我的工具"的问题,都能在这条链路上找到位置。
- Host 启动时拉起 Client,Client 通过 stdio 或 HTTP 连上 Server。
- 双方握手,做能力协商,Server 把自己支持的原语报上去。
- Server 返回工具清单,包括每个工具的名字、描述、参数结构。
- 这些工具清单被拼进模型的上下文,变成模型能"看见"的一批可选动作。
- 用户提问,模型判断是否需要调用工具,需要的话输出一个结构化调用请求。
- Host 把这个请求交给对应的 Client,Client 转发给 Server。
- Server 真正执行逻辑,把结果按协议格式返回。
- 结果回填进上下文,模型基于结果继续生成回答。
第 4 步和第 5 步之间,是最容易出问题的地方。很多人以为"我把工具注册进去了,模型就该会调",实际上模型只能看到你写的名字和描述。描述写得含糊,模型就选不准,甚至干脆不选。
2.3 MCP 提供的三类原语,用途差别很大
协议里主要暴露三类东西,各自适合不同的场景:
- Tools(工具):会产生副作用或者需要实时计算的动作,比如写文件、发请求、跑查询。模型主动调用。
- Resources(资源):只读的数据内容,比如一份文档、一条配置、一段日志。更偏向被动加载。
- Prompts(提示模板):预置好的提示词模板,通常用于把某个固定流程一键触发。
实际项目里,Tools 用得最多,Resources 经常被忽略但其实很有用——把一份经常要参考的规范文档挂成 Resource,比每次让模型去读文件要省事得多。
2.4 "能连上"和"用得好"之间隔着一段距离
我自己总结,MCP server 能不能被用好,八成取决于三件事:
第一是工具粒度。一个工具干一件事,名字要能自解释。我见过一个 server 只暴露了一个叫query的工具,参数是一个自由文本字符串,模型每次都要猜该往里写什么。后来拆成list_tables、describe_table、run_select三个,调用成功率立刻上去了。
第二是返回体大小。有的接口一返回就是几千行 JSON,塞进上下文之后,模型既读不完也读不准。正确做法是在 Server 里就做截断、做摘要、做分页,只把必要字段吐出去。
第三是错误信息的可读性。抛一个500 Internal Error回给模型,模型完全不知道下一步该干嘛;返回字段 user_id 缺失,请先调用 list_users 获取这种描述,模型就能自己纠偏。
3. Skill:把"怎么做"写成文档,让 agent 自己去读
如果 MCP 是把外部能力接进来,那 Skill 就是把内部经验沉淀下来。它本质上是一份写给模型看的说明书,通常是一个 Markdown 文件,加上若干附属资源和可选的辅助脚本。模型在需要的时候把它读进上下文,然后照着做。
这件事听起来很朴素,但威力不小。过去这些"怎么做"的经验大多藏在老员工脑子里,或者散落在各种 wiki 里,模型是看不到的。Skill 相当于把隐性经验显性化,而且用一种模型最容易理解的格式——自然语言加结构化步骤。
3.1 Skill 里到底装了什么
一个写得好的 Skill,内容大致分四类:
- 适用场景说明:什么情况下该用这个 Skill,什么情况下不该用。这一段直接决定模型会不会误触发。
- 执行步骤:分步骤的操作流程,每一步说清楚输入是什么、输出是什么、遇到分支怎么走。
- 判断标准:那些"没有标准答案但有经验倾向"的决策点,比如遇到循环依赖时优先拆哪一层。
- 参考材料:模板文件、字段清单、历史案例,放在附属目录里,需要时再加载。
关键的一点是渐进式加载。Skill 主文件应该尽量短,只写主干流程和"需要的时候去看哪个附属文件"。把几万字的规范全塞进主文件,模型每次都要读完,上下文成本高得离谱,效果反而更差。
3.2 Skill 和 Agent 的区别,别混着用
热词里经常出现"skill 和 agent 的区别",这个问题值得单独说清楚。我的理解是:
Agent 是一个执行主体。它有自己的循环——观察、思考、调用工具、看结果、再思考,直到任务完成。它有目标、有状态、有工具集。
Skill 是一个被调用的知识包。它没有循环,没有状态,不会自己去做事。它只是"当 agent 决定做某件事时,翻开的那本手册"。
打个比方:agent 是员工,Skill 是岗位操作手册,MCP 是员工手上的工具箱,Plugin 是办公桌本身。员工可以翻手册、可以拿工具、可以改桌子,但手册本身不会自己干活。
所以那种"我写个 Skill 让它自己定时跑任务"的想法是行不通的。Skill 不会自己醒过来,必须有 agent 主动去读它。要走定时任务,得靠宿主或者外部调度去触发 agent。
3.3 什么情况下写 Skill 比写 MCP 划算
判断标准很简单:这块内容会不会频繁变,变了之后要不要发版。
会频繁变、而且变了不该发版的,写成 Skill。比如:
- 代码风格和命名规范,季度评审一次改一次。
- 各类文档的写作模板,业务侧随时会提调整。
- 某类问题的排查思路,随着经验积累不断补充。
- 领域内的判断规则,比如建模时该选哪类模型、参数怎么估。
这些都是文字,改一行 Markdown 就生效,不用发版、不用重启、不用重新部署。相比之下,如果把这些塞进 MCP server 的返回值里,每次调整都得走一遍完整的发布流程,运维成本白白翻倍。
反过来说,如果这块内容包含必须真实执行的计算或者访问,那就别硬写成 Skill。我见过有人试图用 Skill 描述一个复杂的 SQL 查询逻辑,让模型"照着写",结果每次都写得略有不同,稳定性极差。这种就该封装成 MCP 工具,让模型只管调用,不管实现。
4. Plugin:宿主程序自己的扩展口
Plugin 这个词比 agent 早出现至少二十年。浏览器有插件,编辑器有插件,各类桌面软件都有插件机制。它的核心特征是:插件跑在宿主程序内部,能直接访问宿主的界面、菜单、快捷键、事件和生命周期。
这个"跑在内部"决定了插件的能力边界和 MCP 完全不同。MCP server 是个独立进程,它永远只能被动接收调用;插件是宿主的一部分,它可以主动监听、主动弹窗、主动改界面。
4.1 IDE 插件和 agent 插件经常是两回事
这是很多人绕不明白的地方。假设你用一个带 agent 的编辑器,装了某个语言的语法插件,又配了一个查文档的 MCP server。这时候会出现三种扩展并存:
- 语法插件:宿主生态的 Plugin,负责高亮、补全、错误提示。
- 文档 server:你配的 MCP,负责把文档内容提供给 agent。
- 团队规范:一份 Skill,负责告诉 agent 写完代码之后该怎么自检。
agent 能"看到"的只有后两者。语法插件做了什么,agent 通常感知不到,除非宿主主动把插件的某些信息暴露给模型。所以别指望"我装了一个强大的插件,agent 就自动会用它",这是两套体系。
4.2 什么时候非 Plugin 不可
以下几种需求,MCP 和 Skill 都做不到,只能上 Plugin:
- 改界面:要在侧边栏加一个面板、在编辑器里加装饰、在状态栏显示提示。
- 接管宿主行为:拦截保存事件、覆盖快捷键、在打开文件时自动执行某段逻辑。
- 常驻监听:持续监听文件变化、监听网络请求、监听剪贴板。
- 深度集成宿主数据:拿到当前打开的文件路径、当前选中的文本、当前光标位置。
这些都是宿主内部的上下文,独立进程拿不到。所以像"在设计稿工具里读取当前选中图层的标注"这类需求,就得看宿主开放了什么能力——有的宿主直接提供了 MCP server(比如设计稿工具自己出的 MCP),那就用 MCP;如果它只提供了插件 API,那就只能写 Plugin,然后由插件把数据转发出来。
4.3 Plugin 的代价:版本绑死和维护成本
Plugin 最容易让人头痛的一点,是它跟宿主版本强绑定。宿主升级,插件接口变了,你昨天还能用的功能今天就报错。这类报错通常长这样:加载失败、找不到入口、版本不匹配。排查过程往往很折磨,因为报错信息本身没什么信息量。
我的经验是:能用 MCP 解决的问题,就不要写 Plugin。MCP 的协议边界清晰,升级影响面小;Plugin 拿到的能力更多,但要承担宿主的升级风险。只有当需求真的必须触达宿主内部时,才去写 Plugin。
5. 选型表和三个真实场景的拆解
前面把三层讲清楚了,这一节把决策路径压缩成可以直接照着走的流程。
5.1 一张表把决策路径框住
| 你的需求长这样 | 首选方案 | 理由 |
|---|---|---|
| 访问外部数据源、内部接口、数据库 | MCP | 有真实代码逻辑,需要鉴权和连接管理 |
| 沉淀判断标准、流程、模板、规范 | Skill | 纯文本资产,改起来不用发版 |
| 加界面、改快捷键、拦截宿主事件 | Plugin | 必须触达宿主内部上下文 |
| 需要读写文件、跑命令 | MCP 或宿主自带工具 | 取决于宿主是否已经内置 |
| 需要"先查数据再按规范处理" | MCP + Skill | 数据获取和判断逻辑分层 |
| 需要"根据当前光标位置生成代码" | Plugin + Skill | 宿主上下文由插件提供,生成规范由 Skill 提供 |
5.2 场景一:让 agent 查内部业务数据
需求是让 agent 能查内网的一套业务数据,然后回答用户的问题。
做法:写一个 MCP server,暴露三个工具——列可用数据集、描述数据集字段、按条件查询。查询工具的参数必须是结构化的,比如dataset、filters、limit,不要让模型自由拼 SQL,那是给自己挖坑。
然后是 Skill:写一份很短的文档,说明"当用户问业务数据相关问题时,先用列数据集工具确认有哪些数据可用,再描述字段,最后查询;单次查询行数不要超过 200,超过就分页"。这份 Skill 解决的是调用顺序和约束,MCP 解决的是怎么真的查到数据。
提示:查询类工具的
limit参数一定要设默认值并在描述里写明上限。我吃过这个亏,模型有一次让我拉了全表,上下文直接被撑爆。
5.3 场景二:让 agent 按团队规范写文档
需求是让 agent 生成接口文档、周报、技术方案时,都符合团队格式。
这种需求几乎百分之百应该写成 Skill。把模板、章节顺序、必填字段、语气要求、常见错误清单全写进去,主文件控制在几百字以内,把详细的模板放在附属文件里按需加载。
为什么不写 MCP?因为这里没有任何需要执行的逻辑。你写一个 MCP server 专门返回一段模板文本,等于为了发一条消息去建一个邮局,纯属多此一举,而且改模板还要发版。
5.4 场景三:让 agent 读设计稿里的标注
需求是让 agent 能拿到设计稿的图层信息、色值、间距,然后生成对应的样式代码。
这个场景的关键是看宿主提供了什么。不少设计工具已经出了自己的 MCP server,能直接暴露图层数据,那你只需要配一下就能用,顺带写个 Skill 说明"颜色值优先用变量、间距取 4 的倍数、字号走 tokens"。如果工具只开放了插件 API,那就要写 Plugin 把选中图层的数据导出来,再由插件把数据交给 agent。
这里有个很实际的经验:先花半小时去翻宿主的官方文档,确认它有没有现成的 MCP。很多时候答案是有的,只是没被写进你看到的教程里。自己写一遍插件再发现官方早就提供了,那种感觉相当难受。
6. 我在这三种扩展上翻过的车
前面讲的都是原理和方式,这一节说点苦的。下面这些坑我自己逐个踩过,写出来是为了让你少走一遍。
6.1 工具描述写成产品说明书,模型反而不调
第一次写 MCP server 的时候,我给每个工具写了一段很正式的功能描述,什么"本工具用于实现 XXX 功能,支持多种参数组合"。结果模型基本不调,宁可自己瞎猜。
后来我把描述改成口语化的短句,直接说清楚什么时候用它、返回什么、不要用它做什么,调用率立刻正常了。比如把"本工具用于查询用户信息"改成"根据用户 ID 查单个用户的姓名和邮箱;如果只有名字没有 ID,先用 search_users"。
注意:工具描述是写给模型看的,不是写给同事看的。判断标准是"模型读完能不能判断出该不该调",而不是"人读完觉得专不专业"。
6.2 一口气挂了三十个工具,上下文直接爆
有一阵我图省事,把一个 server 的所有工具全挂上了,二十多个。结果发现模型变笨了:简单问题也开始乱调工具,回答还经常跑偏。
原因很直白——工具清单是常驻上下文的,挂得越多,模型每次要扫的候选就越多,选择难度上升,而且留给正文推理的空间被挤压。后来的做法是按场景拆 server,需要哪组开哪组,常驻工具控制在十个以内。
6.3 权限没做隔离,让 agent 摸到了不该摸的地方
这个是事后冷汗最多的一个。早期我给查询工具的账号权限给大了,本意是"方便调试",结果有一次 agent 在多轮对话里自己拼出了一个超出预期的查询。虽然没造成后果,但从那之后我立了条规矩:MCP server 的凭证必须是只读的、最小权限的、最好带白名单的。
Skill 里也要写清楚"禁止"的部分。只用正面描述告诉模型"该做什么",模型在边缘情况下容易自由发挥;把明确的禁止项写出来,约束力会强很多。
6.4 版本漂移,昨天还好好的今天就报错
Plugin 类扩展最容易碰到这个。宿主一升级,插件要么加载失败,要么行为变了。我现在的习惯是:
- 给 Plugin 的依赖版本做锁定,能锁就锁。
- 在配置里记录当前验证过的宿主版本,升级前先在一个独立环境里跑一遍。
- 把这套扩展的备用方案写进文档,出问题的时候能快速降级。
MCP 和 Skill 也有漂移问题,但轻得多。Skill 是纯文本,风险主要在内容过时;MCP 的风险主要在协议版本和参数结构变化,通常改几个字段就能修好,不用重写。
7. 把三者叠起来用:一个我自己在用的分层思路
走到这里,选型其实已经不难了。我更想分享的是怎么把它们叠起来用,因为真实项目里几乎不会只用一层。
我的分层习惯是这样的:
最底层是宿主 Plugin,只做一件不得不做的事——把宿主独有的上下文(当前文件、选中内容、光标位置)暴露出来。这一层我尽量写得薄,代码量越少,升级时越不容易坏。
中间层是 MCP,负责所有需要真实执行的动作:查数据、调接口、读写文件、算指标。每个 server 只服务一个明确的场景域,工具数量克制,返回体做截断,错误信息写清楚。
最上层是 Skill,负责把"怎么做"写明白:什么时候用哪个工具、工具返回之后怎么判断、输出格式是什么、哪些是禁止的。这一层改得最频繁,但改起来最安全,因为它就是几个 Markdown 文件。
搭好之后,日常迭代基本都发生在上层。业务规范变了,改 Skill;数据源加了字段,改 MCP;需要新的宿主交互,才动 Plugin。这种分层最大的好处是变更的影响面可控——你不会因为改了一句写作规范,就要重新部署一遍服务。
最后说一句我自己最真实的体会:刚开始接触这三样东西时,我总想找到一个"最正确的那个",结果越找越乱。后来才明白,它们的关系不是替代,而是分工。真正要问的问题从来不是"该用哪个",而是"我这个需求拆开之后,哪一块该落在哪一层"。把这个问对了,剩下的都是执行细节。