[0.8.39] - 2026-11-12
Changed
- Flag ownership now also covers the action-first commands —
plugin,kb,
session,resources,prompts,complete(issue #41, final batch). Their flags
follow a subcommand (mcptoon plugin install <dir> --force), so each set is the
union over the actions, read from_cmd_plugin_*and the command's own module
(kb.py,session_log.py,mcp_extras.py). A flag standing where the action
belongs is still the command's own error, which says more than ours would
(Unknown plugin subcommand: --force. Available: scan | install | list | remove).
The registry now covers 20 commands;auth,bake,openapiandgraphql
stay out because the pre-pass hands them the rest of the line verbatim and their
flags belong to a sub-module. - Flag ownership now covers
call,install,activity,sync,serve,
skillsandretrieve(issue #41, second batch). Each set was read from the
source that parses it — the handler incli.py, or the command's own module
(skills.py,serve.py) — and cross-checked against the invocations the shipped
docs show.auth/bake/openapi/graphqlstay out on purpose: the pre-pass
hands them the rest of the line verbatim, so their flags belong to a sub-module and
cannot be enumerated here. Two consequences of the wider set:--helpnow always
passes (ten commands carry their own help page, where it is not consumed by the
pre-pass and stays in the argument list), and a new test sweeps the docs and fails
if a registered command would reject a flag those docs promise — so the table can
keep growing one command at a time without documenting a rejected invocation. The
error's "did you mean" hint prints names now, not a Python list repr. --formatnow says who owns it, and validates its value. It ismanifest's
export selector (openai|openapi|mcp|json|human), but the global pre-pass consumes
it for every command — it has to, becausemcptoon --format mcp manifestputs the
flag before the command. Measured on 0.8.38:list --format json,
list --format toonandlist --format bogusall printed the same
940-character human list and exited 0 (fmtis set by--json/--toon/--slim,
never by--format). A command with no export now exits 2 and points at the flags
that do set the format, andmanifest --format mpc(a typo) exits 1 with the
allowed list instead of silently dumping JSON — which is whatexport_manifest's
documented fallback used to produce.manifest/toolskeep working, in either
position.- A flag a command does not own is now a usage error.
mcptoon list --verbose
printed the human server list and exited 0:--verboseis a real flag, just
manifest's, so the global pre-pass tolerated it andlistsilently dropped it —
a correctly spelled wrong flag was quieter than the typolist --verbos
(exit 2).list,inspect,searchandmanifestnow declare the flags they own
explicitly and reject anything else with exit 2, naming the command that does own
the flag ('--verbose' is an option of: manifest). A command joins that registry
only once its flags are enumerated by hand — never inferred from a handler's
docstring, which would reject flags the code supports but the prose omits. Every
other command keeps the previous behaviour until its turn (issue #41).
MCPTOON_STRICT_FLAGS=0still downgrades this and the unknown-option error to a
warning.
Fixed
--yamlis no longer accepted. It was registered as a pass-through for a
per-command YAML renderer that was never written:ArgParserFactorydeclared the
flag, no code read the parsed attribute, andoutput.renderhas no yaml branch —
somcptoon list --yamlprinted human text and exited 0 whilelist --json
printed data, andmcptoon --helpnever mentioned the flag at all (found
2026-11-12 while auditing the option-ownership surface, #49). It is now an unknown
option — exit 2 — in either position, and the factory baseline no longer offers it.
YAML output will come back per command, with a renderer and tests, when that topic
is taken up.