Skip to content

Comments

fix: handle concurrent sendMessage calls in StdioServerTransportProvider#834

Open
dominikozi wants to merge 1 commit intomodelcontextprotocol:mainfrom
dominikozi:fix/686-stdio-async-toolcalls
Open

fix: handle concurrent sendMessage calls in StdioServerTransportProvider#834
dominikozi wants to merge 1 commit intomodelcontextprotocol:mainfrom
dominikozi:fix/686-stdio-async-toolcalls

Conversation

@dominikozi
Copy link

Replace tryEmitNext() with emitNext() using a busy-looping retry handler in StdioMcpSessionTransport.sendMessage() to support concurrent tool call responses without crashing.

Motivation and Context

Fixes #686.
When multiple tool calls are executed concurrently on MCP server using StdioServerTransportProvider, the server crashes with RuntimeException: Failed to enqueue message. The reason is that sendMessage() used tryEmitNext() on the outbound sink, which fails immediately when another thread is concurrently emitting instead of retrying.

How Has This Been Tested?

Added shouldHandleConcurrentMessages test that sends two concurrent JSON-RPC requests with delayed responses, verifying both complete without error and are written to the output stream. The test fails on main and passes with this change. Verified all existing tests continue to pass.

Breaking Changes

None.

Types of changes

[X] Bug fix (non-breaking change which fixes an issue)

[ ] New feature

[ ] Breaking change

[ ] Documentation update

Checklist

[X] I have read the MCP Documentation

[X] My code follows the repository's style guidelines

[X] New and existing tests pass locally

[X] I have added appropriate error handling

[X] I have added or updated documentation as needed

Additional context

The fix replaces tryEmitNext() with emitNext() using Sinks.EmitFailureHandler.busyLooping(Duration.ofSeconds(1)) in StdioMcpSessionTransport.sendMessage(). This is the standard Reactor pattern for thread safe emission from multiple threads. Non retryable failures still propagate immediately as Sinks.EmissionException. I dont think this requires a documentation update.


// Verify both concurrent responses complete without error
StepVerifier
.create(Mono.delay(java.time.Duration.ofSeconds(2))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test passes if Duration.ofSeconds(3) is provided. Preferably, instead of using delays, you'd launch a swarm of threads trying to process the messages in parallel and ensure none of them fail and all the messages are processed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP server using StdioServerTransportProvider does not support multiple asynchronous tool calls for the same session

2 participants