StackTraces
LangChain4j已验证

LangChain4j MCP 在 Windows 报 JsonParseException

@debug_master13 天前更新阅读 6 min00

LangChain4j 在 Windows 上跑 MCP stdio 报 JsonParseException: Unrecognized token 'Microsof...',看着像序列化问题,其实是子进程根本没起来。npx.cmd 的路径带空格,命令又拼成单个字符串,进程启动失败,stderr 的中文报错被拿去当 JSON 解析。先查进程启动,别顺着 Jackson 查。

Issue & Env(案发现场与环境)

  • 环境:Windows 11 + Spring Boot 3.5.3 + langchain4j 1.1.0-beta7。
  • MCP server 通过 npx 启动,命令路径是 C:\Program Files\nodejs\npx.cmd,注意路径里有空格。
  • 现象:应用启动时 MCP 连接失败,抛 JsonParseException。问题来自 langchain4j issue #3357。

StackTrace(堆栈日志)

issue #3357 原文:

2025-07-14T10:18:22.575+08:00 DEBUG 27572 --- [spring-ai-study] [           main] d.l.m.c.t.stdio.StdioMcpTransport        : Starting process: [C:\Program Files\nodejs\npx.cmd, -y @smithery/cli@latest run @wonderwhy-er/desktop-commander --key 39b09f76-4bb9-4f04-b393-370129f56bcc]
2025-07-14T10:18:22.582+08:00 DEBUG 27572 --- [spring-ai-study] [           main] d.l.m.c.t.stdio.StdioMcpTransport        : PID of the started process: 27784
2025-07-14T10:18:23.049+08:00 DEBUG 27572 --- [spring-ai-study] [       Thread-2] d.l.m.c.t.stdio.ProcessStderrHandler     : [ERROR] 文件名、目录名或卷标语法不正确。
Exception in thread "Thread-1" java.lang.RuntimeException: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Microsof

看 Starting process: 那行,npx.cmd 的路径带着空格被打了进去。紧接着 ProcessStderrHandler 收到一行本地化中文报错,再往下就是 JsonParseException。

Reproduce(复现代码)

常见踩法:把整条命令拼成一个字符串传给 command(...):

val transport = StdioMcpTransport.Builder()
    .command("C:\\Program Files\\nodejs\\npx.cmd -y @smithery/cli@latest run @wonderwhy-er/desktop-commander --key mykey")
    .build()

Windows 上 npx 实际是 npx.cmd。单个字符串传给 command(...) 时,路径里的空格被错误处理,子进程起不来。

Root Cause(根因分析)

  • 表象是 JSON 解析失败,根因在进程启动阶段。别顺着 JsonParseException 去查序列化。
  • Windows 上 npx 是 npx.cmd,装在 C:\Program Files\ 这种带空格的目录下。命令以单个字符串拼进 StdioMcpTransport.Builder().command(...),空格被错误拆分,子进程没真正起来,或参数被拆错。
  • 子进程启动失败后,stderr 吐出本地化的中文错误「文件名、目录名或卷标语法不正确。」。ProcessStderrHandler 与协议帧解析没有把「非 JSON 的人类可读错误」和「JSON-RPC 消息」区分开,于是 Jackson 去解析一行根本不是 JSON 的文本,抛出 JsonParseException: Unrecognized token 'Microsof...。
  • 报错里的 'Microsof 很怪。结合 ProcessStderrHandler 的输出看,被拿去解析的并不是协议帧,而是进程输出的片段。这一句的确切来源,issue 里没有给出完整后续,社区说法,截至撰写时未核实。
  • 真正要抓的事实是「子进程没起来」。这层原因在 StdioMcpTransport 源码 的启动路径里就能看到。

The Fix(解决方案)

命令要拆成 program + 参数列表,不要把整条命令拼成一个字符串。Windows 上优先用 cmd.exe /c 包一层:

val transport: McpTransport = StdioMcpTransport.Builder()
    .command(
        listOf(
            "cmd.exe", "/c", "npx", "-y",
            "@smithery/cli@latest", "run",
            "@wonderwhy-er/desktop-commander", "--key", "mykey"
        )
    )
    .logEvents(true)
    .build()
  • 或者把 Node 装到没有空格的目录(如 C:\nodejs),用 npx.cmd 的绝对路径加独立 args。
  • 永远给 MCP 进程加关闭钩子:进程内调用 close()(mcpClient.close())。
  • 排查期间先手工验证 cmd.exe /c npx -y <包> 能跑起来,再交给 LangChain4j。
  • 打开 .logEvents(true)。先看 Starting process: 那行打印的命令长什么样,再看 ProcessStderrHandler 的真实 stderr。这两行比 JsonParseException 有用得多。
  • 跨平台建议:生产上优先把 MCP server 换成 SSE 或 Streamable HTTP 端点。stdio transport 在 Windows 上问题最多。

小结

  • JsonParseException: Unrecognized token 'Microsof... 是表象,进程没起来才是根因。
  • Windows 下命令必须拆成 program + 参数列表,路径带空格就上 cmd.exe /c。
  • 排查先开 .logEvents(true),看 Starting process: 和 ProcessStderrHandler 两行。

References(参考来源)

最后更新于 2026-09-28

这篇帮到你了吗?

刚解决了一个棘手的报错?花两分钟记录下来,帮助下一个遇到同样问题的开发者。

贡献一条解法