MCP 大结果报 SSE stream ended
MCP 小结果正常、大工具列表或结果报 SSE stream ended,核对单事件 1 MiB 限制,在支持的 Python SDK 中设置有限上限,并保留重试与版本边界。
MCP 小工具结果能返回,工具列表或较大的结果却报 SSE stream ended without a response,甚至让网关显示零个工具。如果请求已经得到 HTTP 200,响应类型也是 text/event-stream,应继续查看 SSE 解码异常:
Server-sent event exceeded the 1048576 byte limit
这里限制的是单个 SSE 事件,默认上限为 1 MiB。它与整条连接累计传输了多少数据、模型上下文长度、网络包大小都不是一回事。一个合法的 JSON-RPC 结果,也可能在交给 MCP 解析之前就被这个限制挡住。
先确认是否撞到了单事件上限
这一表现已有 Python SDK 2.0.0、2.1.1 的实际反馈,涉及大工具目录和较大的工具结果。不能仅凭 SSE stream ended 就认定是大小限制:代理提前断开、真实网络中断、畸形 JSON 和端点返回 406,分别需要检查自己的原因。
对照已有异常链和受控响应,确认单个事件的实际字节数。计数发生在事件解析之前,不宜用 Python 字符数或结果中的 token 数代替。含非 ASCII 内容时,字符数尤其不能直接当作字节数。
还要区分传输方式。这里讨论 Streamable HTTP 中的 SSE 响应;直接返回 JSON 的响应不受这项 SSE 上限影响,旧的独立 SSE transport 也不能照搬下面的配置。
在实际 MCP transport 上设置有限上限
Python SDK 2.3.0 正式接口提供 max_sse_event_size,默认仍为 1 MiB。它没有自动取消大小限制,而是允许调用方按服务的结果规模设置上限。
下面展示在异步客户端中配置 4 MiB 单事件上限的写法。地址是本机 MCP 服务示例,实际应用应使用原有的可信端点;4 MiB 只是配置示例,是否足够要按实际结果及并发内存预算确定。
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
async def main() -> None:
transport = streamable_http_client(
"http://localhost:8000/mcp",
max_sse_event_size=4 * 1024 * 1024,
)
async with Client(transport) as client:
result = await client.list_tools()
print([tool.name for tool in result.tools])
使用 ClientSessionGroup 时,在对应的 StreamableHttpParameters 上设置同一个选项。通过框架或网关调用 SDK,则要确认这一配置确实传给了底层 MCP 客户端,不能只改外层同名参数。
这项设置会作用于 POST 响应、GET 事件流和恢复后的事件流。自建 httpx2.AsyncClient 上另一处 SSE 配置,不能替代 MCP 内部 reader 的设置。使用自建 HTTP 客户端时,继续保留原有认证、代理、超时和 TLS 校验;这些配置仍由 HTTP 客户端负责。
旧 SDK 没有该参数时,应先选择接口兼容、包含正式支持的版本,核对应用依赖。1.x 应用不能未经迁移检查直接复制 2.x 的调用方式。也不应把修改私有 EventSource 或关闭所有大小限制当作首选方案。
大结果能读完,还要保留失败边界
调整后,用原先失败的工具列表或结果确认客户端真正解析到了内容。工具目录较大时,检查数量和预期工具是否齐全;HTTP 200 或日志不再打印异常,不足以证明目录可用。
超过新上限的事件仍应失败。2.3.0 对 POST 响应及恢复流中的 SSE 错误会给出针对该请求的原因;后台 GET 流则记录错误并重试事件流。不要把这种流恢复理解成业务工具调用可以任意重放。
尤其是已经提交过写入或其他有副作用的工具请求,读取结果失败不代表服务端没有执行。重试前应核对操作结果和幂等约束,不能因为 SSE 被截断就自动重发业务 POST。
如果结果规模持续增长,也应减少不必要的目录元数据,或在服务端支持、客户端能正确跟随游标的前提下分页。提高事件上限会允许更大的缓冲与后续 JSON 解析开销;对来源和规模不可控的响应,保留有限上限仍然有用。


