附录 A.3 常见报错排查与 v1→v2 迁移
本节摘要:附录最后一节,两部分内容。第一部分是常见报错与排查——按高频症状组织的「报错→原因→排查」三列表,覆盖连接、能力、协议版本、交互、平台五类问题。第二部分是 v1(FastMCP)→v2(MCPServer)迁移要点——给一张「旧写法→新写法」的对照表,让维护存量代码的读者快速迁移。本节是实战救急与版本迁移的入口。
一、常见报错:连接类
| 现象 |
多半原因 |
排查 |
| stdio 客户端连不上 |
command 不在 PATH、文件路径错 |
手动跑 command 确认能起;用绝对路径 |
| stdio 服务端拿不到环境变量 |
默认白名单不传 |
显式传 env(第 8.2 节) |
| HTTP 客户端连接超时 |
服务端没起、网络问题 |
检查 URL、服务端状态、防火墙 |
| HTTP 报 DNS 重绑定错误 |
默认只允许 localhost |
配置 allowed_hosts(第 8.5 节) |
| 检查器找不到服务 |
文件里没模块级 mcp 变量 |
确保 mcp = MCPServer(...) 在顶层 |
| 子进程僵尸 |
异常退出未清理 |
用 async with 确保清理 |
二、常见报错:能力类
| 现象 |
多半原因 |
排查 |
| 工具/资源/提示词不出现 |
没注册(不注册不声明) |
确认装饰器加了、server_capabilities 里有对应能力 |
| 补全不工作 |
没注册补全处理器 |
注册 @mcp.completion 才声明 completions(第 5.4 节) |
| 客户端报「方法不存在」 |
服务端没声明该能力 |
print(client.server_capabilities) 看声明了什么 |
| 动态加的工具客户端看不到 |
客户端没收到 list_changed |
确认 list_changed: True、客户端重新 list |
| 引导填写失效 |
客户端没声明 elicitation |
客户端构造时声明支持 elicitation(第 9.4 节) |
三、常见报错:协议版本类
| 现象 |
多半原因 |
排查 |
| 协议版本不兼容 |
客户端与服务端无共同版本 |
升级 SDK、检查 mode |
| legacy 与现代特性冲突 |
现代特性在 legacy 连接不工作 |
用 mode="auto" 或换现代连接 |
| initialize 握手失败 |
legacy 模式下握手异常 |
检查服务端是否支持 legacy、网络是否中断 |
| 引导填写的 MRTR 卡住 |
现代 MRTR 在 legacy 不工作 |
现代连接用 Resolve+Elicit,legacy 用 ctx.elicit(第 7.3 节) |
四、常见报错:交互类
| 现象 |
多半原因 |
排查 |
| 工具调用返回意外结果 |
没检查 is_error |
永远检查 result.is_error(第 9.3 节) |
| 模型乱调工具 |
工具描述/Schema 模糊 |
写清晰 docstring、用 Field 加约束(第 4.5 节) |
| 引导填写没弹窗 |
客户端不支持,或协议不匹配 |
确认客户端声明 elicitation、用现代连接 |
| 采样/根不工作 |
客户端没声明,或已弃用 |
第 7.4 节,新代码用 provider API/显式参数 |
| 进度上报没显示 |
客户端没监听 listen |
客户端用 listen() 收事件(第 10.4 节) |
五、常见报错:平台类(Windows)
| 现象 |
多半原因 |
排查 |
| Windows 子进程卡住 |
编码非 UTF-8、换行符问题 |
服务端设 UTF-8 输出、检查 CRLF/LF |
| 路径问题 |
反斜杠、空格 |
用原始字符串、引号包裹路径 |
| stdio 启动失败 |
Python 命令在 Windows 是 python.exe |
用完整可执行名或 py launcher |
| 子进程僵尸 |
Windows 进程清理机制不同 |
用 async with、显式 terminate |
六、v1→v2 迁移要点
网上大量教程是 v1 写法(FastMCP、旧 ClientSession),直接照抄会报错。下面是迁移对照表。
核心命名变化
| v1 旧名 |
v2 新名 |
说明 |
FastMCP |
MCPServer |
高层服务端类改名 |
from mcp.server.fastmcp import FastMCP |
from mcp.server import MCPServer |
导入路径变 |
旧 ClientSession(手动管理) |
第一类 Client(自动) |
v2 客户端升级 |
| (无 Resolve) |
Annotated[T, Resolve(fn)] |
v2 新增依赖解析 |
| (无 Elicit 对象) |
resolve.Elicit(...) |
v2 现代引导填写 |
工具定义:基本一致
# v1
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo")
@mcp.tool()
def add(a: int, b: int) -> int:
return a + b
# v2(几乎一样,只改导入与类名)
from mcp.server import MCPServer
mcp = MCPServer("Demo")
@mcp.tool()
def add(a: int, b: int) -> int:
return a + b
客户端:v2 简化
# v1(手动管理会话)
from mcp import ClientSession
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("add", {...})
# v2(第一类 Client,自动管理)
from mcp import Client
async with Client("http://...") as client: # 自动选传输、协商、初始化
result = await client.call_tool("add", {...})
引导填写:v2 现代写法
# v1(服务端直接发起)
result = await ctx.elicit(message="...", schema={...})
# v2 现代连接(Resolve 返回 Elicit + MRTR,推荐)
async def get_input(ctx):
return resolve.Elicit(message="...", schema={...})
@mcp.tool()
def op(confirmed: Annotated[bool, Resolve(get_input)]) -> ...: ...
# v2 legacy 连接(ctx.elicit 仍可用)
result = await ctx.elicit(message="...", schema={...})
协议版本:v2 默认现代
# v2 默认走现代协议(2026-07-28),无握手
async with Client(url) as client: ... # mode="auto",优先现代
# 如需强制 legacy
async with Client(url, mode="legacy") as client: ...
弃用项
| v1 能力 |
v2 现状 |
FastMCP 名字 |
改名 MCPServer,旧导入报错 |
| 服务端直接发起引导填写 |
现代协议不支持,用 Resolve+Elicit |
| 采样/根 |
仍在但显弃用趋势,新代码用替代 |
| SSE 传输 |
仍能工作但弃用,新代码用流式 HTTP |
七、迁移建议
| 情况 |
建议 |
| 新项目 |
全程 v2,别碰 v1 |
| 维护 v1 存量 |
暂时保留,规划迁移 |
| 照网上教程 |
认出 v1 写法,翻译成 v2 |
遇到 FastMCP 报错 |
改成 MCPServer + 新导入路径 |
💡 技巧:迁移的核心是「换名字 + 换写法」。FastMCP→MCPServer 换名字;客户端从手动 ClientSession→第一类 Client 换写法;引导填写从 ctx.elicit→Resolve+Elicit 换写法。业务逻辑(工具函数体)基本不变——这是 SDK 设计的连续性。
本节要点回顾
- 五类常见报错:连接、能力、协议版本、交互、平台,各有「报错→原因→排查」表。
- 能力问题排查第一步:
print(client.server_capabilities) 看声明了什么。
- 交互问题排查:检查
is_error、客户端能力声明、协议模式。
- Windows 平台:编码、路径、命令名、进程清理是高频坑。
- v1→v2 核心:
FastMCP→MCPServer、手动 ClientSession→第一类 Client、ctx.elicit→Resolve+Elicit。
- 业务逻辑基本不变,迁移主要是换名字与换写法。
- 新项目全程 v2,存量 v1 规划迁移,网上教程要认出 v1 写法翻译。
附录与全书结束。你已经拥有了从入门到精通 MCP Python SDK 的完整知识体系。