Skip to content

12.3 官方扩展体系 ​

🎯 学习目标:理解 MCP 扩展的协商机制,知道何时该用 Tasks / Apps / Skills ⏱️ 预计时间:45 分钟 📊 难度等级:⭐⭐⭐(概念为主,配有协议示例)

📌 一句话结论:2026-07-28 把一批"实验特性"正式移出核心协议,改为官方扩展。扩展是可选、可组合、独立演进的,一律默认关闭,必须由开发者显式开启并做能力协商;每个扩展还处在 Experimental / Beta / Stable 三阶段之一,阶段决定了它能怎么变、你敢指望它多少。

🧩 什么是 MCP 扩展 ​

扩展是对规范的可选补充,定义了核心协议之外的能力。 它们可以是:

  • 模块化的(如独立的认证机制)
  • 专业化的(如某行业特有逻辑)
  • 实验性的(正在孵化、未来可能进核心)

扩展标识符 ​

每个扩展用一个唯一标识符命名,格式为:

{vendor-prefix}/{extension-name}
  • 官方扩展用 io.modelcontextprotocol 前缀,例如 io.modelcontextprotocol/tasks
  • 第三方扩展请用你拥有的域名倒写做前缀,避免冲突(类似 Java 包命名)。拥有 example.com 的公司用 com.example/,例如 com.example/my-extension

💡 标识符规则与 _meta 键一致,只是强制要求前缀。

🌱 扩展生命周期(Extension Lifecycle) ​

每个扩展都处在三个阶段之一,之后还可能被提升进核心规范。阶段决定了允许哪些改动、由谁批准、实现者能指望什么。完整定义见 SEP-3392: Extension Lifecycle(Process 类型,已 Final)。

阶段协议改动改动由谁批准进入方式实现者能指望什么
Experimental任何改动,随时可改,无需通知扩展维护者由扩展维护者直接加入什么都指望不上,设计可能变也可能消失
Beta可以改,但破坏性变更应当罕见扩展维护者一份 Extensions Track SEP欢迎真实使用;破坏性变更会被记录下来
Stable只随新的核心协议修订而改变扩展维护者第二份 Extensions Track SEP在一个协议修订内行为固定
  • 扩展从 Experimental 起步,必须经过 Beta;从 Beta 要么变成 Stable,要么由一份 Standards Track SEP 提升进核心规范
  • 处于 Beta 的扩展会声明自己的目标去向(Stable 还是 Core),这个去向在 Beta 期间可以调整
  • 改变阶段不会改变扩展的标识符

📦 官方扩展清单 ​

官方扩展放在 MCP GitHub 组织下、以 ext- 为前缀的仓库里。一个仓库可以容纳多个不同阶段的扩展——扩展规范所在的目录就标明了它的阶段:specification/experimental/、specification/beta/、specification/stable/;被提升进核心规范或已终止的扩展,移到 specification/archived/。

🔐 Authorization 扩展(ext-auth) ​

核心授权之外的补充机制。

扩展阶段说明
OAuth Client CredentialsStable机器对机器(M2M)认证的 OAuth 2.0 客户端凭据流
Enterprise-Managed AuthorizationStable需要集中访问控制的企业环境框架

核心授权流程见 12.1 OAuth 2.1 授权体系。

⏳ Tasks 扩展(ext-tasks) ​

扩展阶段说明
MCP TasksBeta(目标:Core)长时操作的异步执行:轮询、途中请求输入、持久化句柄

📌 宿主支持正在铺开:官方客户端支持矩阵的 Tasks 一栏目前登记了 MCPJam、Claude(web)、Claude Code;Claude Desktop、VS Code GitHub Copilot、ChatGPT、Cursor、Postman、Goose、Microsoft 365 Copilot 等仍尚未登记支持。生产落地前请先看该矩阵确认你面向的客户端当前是否可用。

🖼️ MCP Apps 扩展(ext-apps) ​

扩展阶段说明
MCP AppsStable允许服务器在对话里内嵌交互式 UI(图表、表单、视频播放器)

📚 Skills over MCP 扩展(ext-skills) ​

扩展阶段说明
Skills over MCPBeta(去向尚未声明)通过 MCP 资源发现工作流指令并读取配套文件

🪪 Server Cards 扩展(ext-server-card) ​

扩展阶段说明
Server CardsBeta(去向尚未声明)让客户端在连接之前就发现一个服务器的元数据(HTTP 发现)

📌 Tasks 为什么是扩展? 它在 2025-11-25 是实验特性,2026-07-28 被正式移出核心、变成 io.modelcontextprotocol/tasks 扩展(SEP-2663)。这是"实验特性 → 官方扩展"的标准路径。

🧪 实验性扩展 ​

官方给工作组/兴趣组提供了一条孵化通道:在提交 SEP 之前或同期,先用实验扩展原型验证想法。

  • 实验扩展要么放在某个 ext- 仓库的 specification/experimental/ 目录下,要么是自己的 experimental-ext- 前缀仓库(如 experimental-ext-interceptors);experimental-ext- 仓库里的一切都是 Experimental
  • 每个实验扩展必须挂靠一个工作组或兴趣组
  • 已发布的包必须明确标注实验状态(README、包名)
  • 实现者应当锁定到某个 tag 或 commit——Experimental 扩展的两个修订不保证互相兼容
  • 核心维护者保留监督权,包括归档或移除

转正路径:走 Extensions Track SEP(见下节的「提案 Beta」),孵化期的实验仓库与参考实现可以作为"该扩展切实可行"的证据。

🔄 创建一个官方扩展的七步 ​

  1. 原型:在 ext- 仓库的 specification/experimental/ 下加入扩展,或建一个 experimental-ext- 仓库
  2. 提案 Beta:按标准 SEP 指南在规范仓库里提一份 Extensions Track SEP,并声明目标是 Stable 还是被提升进 Core
  3. 实现:至少在一个官方 SDK 里做出参考实现——SEP 进入评审前的硬门槛
  4. 评审:核心维护者评审,对是否纳入有最终决定权
  5. 发布:SEP 通过后,提 PR 把扩展移到 ext- 仓库的 specification/beta/,由核心维护者批准这次移动
  6. 收集证据:Beta 期间持续维护一份公开清单,记录已知实现与收到的反馈
  7. 稳定或提升:第二份 Extensions Track SEP 把扩展推进 Stable——它需要两个互相独立且可互操作的实现(一客户端侧、一服务器侧)和一份一致性场景;或者由一份 Standards Track SEP 把它提升进核心规范

要求:

  • 扩展规范必须使用 RFC 2119 语言(MUST / SHOULD / MAY)
  • 扩展必须有对应的 WG 或 IG,且至少有一名 Extension Maintainer登记在仓库的 MAINTAINERS.md 里
  • 实现是硬门槛:SEP 进入评审前,至少要有一个官方 SDK 的参考实现

SDK 支持:SDK 可以实现扩展,但不是协议一致性所必需的;SDK 维护者自主决定支持哪些扩展,支持的话应在文档里列出。

⚠️ 扩展默认关闭,必须由开发者显式开启——在三个阶段都如此。

🤝 能力协商(Negotiation) ​

双方通过各自能力声明里的 extensions 字段表明支持的扩展。

📌 下面两个示例用的是 2026-07-28 及之后的写法。2025-11-25 及更早版本请见本节末尾的基于握手的版本。

客户端:在每个请求的 _meta 里声明 ​

json
{
  "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 响应里声明 ​

json
{
  "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;空对象表示无设置。

基于握手的版本(Initialization-Based Versions) ​

扩展是到 2026-07-28 才成为协议正式组成部分的。在那之前,很多 SDK、客户端和服务器已经在 2025-11-25 及更早版本上通过 initialize 握手协商扩展了:请求里用 params.capabilities.extensions,响应用 result.capabilities.extensions。扩展标识符与设置对象的规则和上面一致。

⚠️ 在这些协议版本里,extensions 字段不属于已发布的 schema,支持它也不是一致性要求。能透传 capabilities.extensions 的 SDK 被鼓励这样做,好让扩展在各版本间表现一致。请确认你的 SDK 能收发这个字段,且该扩展支持协商出来的协议版本。若对方能力里没有 extensions,或没有某个扩展,就把它当作不支持,按下面的优雅降级处理。

客户端请求

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "roots": { "listChanged": true },
      "extensions": {
        "io.modelcontextprotocol/ui": {
          "mimeTypes": ["text/html;profile=mcp-app"]
        }
      }
    },
    "clientInfo": { "name": "ExampleClient", "version": "1.0.0" }
  }
}

服务器响应

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "tools": {},
      "extensions": {
        "io.modelcontextprotocol/ui": {}
      }
    },
    "serverInfo": { "name": "ExampleServer", "version": "1.0.0" }
  }
}

优雅降级(Graceful Degradation) ​

若一方支持某扩展、另一方不支持,支持方必须二选一:

  • 回退到核心协议行为,或
  • 若该扩展是强制的,用合适的错误拒绝请求

💡 好的扩展文档会写明预期回退行为。例如:提供 UI 增强的服务器,对不支持 UI 扩展的客户端仍应返回有意义的文本内容;而依赖某认证扩展的服务器,则可以拒绝不支持它的客户端。

演进规则 ​

扩展的改动由它的 Extension Maintainers 批准,不需要核心维护者复审。但能改什么取决于阶段:

  • Experimental:什么都能改,随时可改
  • Beta:优先做加法(新增可选字段、在设置对象里加能力标志)。破坏性变更允许,但应当罕见、集中成批处理,先在 WG/IG 里公告,并记进 changelog。做了破坏性变更的扩展,应在设置对象里新增或递增一个 revision 字符串,好让对端检测出不匹配
  • Stable:按核心协议修订发布,形如 specification/stable/<name>/2026-07-28/;已发布的修订不可变。改动先累积在 draft/ 目录里,只在发布新的核心协议修订时生效。一对对端看到的扩展行为,就是它们协商出的那个协议修订所定义的行为

破坏性变更保留原标识符。 只有在同一个协议修订内必须让新旧行为共存时,才用新标识符(如 io.modelcontextprotocol/my-extension-v2)。

  • 破坏性变更包括:删除/重命名字段、改字段类型、改既有语义、新增必填字段

提升进核心(Promotion to Core) ​

当一份 Standards Track SEP 把某个扩展提升进核心规范、落在协议修订 R 上:对于声明了 R 或更高版本的请求,该特性就是核心行为,无论是否声明了该扩展;对于更早的修订,扩展的最后一份修订仍然适用——所以支持旧修订的客户端应当继续声明这个扩展。修订 R 发布后,扩展的规范移到 specification/archived/。

⏳ 深入一: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/listen opt-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 类只是便利封装,不是必需。

环境要求:官方构建指南要求 Node.js 20 或更高(早期文档写的是 18,已上调)。

📚 深入三:Skills over MCP(工作流指令分发) ​

📌 状态:Skills 已是已发布(published)的官方扩展,扩展标识 io.modelcontextprotocol/skills,对应 SEP-2640 已 Final。不过 SDK 与宿主对它的支持仍在陆续落地——生产落地前请看官方 客户端支持矩阵 与 实现清单 确认当前覆盖度。

Skills 扩展让服务器把工作流指令与配套文件暴露给客户端,客户端用既有的 Resources 原语发现元数据、读取内容。

一个 skill 就是一个目录:含一个 SKILL.md 与可选配套文件,遵循 Agent Skills 规范。这个扩展定义的是通过 MCP 发现与读取的方式。

能力声明:服务器必须同时声明 resources 能力和 io.modelcontextprotocol/skills 扩展,并必须实现 skills/list 与 skills/get;技能文件经 resources/read 提供。

json
{
  "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)

缓存提示:skills/list / skills/get 与 resources/directory/read 的结果都带 resultType: "complete", 并附两个缓存字段:ttlMs 是服务端给出的新鲜期(毫秒),cacheScope 为 "public" / "private", 决定响应能不能被共享的中间缓存存下来(语义类比 HTTP 的 Cache-Control: public / private)。

完整性校验(关键):宿主在技能"在用"期间保留其条目,并必须

  1. 把文件读取限制在清单内的 URI
  2. 每次使用前校验原始字节大小与 SHA-256 摘要
  3. 解析 SKILL.md frontmatter 并逐字段与条目里的 frontmatter 比对

校验失败的内容不得使用;持久化的授权绑定到完整的文件 URI + 摘要集合——文件有增删改,授权即失效,需重新获批。

⚠️ 读取 SKILL.md 本身不会激活技能。宿主需经其"技能加载路径"处理,校验内容并在需要时获得用户批准后才载入模型上下文。技能内容按不可信输入对待。

上限建议:单个技能不超过 512 个文件 / 16 MiB(含 SKILL.md)。

🧭 我该用哪个扩展 ​

你的需求选它
工具跑很久,不能阻塞连接Tasks
想在对话里展示图表 / 表单 / 播放器MCP Apps
有一整套工作流指令 + 参考文件要随服务分发Skills over MCP
机器对机器、或企业集中管控授权Auth 扩展(ext-auth)
想在连接之前就知道服务器是什么Server Cards(ext-server-card)

📖 官方资料 ​


👉 下一小节:12.4 官方注册表 Registry

内容依据 MCP 官方规范整理 · 规范以 官方文档 为准