Report expired, not healthy, when an MCP connection's credential is missing - #1582
Open
GeiserX wants to merge 1 commit into
Open
Report expired, not healthy, when an MCP connection's credential is missing#1582GeiserX wants to merge 1 commit into
GeiserX wants to merge 1 commit into
Conversation
…issing checkHealth built its connector from whatever values it had. A missing value is skipped by the renderer, so the probe dialled unauthenticated, and any server that lists tools without auth answered -- discoverTools succeeding maps to healthy. A connection whose credential was gone therefore reported healthy, which is the one status that must never appear in that state, because health is what tells a user to re-authenticate. Mirrors the OpenAPI health check. resolveTools stays ungated on purpose.
This was referenced Aug 13, 2026
Author
|
Context for this one: #1585 explains why this PR and twelve others exist — they came out of a single pass over credential handling, asking for each credential where it ends up, how long it stays, and who can read it once it's there. This PR stands alone and doesn't depend on any of the others. |
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.
TL;DR
An MCP connection whose credential is gone reports
healthy. The health check builds its connector from whatever values it has; the renderer skips a placement whose value is unresolved; the probe therefore goes out unauthenticated, and any server that lists tools without auth answers.discoverToolssucceeding maps straight tostatus: "healthy".That is the one status it must never give in that state, because health is the signal telling a user to re-authenticate.
Fix: gate on the required placement variables and report
expiredwith the missing input names — exactly what the OpenAPI health check already does.Why the three MCP render paths differ
buildConnectorInputrenders auth placements and is reached from three places. They are not the same case, so only one changes:resolveToolscheckHealthexpiredThe renderer's own contract is what makes this a caller's decision rather than a bug in rendering:
Two of the three callers had made that decision explicitly. The health check had not.
Tests
health-missing-credential.test.tsdrives the plugin's owncheckHealthwith a fetch that answers everything200, so nothing except the gate stands between the result andhealthy.Both directions are pinned. A gate that returned
expiredunconditionally would satisfy the headline assertion while breaking every healthy connection, so the second test asserts a resolved input still gets through.Driven at the plugin seam rather than through a live connection deliberately: the precondition — a connection that exists but whose credential does not resolve — is the state the connection APIs are designed to prevent you from creating, so constructing it through them is not possible without faking the thing under test.
Mutation-checked, each mutation verified to have landed, with an unmutated control before and after:
expiredunconditionallyThe second mutation initially matched two sites, because the invoke path's gate opens with the same line; it was re-run with an anchor unique to the health gate rather than mutating an arbitrary one.
Package: 128 passed / 29 skipped.
tsgo --noEmit,oxlint --deny-warningsandoxfmt --checkclean.