12.3 官方扩展体系
🎯 学习目标:理解 MCP 扩展的协商机制,知道何时该用 Tasks / Apps / Skills ⏱️ 预计时间:45 分钟 📊 难度等级:⭐⭐⭐(概念为主,配有协议示例)
📌 一句话结论:2026-07-28 把一批"实验特性"正式移出核心协议,改为官方扩展。扩展是可选、可组合、独立演进的,一律默认关闭,必须由开发者显式开启并做能力协商。
🧩 什么是 MCP 扩展
扩展是对规范的可选补充,定义了核心协议之外的能力。 它们可以是:
- 模块化的(如独立的认证机制)
- 专业化的(如某行业特有逻辑)
- 实验性的(正在孵化、未来可能进核心)
扩展标识符
每个扩展用一个唯一标识符命名,格式为:
{vendor-prefix}/{extension-name}- 官方扩展用
io.modelcontextprotocol前缀,例如io.modelcontextprotocol/tasks - 第三方扩展请用你拥有的域名倒写做前缀,避免冲突(类似 Java 包命名)。拥有
example.com的公司用com.example/,例如com.example/my-extension
💡 标识符规则与
_meta键一致,只是强制要求前缀。
📦 官方扩展清单
官方扩展放在 MCP GitHub 组织下、以 ext- 为前缀的仓库里。
🔐 Authorization 扩展(ext-auth)
核心授权之外的补充机制。
| 扩展 | 说明 |
|---|---|
| OAuth Client Credentials | 机器对机器(M2M)认证的 OAuth 2.0 客户端凭据流 |
| Enterprise-Managed Authorization | 需要集中访问控制的企业环境框架 |
核心授权流程见 12.1 OAuth 2.1 授权体系。
📊 Tasks 扩展(ext-tasks)
| 扩展 | 说明 |
|---|---|
| MCP Tasks | 长时操作的异步执行:轮询、途中请求输入、持久化句柄 |
🖼️ MCP Apps 扩展(ext-apps)
| 扩展 | 说明 |
|---|---|
| MCP Apps | 允许服务器在对话里内嵌交互式 UI(图表、表单、视频播放器) |
📚 Skills over MCP 扩展(ext-skills)
| 扩展 | 说明 |
|---|---|
| Skills over MCP | 通过 MCP 资源发现工作流指令并读取配套文件 |
📌 Tasks 为什么是扩展? 它在 2025-11-25 是实验特性,2026-07-28 被正式移出核心、变成
io.modelcontextprotocol/tasks扩展(SEP-2663)。这是"实验特性 → 官方扩展"的标准路径。
🧪 实验性扩展
官方给工作组/兴趣组提供了一条孵化通道:在正式提 SEP 之前,先用实验仓库原型验证想法。
- 实验仓库以
experimental-ext-为前缀(如experimental-ext-interceptors) - 每个实验扩展必须挂靠一个工作组或兴趣组
- 仓库与已发布包必须明确标注实验状态(README、包名)
- 核心维护者保留监督权,包括归档或移除
转正路径:走标准 SEP 流程(Extensions Track),可以把孵化期的实验仓库与参考实现作为"该扩展切实可行"的证据。
🔄 创建一个官方扩展的五步
要求:
- 扩展规范必须使用 RFC 2119 语言(MUST / SHOULD / MAY)
- 扩展必须有对应的 WG 或 IG
- 实现是硬门槛:SEP 进入评审前,至少要有一个官方 SDK 的参考实现
SDK 支持:SDK 可以实现扩展,但不是协议一致性所必需的;SDK 维护者自主决定支持哪些扩展,支持的话应在文档里列出。
⚠️ 扩展默认关闭,必须由开发者显式开启。
🤝 能力协商(Negotiation)
双方通过各自能力声明里的 extensions 字段表明支持的扩展。
客户端:在每个请求的 _meta 里声明
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "location": "New York" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {
"extensions": {
"io.modelcontextprotocol/ui": {
"mimeTypes": ["text/html;profile=mcp-app"]
}
}
},
"io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" }
}
}
}注意:这是无状态模型的体现——扩展声明随每个请求携带,而不是靠一次握手协商后记住。
服务器:在 server/discover 响应里声明
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28"],
"capabilities": {
"tools": {},
"extensions": { "io.modelcontextprotocol/ui": {} }
},
"_meta": {
"io.modelcontextprotocol/serverInfo": { "name": "ExampleServer", "version": "1.0.0" }
},
"ttlMs": 3600000,
"cacheScope": "public"
}
}每个扩展自己定义其设置对象的 schema;空对象表示无设置。
优雅降级(Graceful Degradation)
若一方支持某扩展、另一方不支持,支持方必须二选一:
- 回退到核心协议行为,或
- 若该扩展是强制的,用合适的错误拒绝请求
💡 好的扩展文档会写明预期回退行为。例如:提供 UI 增强的服务器,对不支持 UI 扩展的客户端仍应返回有意义的文本内容;而依赖某认证扩展的服务器,则可以拒绝不支持它的客户端。
演进规则
- 扩展独立于核心协议演进,由扩展仓库维护者管理,不需核心维护者复审
- 需要改动时优先用能力标志或扩展设置对象内的版本号,而不是新建标识符
- 无法避免破坏性变更时,才用新标识符(如
io.modelcontextprotocol/my-extension-v2) - 破坏性变更包括:删除/重命名字段、改字段类型、改既有语义、新增必填字段
⏳ 深入一:Tasks(长任务)
不是每次工具调用都立刻返回。CI 流水线、批处理、人工审批可能耗时数秒到数小时。Tasks 让服务器返回一个持久化句柄而不是阻塞。
为什么不能"直接阻塞"
| 阻塞的问题 | Tasks 如何解决 |
|---|---|
| 长期占用连接,中间层超时撑不住 | 不长期占用连接 |
| 客户端崩溃/重启就丢了 | task ID 是持久句柄,可用同一 ID 恢复轮询 |
| 看不到进度 | 携带状态元数据与可选进度消息 |
| 需要用户输入时没法交互 | 转 input_required 并浮出请求,客户端用 tasks/update 回 |
| 每工具都要预热/传参开关 | 服务器按请求决定是否建任务,客户端一次性 opt-in |
生命周期
| 状态 | 含义 |
|---|---|
working | 进行中 |
input_required | 需要客户端输入(见 inputRequests) |
completed | 完成,result 含最终输出 |
failed | 执行中发生 JSON-RPC 错误,error 含细节 |
cancelled | 已取消(不保证被遵守) |
completed / failed / cancelled 是终态,一旦到达状态不再改变。
主流程
要点:
- 服务器返回
CreateTaskResult(resultType: "task"),含taskId、初始状态、TTL、建议轮询间隔;任务必须在响应发出前持久化创建 - 客户端用
tasks/get轮询;终态时result(completed)或error(failed)落位 - 没有
tasks/list;用tasks/get轮询客户端已知的句柄 tasks/cancel是协作式取消——服务器确认意图,但不保证停下- 服务器可以通过
notifications/tasks推送(客户端经subscriptions/listenopt-in),省掉轮询往返
何时该用 Tasks:长时操作(CI、批处理、模型训练)、人在环流程(审批门)、已用 job ID 的外部系统、不可靠连接、需要进度可见的批量处理。
🖼️ 深入二:MCP Apps(对话内 UI)
文本响应有极限。有时用户需要与数据交互,而不只是读它。MCP Apps 让服务器返回交互式 HTML 界面(可视化、表单、看板),直接渲染在聊天里。
相比独立 Web 应用的优势:
| 优势 | 说明 |
|---|---|
| 上下文保留 | 应用就在对话里,用户不必切标签页、丢位置 |
| 双向数据流 | 应用可调服务器上任意工具,宿主能把新结果推给应用 |
| 宿主能力整合 | 应用可把动作委托给宿主,由宿主走用户已连接的既有能力(经用户同意) |
| 安全保证 | 运行在宿主控制的沙箱 iframe 里,无法访问父页、偷 cookie、逃逸容器 |
核心模式:一个在描述里声明了 UI 资源的工具 + 一个把数据渲染成交互式 HTML 的 ui:// 资源。
安全模型:所有通信走 postMessage;宿主决定应用能访问哪些能力(如限制可调工具、禁用 sendOpenLink)。资源可带 _meta.ui.csp(允许的外部源)与 _meta.ui.permissions(麦克风/摄像头等)。
何时该用:探索复杂数据(可钻取的地图)、多选项配置(一次性表单)、富媒体查看(PDF/3D/视频)、实时监控、多步工作流。
框架无关:是标准 Web 原语,React / Vue / Svelte / Preact / Solid / 原生 JS 都行;@modelcontextprotocol/ext-apps 的 App 类只是便利封装,不是必需。
📚 深入三:Skills over MCP(工作流指令分发)
Skills 扩展让服务器把工作流指令与配套文件暴露给客户端,客户端用既有的 Resources 原语发现元数据、读取内容。
一个 skill 就是一个目录:含一个 SKILL.md 与可选配套文件,遵循 Agent Skills 规范。这个扩展定义的是通过 MCP 发现与读取的方式。
能力声明:服务器必须同时声明 resources 能力和 io.modelcontextprotocol/skills 扩展,并必须实现 skills/list 与 skills/get;技能文件经 resources/read 提供。
{
"capabilities": {
"resources": {},
"extensions": {
"io.modelcontextprotocol/skills": { "directoryRead": true }
}
}
}三种操作:
| 操作 | 作用 |
|---|---|
skills/list | 发现可用技能,返回 frontmatter 与完整文件清单(含每个文件的 URI、SHA-256 摘要、字节大小) |
skills/get | 按 URI 取单个技能条目(也用于刷新已缓存条目) |
resources/read | 读取 SKILL.md 或配套文件内容;可选 resources/directory/read 列目录(需 directoryRead: true) |
完整性校验(关键):宿主在技能"在用"期间保留其条目,并必须
- 把文件读取限制在清单内的 URI
- 每次使用前校验原始字节大小与 SHA-256 摘要
- 解析
SKILL.mdfrontmatter 并逐字段与条目里的frontmatter比对
校验失败的内容不得使用;持久化的授权绑定到完整的文件 URI + 摘要集合——文件有增删改,授权即失效,需重新获批。
⚠️ 读取
SKILL.md本身不会激活技能。宿主需经其"技能加载路径"处理,校验内容并在需要时获得用户批准后才载入模型上下文。技能内容按不可信输入对待。上限建议:单个技能不超过 512 个文件 / 16 MiB(含
SKILL.md)。
🧭 我该用哪个扩展
| 你的需求 | 选它 |
|---|---|
| 工具跑很久,不能阻塞连接 | Tasks |
| 想在对话里展示图表 / 表单 / 播放器 | MCP Apps |
| 有一整套工作流指令 + 参考文件要随服务分发 | Skills over MCP |
| 机器对机器、或企业集中管控授权 | Auth 扩展(ext-auth) |
📖 官方资料
- 📋 Extensions Overview
- ⏳ MCP Tasks | ext-tasks
- 🖼️ MCP Apps | ext-apps
- 📚 Skills over MCP | ext-skills
- 🔐 Authorization 扩展
- 🧩 扩展客户端支持矩阵