Skip to content

fix(client): keep the original error as the cause of "SSE stream disconnected" - #2948

Draft
n-satoshi061 wants to merge 1 commit into
modelcontextprotocol:mainfrom
n-satoshi061:fix/client-sse-error-cause
Draft

n-satoshi061 wants to merge 1 commit into
modelcontextprotocol:mainfrom
n-satoshi061:fix/client-sse-error-cause

Conversation

@n-satoshi061

@n-satoshi061 n-satoshi061 commented Oct 3, 2026 •

Copy link
Copy Markdown

The SSE stream disconnected error that StreamableHTTPClientTransport passes to onerror now carries the original stream error as its cause. The message is unchanged.

Motivation and Context

  • When an SSE response stream fails while StreamableHTTPClientTransport is reading it, the transport reports new Error(`SSE stream disconnected: ${error}`) to onerror.
  • The original error is only interpolated into the message. Its type and stack are lost, and error.cause is undefined.
  • A caller that wants to tell, say, a TypeError: terminated from another failure has to parse the message string.
  • This is already an acknowledged gap: test/e2e/requirements.ts lists the behaviour as client-transport:http:body-stream-error-preserved (onerror should receive an error that preserves the original one, either as the instance itself or via .cause), with a knownFailures entry describing exactly this wrapper.
  • fix(client): surface underlying network error via Error.cause on probe failures (#2657) #2726 made the same kind of change for probe failures (Error.cause on SdkError).

The change:

  • packages/client/src/client/streamableHttp.ts: pass { cause: error } when constructing the SSE stream disconnected error.
  • One changeset: @modelcontextprotocol/client, patch.

How Has This Been Tested?

  • The two cells of client-transport:http:body-stream-error-preserved pass with the change and fail when only the source change is reverted.
  • Full e2e suite: 44 files, 2697 passed, 139 expected failures.
  • @modelcontextprotocol/client unit tests: 997 passed.
  • typecheck and lint pass for the client and e2e packages.

Breaking Changes

None. An existing error gains a cause; its message and class are the same, so anything matching on the message keeps working.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

The e2e test needed a one-line fix:

  • The existing test for this requirement could not pass regardless of what the transport did.
  • It opens its fake stream with data: {}, then errors the stream, and asserts on errors[0].
  • {} is not a JSON-RPC message, so the transport reports the schema parse failure to onerror first. The stream error arrives second.
  • Observed order with the fix applied:
    1. ZodError (from data: {})
    2. Error: SSE stream disconnected: TypeError: ... with cause === originalError
  • The test now opens the stream with an SSE comment frame (: open), which produces no message and no error, so errors[0] is the stream error.
  • The assertion itself is unchanged.
  • The knownFailures entry for the requirement is removed.

Not included:

  • v1.x has the same line (src/client/streamableHttp.ts). Not touched here; happy to send a separate PR against v1.x if wanted.
  • The other wrappers in the same file (Failed to reconnect SSE stream: ...) are left as they are. The requirement only covers the body-stream error.

…onnected"

When an SSE response stream failed while being read, the transport passed
`new Error(`SSE stream disconnected: ${error}`)` to onerror, which dropped the
type and stack of the original error. The error now carries it as `cause`; the
message is unchanged.

The e2e test for `client-transport:http:body-stream-error-preserved` opened its
stream with `data: {}`, which is not a JSON-RPC message, so the first error
reaching onerror was the parse failure and the test could not pass whatever the
transport did. It now opens the stream with a comment frame, and the
requirement's knownFailures entry is removed.
@changeset-bot

changeset-bot Bot commented Oct 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 11bc250

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@modelcontextprotocol/client Patch
@modelcontextprotocol/codemod Patch
@modelcontextprotocol/core Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/server Patch
@modelcontextprotocol/core-internal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@n-satoshi061 n-satoshi061 changed the title fix(client): keep the original error as the cause of "SSE stream disc… fix(client): keep the original error as the cause of "SSE stream disconnected" Oct 3, 2026
@pkg-pr-new

pkg-pr-new Bot commented Oct 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2948

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2948

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2948

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2948

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2948

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2948

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2948

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2948

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2948

commit: 11bc250

This branch has not been deployed

No deployments
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