fix(mcp): treat any HTTP response as alive in health check (#732)#733
fix(mcp): treat any HTTP response as alive in health check (#732)#733
Conversation
MCP servers using Streamable HTTP with Bearer token auth show "dead" status in the UI despite being fully functional. The root cause is SseTransport::is_alive() which sends a GET request and only treats 2xx and 401 as "alive" — but many servers return 405 for GET since it's optional in the MCP spec. - Add mock MCP Streamable HTTP server (mock-mcp-server.js) - Add 5 Rust unit tests for is_alive() with various HTTP status codes (200, 401, 405, 403, 400) — bug-reproducing tests assert current broken behavior with comments to flip after fix - Add E2E test that starts mock server, adds via UI with Bearer token, and verifies status badge and tool count Entire-Checkpoint: 2696f140ed68
Merging this PR will not alter performance
Comparing Footnotes
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
SseTransport::is_alive() only considered 2xx and 401 responses as proof the server is alive. Streamable HTTP servers commonly return 405 (GET is optional), 403, or 400 for the GET health probe, causing a false "dead" status in the UI despite the server working fine. Now any HTTP response counts as alive — only network errors (connection refused, timeout, DNS failure) mean the server is dead. Entire-Checkpoint: 5c66e532116e
Greptile SummaryFixes MCP status showing "dead" for Streamable HTTP servers that return non-2xx on GET health probes (e.g. 405, 403). The fix is correct and minimal: The five new unit tests correctly assert Confidence Score: 5/5Safe to merge — the fix is correct and focused, all prior review concerns are addressed, and remaining findings are P2 style/completeness suggestions. The core change is a two-line simplification of a condition that was provably wrong per the MCP spec. Unit tests cover all target HTTP status codes. The E2E test uses proper retry-safe Playwright assertions. Only two P2 suggestions remain: adding a debug log for the Err branch and a test for the false path — neither blocks merge. crates/mcp/src/sse_transport.rs — Err branch should log at debug level and deserves one test case.
|
| Filename | Overview |
|---|---|
| crates/mcp/src/sse_transport.rs | Core fix: is_alive() now returns true for any HTTP response, false only on network errors. Change is minimal and correct. Five new unit tests cover 200/401/405/403/400 → true; the Err branch lacks a test and the error is swallowed without a debug log. |
| crates/web/ui/e2e/mock-mcp-server.js | New mock MCP Streamable HTTP server for E2E tests. Returns 405 for GET (configurable via --get-status), handles POST JSON-RPC with optional Bearer auth. Well-structured for its purpose. |
| crates/web/ui/e2e/specs/mcp.spec.js | New E2E test suite for #732: starts mock server via fork(), adds server via UI, asserts status badge shows "running". Correctly uses toHaveText() with retry, stderr captured, clearTimeout called on resolve. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[is_alive called] --> B[Build GET request with auth + session headers]
B --> C{req.send}
C -- Ok(resp) --> D[store_session_id_from_response]
D --> E[return true - Any HTTP status = reachable]
C -- Err: connection refused / timeout / DNS --> F[return false - Server is dead]
style E fill:#22c55e,color:#fff
style F fill:#ef4444,color:#fff
Reviews (4): Last reviewed commit: "test(mcp): address greptile review feedb..." | Re-trigger Greptile
|
@greptile review |
- Clear setTimeout handle on resolve to avoid lingering timers - Add stderr listener to surface mock server startup errors - Clear timeout on error/exit paths too Entire-Checkpoint: f7255ba07cb8
|
@greptile review |
Use Playwright's toHaveText with retry instead of one-shot textContent() to avoid flakes during status transitions. Entire-Checkpoint: de1e4d828854
|
@greptile review |
Summary
SseTransport::is_alive()sent a GET health probe and only treated 2xx/401 as "alive", but GET is optional in the MCP Streamable HTTP spec — servers commonly return 405, 403, or 400mock-mcp-server.js) for testingis_alive()covering 200, 401, 405, 403, 400Validation
Completed
cargo test -p moltis-mcp— all 93 tests passbiome check --write— JS lint cleancargo +nightly-2025-11-30 fmt— no formatting issues in changed filesRemaining
npx playwright test e2e/specs/mcp.spec.js— E2E tests./scripts/local-validate.sh 733Manual QA
node crates/web/ui/e2e/mock-mcp-server.js --bearer-token test123http://127.0.0.1:<port>and headerAuthorization=Bearer test123Fixes #732