Skip to main content
已接受标准轨道
字段
SEP2260
标题要求服务器请求必须与客户端请求关联。
状态已接受
类型标准轨道
创建时间2026-02-16
作者MCP 传输层工作组
赞助人@CaitieM20 - Caitie McCaffrey
PR#2260

摘要

本 SEP 阐明了 roots/listsampling/createMessageelicitation/create 请求 必须 与发起的 客户端到服务器请求关联(例如,在 tools/callresources/readprompts/get 处理期间)。不得 实现这些类型的 独立服务器发起请求(不在通知内)。 尽管当前的 MCP 数据层未强制执行,但在逻辑上这些请求 必须 与有效的客户端到服务器 JSON-RPC 请求 ID 关联。 操作性的服务器到客户端 Ping 不受此限制。

动机

当前规范

当前规范在传输层使用 应该 措辞: 在可流式 HTTP 传输中响应 POST 请求的上下文中 (2025-11-25/basic/transports.mdx:121-L123)
  • “服务器 可以 在发送 JSON-RPC 响应 之前发送 JSON-RPC 请求通知。这些消息 应该 与发起的客户端 请求 相关。”
对于可选的 GET SSE 流 (2025-11-25/basic/transports.mdx:146-L148)
  • “服务器 可以 在流上发送 JSON-RPC 请求通知。”
  • “这些消息 应该 与任何并发运行的客户端 JSON-RPC 请求 无关。”
尽管 GET 流允许“未经请求的”请求,但其使用完全是可选的,MCP 服务器作者不能依赖它。

设计意图

MCP 服务器请求的设计意图是反应式地 嵌套在 其他 MCP 操作中运行:
  • 采样 使服务器能够在处理工具调用、资源请求或提示时请求 LLM 协助
  • 征询 使服务器能够收集完成操作所需的额外用户输入
  • 列出根目录 使服务器能够识别共享存储位置
Ping 具有特殊状态,因为它主要旨在作为保持活动/健康检查机制。 对于可流式 HTTP 服务器,如果没有通知或请求可发送,这使得 SSE 流能够维持较长时间。对于客户端到服务器请求,它们是可关联的。未来的传输实现将消除对独立 Ping 的需求。 当前规范已经描述了此模式:
“MCP 中的采样允许服务器实现代理行为,通过使 LLM 调用能够 嵌套 在其他 MCP 服务器功能内部发生。”
然而,规范性要求并未强制执行此约束。

简化带来的好处

使此约束明确化:
  1. 简化传输层实现 - 传输层不需要支持任意服务器发起的请求/响应流(这需要从服务器到客户端的持久连接);它们只需要请求范围内的双向通信
  2. 澄清用户体验 - 用户理解采样/征询发生是因为他们发起了操作,而不是自发发生的
  3. 减少安全面 - 确保客户端了解额外请求的信息将用于什么范围。这允许客户端就是否提供请求的信息做出更明智的决定。
  4. 与实践保持一致 - 基于对 GitHub 的扫描,所有现有实现都已遵循此模式,除了一个由 SEP 作者拥有的具有虚构场景的仓库。

规范变更

1. 在功能文档中添加警告块

client/sampling.mdx 中(现有安全警告之后):
<Warning>

**请求关联要求**

服务器 **必须** 仅在与发起的客户端请求关联时发送 `sampling/createMessage` 请求(例如,在 `tools/call`、`resources/read` 或 `prompts/get` 处理期间)。

不支持在独立通信流上(与任何客户端请求无关)独立服务器发起的采样,并且 **不得** 实现。未来的传输实现不需要支持此模式。

</Warning>
client/elicitation.mdx 中(现有安全警告之后):
<Warning>

**请求关联要求**

服务器 **必须** 仅在与发起的客户端请求关联时发送服务器到客户端请求(例如 `roots/list`、
`sampling/createMessage` 或 `elicitation/create`)(例如,在 `tools/call`、`resources/read` 或
`prompts/get` 处理期间)。

不支持在独立通信流上(与任何客户端请求无关)独立服务器发起的此类请求,并且
**不得** 实现。未来的传输实现不需要
支持此模式。

</Warning>
client/roots.mdx 中(在 用户交互模型 部分):
<Warning>

服务器 **必须** 仅在与发起的客户端请求关联时发送服务器到客户端请求(例如 `roots/list`、
`sampling/createMessage` 或 `elicitation/create`)(例如,在 `tools/call`、`resources/read` 或
`prompts/get` 处理期间)。

不支持在独立通信流上(与任何客户端请求无关)独立服务器发起的此类请求,并且
**不得** 实现。未来的传输实现不需要
支持此模式。

</Warning>
basic/utilities/ping.mdx 中(在 概述 部分):
<Warning>

`ping` 是 MCP 级别的活性检查,**可以** 由任何一方在
已建立的会话/连接上的任何时间发送。

在可流式 HTTP 中,实现 **应该** 优先使用传输级 SSE
保持活动机制进行空闲连接维护;`ping` 仍然可用于
协议级响应性检查。

`roots/list`、`sampling/createMessage`、
和 `elicitation/create` 的请求关联要求不适用于 `ping`。

</Warning>

2. 澄清传输层约束

basic/transports.mdx 中,POST 发起的 SSE 流(第 ~121 行):
- 服务器 **可以** 在发送
- JSON-RPC _响应_ 之前发送 JSON-RPC _请求_ 和 _通知_。这些消息 **应该** 与发起的客户端
- _请求_ 相关。
+ 服务器 **可以** 在发送
+ JSON-RPC _响应_ 之前发送 JSON-RPC _请求_ 和 _通知_。这些消息 **必须** 与发起的客户端
+ _请求_ 相关。
basic/transports.mdx 中,GET 发起的独立 SSE 流(第 ~147 行):
- 服务器 **可以** 在流上发送 JSON-RPC _请求_ 和 _通知_。
- 这些消息 **应该** 与任何并发运行的客户端 JSON-RPC
- _请求_ 无关。
+ 服务器 **可以** 在流上发送 JSON-RPC _通知_ 和 _pings_。
+ 这些消息 **应该** 与任何并发运行的客户端 JSON-RPC
+ _请求_ 无关,**除了** `roots/list`、
+ `sampling/createMessage` 和 `elicitation/create` 请求 **不得**
+ 在独立流上发送。

向后兼容性

影响评估

预计此变更对现有实现的影响 最小或没有
  1. 保留了常用模式 - 工具执行、资源读取和提示处理内的采样/征询仍然完全支持
  2. 没有已知实现受影响 - 在 GitHub 上进行的研究显示只有一种此模式的实现。这一单一实现由 SEP 作者拥有。

禁止的内容

以下模式从未明确记录或推荐,现在被明确禁止:
# ❌ 禁止:独立服务器推送
async def background_task():
    while True:
        await asyncio.sleep(60)
        # 尝试在没有客户端请求上下文的情况下发起采样
        await session.create_message(...)  # 不允许

保留支持的内容

规范模式仍然完全支持:
# ✅ 支持:工具执行期间的采样
@mcp.tool()
async def analyze_data(data: str, ctx: Context) -> str:
    # 在处理工具调用时请求 LLM 分析
    result = await ctx.session.create_message(
        messages=[SamplingMessage(role="user", content=...)]
    )
    return result.content.text

实现指南

对于服务器实现者

如果您的服务器:
  • 仅在工具处理程序中使用服务器到客户端请求
  • 仅在资源/提示处理程序中使用服务器到客户端请求
  • 作为处理客户端请求的一部分同步使用服务器到客户端请求
不需要更改 如果您的服务器:
  • 尝试在独立 HTTP GET 流上发起服务器到客户端请求
  • 尝试发送独立于客户端操作的服务器到客户端请求
  • 有尝试调用服务器到客户端请求的后台任务
需要更改 对于“需要更改”的情况,将需要实施替代设计。 鼓励执行未经请求的服务器到客户端请求(通常是 URL 征询)的实现者在初始化后立即在需要来自客户端的该信息的客户端到服务器请求范围内延迟执行这些请求。

超时考虑

当 MCP 服务器在客户端请求内发起“嵌套”请求时,父请求的持续时间会扩展以包括用户的响应时间。 实现者 必须 确保:
  1. 传输超时(例如 HTTP 请求超时)足以容纳“人工介入”延迟,这可能是无界的。
  2. 基础设施强制的短超时(例如负载均衡器)可能导致 在用户响应之前连接终止。对于可流式 HTTP, 应该 使用传输级 SSE 保持活动机制来保持 连接活动并重置计时器;ping 请求 可以 另外用于 协议级响应性检查。

对于客户端实现者

不需要更改 - 客户端应该已经在其自己的出站请求上下文中处理采样/征询请求。如果当前支持带外通信,则有可能简化实现。 客户端接收没有关联出站请求的服务器到客户端请求 应该 响应 -32602(无效参数)错误。

对于传输层实现者

未来的传输实现可以依赖以下保证:
  • 采样/征询请求仅发生在客户端发起请求的范围内
  • 传输层不需要支持独立通道上任意服务器发起的请求/响应流
  • 请求关联和生命周期管理被简化

时间线

(本 SEP 旨在作为未来协议版本变更的公开通知,这些版本将不兼容此用法)

考虑的替代方案

1. 软弃用

使用 SHOULD NOT 措辞来不鼓励但不禁止该模式。 拒绝原因: 该行为从未被有意支持,且保留其模糊性会阻碍传输简化。

2. 保持当前模糊性

保持现有的 SHOULD 措辞不变。 拒绝原因: 这会阻碍未来的传输实现,并使实现者不确定该模式是否受支持。

3. 创建能力标志

为想要此行为的服务器添加 sampling.standalone 或类似的能力。 拒绝原因: 这为一个没有已知需求的用例增加了复杂性,并且违背了“嵌套”设计原则。

参考

  • 当前采样文档:/specification/draft/client/sampling.mdx
  • 当前引导文档:/specification/draft/client/elicitation.mdx
  • 传输规范:/specification/draft/basic/transports.mdx
  • 客户端概念文档中的用户交互模型讨论