- 表单模式(Form mode):服务器可以用可选的 JSON schema 向用户请求结构化数据以校验响应
- URL 模式(URL mode):服务器可以为不得经过 MCP 客户端的敏感交互将用户导向外部 URL
用户交互模型
MCP 中的征询允许服务器通过使用户输入请求发生在其他 MCP 服务器特性内部_嵌套_,来实现交互式工作流。 实现可以自由地通过任何适合其需求的界面模式暴露征询——协议本身不强制规定任何特定的用户交互模型。能力
支持征询的客户端**必须(MUST)**在每个请求的_meta.io.modelcontextprotocol/clientCapabilities 中声明 elicitation 能力:
form 模式的支持:
elicitation 能力的客户端**必须(MUST)**至少支持一种模式(form 或 url)。
服务器**不得(MUST NOT)**发送客户端不支持的模式的征询请求。
协议消息
征询请求
服务器**可以(MAY)**在处理一个客户端请求期间通过发送一个包含elicitation/create 请求的 InputRequiredResult 向用户请求信息。
所有征询请求**必须(MUST)**包含以下参数:
mode 参数指定征询的类型:
"form":带可选 schema 校验的带内(in-band)结构化数据收集。数据暴露给客户端。"url":通过 URL 导航的带外(out-of-band)交互。数据(URL 本身除外)不暴露给客户端。
mode 字段。客户端必须(MUST)**将没有 mode 字段的请求视为表单模式。
表单模式征询请求
表单模式征询允许服务器直接通过 MCP 客户端收集结构化数据。 表单模式征询请求**必须(MUST)**要么指定mode: "form",要么省略 mode 字段,并包含这些额外参数:
请求的 Schema
requestedSchema 参数允许服务器使用 JSON Schema 的一个受限子集来定义预期响应的结构。
为简化客户端用户体验,表单模式征询 schema 被限制为仅具有原始属性的扁平对象。
schema 被限制为这些原始类型:
-
字符串 Schema
支持的格式:
email、uri、date、date-time -
数字 Schema
-
布尔 Schema
-
枚举 Schema
单选枚举(不带标题):
单选枚举(带标题):多选枚举(不带标题):多选枚举(带标题):
- 生成适当的输入表单
- 在发送前校验用户输入
- 为用户提供更好的指导
示例:简单文本请求
输入请求(在InputRequiredResult.inputRequests 内投递):
inputResponses 内返回):
示例:结构化数据请求
输入请求(在InputRequiredResult.inputRequests 内投递):
inputResponses 内返回):
URL 模式征询请求
新特性: URL 模式征询在 MCP 规范的
2025-11-25 版本中引入。其设计和实现可能在未来的协议修订版中改变。mode: "url"、一个 message,并包含这些额外参数:
url 参数**必须(MUST)**包含一个有效的 URL。
重要:URL 模式征询不用于授权 MCP 客户端对 MCP 服务器的访问(那由 MCP 授权处理)。相反,它在 MCP 服务器需要代表用户获取敏感信息或第三方授权时使用。MCP 客户端的 bearer token 保持不变。客户端的唯一职责是向用户提供关于服务器想要他们打开的征询 URL 的上下文。
示例:请求敏感数据
本示例展示一个 URL 模式征询请求,将用户导向一个安全 URL,他们可以在那里提供敏感信息(例如一个 API 密钥)。同一个请求可以将用户导向一个 OAuth 授权流程或一个支付流程。唯一的区别是 URL 和 message。 输入请求(在InputRequiredResult.inputRequests 内投递):
inputResponses 内返回):
action: "accept" 的响应表示用户已同意此交互。它并不意味着交互已完成。交互在带外发生,客户端不被直接告知结果。当客户端重试原始请求时,服务器从回传的 requestState(或其自己存储的状态)确定带外交互是否已完成,并要么返回最终结果,要么以另一个 InputRequiredResult 响应。客户端**应当(SHOULD)**提供手动控件,让用户重试或取消原始请求(或以其他方式恢复与客户端的交互)。
消息流
表单模式流程
URL 模式流程
响应操作
征询响应使用一个三操作模型来清晰地区分不同的用户操作。这些操作适用于表单和 URL 两种征询模式。-
接受(Accept)(
action: "accept"):用户显式地批准并带数据提交- 对于表单模式:
content字段包含匹配所请求 schema 的已提交数据 - 对于 URL 模式:省略
content字段 - 示例:用户点击 “Submit”、“OK”、“Confirm” 等
- 对于表单模式:
-
拒绝(Decline)(
action: "decline"):用户显式地拒绝了该请求content字段通常被省略- 示例:用户点击 “Reject”、“Decline”、“No” 等
-
取消(Cancel)(
action: "cancel"):用户在未做出显式选择的情况下关闭content字段通常被省略- 示例:用户关闭对话框、点击外部、按 Escape、浏览器加载失败等
- 接受:处理已提交的数据
- 拒绝:处理显式拒绝(例如提供替代方案)
- 取消:处理关闭(例如稍后再次提示)
实现考量
有状态性
征询不要求服务器通过多轮往返请求机制维护关于用户的状态。 然而,如果存储状态,实现征询的服务器**必须(MUST)**遵循安全最佳实践文档中的指南,将此状态安全地与各个用户关联。具体而言:- 状态存储**必须(MUST)**受到保护以防止未授权访问
- 对于远程 MCP 服务器,用户标识在可能时**必须(MUST)**从通过 MCP 授权获取的凭据派生(例如
subclaim)
本节中的示例是非规范性的,用于说明征询的潜在用途。实现者应在保持安全最佳实践的同时,将这些模式适配到他们的具体要求。
用于敏感数据的 URL 模式征询
对于与需要敏感信息(例如凭据、支付信息)的外部 API 交互的服务器,URL 模式征询提供了一种安全机制,供用户提供此信息而不将其暴露给 MCP 客户端。 在此模式中:- 服务器将用户导向一个安全网页(通过 HTTPS 提供)
- 该页面在用户信任的域上呈现一个带品牌的表单 UI
- 用户将敏感凭据直接输入到安全表单中
- 服务器安全地存储凭据,绑定到用户的身份
- 后续的 MCP 请求使用这些存储的凭据进行 API 访问
用于 OAuth 流程的 URL 模式征询
URL 模式征询实现了一种模式,其中 MCP 服务器充当第三方资源服务器的 OAuth 客户端。由 URL 模式征询实现的与外部 API 的授权与 MCP 授权是分开的。MCP 服务器**不得(MUST NOT)**依赖 URL 模式征询来为它们自己授权用户。理解区别
- MCP 授权:MCP 客户端与 MCP 服务器之间必需的 OAuth 流程(在授权规范中涵盖)
- 外部(第三方)授权:MCP 服务器与第三方资源服务器之间的可选授权,通过 URL 模式征询发起
- 一个 OAuth 资源服务器(对 MCP 客户端而言)
- 一个 OAuth 客户端(对第三方资源服务器而言)
- 一个 MCP 客户端连接到一个 MCP 服务器
- 该 MCP 服务器与各种不同的第三方服务集成
- 当 MCP 客户端调用一个需要访问第三方服务的工具时,MCP 服务器需要该服务的凭据
- 第三方凭据不得经过 MCP 客户端:客户端必须绝不看到第三方凭据以保护安全边界
- MCP 服务器不得为第三方服务使用客户端的凭据:那将是令牌透传,是被禁止的
- 用户必须直接授权 MCP 服务器:交互发生在 MCP 协议之外,不涉及 MCP 客户端
- MCP 服务器负责令牌:MCP 服务器负责存储和管理通过 URL 模式征询获得的第三方令牌(换言之,MCP 服务器必须是有状态的)。
有关额外背景,参阅安全最佳实践文档的令牌透传一节,以理解为何 MCP 服务器不能充当透传代理。
实现模式
在通过 URL 模式征询实现外部授权时:- MCP 服务器生成一个授权 URL,充当第三方服务的 OAuth 客户端
- MCP 服务器存储将征询请求与用户身份关联(绑定)的内部状态。
- MCP 服务器向客户端发送一个 URL 模式征询请求,带一个可以启动授权流程的 URL 和一个可选的
requestState(如果需要),后者编码关于征询请求和用户的信息。 - 用户直接与第三方授权服务器完成 OAuth 流程
- 第三方授权服务器重定向回 MCP 服务器
- MCP 服务器安全地存储第三方令牌,绑定到用户的身份
- 未来的 MCP 请求可以利用这些存储的令牌对第三方资源服务器进行 API 访问
错误处理
服务器**不应(SHOULD NOT)假定征询请求将总是成功,并必须(MUST)**处理用户拒绝或取消征询,或客户端未能处理请求的情况。安全考量
- 服务器**必须(MUST)**将征询请求绑定到客户端和用户身份
- 客户端**必须(MUST)**清晰地指示哪个服务器在请求信息
- 客户端**应当(SHOULD)**实现用户批准控件
- 客户端**应当(SHOULD)**允许用户随时拒绝征询请求
- 客户端**应当(SHOULD)**以一种清楚表明正在请求什么信息以及为什么的方式呈现征询请求
安全的 URL 处理
请求征询的 MCP 服务器:- **不得(MUST NOT)**在 URL 征询请求中发送给客户端的 URL 中包含关于最终用户的敏感信息,包括凭据、个人可识别信息等。
- **不得(MUST NOT)**提供一个预认证以访问受保护资源的 URL,因为该 URL 可能被恶意客户端用来冒充用户。
- **不应(SHOULD NOT)**在表单模式征询请求的任何字段中包含旨在可点击的 URL。
- 对于非开发环境**应当(SHOULD)**使用 HTTPS URL。
- **不得(MUST NOT)**自动预取该 URL 或其任何元数据。
- **不得(MUST NOT)**在未经用户显式同意的情况下打开该 URL。
- **必须(MUST)**在同意之前向用户显示完整的 URL 以供检查。
- **必须(MUST)**以一种不使客户端或 LLM 能够检查内容或用户输入的安全方式打开服务器提供的 URL。例如,在 iOS 上,SFSafariViewController 是好的,但 WkWebView 不是。
- **应当(SHOULD)**高亮 URL 的域名以缓解子域名欺骗。
- **应当(SHOULD)**对模糊/可疑的 URI(即包含 Punycode)发出警告。
- **不应(SHOULD NOT)**在征询请求的任何字段中将 URL 渲染为可点击,URL 征询请求中的
url字段除外(受上面详述的限制约束)。
识别用户
服务器**不得(MUST NOT)在没有服务器验证的情况下依赖客户端提供的用户标识,因为这可以被伪造。相反,服务器应当(SHOULD)**遵循安全最佳实践。 非规范性示例:- 不正确:将像 “I am joe@example.com” 这样的用户输入视为权威
- 正确:依赖授权来识别用户
表单模式安全
- 服务器**不得(MUST NOT)**通过表单模式请求敏感信息(密码、API 密钥等)
- 客户端**应当(SHOULD)**对照所提供的 schema 校验所有响应
- 服务器**应当(SHOULD)**校验收到的数据匹配所请求的 schema
钓鱼
URL 模式征询返回一个攻击者可用来发送给受害者的 URL。MCP 服务器在接受信息之前**必须(MUST)**验证打开该 URL 的用户的身份。 通常,身份验证通过利用 MCP 授权服务器来识别用户完成,通过浏览器中的会话 cookie 或等价物。 例如,URL 模式征询可用于执行 OAuth 流程,其中服务器充当另一个资源服务器的 OAuth 客户端。没有适当的缓解措施,以下钓鱼攻击是可能的:- 一个连接到良性服务器的恶意用户(Alice)触发一个征询请求
- 良性服务器生成一个授权 URL,充当第三方授权服务器的 OAuth 客户端
- Alice 的客户端显示该 URL 并请求同意
- 与其自己点击链接,Alice 诱骗同一良性服务器的一个受害用户(Bob)点击它
- Bob 打开链接并完成授权,以为他们在授权自己到良性服务器的连接
- 良性服务器从第三方授权服务器收到一个回调/重定向,并假定这是 Alice 的请求
- 第三方服务器的令牌被绑定到 Alice 的会话和身份,而不是 Bob 的,导致账户被接管
https://mcp.example.com/connect?... 而不是第三方授权端点的 URL 模式征询。这个”connect URL”必须确保打开该页面的用户与征询所针对的用户是同一个用户。例如,它会检查用户有一个有效的会话 cookie,且该会话 cookie 针对的是使用 MCP 客户端生成该 URL 模式征询的同一个用户。这可以通过比较来自 MCP 服务器授权服务器的权威主体(sub claim)与来自会话 cookie 的主体来完成。一旦该页面确保是同一用户,它就可以将用户发送到位于 https://example.com/authorize?... 的第三方授权服务器,在那里可以完成一个正常的 OAuth 流程。
在其他情况下,服务器可能无法通过 Web 访问,也可能无法使用会话 cookie 来识别用户。在这种情况下,服务器必须使用一种不同的机制来识别打开征询 URL 的用户与征询所针对的用户是同一个用户。
在所有实现中,服务器**必须(MUST)**确保用于确定用户身份的机制能够抵御攻击者可以修改征询 URL 的攻击。