Skip to content

test: cover SSE header forwarding at the declared SDK floor too - #106

Merged
memtomem merged 1 commit into
mainfrom
test/floor-sse-header-leg
Sep 10, 2026
Merged

test: cover SSE header forwarding at the declared SDK floor too#106
memtomem merged 1 commit into
mainfrom
test/floor-sse-header-leg

Conversation

@memtomem

Copy link
Copy Markdown
Owner

Follows #105, which left this gap deliberately and said so in its body.

The odd half of a pair

ServerSpec.headers reaches the SDK by two different spellings: SSE passes
headers= straight to sse_client, while streamable-http cannot take that
kwarg and needs a client built by create_mcp_http_client(headers=...) and
handed over as http_client=. That difference is the entire reason both need
covering — either can stop carrying credentials without the other noticing.

After #105 the coverage was lopsided:

streamable-http sse
pytest, lockfile 2.2.0 yes yes
floor script, pinned 2.1.1 yes no

header_forwarding() now takes (mode, transport, path) the way
http_transport() already did, and main() registers a leg for each. Every
cell in that table is now filled.

No runtime change. The only file under toolgraph/ is
crawler/transports.py, and only its docstring, which had started claiming
something this PR makes false.

Fail fast when the server is up and refusing

The authorized retry loop exists to wait out server startup. A 401 means the
server is already answering, so retrying was pure waste: it burned the full 30s
deadline and then died with a raw transport traceback instead of naming the
cause.

before after
time to catch a dropped header 30s 3s
what it prints httpx2.HTTPStatusError traceback [FAIL] sse headers reach the server — the server refused an authorized request -- headers are not reaching it

_rejections_or_none() is there because the obvious version of this does not
work. Reading the tally during normal startup raises URLError: Connection refused, which broke the clean run. Found by running it, not by reading it.
The wrapper returns None while the server is not answering, so a refused
connection is never mistaken for a verdict.

Verification

uv run pytest -q                                585 passed
uv run ruff check .                             All checks passed
verify_mcp_floor.py @ mcp 2.2.0                 passed, 5s
verify_mcp_floor.py @ mcp 2.1.1 (declared floor) passed, 5s

Mutation tests — each makes the script exit 1 in 3s, naming the transport:

mutation fails
sse_client(spec.url, headers=None) sse leg
if spec.headers:if False: streamable-http leg

minimum-mcp now spawns four fixture servers, sequentially, for four distinct
transport/auth combinations. Codex reviewed and returned SHIP with no findings.

Also retires a comment that this change made false: the explanation of why the
rejection tally beats the exception described streamable-http's 401/500 collapse
as if it were universal. SSE surfaces the 401 itself; the tally is what answers
the same way for both.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ue4wAZWpL7PFe7ARenR7fz

#105 left this gap on purpose and said so: `header_forwarding()` drove
streamable-http only, so SSE header forwarding was proven at the lockfile
version by pytest but not at the pinned floor. The two transports hand headers
to the SDK by different spellings, which is the whole reason both need
covering, so leaving one of them floor-unverified was the odd half of a pair.

`header_forwarding()` now takes (mode, transport, path) the way
`http_transport()` already did, and `main()` registers a leg for each. The
floor script takes 5s and spawns four fixture servers.

Fail fast when the server is up and refusing. The retry loop exists to wait out
server STARTUP; a 401 means the server is already answering, so retrying just
burned the 30s deadline and then died with a raw transport traceback instead of
naming the cause. A dropped header now fails in 3s with "the server refused an
authorized request -- headers are not reaching it".

`_rejections_or_none()` exists because the obvious version of that fail-fast
does not work: reading the tally during normal startup raises URLError, which
broke the clean run. Found by running it. The wrapper returns None while the
server is not answering yet, so "connection refused" is never mistaken for a
verdict.

Also retires two claims that this change makes false: the transports docstring
no longer says the floor pins only streamable-http, and the comment explaining
why the tally beats the exception now covers both transports rather than
describing streamable-http's 401/500 collapse as if it were universal.

Verified at mcp 2.1.1 and 2.2.0. Mutating either transport's header path makes
the script exit 1 in 3s.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ue4wAZWpL7PFe7ARenR7fz
@memtomem
memtomem merged commit 88d7ac2 into main Sep 10, 2026
14 checks passed
@memtomem
memtomem deleted the test/floor-sse-header-leg branch September 10, 2026 01:56
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