You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
#9520 shipped a "version tri-lock across all three servers". checkVersionLock
(scripts/lib/validate-mcp/invariants.ts:60-82) documents which leg matters:
LATEST_RECOMMENDED_MCP_VERSION derives from the package.json today, so two of the three are equal
by construction -- but serverInfo.versionis read independently at server construction and is
the one a client actually sees, so it is the one that can drift.
The test never reads it from a server. It reads packages/loopover-mcp/package.json's version into
a local packageVersion, then calls checkVersionLock({ packageVersion, advertisedLatestVersion: LATEST_RECOMMENDED_MCP_VERSION, serverInfoVersion: packageVersion }) — serverInfoVersion is
literally the same expression as packageVersion, so the one leg the helper says is the drift-prone
one is asserted against itself. This is the exact failure mode the same file warns about six lines
later in checkWatchedPathsExist's doc: "A version lock that only compares constants to each other
stays green while the thing that is supposed to update them has stopped running."
The other two servers are unlocked entirely. The miner reads ownPackageJson.version at packages/loopover-miner/bin/loopover-miner-mcp.ts:217 and nothing asserts it. (The remote server's
hardcoded version: "0.1.0" at src/mcp/server.ts:1204 is explicitly #9526's to fix — do not change
it here.)
The same test file also carries committed debug residue from the PR that landed it: a for (const f of result.failures) process.stdout.write(...) loop at test/contract/validate-mcp.test.ts:197-198 that prints RFAIL lines for the remote surface only,
and a comment block at :186-193 where an earlier and a rewritten version of the same paragraph both
survive.
Requirements
The stdio leg is read from the live server: connect the client (as validateSurface already does)
and take the version from client.getServerVersion(), then feed that into checkVersionLock as serverInfoVersion. It must be obtained from the connected client, never re-read from package.json.
A second lock covers the miner server: its serverInfo.version read from a connected client must
equal packages/loopover-miner/package.json's version.
checkVersionLock gains a failure for a missingserverInfoVersion (an undefined or empty
value from a server that advertised none), so an absent version cannot pass as an accidental
match.
test/contract/validate-mcp.test.ts:197-198's RFAIL debug loop is deleted, and the duplicated
comment paragraph at :186-193 is reduced to the one accurate version.
⚠️ Required pattern: checkVersionLock in scripts/lib/validate-mcp/invariants.ts:60-82 stays the
single pure comparator; the test's job is to supply it a value actually observed on the wire.
Comparing serverInfo.version to a second readFileSync of the same package.json, or asserting
the version inside a server module's unit test instead of over a connected client, do NOT satisfy
this issue.
Deliverables
test/contract/validate-mcp.test.ts's version-lock case obtains the stdio server's serverInfo.version from a connected Client and passes it as serverInfoVersion
A miner version-lock case comparing the miner server's advertised serverInfo.version to packages/loopover-miner/package.json's version
checkVersionLock returns a failure for an absent or empty serverInfoVersion, unit-tested in test/unit/validate-mcp-helpers.test.ts for: all three agreeing, a drifted serverInfo, a
drifted compatibility constant, and an absent serverInfo
The RFAIL debug loop at test/contract/validate-mcp.test.ts:197-198 is deleted and the
duplicated comment at :186-193 is collapsed to one paragraph
npm run validate:mcp green
All Deliverables above are required in a single PR. A PR that satisfies only some of them — for
example adding the miner lock while leaving the stdio leg comparing packageVersion to itself — does
not resolve this issue.
Test Coverage Requirements
99%+ Codecov patch coverage, branch-counted, applies to any src/** or packages/** file you touch
(vitest.config.ts:55-100). scripts/lib/validate-mcp/invariants.ts and test/** are outside coverage.include, so the new checkVersionLock branch is not Codecov-gated — cover both arms in test/unit/validate-mcp-helpers.test.ts anyway, and add a named regression test proving a
deliberately mismatched serverInfoVersion produces a failure string.
Expected Outcome
The version lock fails when the stdio or miner server advertises a version that disagrees with its
own package.json — instead of passing because it compares a value to itself.
Context
#9520 shipped a "version tri-lock across all three servers".
checkVersionLock(
scripts/lib/validate-mcp/invariants.ts:60-82) documents which leg matters:The test never reads it from a server. It reads
packages/loopover-mcp/package.json'sversionintoa local
packageVersion, then callscheckVersionLock({ packageVersion, advertisedLatestVersion: LATEST_RECOMMENDED_MCP_VERSION, serverInfoVersion: packageVersion })—serverInfoVersionisliterally the same expression as
packageVersion, so the one leg the helper says is the drift-proneone is asserted against itself. This is the exact failure mode the same file warns about six lines
later in
checkWatchedPathsExist's doc: "A version lock that only compares constants to each otherstays green while the thing that is supposed to update them has stopped running."
The other two servers are unlocked entirely. The miner reads
ownPackageJson.versionatpackages/loopover-miner/bin/loopover-miner-mcp.ts:217and nothing asserts it. (The remote server'shardcoded
version: "0.1.0"atsrc/mcp/server.ts:1204is explicitly #9526's to fix — do not changeit here.)
The same test file also carries committed debug residue from the PR that landed it: a
for (const f of result.failures) process.stdout.write(...)loop attest/contract/validate-mcp.test.ts:197-198that printsRFAILlines for the remote surface only,and a comment block at
:186-193where an earlier and a rewritten version of the same paragraph bothsurvive.
Requirements
validateSurfacealready does)and take the version from
client.getServerVersion(), then feed that intocheckVersionLockasserverInfoVersion. It must be obtained from the connected client, never re-read frompackage.json.serverInfo.versionread from a connected client mustequal
packages/loopover-miner/package.json'sversion.checkVersionLockgains a failure for a missingserverInfoVersion(an undefined or emptyvalue from a server that advertised none), so an absent version cannot pass as an accidental
match.
test/contract/validate-mcp.test.ts:197-198'sRFAILdebug loop is deleted, and the duplicatedcomment paragraph at
:186-193is reduced to the one accurate version.serverInfo.versionstays out of the lock, with a code comment naming mcp(discovery): server.json + .well-known surfaces, MCP registry publish, and the stdio gateway front door #9526as the issue that makes it derivable.
Deliverables
test/contract/validate-mcp.test.ts's version-lock case obtains the stdio server'sserverInfo.versionfrom a connectedClientand passes it asserverInfoVersionserverInfo.versiontopackages/loopover-miner/package.json'sversioncheckVersionLockreturns a failure for an absent or emptyserverInfoVersion, unit-tested intest/unit/validate-mcp-helpers.test.tsfor: all three agreeing, a drifted serverInfo, adrifted compatibility constant, and an absent serverInfo
RFAILdebug loop attest/contract/validate-mcp.test.ts:197-198is deleted and theduplicated comment at
:186-193is collapsed to one paragraphnpm run validate:mcpgreenAll Deliverables above are required in a single PR. A PR that satisfies only some of them — for
example adding the miner lock while leaving the stdio leg comparing
packageVersionto itself — doesnot resolve this issue.
Test Coverage Requirements
99%+ Codecov patch coverage, branch-counted, applies to any
src/**orpackages/**file you touch(
vitest.config.ts:55-100).scripts/lib/validate-mcp/invariants.tsandtest/**are outsidecoverage.include, so the newcheckVersionLockbranch is not Codecov-gated — cover both arms intest/unit/validate-mcp-helpers.test.tsanyway, and add a named regression test proving adeliberately mismatched
serverInfoVersionproduces a failure string.Expected Outcome
The version lock fails when the stdio or miner server advertises a version that disagrees with its
own
package.json— instead of passing because it compares a value to itself.Links & Resources
test/contract/validate-mcp.test.ts:180-259scripts/lib/validate-mcp/invariants.ts:60-95packages/loopover-mcp/bin/loopover-mcp.ts:177-178, 741-744packages/loopover-miner/bin/loopover-miner-mcp.ts:145-146, 217src/services/mcp-compatibility.ts"0.1.0"belongs to mcp(discovery): server.json + .well-known surfaces, MCP registry publish, and the stdio gateway front door #9526 — out of scope here.