fix(mcp): advertise inherited flags in tool schemas

What does this MR do and why?

Closes #8529 (closed).

glab mcp serve built each tool's JSON schema from cmd.Flags() and cmd.PersistentFlags() only. Cobra folds a parent's persistent flags into cmd.Flags() when a command executes, which never happens for the commands the MCP server inspects: tools are registered up front and the command itself runs later in a subprocess. Any flag registered on a parent noun was therefore invisible to the generator.

The flag this matters for is -R/--repo. cmdutils.EnableRepoOverride is usually called on the noun (issue, mr, ci), so only the 20 leaf commands that also call it on themselves advertised repo. The other 180 did not. An MCP client had no way to target another project, and the call did not fail: it succeeded against whatever project the working directory resolved to, which is a silent wrong-target write.

Changes

  • Add a commandFlags helper that collects a command's own, persistent, and inherited flags, and build the schema from it.
  • Keep the existing skip for hidden flags, which is now load-bearing. cmdutils.AddGlobalRepoOverride registers a root-level --repo and keeps it hidden; EnableRepoOverride unhides it only on subtrees that resolve a project. Filtering on Hidden therefore reproduces exactly the opt-in the CLI already expresses, and commands like glab api, glab auth status, and glab completion still do not offer repo.
  • Fix the handler as well. convertParamsToArgs looked flags up the same way and silently dropped anything it could not find, so advertising repo on its own would not have forwarded it. Schema and handler now read one flag set resolved once at registration time.

Resolving the flag set once also avoids a concurrency hazard: cobra populates inherited flags lazily by mutating the command, which concurrent tool invocations must not do. An earlier revision that called commandFlags per request panicked under the parallel tests in this package.

Result

Measured with a real tools/list request over stdio against a binary built from this branch:

before after
tools exposing repo 20 152
tools without it 180 48

glab_issue_create, glab_issue_view, glab_mr_create, glab_mr_view, and glab_issue_note all expose repo now. The 48 that still do not accept no --repo in their own --help either: the repo_* commands take the project as a positional argument, and alias, auth, api, version, and todo resolve no project.

Testing

Four tests in server_test.go, built on a synthetic tree that mirrors the production wiring (hidden --repo at the root, unhidden on the noun, absent on the leaf):

  • inherited flags appear in the schema
  • a hidden inherited flag does not
  • the handler forwards an inherited flag
  • unknown flags are still ignored

The first and third fail without the fix.

One gap worth naming: #8529 (closed) also asked for a registration test asserting the invariant across the whole real command tree. That cannot live in this package's test file, because internal/commands imports mcp → serve, so importing the real tree from package serve is an import cycle. It would need an external serve_test package plus an export shim. The tests here pin the generator's contract but would not catch a future noun that wires up --repo in a way the generator does not see.

Author checklist

  • Tests added for new functionality
  • make lint passes
  • Documentation is unaffected (no cobra Short, Long, or flag descriptions changed; make gen-docs reports no drift)

Merge request reports

Loading
Loading