fix(sse-retry): gate retry timing only on the early side
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 indetails. 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 test328 passed; typecheck and lint clean.