Skip to content

feat(client)!: support stateful streamable-HTTP servers - #18

Merged
TheGreatAxios merged 1 commit into
cl-9453-mcp-never-echo-credential-material-and-only-use-activefrom
cl-9454-mcp-support-stateful-streamable-http-servers-and-harden-json
Sep 27, 2026
Merged

TheGreatAxios merged 1 commit into
cl-9453-mcp-never-echo-credential-material-and-only-use-activefrom
cl-9454-mcp-support-stateful-streamable-http-servers-and-harden-json

Conversation

@TheGreatAxios

@TheGreatAxios TheGreatAxios commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

The client ignored Mcp-Session-Id and never sent notifications/initialized or MCP-Protocol-Version. Against the official SDK's stateful transport, initialize worked but tools/list and every sidecar tools/call failed with a 400. A non-JSON data: frame threw a raw SyntaxError, and a server request reusing our id was taken as the response.

Changes

  • mcpInitialize sends initialize, then notifications/initialized, and returns an McpSession (protocolVersion, sessionId?, serverInfo?). McpClientOptions.session sends Mcp-Session-Id and MCP-Protocol-Version on later requests. McpSession is exported.
  • Discovery, mcpTools and the sidecar bundle carry the session to tools/list and tools/call. mcpTools and the bundle open one session per server on first use and reopen it after a failed call, in case the server expired it. The discovery route's serverInfo response is unchanged.
  • mcpInitialize refuses a server protocolVersion that is not printable ASCII before echoing it into MCP-Protocol-Version, and a timed-out notifications/initialized is an McpError. Both are tested and fail before the fix.
  • SSE: non-JSON data: frames are skipped. Only a message with result or error and no method counts as the response, for both SSE and JSON bodies.
  • e2e/sdk-transport.test.ts runs discovery, the sidecar bundle and mcpTools against @modelcontextprotocol/sdk's stateless and stateful streamable-HTTP server transports. The stateful cases fail before the fix. The SDK and zod are devDependencies only. New test:e2e script, run in CI.
  • The in-test server answers notifications with 202.
  • README, AGENTS.md and CONTRIBUTING updated; the upgrade notes cover the new mcpInitialize return type.

Breaking

Yes, marked !: mcpInitialize returns McpSession instead of McpServerInfo. It is part of the pending 0.2.0 release, so there is no extra version bump.

Checks

bun run check, bun run test:e2e, bun run build and the Node pack smoke pass locally.

Closes CL-9454

@TheGreatAxios
TheGreatAxios added this pull request to stack #12 September 27, 2026 02:23
@TheGreatAxios
TheGreatAxios force-pushed the cl-9454-mcp-support-stateful-streamable-http-servers-and-harden-json branch from c050555 to 9dc9f6b Compare September 27, 2026 02:44
@TheGreatAxios
TheGreatAxios force-pushed the cl-9454-mcp-support-stateful-streamable-http-servers-and-harden-json branch from 9dc9f6b to 1a6c11f Compare September 27, 2026 02:44
@TheGreatAxios
TheGreatAxios force-pushed the cl-9454-mcp-support-stateful-streamable-http-servers-and-harden-json branch from 1a6c11f to a651f08 Compare September 27, 2026 18:35
mcpInitialize now sends notifications/initialized and returns an McpSession
whose Mcp-Session-Id and MCP-Protocol-Version later requests carry. Discovery,
mcpTools and the sidecar bundle pass it on, and reopen it after a failed
call. A protocolVersion that is not printable ASCII is refused before it is
echoed into a header, and a timed-out notification is an McpError. Non-JSON
data frames are skipped, and only a message with result or error and no
method counts as the response. e2e covers the official SDK's stateless and
stateful server transports; the SDK is a devDependency only.

BREAKING CHANGE: mcpInitialize returns McpSession instead of McpServerInfo.
@TheGreatAxios
TheGreatAxios force-pushed the cl-9454-mcp-support-stateful-streamable-http-servers-and-harden-json branch from a651f08 to e13d7b3 Compare September 27, 2026 18:49
@TheGreatAxios
TheGreatAxios merged commit 183560e into main Sep 27, 2026
1 check passed
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.

1 participant