Skip to main content
多轮往返请求(Multi Round-Trip Requests,MRTR)在本版本的 MCP 规范中引入。它替换了之前发送服务器发起请求的方法。服务器**必须(MUST)**使用 MRTR 模式发送服务器到客户端的请求(例如 roots/listsampling/createMessageelicitation/create)。之前的服务器发起请求模式不再受支持。这是一个破坏性变更。
为简洁起见,本页的请求示例省略了 _meta 请求元数据(io.modelcontextprotocol/protocolVersionio.modelcontextprotocol/clientInfoio.modelcontextprotocol/clientCapabilities)。每个请求**必须(MUST)**包含必需的 _meta 字段;参见 _meta

多轮往返请求

模型上下文协议(MCP)定义了若干方式,供服务器在处理客户端请求(例如 roots/listsampling/createMessageelicitation/create)期间向用户请求额外信息。多轮往返请求模式提供了一种标准化的方式来处理这些服务器请求,而无需跨服务器实例的共享存储层,也无需有状态的负载均衡。 高层流程运作如下:
  1. 客户端向服务器发送一个初始请求,带有执行操作所需的参数。
  2. 服务器确定需要额外信息来完成该请求,并以请求更多信息的方式响应。
  3. 客户端从用户或其他来源收集所请求的信息,然后重试原始请求,其中包含额外请求的信息。
  4. 服务器确定它有足够的信息来完成操作,并以最终结果响应。

核心类型

此流程在 MCP 中使用以下类型实现。

InputRequests

一个 InputRequests 对象是一个服务器-客户端请求的映射。键是服务器分配的字符串标识符;值是请求对象(例如 ElicitRequestCreateMessageRequestListRootsRequest)。

InputResponses

一个 InputResponses 对象是一个客户端对服务器请求的响应的映射。键对应于 InputRequests 映射中的键;值是客户端对每个请求的结果(例如 ElicitResultCreateMessageResultListRootsResult)。

InputRequiredResult

一个 InputRequiredResult 是一种 Result,表示在请求可以完成之前需要额外的输入。
  • inputRequests可选):一个 InputRequests 映射,包含客户端必须完成的服务器发起请求。
  • requestState可选):一个仅对服务器有意义的不透明字符串。客户端**不得(MUST NOT)**检查、解析、修改或对其内容做出任何假设。

受支持的请求

服务器**可以(MAY)**在以下客户端请求上发送 InputRequiredResult 响应: 服务器**不得(MUST NOT)**在任何其他客户端请求上发送 InputRequiredResult 响应。

基本工作流

基本工作流描述服务器如何作为客户端-服务器请求的一部分向客户端请求额外的输入。在本示例中,我们使用 tools/call 作为客户端请求,但同样的模式适用于上面列出的任何受支持的请求。 值得注意的是,它允许服务器在不维护任何服务器端状态的情况下请求额外信息。服务器将任何所需的上下文编码到 requestState 字段中,客户端在重试时将其回传。 请注意,每个步骤中的请求是完全独立的:处理重试的服务器不需要任何超出重试请求中直接存在的信息之外的信息。

服务器要求(基本工作流)

  1. 服务器**可以(MAY)**以一个 InputRequiredResult 响应任何受支持的客户端请求
  2. InputRequiredResult **可以(MAY)**包含一个 inputRequests 字段。
  3. InputRequiredResult **可以(MAY)**包含一个 requestState 字段。如果指定,此字段是一个仅对服务器有意义的不透明字符串。服务器可以自由地以任何格式编码状态(例如 base64 编码的 JSON、加密的 JWT、序列化的二进制)。
  4. 如果一个客户端请求包含一个 requestState 字段,服务器**必须(MUST)requestState 视为攻击者控制的输入。如果 requestState 影响授权、资源访问或业务逻辑,服务器必须(MUST)保护其完整性(例如 HMAC 或 AEAD),并必须(MUST)拒绝未通过验证的状态。仅当篡改不会造成比请求失败更糟的后果时,才可以(MAY)**省略完整性保护。
  5. 为防止重放,服务器**应当(SHOULD)**在受完整性保护的 requestState 负载内包含以下内容,并在接收时逐一验证:
    • 已认证的主体(principal),拒绝由不同主体出示的状态。
    • 一个短的过期时间(TTL),拒绝在其失效后出示的状态;
    • 一个发起请求的标识符,例如方法名及其显著参数的摘要,拒绝在不匹配的请求上出示的状态。
      请注意,这些措施限制了重放窗口并防止跨用户和跨请求的重用,但它们本身并不保证单次使用。对于给定的 requestState 必须至多被消费一次的服务器(例如一次性兑换),**必须(MUST)**在服务器端强制执行该不变量。
  6. 服务器**必须(MUST)**在每个 InputRequiredResult 响应中至少包含 inputRequestsrequestState 之一。
  7. 服务器**不得(MUST NOT)发送客户端未在其能力中声明支持的 inputRequests。例如,如果客户端不声明对 elicitation 的支持,服务器不得(MUST NOT)**在 inputRequests 字段中包含任何 elicitation/create 请求。
  8. 服务器**不得(MUST NOT)假定客户端会完成 inputRequests 或重试原始请求。如果服务器想要反复提示用户提供信息,直到它有了完成请求所需的内容,它可以(MAY)**选择在同一请求的多次尝试中返回 InputRequiredResult

客户端要求(基本工作流)

  1. 如果客户端收到一个包含 inputRequests 字段的 InputRequiredResult,客户端**必须(MUST)在重试原始请求之前构造所请求的输入。如果 InputRequiredResult _不_包含 inputRequests 字段,客户端可以(MAY)**立即重试原始请求。
  2. 如果一个 InputRequiredResult 包含 requestState 字段,客户端在重试原始请求时**必须(MUST)回传该字段的确切值。客户端不得(MUST NOT)检查、解析、修改或对 requestState 内容做出任何假设。如果 InputRequiredResult 不包含 requestState 字段,客户端不得(MUST NOT)**在重试中包含一个。
  3. JSON-RPC id 在初始请求和重试之间**必须(MUST)**不同,因为它们是独立的请求。
  4. inputRequestsrequestState 字段都只影响客户端对原始请求的重试。它们**不得(MUST NOT)**用于客户端可能并行发送的任何其他请求。

错误处理

服务器**应当(SHOULD)**校验客户端所提供的数据是一个有效的 InputResponses 对象,并且其中的信息可以被正确解析。协议错误(格式错误的 JSON、无效的 schema、内部服务器错误)**应当(SHOULD)**返回一个带有适当错误代码和消息的 JSON-RPC 错误响应。 如果 InputResponses 对象中提供了额外的、意外的参数,服务器**应当(SHOULD)**忽略任何它不识别或不需要的信息。 如果客户端未能发送先前 InputRequests 中所请求的所有信息,且缺失的信息是服务器处理请求所必需的,服务器**应当(SHOULD)**以一个新的 InputRequiredResult 响应,再次请求缺失的信息,而不是返回一个错误。

安全考量

由于 requestState 经过客户端,恶意或被入侵的客户端可能试图修改它以改变服务器行为、绕过授权检查或破坏服务器逻辑。服务器**必须(MUST)**如上面服务器要求中所述校验请求状态。