Skip to content

fix(mcp): print usage help for bare loopover-mcp invocation instead of starting stdio server - #8486

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
tryeverything24:fix-mcp-bare-invocation-8313
Jul 24, 2026
Merged

fix(mcp): print usage help for bare loopover-mcp invocation instead of starting stdio server#8486
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
tryeverything24:fix-mcp-bare-invocation-8313

Conversation

@tryeverything24

Copy link
Copy Markdown
Contributor

Summary

Running loopover-mcp with no arguments — the natural first thing a new user tries — silently started the stdio MCP server and hung waiting for JSON-RPC input, instead of printing usage help.

Two top-level gates in packages/loopover-mcp/bin/loopover-mcp.ts caused this:

  • The CLI-dispatch gate (if (runAsCliEntrypoint && cliArgs[0] && cliArgs[0] !== "--stdio")) only ran when cliArgs[0] was truthy. A bare invocation leaves cliArgs[0] as undefined, so the whole block was skipped — no runCli, no process.exit.
  • Execution then fell through unconditionally to if (runAsCliEntrypoint) await server.connect(new StdioServerTransport()), binding the stdio transport to the real stdin/stdout — the exact effective behavior of loopover-mcp --stdio.

Fix

  • Entry gate (:1645): drop the cliArgs[0] && truthiness requirement so a zero-argument invocation reaches runCli([]) instead of falling through to the stdio bind. An explicit --stdio is still routed to the server (its behavior is unchanged).
  • runCli (:4105): add command === undefined to the existing --help/help branch so runCli([]) prints the usage banner via printHelp() and returns (exit 0), mirroring the existing help handling rather than reaching the "Unknown command" path.
  • runCli is exported as a separate statement (same rationale as the neighboring runAgentCli/maintainCli exports) so an in-process unit test can drive the new branch for Codecov coverage — a bare invocation is otherwise only reachable via subprocess spawn, which v8 coverage cannot instrument.

Only an explicit loopover-mcp --stdio starts the MCP stdio server now; a bare loopover-mcp behaves like every other documented CLI's bare invocation — it prints usage help and exits.

Tests

New dedicated test/unit/mcp-cli-bare-invocation.test.ts:

  • In-process (Codecov-attributed): drives runCli([]), runCli(["--help"]), runCli(["help"]) — asserting all three produce byte-identical usage output — plus runCli(["version"]) to exercise the changed condition's false path. This covers the new command === undefined branch's statement and every branch (both if outcomes and all three || operands).
  • Subprocess regression: spawns the bare command and asserts it exits 0 without hanging and prints the same banner as --help, proving the end-to-end entry-gate fix.

Closes #8313

…f starting stdio server

A bare `loopover-mcp` (zero arguments) fell through the CLI-dispatch gate,
whose guard required `cliArgs[0]` to be truthy, and reached the unconditional
StdioServerTransport bind -- silently starting the MCP stdio server and hanging
on a plain terminal that never sends JSON-RPC, instead of printing usage help.

Relax the entry gate so a zero-arg invocation reaches `runCli([])`, and add a
`command === undefined` case to runCli's existing --help/help branch so it prints
the usage banner via printHelp() and exits 0. Only an explicit --stdio invocation
still starts the stdio server; --stdio behavior is unchanged.

Export runCli (separate statement, mirroring runAgentCli/maintainCli) so a new
in-process test drives the changed branch for Codecov coverage; a dedicated
regression test also asserts the bare subprocess exits 0 with the banner.

Closes JSONbored#8313
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.50%. Comparing base (32f37d5) to head (7a18423).
⚠️ Report is 18 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #8486       +/-   ##
===========================================
+ Coverage   66.08%   82.50%   +16.41%     
===========================================
  Files         791       98      -693     
  Lines       79333    24962    -54371     
  Branches    23961     4729    -19232     
===========================================
- Hits        52430    20594    -31836     
+ Misses      22909     4176    -18733     
+ Partials     3994      192     -3802     
Flag Coverage Δ
shard-1 11.21% <100.00%> (?)
shard-3 ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-mcp/bin/loopover-mcp.ts 11.21% <100.00%> (-2.80%) ⬇️

... and 693 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 24, 2026
@loopover-orb

loopover-orb Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-24 15:31:28 UTC

2 files · 1 AI reviewer · no blockers · readiness 93/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
The fix directly addresses the described bug: the entry-gate at loopover-mcp.ts:1645 previously required `cliArgs[0]` to be truthy before dispatching to `runCli`, so a bare invocation (`cliArgs[0] === undefined`) fell straight through to the unconditional `server.connect(new StdioServerTransport())`, hanging on stdin. Dropping the truthiness check so the gate is just `cliArgs[0] !== "--stdio"` correctly routes `runCli([])` instead, and the added `command === undefined` operand in runCli's existing help branch (line ~4105) makes that call print the usage banner and return, matching the described contract. The `--stdio` path is unaffected (`"--stdio" !== "--stdio"` is false, so the gate still skips runCli and falls to the stdio bind), and the new test exercises both the in-process branch (for coverage attribution) and a real subprocess spawn asserting the process exits promptly with matching output.

Nits — 3 non-blocking

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8313
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 86 registered-repo PR(s), 38 merged, 4 issue(s).
Contributor context ✅ Confirmed Gittensor contributor tryeverything24; Gittensor profile; 86 PR(s), 4 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The diff makes exactly the two changes the issue specifies: the entry gate at line 1645 drops the `cliArgs[0] &&` truthiness check so bare invocation reaches runCli, and runCli's help branch is extended with `command === undefined` to route to printHelp() instead of the stdio bind or unknown-command path, with `--stdio` behavior untouched. A regression test file explicitly asserts bare invocation

Review context
  • Author: tryeverything24
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: JavaScript, TypeScript, Python, HTML, C++, Java, PHP, C#
  • Official Gittensor activity: 86 PR(s), 4 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Triage stale or unlinked PRs.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask 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.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

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.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit c096106 into JSONbored:main Jul 24, 2026
12 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 24, 2026
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(mcp): bare loopover-mcp invocation silently starts the stdio MCP server instead of printing help

1 participant