fix(sse-retry): gate retry timing only on the early side

Merged
MA
2mo ago
+11-36

Problem

sse-retry flakes in python-sdk CI (~4–5% of runs, including recent failures on every push to main), always with the signature ✗ sse-retry: 2 passed, 0 failed, 1 warnings — the retry-timing check landing in its (700, 1000]ms "slightly late" WARNING band, which fails the scenario under the WARNING policy (#245). Example run: https://github.com/modelcontextprotocol/python-sdk/actions/runs/28443055485

The 2025-11-25 spec sentence is "The client MUST respect the retry field, waiting the given number of milliseconds before attempting to reconnect" — a lower bound. Neither MCP nor WHATWG SSE bounds reconnect delay from above. The measured delay is the client's sleep (≥ retry) plus EOF detection, GET propagation, and harness dispatch — all inflated by load, and suite mode runs every scenario's client concurrently. Measured locally with the python client: 503ms idle against the 700ms gate, 591–674ms with the suite pinned to 2 cores. The band gates the environment, not the client.

Change (one file, +11/−36)

  • Delete the slightly-late WARNING and >2× FAILURE bands: the timing check is now FAILURE only when the reconnect arrives earlier than retry − 50ms, otherwise SUCCESS, with the measured delay kept in details. Load can only push a compliant client deeper into the passing region, so the flake is structurally gone.
  • Demote the "could not measure timing" path from WARNING to INFO (the other spurious-warning path).
  • One-line fix: the initialize response negotiated protocolVersion: 2025-03-26, a version whose spec had no retry MUST; now 2025-11-25 (same issue 4686e06 fixed for server-sse-polling).

Strictly relaxing — no SDK that passes today can start failing on a pin bump; retry stays at 500ms so test duration is unchanged.

Trade-off accepted: the >2× band was the only (unsound) detector for clients that ignore the retry field — a client's ~1000ms default backoff sat near that threshold by coincidence, and a loaded runner pushed compliant clients over it. With the band gone, retry-field-ignorance is untested, which seems proportionate for a scenario that is removed in draft.

Verification

  • python-sdk client, real run: 3/3 SUCCESS (actualDelayMs: 502).
  • python-sdk client patched to ignore the retry hint (reconnects at its 1000ms fallback, previously red): now passes, delay recorded in details.
  • npm run test 328 passed; typecheck and lint clean.

AI Disclaimer