- 人工智能
- AI Agent
- 工具调用
【免费下载链接】specification
Specification and documentation for the Model Context Protocol
本篇文章以 SEP-1036(URL Mode Elicitation for secure out-of-band interactions) 为核心,系统讲解 Model Context Protocol(MCP)如何在不经过 MCP 客户端的前提下,安全收集敏感凭据、执行第三方 OAuth 授权与支付流程。读完本文,你将掌握 URL 模式 Elicitation 的协议消息结构、能力协商方式、响应动作语义、错误处理机制,以及客户端与服务端各自必须遵守的安全边界和防钓鱼要点,并了解该特性从 2025-11-25 版本引入到 2026-07-28 版本随 Multi Round-Trip Requests(MRTR)模式演进后的最新形态。
背景与动机:为什么需要"带外"交互
MCP 自 2025-06-18 版本起提供了 Elicitation(诱导式信息收集)机制,让服务端可以在处理客户端请求的过程中,通过结构化、带内(in-band)的请求向用户收集非敏感信息——最常见的形态是 MCP 客户端渲染一个表单供最终用户填写。然而,有三类关键场景要求交互绝不能经过 MCP 客户端:
- 敏感数据收集:API Key、密码等凭据绝不允许穿过任何中间系统(包括 MCP 客户端与 LLM 上下文)。
- 外部(第三方)授权:MCP 服务端经常需要以用户名义访问第三方 API。MCP 授权规范只覆盖"客户端到服务端"的授权,不覆盖"服务端到第三方"的授权;官方 Security Best Practices 文档明确禁止 token passthrough(令牌透传)。因此必须有一种安全机制来承载外部 OAuth 流程,这来自 #234 和 #284 等讨论。
- 支付与订阅流程:金融交易需要满足 PCI 合规与安全的支付处理,无法通过带内的表单式数据采集实现。
在没有标准化机制之前,MCP 服务端只能退回到非标准变通方案,甚至采用"通过带内表单收集 API Key"这类不安全做法。SEP-1036 正是针对这些缺口,引入了复用成熟 Web 安全模式的 URL 模式 Elicitation。
需要特别强调:URL 模式 Elicitation 与 MCP 授权是两回事。它不是用于授权 MCP 客户端访问 MCP 服务端(那由 MCP 授权规范处理),而是用于 MCP 服务端需要代表用户获取敏感信息或第三方授权时。在整个过程中,MCP 客户端的 bearer token 保持不变,客户端的唯一职责就是向用户展示服务端希望其打开的 Elicitation URL 并获取上下文。
两种模式:Form 与 URL
Elicitation 被更新为支持两种模式:
- Form 模式(带内):服务端通过可选的 JSON Schema 校验,向用户请求结构化数据。此模式在既有能力上基本无变化,只是为既有能力补上了名称。
- URL 模式(带外):服务端将用户引导到外部 URL,完成不能经过 MCP 客户端的敏感交互。
这一"同一机制、两种模式"的设计在 2026-07-28 规范中依然保留。官方规范原文见 docs/specification/2026-07-28/client/elicitation.mdx,其中明确指出 URL 模式是敏感信息交互(密码、API Key、访问令牌、支付凭据)的唯一合法通道:服务端MUST NOT使用 Form 模式请求此类敏感信息。
能力声明与协商
支持 Elicitation 的客户端MUST声明elicitation能力。在 2025-11-25 及之前版本中,该声明位于初始化阶段的capabilities字段:
{ "capabilities": { "elicitation": { "form": {}, "url": {} } } }在 2026-07-28 版本中,协议改为无状态(SEP-2575),能力声明随每个请求携带在_meta.io.modelcontextprotocol/clientCapabilities中:
{ "_meta": { "io.modelcontextprotocol/clientCapabilities": { "elicitation": { "form": {}, "url": {} } } } }向后兼容规则不变:空的能力对象等价于只声明支持form模式:
{ "capabilities": { "elicitation": {} // 等价于 { "form": {} } } }客户端声明了elicitation能力后MUST至少支持一种模式(form或url);服务端MUST NOT向不支持对应模式的客户端发送 Elicitation 请求。
URL 模式请求规范
URL 模式 Elicitation 请求MUST指定mode: "url",并包含以下参数:
| 名称 | 类型 | 说明 |
|---|---|---|
url | string | 用户需要导航到的 URL(MUST是有效 URL) |
elicitationId | string | Elicitation 的唯一标识符(2025-11-25 版) |
message | string | 向用户解释为何需要该交互的可读消息 |
版本差异提示:
elicitationId仅在 2025-11-25 版本中存在。2026-07-28 版本(changelog 第 11 条)移除了该字段与notifications/elicitation/complete通知,详见下文"演进"小节。
典型示例:OAuth 授权流程
{ "jsonrpc": "2.0", "id": 3, "method": "elicitation/create", "params": { "mode": "url", "elicitationId": "550e8400-e29b-41d4-a716-446655440000", "url": "https://github.com/login/oauth/authorize?client_id=abc123&state=xyz789&scope=repo", "message": "Please authorize access to your GitHub repositories to continue." } }相同的请求结构也可以指向"输入 API Key 的安全页面"或"支付页面",区别仅在于 URL 与 message 内容。
Schema 层面的定义
在 schema/2026-07-28/schema.ts 中,两种模式的请求参数被建模为可辨识联合类型:
ElicitRequestFormParams:mode?为可选的"form"(省略时默认为 form),携带message与requestedSchema(仅允许顶层属性、无嵌套的 JSON Schema 受限子集)。ElicitRequestURLParams:mode为必填的"url",携带message与带@format uri标注的url字段。
export interface ElicitRequestURLParams { /** The elicitation mode. */ mode: "url"; /** The message to present to the user explaining why the interaction is needed. */ message: string; /** The URL that the user should navigate to. @format uri */ url: string; }从源码结构可以看出:URL 模式在类型层面就强制要求mode与url同时存在,而 Form 模式允许省略mode以保持向后兼容——这与规范正文的表述完全一致。
响应动作模型
URL 模式 Elicitation 的响应沿用与 Form 模式相同的三动作模型:
{ "jsonrpc": "2.0", "id": 3, "result": { "action": "accept" // 或 "decline" 或 "cancel" } }三种动作的语义:
- accept:用户明确同意并提交。
- Form 模式:
content字段携带符合请求 schema 的数据; - URL 模式:
content字段必须省略(用户提交的数据在带外发生,客户端不接触)。
- Form 模式:
- decline:用户明确拒绝,
content通常省略(如点击"Reject/Decline/No")。 - cancel:用户未做明确选择即关闭(如关闭对话框、按 Esc、浏览器加载失败)。
关键语义:action: "accept"仅表示用户已同意交互,不代表交互完成。带外交互的最终结果客户端无从直接得知,服务端需要自行判断。
完成通知:从 2025-11-25 到 2026-07-28 的演进
2025-11-25 版本:显式完成通知
SEP-1036 于 2025-11-25 版本正式落地(见 docs/specification/2025-11-25/changelog.mdx 第 6 条)。该版本中,服务端SHOULD在带外交互完成后发送notifications/elicitation/complete通知,使客户端能够程序化响应:
{ "jsonrpc": "2.0", "method": "notifications/elicitation/complete", "params": { "elicitationId": "550e8400-e29b-41d4-a716-446655440000" } }规则要点:
- 通知MUST只发送给发起 Elicitation 请求的那个客户端;
- 通知MUST携带原始
elicitation/create请求中的elicitationId; - 客户端MUST忽略引用未知或已完成 ID 的通知;
- 若完成通知迟迟不来,客户端SHOULD提供让用户手动继续交互的方式,且不能无限等待(通知投递不保证送达)。
客户端MAY利用该通知自动重试收到URLElicitationRequiredError的请求、更新界面或继续交互。
2026-07-28 版本:并入 MRTR 模式
随着 SEP-2322(MRTR) 的引入,2026-07-28 版本发生了结构性变化(changelog 第 11 条):notifications/elicitation/complete通知与elicitationId字段被移除。
原因在于:MRTR 模式下,elicitation/create不再作为服务端发起的独立请求,而是被包装在服务端返回的InputRequiredResult(resultType: "input_required")的inputRequests字段中;客户端在重试原始请求时通过inputResponses回传结果。客户端通过重试原始请求就能得知带外交互的最终结果,服务端发起的完成信号以及用于关联的 ID 便不再契合协议形态。需要跨重试关联 Elicitation 的服务端,改为在自己的requestState中编码自有的标识符。
MRTR 模式的详细说明见 docs/specification/2026-07-28/basic/patterns/mrtr.mdx,其类型定义(InputRequiredResult)可在 schema/2026-07-28/schema.ts 中查看。该版本中客户端收到accept后重试原始请求时,服务端根据回显的requestState(或自身存储的状态)判断带外交互是否完成,并返回最终结果或再次下发InputRequiredResult;客户端SHOULD提供手动重试/取消的控件。
URL 模式完整消息流(2026-07-28 版)
URLElicitationRequiredError 错误处理
当请求在 Elicitation 完成前无法继续处理时,服务端MAY返回URLElicitationRequiredError(错误码-32042),明确告知客户端"需要一次 URL 模式 Elicitation"。服务端MUST NOT在非此场景下返回该错误。
{ "jsonrpc": "2.0", "id": 2, "error": { "code": -32042, "message": "This request requires more information.", "data": { "elicitations": [ { "mode": "url", "elicitationId": "550e8400-e29b-41d4-a716-446655440000", "url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...", "message": "Authorization is required to access your Example Co files." } ] } } }规则要点:
- 错误中返回的 ElicitationMUST全部是 URL 模式,且MUST携带
elicitationId(2026-07-28 版起不再要求该字段); - 返回该错误等价于发送一次
elicitation/create请求——这是给客户端的提示,使其明确"某个 Elicitation 与某个失败的客户端请求直接相关"; - 客户端必须将
URLElicitationRequiredError视同elicitation/create请求处理,可在外交互成功完成后(例如收到完成通知后)自动重试失败的请求。
设计原理与备选方案
为什么扩展现有 Elicitation 而非另建机制
最初曾考虑为带外交互单独设计一套机制(#475 讨论),但与 MCP maintainers 沟通后决定扩展现有 Elicitation,理由有三:
- 两种机制的根本目的相同——向用户收集信息;
- 两个"相似但不相同"的机制并存容易造成混淆与错误;
mode参数可以干净地区分两种交互模式。
为什么客户端不能代为执行交互
一个诱人的想法是让 MCP 客户端亲自执行交互(例如充当第三方授权服务器的 OAuth 客户端),但这不可行:
- 若客户端从第三方授权服务器取得用户令牌并转交给服务端,服务端就变成了被明确禁止的 token passthrough 服务器;
- 对支付类流程,客户端将被迫承担 PCI 合规的支付处理责任,这不应成为 MCP 客户端的义务。
为什么服务端不阻塞等待 Elicitation 完成
URL 模式 Elicitation 在设计上就是异步("断连式")流程,因为其承载的交互天然异步:支付流程、外部授权可能耗时数分钟,甚至可能被用户放弃而永不完成。
为什么 Form 模式禁止 URL
在规范层面严格限定"URL 只能出现在 URL 模式请求的url字段中",能显著改善客户端的整体安全姿态:客户端可以实现与安全模型一致的 UX 模式,例如拒绝把 Form 模式请求中的 URL 渲染成可点击超链接,从而降低用户误点恶意服务端发送的恶意 URL 的概率。
被否决的备选方案
- Token Passthrough:将 MCP 客户端的令牌直接透传给外部服务,或因安全考虑由客户端代取额外令牌再转交服务端——均因 Security Best Practices 中记录的安全问题被否决。
- OAuth 专用能力:曾考虑为第三方 OAuth 授权创建专门能力,最终被否决,转而采用能覆盖多类用例的更通用的 URL 模式 Elicitation。
社区反馈
该提案整合了 #475、#234、#284 讨论以及 Discord 上 #auth-wg 工作组的大量社区反馈。社区明确提出了四方面需求:不暴露给客户端的凭据安全收集、独立于 MCP 授权的第三方授权模式、支付与订阅流程支持、清晰的安全边界与信任模型。
安全影响与实现要求
URL 安全要求
- SSRF 防护:客户端必须校验 URL 以防服务端请求伪造(Server-Side Request Forgery);
- 协议限制:URL 模式 Elicitation 只允许 HTTPS URL;
- 域名明示:客户端必须向用户清晰展示目标域名。
信任边界
URL 模式 Elicitation 明确建立了三条信任边界:
- MCP 客户端永远看不到服务端通过 URL 模式 Elicitation 获取的敏感数据;
- MCP 服务端必须独立验证用户身份;
- 第三方服务通过安全的浏览器上下文与用户直接交互。
身份验证
服务端必须验证"完成 URL Elicitation 的用户"与"发起该请求的用户"是同一人,且验证不能依赖来自客户端的不可信输入(如用户自述)。
实现要求清单
客户端必须:
- 使用可防止用户输入被检视的安全浏览器上下文(例如 iOS 上使用
SFSafariViewController而非WKWebView); - 校验 URL 以防 SSRF;
- 在打开 URL 前取得用户明确同意;
- 清晰展示目标域名。
服务端必须:
- 将 Elicitation 状态绑定到已认证的用户会话;
- 在 URL Elicitation 流程开始与结束时验证用户身份;
- 实施适当的速率限制。
双方应当:
- 记录安全事件以供审计;
- 为 Elicitation 请求实现超时机制;
- 对安全失败提供清晰的错误消息。
防钓鱼:一个必须防范的攻击场景
URL 模式 Elicitation 会返回一个可被攻击者转发的 URL。服务端MUST在接收信息前验证打开该 URL 的用户身份,典型的验证方式是借助 MCP 授权服务器(通过浏览器会话 cookie 或等价物)识别用户。
一个典型的钓鱼攻击路径是:恶意用户 Alice 连接良性服务端并触发 Elicitation → 服务端生成指向第三方授权服务器的授权 URL → Alice 的客户端展示 URL 征求同意 → Alice 不去点击,而是诱骗同一服务端的受害者 Bob 点击 → Bob 误以为是在为自己授权而完成流程 → 服务端收到回调后误认为是 Alice 的请求 → 第三方令牌被绑定到 Alice 的身份,造成账户接管。
标准缓解做法(非规范性示例):服务端把 Elicitation URL 指向自己的https://mcp.example.com/connect?...页面(而非第三方授权端点),该"connect 页面"校验访问者是否持有与发起 Elicitation 用户一致的有效会话 cookie——例如比对 MCP 授权服务器给出的权威subclaim 与会话 cookie 中的 subject。确认同一用户后,再将其引导至第三方授权服务器完成正常 OAuth 流程。若服务端无法通过 Web 访问、无法使用会话 cookie,则必须采用其他机制,且所有实现都必须保证身份判定机制能抵御攻击者对 Elicitation URL 的篡改。
向后兼容与迁移路径
SEP-1036 引入了两类破坏性变更:
- 能力声明:客户端必须显式声明支持的 Elicitation 模式(
form/url),而此前仅声明"elicitation": {}; - mode 参数:所有
elicitation/create请求必须携带mode参数("form"或"url")。
迁移建议:
- 服务端SHOULD在发送模式相关请求前检查客户端能力;
- 客户端MAY初期只支持 form 模式以维持兼容;
- 既有 Form 模式实现加上
mode参数后即可继续工作(省略时默认按 form 处理)。
从 SEP 到规范的落地验证
如果你想在仓库中追踪该特性的完整生命周期,可以按以下路径串联:
- 提案原文:seps/1036-url-mode-elicitation-for-secure-out-of-band-intera.md
- 2025-11-25 版规范(含
elicitationId与完成通知):docs/specification/2025-11-25/client/elicitation.mdx - 2026-07-28 版规范(MRTR 化后的最新形态):docs/specification/2026-07-28/client/elicitation.mdx
- 版本变更记录:docs/specification/2026-07-28/changelog.mdx
- 类型定义:schema/2026-07-28/schema.ts
- MRTR 模式详解:docs/specification/2026-07-28/basic/patterns/mrtr.mdx
总结
SEP-1036 通过为既有 Elicitation 能力增加 URL 模式,为 MCP 补上了"安全的带外交互"这一关键拼图:凭据收集、第三方 OAuth 授权与支付流程从此有了标准化、不经过 MCP 客户端的通道。其核心设计原则——同一机制、两种模式、严格的 URL 安全边界、服务端身份绑定与防钓鱼验证——贯穿了从 2025-11-25 引入到 2026-07-28 随 MRTR 模式重构的整个演进过程。对于 MCP 客户端与服务端的实现者而言,理解能力协商、三动作响应模型、URLElicitationRequiredError语义以及客户端/服务端各自的安全义务清单,是正确、安全地落地这一特性的前提。
- 人工智能
- AI Agent
- 工具调用
【免费下载链接】specification
Specification and documentation for the Model Context Protocol
相关推荐
在 mcp-use 中实现 MCP Elicitation:表单确认与外部授权 URL 双模式实战
在 mcp use 中实现 MCP Elicitation:表单确认与外部授权 URL 双模式实战 本篇技术指南基于 mcp use 仓库中的 Elicitat
后端MCP 服务MCP ClientsAI Agent人工智能python-sdk 中的 MCP Elicitation 引导式交互:Resolver、表单与 URL 跳转实战
python sdk 中的 MCP Elicitation 引导式交互:Resolver、表单与 URL 跳转实战 Elicitation(引导式交互)让 MC
人工智能MCP 服务MCP Clientspython-sdk 中的 MCP 询问(Elicitation)完全指南:表单模式、URL 模式与 Resolver 深度解析
python sdk 中的 MCP 询问(Elicitation)完全指南:表单模式、URL 模式与 Resolver 深度解析 Elicitation(询问)
人工智能MCP 服务MCP Clients
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考