feat(mcp): mirror loopover_monitor_open_prs to the stdio wrapper and CLI#6789
Conversation
The MCP tool loopover_monitor_open_prs and GET /v1/contributors/:login/open-pr-monitor already served this, but the stdio wrapper registered no matching tool and the CLI had no command, so a contributor could not review their own open PRs from the terminal. - register loopover_monitor_open_prs in loopover-mcp.js, proxying the existing route (category: discovery, alongside loopover_get_decision_pack), taking the tool count 63 -> 64 - add `loopover-mcp monitor-open-prs --login <login> [--json]`, resolving the login from --login / LOOPOVER_LOGIN / GITHUB_LOGIN exactly as decisionPackCli does - reuse the API's own summary so the CLI and the MCP tool never drift into two sentences - sanitize API-chosen text on the plain-text path per JSONbored#6261 (the API composes the summary and guidance and echoes third-party PR titles); --json stays raw, as JSON.stringify escapes U+001B and callers parse that contract No new dependency, no route change, no source upload.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6789 +/- ##
=======================================
Coverage 93.63% 93.63%
=======================================
Files 683 683
Lines 68148 68148
Branches 18703 18703
=======================================
Hits 63812 63812
Misses 3350 3350
Partials 986 986
Flags with carried forward coverage won't be shown. Click here to find out more. |
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-17 06:42:58 UTC
Review summary Nits — 5 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
Closes #6732. Supersedes #6781, which was auto-closed on a CI failure that came from its base, not its diff — see the note at the end.
loopover_monitor_open_prs(src/mcp/server.ts) andGET /v1/contributors/:login/open-pr-monitor(src/api/routes.ts, gated byrequireContributorAccess) already do this work, but the stdio wrapper registered no matching tool and the CLI had no command — so a contributor could not review their own open PRs from the terminal. This mirrors the existing surface; it adds no route, no dependency, and no source upload.What changed
registerStdioTool("loopover_monitor_open_prs", ...)inpackages/loopover-mcp/bin/loopover-mcp.js, proxying the existing route viaapiGetand reusingloginShape. Its descriptor carries the same description the MCP tool already publishes, undercategory: "discovery"alongsideloopover_get_decision_pack. Tool count 63 → 64.loopover-mcp monitor-open-prs --login <github-login> [--json], resolving the login from--login/LOOPOVER_LOGIN/GITHUB_LOGINexactly asdecisionPackClidoes, registered inCLI_COMMAND_SPEC(so shell completion andsuggestCommand's "did you mean" pick it up) and listed in--help+ the Environment block.summaryrather than composing a second sentence, so the two mirrored surfaces cannot drift apart for one payload. A test pins that.#6261sanitization: the plain-text path passes API-chosen text throughsanitizePlainTextTerminalOutput— the API composessummary/guidanceand echoes PR titles back from third-party repos, so a hostile string must not be able to repaint the terminal.--jsondeliberately stays raw, sinceJSON.stringifyescapesU+001Band callers parse that contract.Tests
New
test/unit/mcp-cli-monitor-open-prs.test.ts(8 tests, in themcp-cli-*style): tool registration, route+method proxied, output parity between the mirrored surfaces for identical input, plain-text rendering, login resolution via both env vars, the shared login-required failure, ANSI sanitization (plain-text stripped /--jsonpreserved), and--help/completion documentation. The fixture route +openPrMonitorFixture()mirror the realContributorOpenPrMonitorshape.Each new test was verified to fail against the un-mirrored bin before passing, and the sanitization test was verified to fail against an un-sanitized build — they catch the defects they describe rather than merely passing.
Validation
Rebased onto
ab84f78— the first greenmainafter #6785 fixed theselfhost-grafana-dashboardassertions.npx vitest runbackend suite on this base: green, includingtest/unit/selfhost-grafana-dashboard.test.ts(30/30), the suite that failed on feat(mcp): mirror loopover_monitor_open_prs to the stdio wrapper and CLI #6781's basenpm run typecheck: clean ·npm run build:mcp+npm run test:mcp-pack: passloopover-mcp tools --jsonreports 64, matching the bumped assertion inmcp-tool-rename-aliases.test.tsWhy #6781 was closed, and what changed here
#6781 carried this same diff. Its
validate-tests (6)shard failed ontest/unit/selfhost-grafana-dashboard.test.ts— six assertions in a file this diff does not touch. That break arrived with #6779 (b440c84) at 05:29Z and leftmain's ownci.ymlred (42cca18,67af510); #6781 was branched from67af510and inherited it. #6785 has since fixed those assertions andmainis green again atab84f78, which is this PR's base — so the shard-6 failure is gone rather than argued away.The only change from #6781 is the base. The diff is byte-identical.
Note on the issue text
The issue specifies the assertion bump as 63 → 64, which is exactly right; this PR does that. It also asks for 99% patch coverage on "the new route/tool/CLI code" — worth flagging that the route and MCP tool already exist and are unchanged here, and
packages/loopover-mcp/bin/**is outside the coverageincludeinvitest.config.ts, so this diff adds no Codecov-measured lines (codecov/patchpassed on #6781 for that reason). The behaviour is covered by the unit tests above regardless.