mcp server 调用失败 怎么排查

接入与开发

把 MCP Server 调用失败拆成连接、握手、工具发现、参数与超时几段,给出一套能照着走的排查顺序。

本地能跑通的 MCP Server,接进客户端就报错,这类问题最烦的地方是报错信息往往只说「调用失败」,不说是哪一段断了。这篇按调用链的顺序给你一份排查清单:从进程起没起来、握手有没有过、工具列表拿到没有,到参数校验和超时,按顺序走一遍,基本能定位到具体环节。

本地能跑通的 MCP Server,接进客户端就报错,这类问题最烦的地方是报错信息往往只说「调用失败」,不说是哪一段断了。排查的第一原则是:别急着改配置,先把这次失败归到调用链的某一段上,再动手。

下面按调用链顺序给你一份排查清单:从进程起没起来、握手有没有过、工具列表拿到没有,到参数校验和超时。旁边备两样东西:客户端的日志和 Server 自己的 stderr 输出,只有一边的日志经常看不出问题。

先分清是「连不上」还是「调不动」

很多人一上来就翻配置,其实先该做的是给失败现象分类。同样一句「调用失败」,落在不同阶段,排查方向完全不同。先分类再动手,能省掉一半瞎试的时间。

现象大概率断在哪先看什么
进程根本没起来进程启动 / 环境客户端日志里有没有 spawn 报错、命令能不能手打跑通
连上了但初始化就断握手 / 协议版本两边日志里初始化阶段的第一条错误
握手成功、列工具失败Server 侧工具注册Server stderr 有没有启动期异常
列得出工具、调就报错参数 / 权限 / 返回格式这次调用传了什么参数、返回体长什么样
  • 记下报错原文,别只记「失败了」,原文里的字段名和阶段名往往就是线索
  • 记下失败发生在哪个动作:启动、列工具清单、还是具体调某个工具
  • 客户端日志和 Server 的 stderr 两边都看,互相对时间点,能定位是哪一侧先断的
  • 如果报错是客户端自己包装过的通用文案,优先去找原始错误,而不是照着通用文案猜

传输方式与进程启动:最常见的两类翻车

MCP Server 接不进来,绝大多数问题出在两处:stdio 方式下进程压根没起来,或者 HTTP/SSE 方式下地址根本不通。这两个都属于环境层面,跟工具逻辑无关。

stdio:命令在客户端环境里能不能跑

  • 命令用绝对路径,别依赖 PATH,客户端进程的 PATH 和你终端里的经常不是一套
  • 依赖装在哪个环境要确认清楚,用了虚拟环境或版本管理工具时尤其容易错位
  • 工作目录不一样会导致相对路径的配置、脚本、数据文件全部找不到
  • 先在你自己的终端里按客户端那套参数原样跑一遍,能跑通再谈配置

HTTP / SSE:地址本身通不通

  • 核对协议、地址、端口、路径后缀,少一段前缀或后缀就是连不上
  • 绕过客户端,直接用命令行请求一次这个地址,先确认 Server 在监听
  • 端口被占用、Server 只监听本机回环地址而客户端跑在容器里,都会表现成「连不上」
  • 涉及鉴权的,确认请求头有没有带、格式对不对,这类失败常常被包装成通用网络错误

如果你是在中转站环境下接的 Server,先确认中转那层的地址和鉴权是否正常,再去纠结工具逻辑。中转站本身的可用性和延迟表现可以到 /tools/speed-test 做个体检,把「网络这层没问题」先排除掉。

握手与工具列表:能连上但拿不到工具

进程起来了、连接也通了,但客户端里看不到任何工具,或者一列工具就报错,问题基本落在初始化握手和工具注册这两步。这一步的关键判断是:工具清单到底列出来没有。

列不出来
问题在 Server 侧,重点看它启动时注册工具有没有抛异常
列得出来但调不动
问题多半在参数、权限或返回格式,往下走第三节
只列出部分工具
某个工具的注册代码有问题,会连累整个清单或后续调用
  • 初始化阶段会校验协议版本和能力声明,版本对不上通常在这一步直接断,优先看两边日志的版本字段
  • 工具名、描述、参数 schema 写得含糊,模型容易选错工具或漏填参数,表现上就像「调用失败」
  • 每个工具的必填项和类型写清楚,能挡掉大量后续的参数类报错
  • 改完工具描述后重启 Server 再试,很多客户端会缓存工具清单,不重启看不到变化

参数、超时与返回体:真正调下去之后才出的错

工具清单能列出来,说明链路已经通了,剩下的错误都发生在「这一次具体调用」上。这类问题最好定位,因为可复现,但也最容易被误判成 Server 坏了。

  1. 核对参数类型按工具声明的 schema 一项项对,数字传成字符串、布尔传成字符串都是高频错误;对照报错里提到的字段名去看。
  2. 检查有没有多包一层参数被额外包进一层对象或数组,Server 侧解析时拿不到字段,报错文案往往很含糊。
  3. 确认必填项齐了缺必填字段通常报错很直接,但如果必填项是嵌套结构里的,容易被忽略。
  4. 看超时停在哪一段区分连接超时和读取超时,前者是连不上,后者是连上了但 Server 迟迟不回,处理方向不同。
  5. 对齐返回格式Server 返回纯文本而客户端按结构化解析,会直接抛错;返回体要和工具的声明保持一致。

超时上限别设成默认值就不管了,按工具的实际耗时分级设置,卡住的时候先看它停在哪一段,比盲目加大超时更有用。参数和超时的具体默认值因客户端而异,到 /guides 里对应的接入指南核对当时的配置说明。

缩小范围的固定动作

前面几节是「往哪看」,这一节是「怎么快速把范围切小」。核心思路是:一次只变一个变量,直到能稳定复现或者稳定跑通。

  • 换成最小可复现输入:只留一个工具、只传一个必填参数,跑通再逐步加回来
  • 绕开客户端,用另一种调用方式单独打同一个工具,能区分是 Server 问题还是客户端配置问题
  • 换一个已知可用的 Server 做对照,判断是环境问题还是这个 Server 本身的问题
  • 把每次排查的结论记成一份配置清单,下次接新 Server 直接照着过一遍

不适用的情况也说清楚:如果失败是间歇性的、同一份配置有时成有时败,那多半是并发、资源占用或网络抖动,按上面这套静态清单排查效果有限,这时应该先加日志观察失败的时间分布,再决定往哪个方向查。

下一步如果你正卡在「换个 Server 试试」这一步,站内收录了一批经过可信度检测的中转站和工具目录,可以直接挑一个做对照测试,省去自己踩坑的时间。

常见问题

本地命令行能跑通,接进客户端就失败,先查什么?

先查客户端用的是不是同一个可执行路径和同一个运行环境。命令行里能跑,往往是因为你当前 shell 的 PATH 和工作目录补齐了依赖;客户端启动时的环境通常更干净。把命令改成绝对路径,依赖装在系统级或写进启动脚本,再试一次。

工具列表能出来,但一调用就报错,问题在哪?

大概率在参数和返回体,不在连接。核对工具声明的参数类型和必填项,看模型传过去的值是不是多包了一层或者类型不符;再看 Server 返回的结构和客户端预期是否一致。这两类占了「列得出但调不动」的多数情况。

怎么判断是超时还是 Server 真的挂了?

看报错文案和时间点:超时通常是等到设定上限才返回,Server 挂掉往往是立刻断开或长时间无响应。把连接和读取超时分开设置,卡住时看停在哪一段。同时确认 Server 进程还在不在,进程没了就是启动或崩溃问题,不是超时。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。