[v2] e2e `protocol:timeout:max-total` is flaky over SSE: fake timers advance before the request reaches the server
Maintainer antworten meist innerhalb von 1 Tag
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 72/100
- Issue-Typ
- Bug
- Klarheit
- Größtenteils klar
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- typescript
- Bereich
- testing-qa
Rechercherichtung
Beginne mit den SSE-Varianten von protocol:timeout:max-total in test/e2e/scenarios/protocol.test.ts und vergleiche ihre Schritte mit Fake-Timern mit dem vi.waitFor-Muster des timeout:reset-on-progress-Tests. Führe den Reproduktionsbefehl aus dem Issue einschließlich wiederholter Durchläufe aus, um den intermittierenden Fehler zu bestätigen. Fertig ist die Aufgabe, wenn der Test zuverlässig die Progress-Ereignisse des Servers erreicht und SSE Maximum total timeout exceeded wie die anderen Transports meldet.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
What happened?
On macOS, the two SSE variants of protocol:timeout:max-total in test/e2e/scenarios/protocol.test.ts fail intermittently on a clean clone of main. The other transports always pass, and CI on main is green.
AssertionError: expected 0 to be greater than or equal to 3
❯ scenarios/protocol.test.ts:713:30
followed by an unhandled SdkError: Request timed out.
The failure rate moves around. On Oct 14 it failed in the full suite and in 3 of 3 isolated runs. On Oct 16, -t "timeout:basic|timeout:max-total" failed 3 of 6 times, while the max-total test on its own passed 6 of 6.
What I think is happening: the test switches to fake timers, starts the call, and immediately advances the clock in 200ms steps. Over SSE, the tools/call request is a real HTTP POST, and the fake clock doesn't wait for it. When the POST is slow to land, the clock is already past the 500ms per-request timeout, so the call rejects with Request timed out before the server sends any progress. In those runs the test never reaches maxTotalTimeout at all.
To check, I added temporary logging of server-sent progress, client-received progress, and each clock step. In failing runs, the server's first progress shows up only after the clock reaches 600ms, by which point the call has already been rejected. Then I added 10ms of real time (a setTimeout captured before useFakeTimers) after each advanceTimersByTimeAsync. With that, all 12 variants passed on 3 of 3 runs, and SSE rejects with Maximum total timeout exceeded after 4 progress ticks, the same as the other transports.
The sleep only confirms the cause; it isn't a fix. protocol:timeout:reset-on-progress already avoids this race by awaiting vi.waitFor(() => expect(received.length).toBeGreaterThanOrEqual(i)) after each step, and max-total has no equivalent. Waiting until the server has received the call before advancing the clock should fix it. One wrinkle: vi.waitFor advances fake timers while it polls, so the wait needs to sit where it can't eat into the timeout budget under test.
Happy to open a test-only PR if that approach sounds right.
What did you expect?
The test passes regardless of machine speed, and actually exercises maxTotalTimeout over SSE.
Code to reproduce
cd test/e2e
pnpm vitest run scenarios/protocol.test.ts -t "timeout:basic|timeout:max-total"
# intermittent, so run it several times
SDK version
main @ 9bc40e90 (macOS / Darwin 27, Node 24.16.0, pnpm 10.26.1)
Area
Transports
- Vorherrschende Sprache
- TypeScript
- Sterne
- 13.6k
- Forks
- 2.3k
- Ø Merge
- 1 T. 2 Std.
- Gemergte PRs (30 T.)
- 51
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus modelcontextprotocol/typescript-sdk
-
[v1.x] Backport #2654: `notifications/cancelled` with `requestId: 0` is ignored, so the first server→client request cannot be cancelled (still in 1.32.1)Evtl. vergeben @CloudCorpRecords hat das vor 1 Tag übernommen. Offenv1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 77/100
modelcontextprotocol/typescript-sdk#3043 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Stateless 405 response omits the Allow headerEvtl. vergeben @Hugo-DDT hat das vor 7 Tagen übernommen. Offenv2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
modelcontextprotocol/typescript-sdk#2970 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
[v2] @modelcontextprotocol/server inlines fast-uri 3.1.0, which has 9 published advisoriesEvtl. vergeben @Andiii208 hat das vor 10 Tagen übernommen. Offenv2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
modelcontextprotocol/typescript-sdk#2966 · 3 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
v1 v2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
modelcontextprotocol/typescript-sdk#2946 · 4 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
[v2] URI template reserved expansions encode existing %HH sequences againEvtl. vergeben @takagibit18 hat das vor 16 Tagen übernommen. Offenv1 v2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
modelcontextprotocol/typescript-sdk#2920 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in modelcontextprotocol/typescript-sdk
Ähnliche Issues
-
"Contains" page watch never matches when its text has a trailing spaceEvtl. vergeben @RaphaelFakhri hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 77/100
CopilotKit/openmuse#184 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 88/100
Maintainer antworten meist innerhalb von 1 Tag
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 67/100
bootstrap-vue-next/bootstrap-vue-next#3357 ·
Maintainer antworten meist innerhalb von 1 Tag
-
[quality] tide.ts: six mutation survivors in the merge-queue gate, draft refusal, fork-403 workflow-file diagnosis and getPull's fork flag are unpinned by any testEvtl. vergeben @hivecommons-hive hat das heute übernommen. Offenagent/quality needs-kind stage/040-covered-by-pr testing
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
cncf/prow-github-actions#517 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Unsampled pageload span is profiled when profileLifecycle is 'trace' (browser UI profiling)Evtl. vergeben @Jxxunnn hat das heute übernommen. OffenBrowser Waiting for: Product Owner
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
getsentry/sentry-javascript#25497 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag