Repository navigation
fix(client): honor the connect signal during the server/discover probe - #3134
Open
JosephDoUrden wants to merge 1 commit into
Open
JosephDoUrden wants to merge 1 commit into
JosephDoUrden wants to merge 1 commit into
Conversation
The signal passed to connect() never reached the version-negotiation probe, so an aborted connect waited out the probe timeout and an already-aborted signal still sent the probe. Thread it through NegotiationDeps into ProbeWindow.exchange (early return, abort listener before send, requestSignal on the transport), re-check it after every exchange and before super.connect, and map the abort to the same error the legacy path produces. Fixes modelcontextprotocol#3133
🦋 Changeset detectedLatest commit: b7111c5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
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 |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3133.
connect()documents thattimeoutandsignalboth apply to the handshake or probe, but only the timeout reached theserver/discoverprobe. Aborting the signal did nothing until the probe timed out (60 s by default), and an already-aborted signal still sent the probe.What changed in
packages/client:NegotiationDepscarries the connect signal.ProbeWindow.exchangereturns early if it is already aborted, listens for abort beforesend(), and passes it to the transport asrequestSignal, so an in-flight HTTP POST is torn down too.negotiateErachecks the signal before opening the window, after every exchange whatever the reply was, and once more before handing the transport over, so a reply landing with the abort still rejects, no retry or corrective probe goes out after an abort, and a failed connect leaves the transport'sstartuntouched.negotiateStdioViaSiblingchecks it after the sibling is reaped, next to the existing caller-close()check, so an abort landing during disposal never starts the session transport.client.tsonly passesoptions.signalinto the negotiation deps.SdkErrorreason as is, otherwiseSdkError(RequestTimeout, String(reason)), mirroringProtocol.request. fix: distinguish AbortSignal cancellation from a real timeout #3046 wants to change that mapping; the helper here is one place to update with it.Not in this PR:
connect({ prior: { kind: 'modern', … }, signal })still ignores the signal. There is no probe or handshake on that path, so it is arguably documented out, but it is a separate decision.Tests:
test/client/connectSignalProbe.test.ts, built on the cases in @Floriferous's repro branch (legacy control, auto, pin, pre-aborted, stdio sibling, real HTTP) plus same-tick reply-then-abort, abort between verdict and handover, abort during sibling disposal, abort insidesend()undermaxRetries, listener removal,requestSignalforwarding and the error mapping. On real stdio the rejection waits for the sibling to be reaped (up to about 1 s if it ignores SIGTERM); the changeset says so.pnpm typecheck:all,pnpm lint:allpnpm test:all: all packages green; one e2e timing scenario (protocol:timeout:max-total [sse 2025-11-25], fake timers) failed once under full load and passed on rerun, unrelated to this changeAI Disclosure
AI assistance (Claude) was used for issue research and test scaffolding. The implementation was written and reviewed by the author.