ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MCP 协议重大更新:Session 与 Sampling 废弃后的迁移指南

MCP 协议重大更新:Session 与 Sampling 废弃后的迁移指南 1. 这回真把地基拆了Session 和 Sampling 到底改了什么1.1 一句话看懂新版 MCP 的变化MCP 协议在 2025 年这轮更新里把 Session 这个概念从核心流程里摘掉了Sampling 也正式进入废弃通道。我刚从官方 SDK 的 changelog 里看到这消息时第一反应是“完了我手里几套教程全白写了”。如果你现在打开那些 2025 年初发布的、标题写着“从零玩转 MCP”的文章对照最新规范去跑代码大概率会遇到方法不存在、字段被移除、握手流程对不上的情况。我说的不是某个第三方插件的小调整是协议层的结构性改动。原来你学的那套“先建 Session再通过 Session 发请求”的思路在新规范里基本不成立原来你调用的 Sampling 接口现在要么被宿主应用接管要么就得换成别的方式实现。很多朋友可能觉得“协议更新关我什么事我跟着 demo 写就行”但协议一变所有基于它的 SDK、框架、平台服务都会跟着变你手上的代码迟早要适配。这篇文章不打算给你背一遍官方文档而是想把这次变化讲清楚Session 为什么被拿掉Sampling 为什么被废老教程的写法该怎么迁移以及以后怎么快速判断一套教程是否已经过期。适合正准备学 MCP、或者已经在生产环境里用 MCP 的开发者看尤其是那些依赖网上教程而不是官方规范的人。1.2 为什么大家会误以为“2025 年教程没过期”MCP 自打 2024 年底爆火以来迭代速度比大部分人的学习速度还快。最典型的情况是你跟着 B 站或掘金的一篇热门文章写好了 server三个月后官方 SDK 一升级代码直接编译不过。为什么这么容易踩坑因为很多教程是照着一两个稳定版本写的但协议本身并没有“稳定”到可以保证长时间不变。我复盘了一下自己的学习路径发现一个规律网上九成教程都在讲“MCP 是什么、怎么配一个文件服务器、怎么接大模型”很少人提醒你“去读当前版本规范”。而协议恰恰是最该看规范的地方。你只要在教程里看到initialize之后还要处理session/create这类旧字段或者看到sampling/createMessage这种旧接口基本可以判断这篇教程写的是老版本了。更麻烦的是搜索引擎会把旧文章排在最前面。2025 年发布的内容在 2025 年下半年看起来当然不算“旧”但协议恰恰在“上个月”发生了破坏性变化。所以最稳妥的办法不是收藏教程而是直接看官方仓库的 CHANGELOG 和 SDK 的版本更新说明。实际操作中我每次开始一个新项目前都会花十分钟确认三件事当前协议版本号、我用的 SDK 版本号、官方示例里有没有出现被废弃的关键字。这十分钟能省掉后续几小时的排查时间。2. Session 删除背后的设计逻辑2.1 从“建立连接”到“请求即上下文”旧版 MCP 的核心流程里客户端和服务器要先完成一次握手建立一个长期有效的 Session后续所有 JSON-RPC 请求都挂在 Session 下面。这种设计很符合直觉先打电话再说事。可它带来的问题是状态维护成本太高。服务器要记得每个 Session 的创建时间、权限、能力集、消息历史一旦 Session 失联还要做超时清理。新版的做法更干脆不维护全局 Session每个请求本身就是完整的上下文。你发一个tools/call里面就把客户端标识、能力列表、需要的数据全部带上服务器处理完就返回不保留中间状态。用生活化类比旧版是“你跟饭店订了个包间服务员全程只服务这个包间”新版是“你每次点菜都用同一个菜单但不需要固定座位”。这个改动让 MCP 彻底变得无状态。无状态意味着更容易做水平扩展服务器挂了可以随时换一台请求重发也不会有副作用。代价是什么呢开发者的心智要改过来不能再靠“把上下文存在 session 里”偷懒必须在请求参数里设计好完整的上下文信息。我实际改代码时最深的感受是以前偷懒写在 session 临时变量里的东西现在全部得显式传参。看着啰嗦但对于分布式场景和边缘计算来说这反而是最合理的取舍。2.2 对开发者的实际影响少写状态多写幂等Session 从协议核心消失影响最大的不是纯客户端调用而是那些“带状态”的服务端实现。比如老代码里常见这种逻辑用户登录后把 token 放进 session后续每个请求从 session 里取 token。新版协议不再帮你存这些你得在请求头或参数里自己带身份信息每次都携带。我遇到的一个实际项目里旧服务端用 session 缓存了一份很大的上下文每次请求都基于这份上下文做推理。改成无状态后缓存策略得挪到外部存储比如 Redis 或数据库请求进来时显式加载。这其实对系统健壮性更友好不再依赖单个进程的内存服务重启也不丢上下文了。另一个要注意的点是幂等性。以前请求在 Session 内按顺序执行重复发送的风险比较低现在每个请求独立处理同一个操作可能被客户端重试多次。所以服务端最好给每个请求设计request_id或者幂等键保证重复请求不会重复扣款、重复写库。坦白讲这个习惯在任何 API 设计里都该有只是 MCP 这次更新把它变成了硬性要求。2.3 迁移检查清单我整理了一份从旧 Session 思路迁移到新无状态写法的检查清单照着过一遍基本就能把老工程的坑踩平把代码里所有“从 session 取东西”的逻辑改成“从请求参数或上下文对象里取”。检查有没有依赖 session 的鉴权方式比如session.get(user_id)改成 JWT 或显式 Authorization 头。如果你用的是官方 SDK直接升级到最新版老的 Session API 很可能已经删了。给所有写操作加上幂等键至少留一个重试去重的字段。测试时故意把连接断开重连看看客户端是否能无感续传这是无状态服务必须通过的一项验证。按这个清单走一遍你会发现大部分迁移工作其实不复杂复杂的是心态以前习惯有状态地思考现在要换成“每次请求都是全新的”。用熟了以后调试起来反而更清爽因为一个请求一个响应日志链路清清楚楚。3. Sampling 被弃用以后我们还能怎么“让模型说话”3.1 老 Sampling 的诱人之处和它的坑Sampling 是什么简单说它允许 MCP 服务器在运行过程中反向要求客户端调用大模型生成一段文本或补全。这个能力听起来很爽服务器不再只是被动地提供工具而是能主动“让模型帮个忙”。比如你写了个文档分析服务器分析到一半发现需要给某个术语配个解释于是发起一次 sampling让大模型生成一段解释再继续分析。我第一次看到 Sampling 时觉得它是整个协议里最有想象力的设计但实际用起来问题一堆。首先是权限边界模糊。服务器只是通过 MCP 连接到了客户端客户端背后到底是什么模型、有没有权限、要不要花钱全都没有清晰的授权机制。这就好比一个外卖员进了你家厨房虽然没有钥匙但他可以直接从冰箱里拿食材做饭你不知道他哪次拿多了。其次是递归风险。服务器发起 sampling模型返回内容服务器可能又基于这个内容发起新的 sampling一不小心就变成无限循环。我在一个实验项目里真遇到过一次请求触发了几十次模型调用账单刷刷往上涨。协议设计者显然比我早吃过这些亏所以在新版里干脆把 Sampling 从标准流程里剥出去只保留“由宿主应用自行决定是否支持”的扩展口。表面上看是功能变弱了实际上是安全模型变清晰了模型调用必须由用户或宿主应用发起服务器不能偷偷调用。3.2 替代方案工具、资源、宿主能力弃用了 Sampling 不代表这个需求消失了。服务器想让模型帮忙在新规范里至少有三种正规路径第一条路径是把“让模型做某事”建模成工具。服务器自己定义好工具名和参数客户端调用模型后把结果以工具返回值的形式回传给服务器。这样整个流程是显式的、可审计的用户能看到模型在做什么。第二条路径是使用资源引用。如果服务器只需要给模型提供一段资料不要求模型生成结果完全可以用 resource 的方式暴露给客户端让客户端自己决定什么时候加载。这比偷偷调用 sampling 更透明。第三条路径是依赖宿主应用提供的原生能力。很多 MCP 客户端本身就有“把模型输出给你”的能力比如 Claude Desktop、各类 Agent 框架它们会按自己的权限规则决定是否调用模型。服务器不应该越俎代庖。我个人的建议是能用工具就用工具能传资源就传资源别老想着让服务器直接调模型。模型调用应该掌握在客户端手里这既是安全边界也是责任边界。新版规范等于替大家把这个边界画清楚了。3.3 权限模型的变化Sampling 被弃用本质上是权限模型从“服务器可主动发起动作”变成“一切动作都由客户端控制和委托”。这对生态建设是好事。以前服务器只要获得连接资格就能间接动用客户端的模型资源这是很危险的安全漏洞。现在新版要求每个敏感动作都要经过授权而且更强调 OAuth 和设备授权码这类标准流程。做企业级应用的朋友应该深有体会权限这东西宁可绕路也不能省。MCP 在这一点上终于想明白了。我写授权代码时踩过一个坑老版本里只要在 initialize 时声明支持 sampling客户端就无条件放行现在新版本里服务器如果还想请求模型能力必须先声明需要哪些 scope再由用户或管理员审批。流程变重了但至少每个人都知道“谁在什么时候用了什么能力”。所以你如果看到网上教程里还在教人用 sampling 实现“服务器自动写摘要”请自动把这段内容替换成“定义工具、声明权限、回传结果”。功能上能做到九成相似安全性却高了一个量级。4. 实操按新规范搭一个 MCP Server 和 Client4.1 先确认版本实操之前第一步永远是确认自己手里的依赖版本。我通常看三个地方首先是官方协议仓库的 README 和 CHANGELOG看当前主线版本是多少有没有标记 breaking change。其次是 SDK 的package.json或pyproject.toml看装上的是不是最新版。最后是跑一个官方示例看编译是否有废弃警告。以 Python 为例如果你还在用旧版 SDK代码里很可能出现from mcp.server.session import ServerSession这种导入。新版本 SDK 里这个路径基本已经移除了。正确做法是去官方仓库的 examples 目录里复制一份最新代码确认 import 路径和初始化方式再动手。我常用的判断方法是搜索自己代码里有没有session和sampling这两个词。如果有再看它是不是业务自建术语。如果发现是直接调用 SDK 的 Session API 或create_message那基本可以确定该升级了。升级不过是pip install --upgrade mcp或npm update modelcontextprotocol/sdk一条命令但升级之后要跑一遍回归测试因为接口变动会用编译错误直接给你提示。4.2 最小 server 实现新规范下一个最小的 MCP Server 其实比旧版更像“一个普通 JSON-RPC 服务”。下面我用伪代码演示结构真实项目里请换成官方的 FastMCP 或同类封装from mcp.server.fastmcp import FastMCP mcp FastMCP(demo-server) mcp.tool() def add(a: int, b: int) - int: 两数相加纯函数无状态 return a b mcp.run(transportstdio)注意这里完全没有session相关的初始化也没有声明支持sampling。工具函数只接收参数、返回结果状态全部在调用方手里。如果要用 JSON-RPC 裸协议理解也行。新版里的请求大概长这样{ jsonrpc: 2.0, id: 1, method: tools/call, params: { name: add, arguments: {a: 1, b: 2} }, meta: { client_id: abc-123 } }响应则是标准的 JSON-RPC 返回不需要关联任何会话 ID。这种设计让抓包调试变得特别舒服你可以把每个请求独立地发给任意一个后端实例返回结果不受历史请求影响。4.3 Client 侧适配不要再用 session/sampling客户端适配同样简单。下面是一个发送工具调用的最小示例import { Client } from modelcontextprotocol/sdk/client/index.js; import { StdioClientTransport } from modelcontextprotocol/sdk/client/stdio.js; const transport new StdioClientTransport({ command: python, args: [server.py] }); const client new Client({ name: demo-client, version: 1.0.0 }); await client.connect(transport); const result await client.callTool({ name: add, arguments: { a: 1, b: 2 } }); console.log(result);关键点在于连接建立后不需要向服务器索取 session id也不要在后续调用里带 session 字段。你可能会在旧文档里看到类似client.session的属性新版里我已经不推荐再用了。若代码里出现.session的链式调用最好先查一下 SDK 版本。还要注意旧版客户端最常见的报错是“session not initialized”。新版里这个错误会变成“transport not connected”或“server capabilities not found”。意思类似但排查路径变了你不是去查 session 初始化顺序而是去查传输层有没有真正连上、服务器有没有声明对应能力。4.4 如何把老教程改造成新写法假设你手头有一篇老教程写得很好只是用的旧 API怎么快速改造成新规范我一般分四步第一步把所有session相关的初始化代码删掉。别想留个兼容层新协议下 Session 已经被移除兼容层等于自己造了个没人认的伪协议。第二步把sampling调用改成普通工具调用。比如旧代码里await session.sample(prompt)改成await client.callTool({ name: ask_model, arguments: { prompt } })。服务器侧实现一个ask_model工具内部再走自己的模型通道并在工具说明里标注权限。第三步重启所有能力协商流程。新版 initialize 里会交换 capabilities你看看服务器有没有声明tools、resources、prompts。如果服务器没有声明客户端根本不会发对应请求这是很多“工具调不通”的根源。第四步跑官方 example 做对照组。我几乎每次改完都会用一个官方最小 demo 验证环境没问题再逐步把我的逻辑加上去。这样能把“我的 bug”和“协议理解错误”严格区分开。改造过程听起来琐碎但真花不了太多时间。我最近帮一个同事迁移老项目总共也就两个晚上。真正花时间的不是改代码而是说服自己“旧思路已经不适用了”。5. 从老教程迁移的故障排查速查表5.1 常见报错一览我把这轮升级过程中容易遇到的报错整理成了表格方便大家直接对照报错信息常见原因新规下的处理方式Session not found服务器还在按旧协议维护 Session去掉 Session 管理改为无状态处理检查请求是否自带完整上下文Unknown method: session/create客户端调用了旧协议方法升级 SDK删除session/create、session/close等调用Sampling not supported服务器声明了旧能力但客户端不再支持改用工具或资源来传递模型调用需求不要依赖 samplingCapabilities not negotiatedinitialize 阶段能力声明不完整在 initialize 响应里里明确声明 tools/resources/prompts 支持Timeout waiting for response服务器在处理长任务但没有流式反馈改用tools/call的流式模式或分步轮询请求里带上_meta提示Deprecated: createMessage代码中仍使用旧 sampling API移除该调用改走工具流程Client transport already connected重复调用 connect 且旧连接未关闭每次连接前先 close或复用同一个 client 实例别小看这些报错很多都是“照着旧教程写然后报错查了半天”的典型场景。我把它们写下来是因为我本人至少踩过其中五个。5.2 排查方法论规范版本、SDK 版本、能力协商遇到 MCP 相关的问题我通常不急着看堆栈而是按顺序检查三个东西首先看规范版本。打开官方文档看当前最新版本号再对比你代码里的协议版本协商参数。如果 initialize 里写的版本和服务器支持版本对不上后面所有请求都会异常。其次看 SDK 版本。这一步最简单也最容易忽略。很多人用的是 IDE 自动补全出来的旧版本 SDK或者项目里 lock 文件锁了一个老版本。升级前建议先读一下官方变更日志确认你要用的功能没有被改名或删除。最后看能力协商。新版协议里客户端和服务器像两个人见面先互报技能树你说你会工具我说我会流式输出那么后面才有可能协作。如果能力没对上哪怕代码写得再对请求也会石沉大海。我遇到过不少次“代码完全没错但就是不响应”的情况最后查出来是 capabilities 没带上简直气死人。这三板斧看着简单能解决我遇到过的百分之八十的问题而且不依赖任何魔法就是老老实实核对版本、核对能力、核对日志。5.3 一个实战排查案例上个月我给一个内部工具升级遇到一个诡异现象客户端能连上服务器但调用任何工具都返回空结果。我一开始怀疑是业务代码问题后来抓了原始报文才发现服务器返回的内容里 capabilities 只有resources没声明tools。客户端一看你不支持工具就直接把 tools 相关的请求拦下了根本不发给服务器。原因是服务器在 initialize 时没有把tools列进能力列表而代码里确实定义了工具函数。改法特别简单在能力声明里补上tools: {}或者用框架默认值。但排查过程花了两个小时。如果早点检查能力协商一分钟就能定位。这件事之后我给自己定了个规矩凡是用框架搭的 MCP Server启动后先打一条日志把实际声明的能力打印出来和预期比对一次。这个案例给我们的启示是协议升级后很多“旧方法报错”其实都变成了“能力没对上”的静默失败。报错还好查最怕的就是不报错但行为不对。所以排查时一定不要只看应用层要下到协议层看原始消息。5.4 防止下一次被过时教程坑的经验最后分享几个我这几年总结出来的实在经验第一个经验是永远把官方文档放在浏览器收藏夹第一位。你可以不看教程但一定要会看规范。规范里看到Deprecated字样时说明这个功能已经进入倒计时了别再用它写新代码。第二个经验是学 MCP 不要只学一个 SDK最好同时看一下协议层是怎么定义消息的。很多教程直接把 API 包装成“神秘黑盒”遇到版本升级你就完全傻眼。但如果你理解 JSON-RPC 的基础结构版本再变你也能自己推断出新写法。第三个经验是每季度固定花半天做一次依赖升级和回归测试。协议类依赖特别容易出现连锁变更晚升不如早升。我在计划任务里加了这条已经救了我好几次。第四个经验是遇到不确定的写法先问官方示例再问搜索引擎。搜索引擎只会给你一堆复制粘贴的旧代码而官方示例永远是紧跟当前版本的。两者冲突时以官方示例为准。说实话MCP 这次把 Session 和 Sampling 拿掉短期确实让很多人难受但这恰恰说明协议在往更成熟的方向走。那些还停在 2025 年的教程不是没用它们教会了我们基础概念但要真正把 MCP 用好还是得学会跟着协议版本往前走而不是守着旧 API 过日子。我个人的体会是能不能跟上协议变化本质上取决于你是在“学一个工具”还是在“学一种思想”。工具会过期思想不会。新版 MCP 用无状态的请求模型和显式的工具调用把 Agent 之间的协作方式定义得更干净了。顺着这个思路走你不仅能看懂新版代码还能预判下一次协议更新会朝哪个方向去。这比多记几个 API 重要得多。
返回列表