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

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法