fix(server): remove initialized notification gate to support Streamable HTTP - #788
Merged
DaleSeo merged 2 commits intoApr 9, 2026
Conversation
…le HTTP The server's init handshake loop fatally rejected any request arriving before the `notifications/initialized` message. This breaks Streamable HTTP clients where each JSON-RPC message is a separate POST with no ordering guarantee — `tools/list` can easily arrive before `initialized`. Remove the ~40-line wait loop and enter `serve_inner` immediately after sending `InitializeResult`. The `initialized` notification is now handled as a regular notification by the main service loop, matching the TypeScript SDK behavior (validated in typescript-sdk#578). Also remove the now-unreachable `ExpectedInitializedNotification` error variant from `ServerInitializeError`. Closes modelcontextprotocol#783 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merged
3 tasks
Contributor
Author
|
@DaleSeo @alexhancock can anyone review this please. |
DaleSeo
reviewed
Apr 9, 2026
Summary
initializednotification wait loop that fatally rejected any request arriving beforenotifications/initializedserve_innerimmediately after sendingInitializeResult, letting the main service loop handle all messages includinginitializedExpectedInitializedNotificationerror variant fromServerInitializeErrorMotivation
Streamable HTTP requires each JSON-RPC message as a separate POST request. The transport layer cannot guarantee delivery order, so
tools/listcan easily arrive beforenotifications/initialized, causing a fatal HTTP 500 error.The MCP spec uses SHOULD NOT (RFC 2119), not MUST NOT, for pre-initialized messages — allowing exceptions in specific circumstances like HTTP's lack of ordering guarantees.
This aligns with the TypeScript SDK's behavior, which processes requests immediately after
initializewithout gating oninitialized(validated in modelcontextprotocol/typescript-sdk#578).Test plan
server_init_set_level_response_is_empty_resultto handle notifications fromserve_innerdispatchserver_init_succeeds_after_set_level_before_initializedsimilarlyserver_init_rejects_unexpected_message_before_initializedwithserver_init_buffers_request_before_initialized— verifiestools/listbeforeinitializedis processed successfullyserver_init_buffers_multiple_requests_before_initialized— verifies multiple pre-init messages are all processedCloses #783