Fix concurrent sendMessage race in StdioClientTransport by AbbasNS · Pull Request #876 · modelcontextprotocol/java-sdk

added 2 commits

March 20, 2026 15:11
When two threads call sendMessage() concurrently on the same
StdioClientTransport, the unicast sink's SinkManySerialized wrapper
returns FAIL_NON_SERIALIZED via its CAS guard, causing
"Failed to enqueue message".

This test reproduces the race: 19/20 repetitions fail.

Closes modelcontextprotocol#875
Replace tryEmitNext (fail-fast) with emitNext + busyLooping(100ms)
in StdioClientTransport.sendMessage().

The unicast sink's SinkManySerialized wrapper returns FAIL_NON_SERIALIZED
when two threads call tryEmitNext concurrently. busyLooping retries the
CAS spin instead of immediately failing, making concurrent sends safe.
The contention window is microseconds (single CAS operation), so the
100ms duration is just a generous upper bound for pathological cases
like GC pauses.

Before: 19/20 test repetitions fail
After:  20/20 pass

Closes modelcontextprotocol#875