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
Part of #9515; the AMS third of what #9518 originally covered, split out so each migration is a single reviewable PR.
packages/loopover-miner/bin/loopover-miner-mcp.ts registers 11 tools, and not one of them declares an outputSchema or returns structuredContent — every handler returns { content: [{ type: "text", text: JSON.stringify(...) }] }. It is the only one of LoopOver's three MCP servers with no structured output at all, so a client has to parse a JSON string out of a text block and hope the shape holds. Input schemas are raw zod shapes with no shared source.
Two more defects in the same file, both to fix here:
Inconsistent error envelopes. Only loopover_miner_get_audit_feed catches store failures and returns isError: true; the other ten throw, so a missing or corrupt store surfaces as a protocol error from ten tools and a clean structured result from one.
A hardcoded tool-name list in the tests.test/unit/miner-mcp-scaffold.test.ts pins the 11 names inline, so adding a tool needs a manual edit there and in the README — the exact hand-maintenance this epic exists to remove.
Because these tools read the miner box's own SQLite stores, every one of them is locality: "miner" — the property that makes explicit why they cannot be served from a Worker.
Requirements
Contract entries for all 11 tools in @loopover/contract, each with a real input schema and a real output schema modelled from what the handler actually returns (collectPortfolioDashboard, collectManageStatus, collectEventLedgerAuditFeed, buildCalibrationReport, collectStatus/runDoctorChecks, and the plan/claim/governor/run-state store readers). Metadata: locality: "miner", category, auth, availability, read-only annotations.
Every tool emits structuredContent alongside its existing text block. Keep the text payload byte-identical so no current consumer breaks — this is additive, and a before/after snapshot test proves it.
Unified error envelope across all 11. Extend test/unit/miner-mcp-contract.test.ts's existing parity suite (which already runs a per-tool table for secret-shaped values and excluded raw columns) to assert the same schema-described error result for a missing store, a corrupt store, and an unreadable one — for every tool, not just the audit feed.
Delete the hardcoded name list in miner-mcp-scaffold.test.ts; assert against the contract registry filtered to locality: "miner" instead, so a new tool cannot miss the test surface.
No wire regression: every currently-advertised tool name, description, and input shape is preserved or widened, never tightened. Assert with a tools/list snapshot.
Full branch-counted patch coverage per the house bar. Defects found in a migrated handler get fixed in this PR.
11 contract entries with real input + output schemas
structuredContent on every tool, text payload unchanged
Unified error envelope + parity-suite coverage for all 11
Hardcoded name list replaced by a registry assertion
tools/list snapshot proving no wire regression
Expected outcome
The AMS server stops being the odd one out: every tool advertises a validated output schema, emits structured content, and fails the same way, all from the same registry the other two servers read — and the contract validator (#9520) can then hold it to that contract mechanically.
References
Part of #9515. Blocked by #9517 (the contract package). Split from #9518, alongside the stdio server migration. Unblocks #9523 (AMS management tools).
Context
Part of #9515; the AMS third of what #9518 originally covered, split out so each migration is a single reviewable PR.
packages/loopover-miner/bin/loopover-miner-mcp.tsregisters 11 tools, and not one of them declares anoutputSchemaor returnsstructuredContent— every handler returns{ content: [{ type: "text", text: JSON.stringify(...) }] }. It is the only one of LoopOver's three MCP servers with no structured output at all, so a client has to parse a JSON string out of a text block and hope the shape holds. Input schemas are raw zod shapes with no shared source.Two more defects in the same file, both to fix here:
loopover_miner_get_audit_feedcatches store failures and returnsisError: true; the other ten throw, so a missing or corrupt store surfaces as a protocol error from ten tools and a clean structured result from one.test/unit/miner-mcp-scaffold.test.tspins the 11 names inline, so adding a tool needs a manual edit there and in the README — the exact hand-maintenance this epic exists to remove.Because these tools read the miner box's own SQLite stores, every one of them is
locality: "miner"— the property that makes explicit why they cannot be served from a Worker.Requirements
@loopover/contract, each with a real input schema and a real output schema modelled from what the handler actually returns (collectPortfolioDashboard,collectManageStatus,collectEventLedgerAuditFeed,buildCalibrationReport,collectStatus/runDoctorChecks, and the plan/claim/governor/run-state store readers). Metadata:locality: "miner",category,auth,availability, read-only annotations.structuredContentalongside its existing text block. Keep the text payload byte-identical so no current consumer breaks — this is additive, and a before/after snapshot test proves it.test/unit/miner-mcp-contract.test.ts's existing parity suite (which already runs a per-tool table for secret-shaped values and excluded raw columns) to assert the same schema-described error result for a missing store, a corrupt store, and an unreadable one — for every tool, not just the audit feed.miner-mcp-scaffold.test.ts; assert against the contract registry filtered tolocality: "miner"instead, so a new tool cannot miss the test surface.tools/listsnapshot.Non-goals
github-token-resolution.ts's hand-copied config logic (contract: generate every derived surface — typed stdio client, CLI from one spec table, tool-reference docs, miner dedup, UI z.infer types #9521).Deliverables
structuredContenton every tool, text payload unchangedtools/listsnapshot proving no wire regressionExpected outcome
The AMS server stops being the odd one out: every tool advertises a validated output schema, emits structured content, and fails the same way, all from the same registry the other two servers read — and the contract validator (#9520) can then hold it to that contract mechanically.
References
Part of #9515. Blocked by #9517 (the contract package). Split from #9518, alongside the stdio server migration. Unblocks #9523 (AMS management tools).