🦞 核心保持精简;可选能力通过 Skills、Plugins 与 MCP 分层扩展。关键不是“什么都能接”,而是“把变化隔离在该隔离的地方”。
MCP 与插件生态
flowchart LR
A["MCP 与插件生态"]
A --> B["分类:OpenClaw"]
A --> C["关键词:OpenClaw"]
A --> D["关键词:MCP"]
A --> E["关键词:mcporter"]
A --> F["关键词:Plugin"]
前文讲的是安全模型,回答的是“能力为什么不能无边界地给”。本文继续往前走一步,讨论另一个同样重要的问题:当能力需要扩展时,应该把扩展放在哪里。
OpenClaw 没有把所有能力都做进核心,而是采用了几层不同的扩展机制:面向 Agent 行为与任务组织的 Skills,面向运行时能力与工具接入的 Plugins,以及面向外部工具生态互联的 MCP。这三者看起来都像“扩展”,但关注点并不相同。如果边界划错,系统很容易变成一团:能力能跑,但难维护;能接很多东西,但稳定性和可观测性迅速下降。
本文重点讲四件事:
- MCP 在 OpenClaw 中为何通过 mcporter 以桥接方式接入
- Plugin API 解决的到底是什么问题
- Memory 为什么是一个“特殊插件槽位”
- Skills、Plugins、MCP 分别该在什么场景下使用
这篇文章的核心结论可以先说在前面:
- Skills 负责“让 Agent 更会做事”
- Plugins 负责“让运行时多出可控的新能力”
- MCP 负责“把外部工具生态接进来”
- 真正重要的不是功能名词,而是变化边界、故障隔离与长期维护成本
为什么扩展层设计比“能不能接”更重要
很多系统一开始讨论扩展能力,容易停留在“支不支持某协议”“能不能接某服务”这种表面问题上。但工程里更难的并不是第一次接通,而是接通以后怎么长期演进。
扩展机制一旦进入核心,就会带来几个长期成本:
- 接口稳定性负担:核心一旦承诺某种集成方式,后续每次调整都要考虑兼容
- 故障传播风险:外围能力的不稳定,可能直接影响主链路
- 认知复杂度上升:核心承担过多职责后,用户和开发者都很难判断该在哪里扩展
- 升级耦合:一个外围生态的小变化,可能迫使核心发布新版本甚至重启服务
因此,OpenClaw 在扩展能力上采取的不是“尽可能内建”,而是更克制的做法:核心只保留必须稳定、必须通用、必须可审计的部分;把波动更大、演化更快、依赖更杂的能力尽量放到外层。
从这个角度看,MCP、Plugin、Memory 不是几个彼此独立的小功能,而是一套一致的系统设计取向。
MCP 支持:通过 mcporter 桥接,而不是直接做进核心
先看定义:OpenClaw 对 MCP 的支持不是把 MCP 直接嵌入核心运行时,而是通过 mcporter 以 bridge 的方式接入,从而把 MCP 生态与核心解耦。
先看它解决的是什么问题。
MCP 的价值在于,它提供了一种相对统一的方式,让模型或 Agent 去连接外部能力:文件系统、数据库、开发工具、内部服务、知识源,甚至其他代理层。问题在于,MCP 本身是一个外部生态,而不是 OpenClaw 核心的内部抽象。如果直接把它做成 first-class、深度嵌入核心,表面上看集成更“完整”,但代价往往也更高:
- 核心需要更早承诺 MCP 的对象模型、生命周期与错误语义
- MCP server 的多样性会把复杂性直接带进核心
- 外部 server 的升级、兼容问题、行为差异,会放大到主运行时
- 用户很难区分:某个问题是 OpenClaw 核心问题,还是某个 MCP server 的问题
mcporter 的桥接模式,本质上是在说:MCP 很重要,但它的重要性并不意味着它必须成为核心内部的一等公民。
bridge 模型的实际含义
这里的“桥接”不是一句架构口号,而是一个很具体的工程边界:
| 特性 | 说明 |
|---|---|
| 接入方式 | MCP 通过 mcporter 进入系统,而不是直接嵌入核心 |
| 生命周期解耦 | MCP server 的增删、替换、升级不必与 Gateway 生命周期绑定 |
| 核心表面控制 | 核心仍只暴露自己认可的 tool / context 运行时表面 |
| 风险隔离 | 将外部协议演化与 server 差异隔离在桥接层 |
| 演进灵活性 | mcporter 可独立演进,不必每次都推动核心架构变化 |
一个常被低估的收益是:桥接层让“接入能力”与“核心承诺”分离。
这意味着,OpenClaw 可以支持 MCP 生态,但不必把 MCP 的每一个细节都变成核心长期背书的一部分。这对一个要长期演进的运行时来说非常关键。
为什么“不重启 Gateway”不是小事
文档里常被提到的一点是:增删 MCP server 不需要重启 Gateway。表面看这只是运维便利,实际上它反映的是一种更深的架构取向。
如果一个外部能力的接入需要牵动主进程重启,意味着它和核心生命周期是强绑定的。强绑定会带来三类问题:
- 可用性问题:外围能力的调整影响主链路服务
- 试错成本问题:接一个新 server、改一个配置、做一次灰度都变得更重
- 边界感消失:大家会默认“只要能接进来,就是核心的一部分”
而桥接方式让 MCP server 更像“可管理的外围能力”,而不是“核心结构的一部分”。这不只是更方便,而是更符合系统稳定性的常识。
为何不做 first-class MCP
先看定义:不是因为 MCP 不重要,而是因为它足够重要,所以更要谨慎定义它与核心之间的边界。
VISION 中偏好 bridge 模型,背后其实有三层考虑。
1. 保持核心精简
核心最怕的不是功能少,而是承担过多变化来源。 MCP 生态天然是多实现、多 server、多行为差异的,如果直接深度内建,核心就会被迫吸收很多本不该由它承担的复杂性。
2. 降低生态变动对核心的扰动
协议、server、能力模型、认证方式、上下文结构都会变化。桥接层的价值,就是让这些变化优先在外围消化,而不是每次都传导到核心架构。
3. 允许独立演进
有些问题应该在 mcporter 里解决,而不是在 OpenClaw 核心里解决。 这点非常重要:如果某个能力缺口属于桥接层职责,就应该在桥接层修,而不是倒逼核心扩张。
因此,遇到“mcporter 不支持某功能”的情况,优先应该去 mcporter 仓库提 issue,而不是直接把问题归因到 OpenClaw 核心“没做完”。
这不是甩锅,而是对职责边界的尊重。
使用 MCP 时最容易踩的几个误区
MCP 很容易让人产生一种错觉:好像接入协议之后,外部能力就自然变得“统一且可靠”。实际并非如此。
误区一:协议统一,不等于能力语义统一
即便都叫 MCP server,不同 server 在以下方面仍可能差异很大:
- 工具命名和参数设计是否清晰
- 错误返回是否可判定、可恢复
- 权限模型是否细粒度
- 延迟、吞吐、超时策略是否适合在线调用
- 输出是否稳定、是否容易被模型正确消费
这意味着,MCP 解决的是接入层一致性,不自动解决能力层一致性。
误区二:能接就适合在线主链路
有些外部能力适合被 Agent 在线调用;有些则更适合作为后台任务、异步工作流或离线索引流水线。 如果把所有 MCP server 都当成“随时可调用工具”,很容易出现:
- 延迟过高,拖慢主响应
- 错误过多,影响整体成功率
- 返回内容过大,污染上下文
- 权限或审计边界不清晰
所以引入 MCP 之前,应该先判断:这是一个适合实时工具调用的问题,还是一个更适合异步系统集成的问题。
误区三:把 MCP 当作万能扩展接口
MCP 很适合“连接外部能力”,但它不天然适合所有扩展需求。 如果你真正想做的是:
- 修改 Agent 的任务行为
- 注入领域方法论
- 改写提示词结构
- 定义专门的工作流模板
那往往更接近 Skills,而不是 MCP。
这也是后文选型部分要反复强调的:不要因为 MCP 很通用,就把所有扩展需求都往 MCP 上压。
Plugin API:扩展运行时能力,而不是把一切都做进核心
先看定义:Plugin API 的目标不是“插件越多越好”,而是让一些确实有必要存在、但又不适合进入核心的能力,以可装载、可替换、可本地开发的方式存在。
OpenClaw 的插件通过 npm 包分发,并支持本地 extension 加载。这背后体现的是一种非常现实的工程判断:很多能力是有用的,但并不值得直接进入核心。
例如:
- 某些工具集成只对一部分用户有意义
- 某些能力依赖特定平台、存储或环境
- 某些实现还在探索期,不适合核心长期背书
- 某些功能虽然稳定,但本质上属于可替换策略,而不是统一标准
这类能力如果直接进入核心,会带来两个坏结果:
- 核心越来越重,默认分发越来越臃肿
- 用户很难判断什么是平台承诺,什么只是某个具体实现
Plugin API 的存在,就是为了把这类能力放到一个更合适的位置上。
| 机制 | 说明 |
|---|---|
| 分发方式 | 通常以 npm 包形式分发 |
| 开发方式 | 支持本地 extension 加载,便于开发与调试 |
| 设计原则 | 核心保持精简,可选能力通过插件提供 |
| 准入标准 | 真正进入核心分发或官方推荐范围的插件门槛较高 |
插件文档见:docs/tools/plugin.md。社区插件列表见:https://docs.openclaw.ai/plugins/community。
插件真正解决的,不只是“扩展功能”
很多人第一次看插件机制,会把它理解成一个单纯的分发渠道:核心没有的功能,可以靠插件补。这个理解不算错,但不够完整。
Plugin API 更重要的作用有三个:
1. 把“策略差异”从核心拿出去
有些问题并没有单一正确答案,比如:
- 记忆存储用 SQLite、Postgres 还是别的后端
- 某类工具能力是否默认启用
- 某些运行时增强应该如何实现
这类问题如果强行统一进核心,往往会让核心卷入实现偏好之争。插件化可以把这些差异外置。
2. 给实验性能力一个可控落点
真正的工程系统不能只追求纯粹,还要允许试验。但试验能力不应该直接污染核心。 插件层提供了一个比较自然的“缓冲区”:可以试,可以替换,可以淘汰。
3. 让用户按需组合能力,而不是接受一整套重默认
并不是每个部署都需要相同的能力面。有的部署看重长期记忆,有的部署看重本地工具,有的部署几乎只想保持最小运行面。 插件机制让系统更像一组可拼装能力,而不是一个越来越厚的大一统框架。
什么样的能力更适合做插件
通常来说,具备以下特征的能力,更适合插件化:
- 不是每个用户都需要
- 依赖特定运行环境或外部资源
- 存在多种合理实现
- 需要较快演进
- 失败后应尽量局部化,不应影响核心主链路
反过来说,如果某个能力:
- 是系统最基础的运行前提
- 所有用户都必须依赖
- 需要被核心严格统一定义
- 与核心安全模型、执行模型深度耦合
那它往往不适合先做插件。
这也是为什么“能做成插件”并不意味着“核心不重要”;它只是说明这个能力更适合以外层方式存在。
Memory 插件:一个“特殊槽位”,不是普通工具插件
先看定义:Memory 在 OpenClaw 中不是随便挂载的一类普通插件,而是一个特殊插件槽位;同一时间通常只激活一个具体实现。
这背后的原因很简单:记忆不是一个普通工具,而是系统级行为的一部分。
普通工具通常是“需要时调用”;而 Memory 往往会影响:
- 会话之间的信息延续方式
- 用户偏好的持久化
- 过去交互内容的摘要与回灌
- Agent 对“这个用户是谁、之前做过什么”的长期认识
这意味着 Memory 不是一个随意并列在工具列表里的能力。它更像运行时中的一项基础策略,因此需要更明确的装配位置与更清晰的唯一性约束。
| 特性 | 说明 |
|---|---|
| 槽位类型 | 特殊插件槽位,而非普通工具插件 |
| 激活方式 | 一次通常只激活一个实现 |
| 典型用途 | 长期记忆、用户偏好、会话摘要、状态延续 |
| 当前状态 | 可能存在多种实现可选 |
| 未来方向 | 倾向收敛到一个更明确、推荐的默认实现 |
为什么一次只激活一个 Memory 实现
表面上看,多个 Memory 插件同时启用似乎也不是不可以:一个管偏好,一个管摘要,一个管长期知识。 但工程上这往往会迅速变得混乱。
原因包括:
1. 写入语义容易冲突
同一条用户信息到底写入哪里? 是写一份还是写多份? 谁负责去重、合并、过期和冲突解决?
一旦多个实现都能写,系统就需要额外定义大量一致性规则。
2. 读取优先级不清晰
当模型需要回忆用户信息时,应该先查哪个存储? 如果多个来源返回互相矛盾的结果怎么办? 谁是权威来源?
3. 调试与可解释性迅速恶化
“为什么模型记住了这个?” “为什么它又忘了?” “这条记忆是从哪来的?” 如果记忆层是多实现叠加,排查会非常痛苦。
因此,把 Memory 设计成一个单槽位、可替换实现,是一种更克制但更稳的选择。它牺牲了一点表面上的“灵活”,换来了语义清晰和运维可控。
Memory 真正难的,不是存下来,而是“什么时候该记、什么时候该忘”
在很多介绍里,Memory 很容易被写成“长期记忆插件”这么一句话,听起来像是个数据库接口。但真正的难点其实不在存储层,而在记忆策略层。
长期记忆系统至少要回答以下问题:
- 什么信息值得持久化,什么只是一次性上下文
- 用户偏好和临时意图如何区分
- 过时信息何时淘汰
- 错误记忆如何纠正
- 不确定的信息是否应进入长期记忆
- 摘要写回时如何避免“摘要漂移”
这里最容易出现的失败模式包括:
1. 过度记忆
把大量一次性信息写入长期记忆,导致后续召回噪声越来越多。 模型表面上“记住了更多”,实际上是在不断污染后续上下文。
2. 错误固化
模型在一次会话中误解了用户意思,如果这条误解被写进长期记忆,错误会跨会话持续存在,而且越来越像“系统自信知道的事实”。
3. 旧信息覆盖新信息
用户偏好、项目状态、工作上下文都会变化。如果没有时间性和更新策略,记忆会逐渐失真。
4. 摘要替代原始事实
很多 Memory 实现为了节省空间,会写入摘要而非原始片段。摘要固然高效,但摘要本身是一种压缩;压缩就意味着丢信息,也意味着可能引入解释偏差。
所以讨论 Memory,不应该只问“支持哪些后端”,更应该问:
- 写入策略是什么
- 更新策略是什么
- 召回策略是什么
- 冲突怎么处理
- 用户是否能观察、修正、清除记忆
这些问题决定了 Memory 是在帮系统,还是在慢慢制造一个不稳定的信息黑箱。
Memory 更适合保存什么,不适合保存什么
从经验上看,以下内容更适合进入长期记忆:
- 相对稳定的用户偏好
- 长期反复出现的工作背景
- 明确、持续的写作或协作习惯
- 对后续任务持续有帮助的固定约束
而以下内容通常不适合直接沉淀为长期记忆:
- 一次性任务细节
- 尚未确认的推断
- 容易过时的项目状态
- 高噪声、低复用的信息碎片
从工程上看,Memory 不是“把历史都存起来”,而是“把未来还会有用的稳定信息留下来”。
配置示例
在 openclaw.json 中可指定当前使用的 Memory 插件,例如:
{
"plugins": {
"memory": "openclaw-memory-sqlite"
}
}
具体插件名与配置项以社区列表及对应插件文档为准。 更重要的是,在选定某个 Memory 插件前,应先确认它的三个问题:
- 它存什么
- 它怎么召回
- 它如何处理更新、冲突与删除
只看“能不能存”通常不够。
Skills vs Plugins vs MCP:不要按名词选,要按变化边界选
先看定义:Skills、Plugins、MCP 看起来都能“扩展能力”,但它们扩展的是系统的不同层面。真正合理的选型方式,不是看哪个更强,而是看你的需求属于哪一层变化。
先给一个简化版本:
| 类型 | 主要扩展对象 | 更适合的场景 |
|---|---|---|
| Skills | Agent 能力、任务模式、提示词组织、领域方法 | 日常任务、领域工作流、面向任务的能力增强 |
| Plugins | 运行时能力、工具注入、策略实现 | Memory、自定义工具、本地运行时扩展 |
| MCP | 外部工具与上下文生态连接 | 连接 MCP server、文件系统、数据库、外部服务 |
这个表很有用,但还不够。因为工程上最常见的问题不是“完全不知道怎么选”,而是明明三个都能做一点,于是选了最顺手但最不合适的那个。
下面分别看。
Skills:当你要扩展的是“做事方式”
如果你希望 Agent:
- 更懂某一类领域任务
- 按某种结构去思考和输出
- 具备特定方法论、流程模板、检查清单
- 在某一类任务中表现得更稳定
那么你想扩展的通常不是运行时能力,而是任务行为模式。这时更适合用 Skills。
Skills 的价值在于,它能把“怎么做这类事”沉淀成可复用单元,而不是每次都靠临时 prompt 手写。这种扩展更接近“经验封装”和“任务编排约束”。
典型例子包括:
- 代码评审技能
- PRD 拆解技能
- 技术写作技能
- 面向特定领域知识的工作流模板
- ClawHub 中面向场景分发的技能包
如果你的目标是让 Agent 在某个任务上更稳定、更像一个有方法的熟手,而不是单纯多接一个外部服务,Skills 往往是第一选择。
Plugins:当你要扩展的是“运行时能力”
如果你需要的是:
- 新的工具能力
- 某种存储或策略实现
- 某个本地扩展机制
- 某个运行时级别的增强
那么它更接近 Plugins。
Plugin 更像是给系统“安装部件”。它关注的是能力注入、装配和替换,而不是直接定义 Agent 的工作方式。
一个简单判断方法是:如果把 LLM/Agent 暂时拿掉,这个扩展是否仍然像一个独立的系统能力? 如果答案是是,那么它通常更接近插件而不是 Skill。
Memory 就是最典型的例子。它不是“会不会做任务”的问题,而是“系统怎么保留和取回信息”的问题。
MCP:当你要扩展的是“外部连接面”
如果需求是把 OpenClaw 接到已有外部生态中,尤其是通过 MCP server 获得工具和上下文,那么应优先考虑 MCP。
典型场景包括:
- 连接文件系统能力
- 暴露数据库访问能力
- 接入已有的开发工具 server
- 将某类外部上下文源通过 MCP 暴露给 Agent
但这里有一个非常关键的边界:MCP 解决的是连接问题,不自动替代系统内的产品化设计。
也就是说:
- 它能帮你把能力接进来
- 但不自动帮你定义最合理的任务体验
- 不自动帮你处理所有失败模式
- 不自动帮你决定哪些信息该入上下文、哪些调用该被限制
所以 MCP 很强,但不应被神化为“统一扩展终点”。
一个更实用的选型框架
如果只记一句话,可以记这个判断顺序:
先问“我要改变的到底是哪一层”,再决定用 Skills、Plugins 还是 MCP。
下面是一套更实用的判断方式。
| 场景 | 更推荐的选择 | 原因 |
|---|---|---|
| 想让 Agent 更会做某类任务 | Skills | 重点在行为模式与方法沉淀 |
| 想增加某种系统能力或策略实现 | Plugins | 重点在运行时装配与能力扩展 |
| 想连接外部服务或工具生态 | MCP + mcporter | 重点在外部能力接入与解耦 |
| 想做长期记忆 | Memory 插件 | 属于特殊运行时策略,不宜散落在别处 |
几个常见决策例子
例子一:我想做一个“技术文章润色能力”
更适合 Skill。 因为你要增强的是写作方法、结构化检查、输出风格与工作流,而不是新增一个底层系统接口。
例子二:我想让系统支持一种新的本地工具调用机制
更适合 Plugin。 因为这是运行时能力,不是任务模板。
例子三:我想把数据库或文件系统暴露给 Agent
更适合 MCP。 因为这是外部连接面问题,而不是核心内建能力问题。
例子四:我想让系统记住用户长期偏好
更适合 Memory 插件。 因为这是系统级信息持久化策略,需要明确的读写边界与唯一实现位点。
选型时真正应该关注的,不只是功能,而是代价
扩展机制选错,通常不是因为功能做不出来,而是因为长期代价被低估了。下面这几个维度,比“能不能实现”更重要。
1. 变化频率
变化快、试验性强、依赖外部生态的东西,不应该轻易进入核心。 变化越快,越应该考虑放在 Plugin 或 MCP 这一层。
2. 故障影响面
一个能力失败后,应该只是局部退化,还是会拖垮主链路? 如果不希望外围故障扩大影响,就要把边界放在外层,并做好降级。
3. 可审计性
这个能力是否容易解释:
- 它从哪里来的
- 为什么被调用
- 出错时该看哪一层
- 是否能清晰归责
边界越模糊,问题越难排查。
4. 用户心智负担
用户是否能清楚知道:
- 这是 Skill、Plugin 还是 MCP
- 配置改动会影响什么
- 出问题应该先查哪里
系统扩展层越多,越要靠清晰分工来维持可理解性。
配置与开发:先从局部验证,再决定是否沉淀
启用 Memory 插件
如前所示,可在 openclaw.json 中配置当前使用的 Memory 插件:
{
"plugins": {
"memory": "openclaw-memory-sqlite"
}
}
这类配置表面上很简单,但在实践里建议先做三件事:
- 用真实会话验证写入内容是否过多或过少
- 检查召回内容是否稳定、是否真的提高后续任务表现
- 验证清除、更新、纠错路径是否清晰
否则很容易得到一个“配置成功但体验变差”的记忆系统。
本地插件开发
开发阶段可通过本地路径加载插件,无需先发布到 npm。详见 docs/tools/plugin.md 中关于 local extension 的说明。
本地开发模式的重要性不只是方便,而是它允许你先验证三个关键问题:
- 这个能力是否真的值得存在
- 它适合留在插件层,还是其实应该做成 Skill
- 它的失败模式是否可控
很多扩展一开始看起来像“缺一个插件”,实际做完后会发现,问题真正缺的不是能力注入,而是任务层的组织方式。越早在本地验证,越能避免架构误判。
社区插件生态:可用不等于默认值得启用
访问 https://docs.openclaw.ai/plugins/community 可浏览社区维护的插件列表,常见包括:
- Memory 插件(不同存储后端或策略实现)
- 工具类插件
- 频道增强插件
安装方式一般是 npm install 或 pnpm add,然后在配置中启用。
但这里有一个很现实的提醒:社区生态的丰富,不等于你应该尽量多装。
对扩展系统来说,默认“多装一点再说”几乎总会带来后续成本:
- 能力面扩大,权限与审计压力上升
- 工具选择变多,模型更容易误用
- 故障来源增多,排查路径变长
- 上下文与配置复杂度增加
因此,更好的策略通常是:
- 先装最少一组、能覆盖核心场景的能力
- 通过真实任务验证收益
- 对低频、低收益、高噪声能力保持克制
在 Agent 系统里,“可扩展”真正的价值,不是让系统不断变大,而是让它在必要时增加能力,在不必要时保持克制。
本文小结
这一篇看似在讲三个名词:MCP、Plugins、Memory;实际上讨论的是同一个工程问题:扩展能力应该放在哪一层,才能既有弹性,又不破坏系统稳定性。
可以把本文压缩成下面四句话:
- MCP 适合连接外部工具生态,但通过 mcporter 桥接,而不是直接做成核心 first-class 集成
- Plugins 适合承载那些有价值、但不应进入核心的运行时能力
- Memory 是特殊插件槽位,因为它影响的是系统级长期状态,而不是一次性工具调用
- Skills / Plugins / MCP 的区别,不在于“谁更强”,而在于“你到底在扩展 Agent 的行为、系统能力,还是外部连接面”
理解这套分层之后,很多看似零碎的设计选择就会变得顺理成章:为什么核心保持精简,为什么强调 bridge,为什么 Memory 不能随意堆实现,为什么新能力不应轻易合入核心。
这不是保守,而是一种面向长期演进的克制。