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
commandFlagshelper 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.AddGlobalRepoOverrideregisters a root-level--repoand keeps it hidden;EnableRepoOverrideunhides it only on subtrees that resolve a project. Filtering onHiddentherefore reproduces exactly the opt-in the CLI already expresses, and commands likeglab api,glab auth status, andglab completionstill do not offerrepo. - Fix the handler as well.
convertParamsToArgslooked flags up the same way and silently dropped anything it could not find, so advertisingrepoon 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 lintpasses - Documentation is unaffected (no cobra
Short,Long, or flag descriptions changed;make gen-docsreports no drift)