modelcontextprotocol / modelcontextprotocol/java-sdk

StdioClientTransport does not propagate unexpected child process exit during initialization

未关闭
#959 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

area/transport bug P2
主要语言
Java
星标
3.7k
派生
1.1k
平均合并
1 天 15 小时
30 天内合并 PR
9

描述

StdioClientTransport does not propagate unexpected child process exit during initialization

Bug description

When a stdio MCP server process starts successfully and then exits before it can
reply to the initialize request, the client waits for the request timeout and
surfaces a timeout error. The child process exit and exit code are not surfaced
to the caller through the initialize() failure.

This is different from a ProcessBuilder.start() failure: the process is
created successfully, then exits shortly after startup.

This also seems distinct from #937, which is about bounded termination during
shutdown. The failure here happens during initialization, before the client gets
an initialize response.

This also appears to be the lower-level cause behind
spring-projects/spring-ai#5982, where Spring AI waits for its MCP client
initialization timeout instead of reporting the stdio process exit.

Environment

  • Java 17+
  • io.modelcontextprotocol.sdk:mcp:2.0.0-M2
  • Stdio client transport

Steps to reproduce

I prepared a minimal reproducer:

https://github.com/DragonFSKY/mcp-stdio-exit-reproducer

The reproducer starts a Java child process through StdioClientTransport. The
child process starts successfully and then immediately exits with code 127
before sending an MCP initialize response.

Run:

./mvnw test

The regression test is intentionally written for the expected behavior, so it
fails with the current SDK.

To print the observed behavior directly:

./mvnw -q -DskipTests exec:java

Observed output:

Expected: fail quickly and include child process exit code 127
Actual elapsed millis: 826
Actual exception type: java.lang.RuntimeException
Actual exception message: Client failed to initialize by explicit API call
Stack trace contains TimeoutException: true
Error contains child exit code 127: false

Expected behavior

McpClient.initialize() should fail promptly when the stdio child process exits
unexpectedly during initialization. The failure should include enough context for
the caller to understand that the child process exited, ideally including the
command and exit code.

Actual behavior

McpClient.initialize() waits for the request timeout and reports a timeout. The
exit code is not available in the exception reported to the caller.

Minimal Complete Reproducible example

The reproducer above contains:

  • a minimal child process that calls System.exit(127)
  • a stdio MCP client using StdioClientTransport
  • a failing JUnit test that demonstrates the timeout and missing exit code

From looking at the current implementation, StdioClientTransport.connect()
completes after ProcessBuilder.start() succeeds. If the process exits shortly
afterward, the pending initialize request remains pending until the request
timeout. The exit code is only observed later on close, not propagated to the
pending initialization request.

If this behavior and scope look valid, I would be happy to work on a focused PR.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 StdioClientTransport.connect() 和 issue 中描述的待处理 initialize 请求路径开始。使用 ./mvnw test 运行复现程序,以观察失败的 JUnit 测试,然后验证意外的子进程退出会立即导致初始化失败,并包含退出代码,而不是超时。

由索引模型根据 Issue 内容生成。

评估

技术栈
java
领域
api
Issue 类型
缺陷
难度
3/5
预计耗时
1-2 天
活跃度
冷清
描述清晰度
基本清楚
新手友好度
55/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。