⚠️ 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
After #9518/#9536/#9537 every MCP tool registers from @loopover/contract — with exactly one
exception. src/mcp/server.ts:2398 registers loopover_admin_rotate_secret with
inputSchema: adminRotateSecretShape and outputSchema: adminRotateSecretOutputSchema, both
declared locally in src/mcp/server.ts. Its four siblings (loopover_admin_get_config,
loopover_admin_write_config, loopover_admin_list_config_backups,
loopover_admin_trigger_redeploy) all have contract entries in
packages/loopover-contract/src/tools/admin-config.ts; rotate_secret does not, and
TOOL_CONTRACTS (packages/loopover-contract/src/tools/index.ts:152-155) lists only those four.
The reason it went unnoticed is the second half of this issue. The five admin tools are registered
only when isMcpAdminEnabled(env) is true (src/mcp/server.ts:2355), and
test/contract/validate-mcp.test.ts:181 boots the remote server with createTestEnv(), which does
not set LOOPOVER_MCP_ADMIN_ENABLED. So the admin category is never in tools/list during
validate:mcp: never diffed against the registry, never Ajv-compiled, never smoke-called, never
output-schema-validated. The validator's own strict assertion — "nothing is registered without a
contract entry" (test/contract/validate-mcp.test.ts:186-195) — is structurally unable to see the
one tool that violates it.
This is also why the #9522 catalog says "existing 4 admin tools migrate to the registry": the
fifth is invisible to every inventory the repo can currently produce.
Requirements
adminRotateSecretShape and adminRotateSecretOutputSchema move into
packages/loopover-contract/src/tools/admin-config.ts as AdminRotateSecretInput /
AdminRotateSecretOutput, with an adminRotateSecretTool defineTool entry
(category: "admin", auth: "mcp-admin", locality: "remote", availability: "selfhost",
annotations: { readOnlyHint: false, destructiveHint: true }, matching
adminWriteConfigTool/adminTriggerRedeployTool at admin-config.ts:93 and :161), added to
TOOL_CONTRACTS, and the registration at src/mcp/server.ts:2398 reads from it. The local
declarations are deleted.
- The schemas move verbatim. The accepted field set, every bound, and the returned shape are
byte-identical before and after; test/unit/mcp-admin-rotate-secret-tool.test.ts must pass
unchanged apart from import paths.
test/contract/validate-mcp.test.ts's remote surface boots a second LoopoverMcp with
LOOPOVER_MCP_ADMIN_ENABLED set, and runs the full validateSurface pass over it, so all five
admin tools are diffed, compiled, smoke-called and output-validated like every other tool.
- The admin tools must answer (not throw) in that cold fixture environment — the capability
registries are unfilled there, so each returns its configured: false result and the smoke call
records a normal validated or declined outcome. Add SMOKE_ARGUMENT_OVERRIDES entries in
scripts/lib/validate-mcp/overrides.ts only where the synthesized minimum is not semantically
inert.
- No change to the rotation behaviour, the redeploy-companion protocol, the
requireMcpAdmin gate,
or isMcpAdminEnabled. This issue relocates schemas and adds test coverage; it touches no
secret-handling code path.
⚠️ Required pattern: mirror adminTriggerRedeployTool in
packages/loopover-contract/src/tools/admin-config.ts:120-164 — the sibling tool with the same
auth level, the same capability-registry "not configured" result, and the same destructive
annotations. Leaving the schemas in src/mcp/server.ts and merely re-exporting them, or enabling
admin registration in the validator without adding the contract entry (which makes the run fail
rather than pass), do NOT satisfy this issue.
Deliverables
All Deliverables above are required in a single PR. A PR that satisfies only some of them — for
example adding the contract entry without the admin-enabled validator pass, so the next admin tool
can repeat the same escape — does not resolve this issue.
Test Coverage Requirements
99%+ Codecov patch coverage, branch-counted, applies: src/mcp/server.ts and
packages/loopover-contract/src/** are both in coverage.include (vitest.config.ts:55-100). Every
branch of the moved zod schema that has a distinct accept/reject outcome needs a case on both sides
(the existing test/unit/mcp-admin-rotate-secret-tool.test.ts rejection table is the model), and a
named regression test must assert getToolContract("loopover_admin_rotate_secret") is defined.
scripts/lib/validate-mcp/** and test/** are outside coverage.include.
Expected Outcome
Every tool any LoopOver MCP server registers has a contract entry, and npm run validate:mcp
exercises the admin category instead of silently skipping it — so the "nothing is registered without
a registry entry" assertion is true rather than unfalsifiable.
Links & Resources
Context
After #9518/#9536/#9537 every MCP tool registers from
@loopover/contract— with exactly oneexception.
src/mcp/server.ts:2398registersloopover_admin_rotate_secretwithinputSchema: adminRotateSecretShapeandoutputSchema: adminRotateSecretOutputSchema, bothdeclared locally in
src/mcp/server.ts. Its four siblings (loopover_admin_get_config,loopover_admin_write_config,loopover_admin_list_config_backups,loopover_admin_trigger_redeploy) all have contract entries inpackages/loopover-contract/src/tools/admin-config.ts;rotate_secretdoes not, andTOOL_CONTRACTS(packages/loopover-contract/src/tools/index.ts:152-155) lists only those four.The reason it went unnoticed is the second half of this issue. The five admin tools are registered
only when
isMcpAdminEnabled(env)is true (src/mcp/server.ts:2355), andtest/contract/validate-mcp.test.ts:181boots the remote server withcreateTestEnv(), which doesnot set
LOOPOVER_MCP_ADMIN_ENABLED. So the admin category is never intools/listduringvalidate:mcp: never diffed against the registry, never Ajv-compiled, never smoke-called, neveroutput-schema-validated. The validator's own strict assertion — "nothing is registered without a
contract entry" (
test/contract/validate-mcp.test.ts:186-195) — is structurally unable to see theone tool that violates it.
This is also why the #9522 catalog says "existing 4 admin tools migrate to the registry": the
fifth is invisible to every inventory the repo can currently produce.
Requirements
adminRotateSecretShapeandadminRotateSecretOutputSchemamove intopackages/loopover-contract/src/tools/admin-config.tsasAdminRotateSecretInput/AdminRotateSecretOutput, with anadminRotateSecretTooldefineToolentry(
category: "admin",auth: "mcp-admin",locality: "remote",availability: "selfhost",annotations: { readOnlyHint: false, destructiveHint: true }, matchingadminWriteConfigTool/adminTriggerRedeployToolatadmin-config.ts:93and:161), added toTOOL_CONTRACTS, and the registration atsrc/mcp/server.ts:2398reads from it. The localdeclarations are deleted.
byte-identical before and after;
test/unit/mcp-admin-rotate-secret-tool.test.tsmust passunchanged apart from import paths.
test/contract/validate-mcp.test.ts's remote surface boots a secondLoopoverMcpwithLOOPOVER_MCP_ADMIN_ENABLEDset, and runs the fullvalidateSurfacepass over it, so all fiveadmin tools are diffed, compiled, smoke-called and output-validated like every other tool.
registries are unfilled there, so each returns its
configured: falseresult and the smoke callrecords a normal validated or declined outcome. Add
SMOKE_ARGUMENT_OVERRIDESentries inscripts/lib/validate-mcp/overrides.tsonly where the synthesized minimum is not semanticallyinert.
requireMcpAdmingate,or
isMcpAdminEnabled. This issue relocates schemas and adds test coverage; it touches nosecret-handling code path.
Deliverables
AdminRotateSecretInput,AdminRotateSecretOutputandadminRotateSecretToolinpackages/loopover-contract/src/tools/admin-config.ts;adminRotateSecretToolinTOOL_CONTRACTSadminRotateSecretShape/adminRotateSecretOutputSchemadeleted fromsrc/mcp/server.ts;the
register("loopover_admin_rotate_secret", ...)call reads the contracttest/unit/mcp-admin-rotate-secret-tool.test.tspasses with no assertion changestest/contract/validate-mcp.test.tsthat boots the remote server withLOOPOVER_MCP_ADMIN_ENABLEDtruthy and runsvalidateSurfaceover it, asserting all fiveadmin tool names are present and
result.failuresis emptylistToolDefinitions({ category: ["admin"] })has exactly 5 entries, so asixth admin tool added without a contract entry fails
All Deliverables above are required in a single PR. A PR that satisfies only some of them — for
example adding the contract entry without the admin-enabled validator pass, so the next admin tool
can repeat the same escape — does not resolve this issue.
Test Coverage Requirements
99%+ Codecov patch coverage, branch-counted, applies:
src/mcp/server.tsandpackages/loopover-contract/src/**are both incoverage.include(vitest.config.ts:55-100). Everybranch of the moved zod schema that has a distinct accept/reject outcome needs a case on both sides
(the existing
test/unit/mcp-admin-rotate-secret-tool.test.tsrejection table is the model), and anamed regression test must assert
getToolContract("loopover_admin_rotate_secret")is defined.scripts/lib/validate-mcp/**andtest/**are outsidecoverage.include.Expected Outcome
Every tool any LoopOver MCP server registers has a contract entry, and
npm run validate:mcpexercises the admin category instead of silently skipping it — so the "nothing is registered without
a registry entry" assertion is true rather than unfalsifiable.
Links & Resources
src/mcp/server.ts:2349-2404(the admin block), the localadminRotateSecretShape/adminRotateSecretOutputSchemadeclarationspackages/loopover-contract/src/tools/admin-config.ts,packages/loopover-contract/src/tools/index.ts:152-155test/contract/validate-mcp.test.ts:180-212,test/unit/mcp-admin-rotate-secret-tool.test.ts