Send current MCP protocol version in readiness probe - #5940
Conversation
|
CI note: the only red check here is Tests / Test Go Code, failing on an unrelated pre-existing flake — Root-cause fix split out to #5941 (raise the wait deadline to 15s). Once that merges, I'll rebase this branch on |
The readiness probe hardcoded protocolVersion "2024-11-05" in its initialize request. MCP servers that reject that ancient revision report as never-ready even when healthy, so ToolHive waits out the full timeout before failing to start them. Advertise a pinned, current revision (2025-11-25) in the initialize body instead. The version is deliberately pinned rather than tracking mcp.LATEST_PROTOCOL_VERSION: the upcoming 2026-07-28 revision removes the initialize method entirely (SEP-2575), so coupling the probe to a moving "latest" constant would eventually emit a method:"initialize" request stamped with a version that no longer defines it. The 2026-07-28 path (server/discover) is deferred to #5754. Also stop sending the MCP-Protocol-Version header on the initialize request. The spec scopes that header to post-initialization requests carrying the negotiated version and requires a server to reject an unsupported value with HTTP 400 -- so a header would let a backend that only supports an older revision fail the probe, whereas body-based version negotiation degrades gracefully to HTTP 200. This closes item 1 of #5764. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1f801bf to
2dddbbd
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5940 +/- ##
==========================================
- Coverage 71.77% 71.76% -0.02%
==========================================
Files 705 705
Lines 72157 72159 +2
==========================================
- Hits 51794 51783 -11
- Misses 16662 16675 +13
Partials 3701 3701 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Summary
Why: The runner's readiness probe hardcoded
"protocolVersion":"2024-11-05"in itsinitializerequest (and repeated it in theMCP-Protocol-Versionheader). MCP servers that reject that ancient revision report as never-ready even when healthy, so ToolHive waits out the full readiness timeout before failing to start them. This got more likely as backends move to newer, stricter SDKs.What:
probeProtocolVersion = "2025-11-25"— in theinitializebody instead of the hardcoded2024-11-05.mcp.LATEST_PROTOCOL_VERSION. The upcoming 2026-07-28 revision removes theinitializemethod entirely (SEP-2575, replaced byserver/discover+ per-request_meta), so coupling the probe to a moving "latest" constant would eventually emit amethod:"initialize"request stamped with a version that no longer defines it. The 2026-07-28 migration is deferred to Adopt go-sdk v1.7 for MCP 2026-07-28 stateless support #5754.MCP-Protocol-Versionheader on the initialize request. The spec scopes that header to post-initialization requests carrying the negotiated version, and requires a server to reject an unsupported value with HTTP 400. Sending it oninitializewould let a backend that only supports an older revision fail the probe, whereas body-based version negotiation degrades gracefully (the server answers HTTP 200 with its own supported version). This makes the probe robust across backend revisions in both directions.Addresses item 1 of #5764 (readiness probe protocol version). Items 2 (JSON-RPC error for filtered tool calls) and 3 (version-agnostic proxying docs + strict mode) remain, so this does not close the issue.
Type of change
Test plan
go test -race ./pkg/runner/(full package) passes, including a newTestWaitForInitializeSuccesssubtest that captures the probe request and asserts: the body carries"protocolVersion":"2025-11-25"(independent literal, so the deliberate pin can't silently drift), the body contains neither2024-11-05nor2026-07-28, and noMCP-Protocol-Versionheader is sent.task lintreports 0 issues;task buildsucceeds.Does this introduce a user-facing change?
No behavioral change users configure directly. Operationally, MCP servers that only accept recent protocol revisions now pass ToolHive's readiness probe instead of timing out at startup.
Implementation plan
Approved implementation plan
Planned with Claude Code via an architect → worker → cross-axis-review pipeline:
2024-11-05. Initially proposedmcp.LATEST_PROTOCOL_VERSION.LATESTis unsafe because 2026-07-28 removesinitialize, so the version was pinned to2025-11-25behind a documentedprobeProtocolVersionconstant; and (b) theMCP-Protocol-Versionheader oninitializecan trigger a spec-mandated HTTP 400 from older backends, so the header was dropped in favor of graceful body-based negotiation.fmt.Sprintfbody, header removal, and the regression test.Special notes for reviewers
MCP-Protocol-Versionheader". This PR instead removes that header from the probe, because the review found keeping it (even at a current version) can falsely mark older-but-healthy backends as not-ready. The body-based version is the spec-correct negotiation channel.waitForInitializeSuccessintentionally left out of scope: thedefer resp.Body.Close()inside the retry loop and closing the body without draining. Worth a separate cleanup PR.Generated with Claude Code