Skip to content

Commit 0d33052

Browse files
author
Ismar Iljazovic
committed
fix: SendRequest hangs forever when server process dies
SendRequest's select only watched ctx.Done() and responseChan, missing the done channel. When the server process dies (crash, pipe break, startup failure), the reader goroutine exits but SendRequest blocks forever waiting for a response that will never come. This causes MCP clients to become permanently unresponsive. Root cause: readResponses exited silently on EOF without signaling the done channel, so in-flight requests had no way to know the server died. Fix (5 changes in client/transport/stdio.go): 1. Add closeDone() using sync.Once to safely close the done channel from multiple goroutines without panicking on double-close. 2. readResponses calls closeDone() on unexpected exit (EOF/error), so in-flight requests unblock automatically on server death. 3. SendRequest's select includes <-c.done (both pre-check and response-wait) to return ErrTransportClosed immediately. 4. SendNotification gets matching done+ctx pre-check for consistency. 5. Close() uses a separate closeCleanupOnce to always perform resource cleanup (stdin, stderr, cmd.Wait) even when readResponses already called closeDone(), preventing FD leaks and zombie processes. Includes 8 regression tests covering server death, concurrent close, FD cleanup, and concurrent request stress scenarios.
1 parent b2fb8ba commit 0d33052

File tree

2 files changed

+455
-25
lines changed

2 files changed

+455
-25
lines changed

0 commit comments

Comments
 (0)