| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
When a server-side request handler returns a Mono that completes empty, McpServerSession.handleIncomingRequest and DefaultMcpStatelessServerHandler.handleRequest propagated the empty completion, so no JSON-RPC response was ever sent for the request. This violates JSON-RPC 2.0's one-response-per-request contract and leaves the client waiting indefinitely. Both dispatch paths now complete with an internal error (-32603) response when the handler completes without a result, and log a warning naming the method. Normal result and error behavior is unchanged. Adds regression tests for the empty-completion, normal-result and error paths in both the stateful (McpServerSession) and stateless (DefaultMcpStatelessServerHandler) dispatch layers. Fixes modelcontextprotocol#1081 Signed-off-by: zhaoyuzhe <1991039819@qq.com>
| Back | FazBrowse Home | New Git URL |
When a server-side request handler returns a Mono that completes empty, the SDK previously sent no response at all for that request, leaving the client waiting indefinitely. This violates JSON-RPC 2.0's one-response-per-request contract.
Motivation and Context
MCP rides on JSON-RPC 2.0, which requires that every request carrying an id receives exactly one response (a result or an error). Two server-side dispatch paths had the gap:
An empty completion is a common Reactor idiom (e.g. a reactive repository's get(id) completing empty when nothing matches), so this is a realistic failure mode, not a theoretical one. Fixes #1081.
Both paths now append .switchIfEmpty(...): an empty completion produces exactly one JSON-RPC error response (-32603 Internal error) naming the method, plus a WARN log. Normal result and error behavior is unchanged — switchIfEmpty only fires on empty completion.
How Has This Been Tested?
Breaking Changes
None. This is an additive fix for a previously-broken path (empty handler completion previously produced no response; it now produces an error response). Existing successful/error behavior is byte-for-byte unchanged.
Types of changes
Checklist
Additional context
Root cause: Mono.map() does not emit for an empty source and onErrorResume does not trigger without an error, so the empty completion propagated silently through both dispatch chains. The fix converts that silent empty completion into a contract-compliant error response.