Spring AI MCP Stdio 报错信息排查

本文汇总一下 Spring AI 通过 STDIO 方式接入 MCP Server 时,常见报错的排查思路。这里讨论的场景是:Spring AI 客户端通过 spring.ai.mcp.client.stdio 启动外部 MCP Server,并通过 stdio 与它通信。

具体课程 MCP 链接:https://www.codefather.cn/course/1915010091721236482/section/1923324591245287425

一、先看结论

如果你遇到了 Spring AI MCP stdio 相关报错,建议按下面顺序排查:

  1. 先单独验证 yu-image-search-mcp-server 本身的业务逻辑,不要一上来就从 AI 对话入口排查。
  2. 只要改过 MCP Server 代码,就重新执行 package,因为 Spring AI 客户端最终拉起的是 jar,不是 IDEA 里的源码。
  3. 手动运行 jar,确认进程能否正常拉起。对 stdio 场景来说,“进程没有立刻退出”往往比“终端打印了日志”更重要。
  4. 核对 application.yml 和 mcp-servers.json,尤其是命令、参数、工作目录和 jar 路径。
  5. stdio 模式下,MCP Server 只能把协议消息写到 stdout;普通日志应该写到 stderr 或文件,不能污染 stdout。
  6. 调试时看到 exitValue() 取不到值,只能说明子进程还没退出,不能单独当作“启动成功”的充分证据。

二、推荐排查顺序

1. 先单独验证 yu-image-search-mcp-server

需要先把 ImageSearchTool 的 API_KEY 替换成你自己的真实 Key。Pexels API Key 获取地址:https://www.pexels.com/api/key/

配置完成后,先单独运行 ImageSearchToolTest#searchImage,确认图片链接能否正常返回。

如果这一步就失败了,那么问题通常还不在 MCP,而在下面这些地方:

  1. API_KEY 不正确或未生效。
  2. 工具代码本身有问题。
  3. 依赖版本和源码示例不一致。

image.png

2. 改完代码后重新打包 jar

只要改了 yu-image-search-mcp-server 的代码,就一定要重新执行 package。因为 Spring AI 通过 ProcessBuilder 拉起的是磁盘上的 jar,不是你当前 IDEA 里尚未打包的代码!

image.png

3. 手动运行 jar,确认 stdio Server 能否启动

建议在父项目目录打开终端,然后手动执行和 mcp-servers.json 中一致的命令。

找到父项目,右键选择 OpenIn -> Terminal:

image.png

执行命令:

▼
bash
复制代码
java "-Dspring.ai.mcp.server.stdio=true" "-Dspring.main.web-application-type=none" -jar yu-image-search-mcp-server/target/yu-image-search-mcp-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=stdio

这里有几个关键点:

  1. spring.ai.mcp.server.stdio=true 表示以 STDIO 模式启动 MCP Server。

  2. spring.main.web-application-type=none 表示不要按 Web 应用启动。

正常可以发现启动成功:

如果启动失败需要排查一下自己的 Java 版本是否是 >= 21

image.png

4. 核对 application.yml 和 mcp-servers.json

先看客户端配置:

▼
yaml
复制代码
spring: ai: mcp: client: stdio: servers-configuration: classpath:mcp-servers.json

这里的 servers-configuration 是 Spring AI 官方支持的 stdio 外部配置方式。

准备 mcp-servers.json:

排查阶段建议先只保留一个待排查的 MCP Server,不要同时把多个 MCP 都配进去(amap-maps 不要先写进入),避免互相干扰。

▼
json
复制代码
{ "mcpServers": { "yu-image-search-mcp-server": { "command": "java", "args": [ "-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-Dspring.main.banner-mode=off", "-Dlogging.pattern.console=", "-jar", "yu-image-search-mcp-server/target/yu-image-search-mcp-server-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=stdio" ], "env": {} } } }

这一段最容易出错的地方主要有二个:

  1. command 和 args 与你手动验证成功的命令不一致。
  2. jar 路径写错。

5. 通过 Debug 或独立测试进一步定位

如果上面的步骤都做过了,还是报错,那么可以继续往下定位。

首先运行测试类 doChatWithMcp():

image.png

然后可以在 io.modelcontextprotocol.client.transport.StdioClientTransport 附近打断点,再 Debug 运行 doChatWithMcp():

image.png

如果这里的 exitValue 是 not exited 的话,那么大概率是启动成功了。如果没有走到这个断点,那么就检查自己的配置文件是否配置正确,也就是上面一节。

可以走到断电,但是值不是 not exited 的话就需要再单独测试,具体如何测试需要看下面的代码。

下面这段代码可以放到 src/test/java/com/yupi/yuaiagent/app 包下:

▼
java
复制代码
import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.TimeUnit; public class McpServerChecker { public static void main(String[] args) { List<String> command = List.of( "java", "-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-Dspring.main.banner-mode=off", "-Dlogging.pattern.console=", "-jar", "yu-image-search-mcp-server/target/yu-image-search-mcp-server-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=stdio" ); ProcessBuilder pb = new ProcessBuilder(command); pb.redirectErrorStream(true); try { Process process = pb.start(); boolean exited = process.waitFor(5, TimeUnit.SECONDS); if (!exited) { System.out.println("进程 5 秒内没有退出,说明服务大概率已经拉起,正在等待 MCP Client 通过 stdin 建连。"); process.destroy(); return; } String output = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8); System.err.println("进程启动失败,exitCode = " + process.exitValue()); System.err.println(output); } catch (IOException e) { System.err.println("启动异常: " + e.getMessage()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("等待进程结果时被中断"); } } }

这个测试的意义是:

  1. 验证命令本身能不能成功拉起子进程。
  2. 如果进程立即退出,就能直接看到退出码和错误输出。
  3. 如果进程没有立即退出,至少说明“命令层面”基本没问题,下一步就要继续看 MCP 握手和工具调用链路。
  4. 最后需要手动停止这个测试方法

三、系统编码的问题

如果遇到的报错信息类似下面的报错信息:

▼
text
复制代码
2025-10-20 10:10:31.298 [pool-2-thread-1] ERROR i.m.client.transport.StdioClientTransport - Error processing inbound message for line: Active code page: 65001 com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Active': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')

并且打开 cmd 可以发现这个信息:

image-20260401133800231

满足以上两点就证明系统编码有问题,我是不太推荐解决的(因为编码问题一旦随便修改可能会导致系统环境变量出现问题,如果要修改也建议先设置一下系统还原点),如果是这个问题我个人建议是使用 Linux 系统测试代码是否可以正常运行,如果正常运行就直接继续写代码即可。解决的话也可以参考一下这位大佬的文章:https://www.codefather.cn/post/1980098355279175681

四、如何判断最终排查成功

最终用下面这条链路判断是否真的排查完成:

  1. ImageSearchToolTest#searchImage 单独运行成功。
  2. 重新 package 后,jar 手动运行不会立刻退出。
  3. doChatWithMcp() 能正常拿到图片 URL。
  4. 图片 URL 可以实际访问,说明结果来自工具调用,而不是模型幻觉。

正常情况下,doChatWithMcp() 的返回内容里会包含真实图片链接,并且链接可以正常访问:

image.png

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
leikooo
作者分享
提到用 Rust 重写项目,很多人的第一反应往往是性能提升。以 Bun 为例,它最初主要采用 Zig 开发,后来在 2026 年发布的 v1.4 版本中将核心代码迁移到了 Rust。用 Rust 重写,性能、安全性往往是大家想要的,但是有没有想过用 Rust 重写还能发现 bug 呢? pgrust 这个项就是,他用 Rust 重新实现 PostgreSQL,保持通信协议和 SQL 方言兼容。为了确认新系统的行为和原版一致,开发者需要对着 PostgreSQL 的实际返回逐个比对。结果查着查着,有些异常不是新代码的锅,PostgreSQL 自己就是这样的。pgrust 开发者 Michael Malis 把其中几个报告给了 PostgreSQL 社区。 大概的问题: 1)SP-GiST 空间索引里有个函数判断点的方位,代码认为上、下、同一水平线三种情况已经穷尽了,末尾放了句「impossible case」兜底。结果在特定浮点边界附近,三种判断同时不成立,程序真走进了这个「不可能」的分支 2)日期格式缓存复用时,一个解析模式的标记没重置,导致同一条 JSONPath 查询在同一个会话里,换个执行顺序结果就不一样。 3)pgcrypto 的 crypt() 在某些输入下截断了多字节字符,返回的文本编码不合法。能存进去,但 pg_dump 导出时就炸了。 一个用 Rust 重写的新项目,测着测着,把运行了几十年的 PostgreSQL 里埋着的东西翻了出来。Rust 重写的价值,不一定只在跑得更快、更安全这一件事上。为了做到真正的兼容,开发者得把前人没怎么碰过的边界全走一遍,这个过程本身就在帮原版排雷。
4
ARTS 1025: 唯一字符与同构字符串、省词可能增加阅读负担与重新估算软件的实现成本
5
🎉 1024 程序员节快乐! 祝编程导航里的每一位程序员:offer 多多,薪资翻倍,面试顺利,早日拿下心仪 offer!💻
17
AST:从 Java 代码理解抽象语法树
5
原来维基百科还有专门研究「AI 味」的页面 今天偶然发现一个挺有意思的维基百科页面:https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing,专门整理 AI 写作的典型特征。 里面总结了很多我们平时经常看到的 AI 味,比如喜欢用“值得注意的是”“在当今快速发展的时代”“综上所述”,还有过度使用排比、加粗、列表,以及一些看起来很有道理,实际上没什么信息量的表达。 感觉以后可以定期翻翻这个 wiki,尤其是经常使用 AI 辅助写作的人,应该能从中发现不少所谓的 AI 味。 链接: https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing
5
下载 APP