test(vmcp): pin that the health path never opens a standalone GET stream - #6520
Open
jstar0 wants to merge 1 commit into
Open
test(vmcp): pin that the health path never opens a standalone GET stream#6520jstar0 wants to merge 1 commit into
jstar0 wants to merge 1 commit into
Conversation
Issue stacklok#6497 reported a healthy Tableau MCP backend being marked unavailable because the vMCP health probe used a bare HTTP GET, which that backend rejects with 400 for lack of a session id. Current main no longer probes with GET: the health check is BackendClient.ListCapabilities, and newStreamableHTTPClient enables transport.WithContinuousListening — the standalone server->client SSE stream, the only GET vMCP makes — solely on the forwarding tools/call path. Nothing pinned that, so add the regression the issue describes: a real go-sdk stateful streamable-HTTP backend behind a handler that answers every GET with Tableau's 400, asserting that ListCapabilities both succeeds and issues no GET at all. Verified to have teeth: appending WithContinuousListening unconditionally in newStreamableHTTPClient makes the test fail on the GET assertion.
jstar0
requested review from
ChrisJBurns,
JAORMX,
amirejaz,
jerm-dro,
jhrozek and
tgrunnagle
as code owners
September 6, 2026 14:34
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6520 +/- ##
==========================================
- Coverage 78.43% 78.38% -0.06%
==========================================
Files 776 776
Lines 76094 76094
==========================================
- Hits 59685 59643 -42
- Misses 16404 16446 +42
Partials 5 5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Contributor
Author
|
CI note so nobody has to re-derive this: the one red check, The single real failure is and the other five entries in the summary are Two things say this isn't mine:
Happy to rebase or push an empty commit if you'd like the job re-run. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Relates to #6497.
@blkt — you were right that the reported behaviour no longer applies to
main, and I verified it before writing anything:health.NewHealthCheckerusesBackendClient.ListCapabilities, not a bare GET (pkg/vmcp/health/checker.go).newStreamableHTTPClientappendstransport.WithContinuousListening()only whenfwd != nil && forwarding— thetools/callpath. Aggregation, list, read, prompt, complete and the health check all get the plain client.So there is no bug left to fix here, and I'm not proposing a behaviour change. What is missing is a pin. The property that closes #6497 — a backend that rejects GET is still healthy — is currently implied by a condition in
newStreamableHTTPClientand by comments; nothing fails if that condition is loosened.revision_realbackend_test.gopins the neighbouring property (the version gate suppressing the stream on the forwarding path), which is the opposite arm.This PR adds the regression the issue describes, in the style of that file: a real go-sdk stateful (Legacy) streamable-HTTP backend behind a handler that answers every GET with Tableau's exact
400 Invalid or missing session IDand records the method of every request.The assertion is deliberately two-sided:
The
NotContainshalf is the one with teeth. AppendingWithContinuousListening()unconditionally innewStreamableHTTPClientdoes not makeListCapabilitiesreturn an error against this backend — the call still round-trips — it only starts a GET that the backend rejects:That is what a regression here would look like in production too: not a loud failure, but a stream opened against every session-requiring backend, which is what put Tableau into
unavailableand dropped its tools fromtools/listin the first place.I deliberately did not touch
ping. Your correction stands — it is neither universally sessionless nor unauthenticated, and2026-07-28removes it — so it is the wrong health primitive, andListCapabilitiesis already the protocol-version-aware one.Verification:
go test ./pkg/vmcp/client/ ./pkg/vmcp/health/passes;golangci-lint run ./pkg/vmcp/client/...reports 0 issues.If you'd rather close #6497 as already-fixed without carrying a test for it, say the word and I'll close this.