cli: boolean flags silently discard an inline value, so mcp-use dev --tunnel=false opens a public tunnel
Summary
parseArgs in libraries/typescript/packages/cli/src/bin/args.ts splits --flag=value for every ---prefixed token (lines 98-107), but the boolean cases in the switch (lines 147-164) never read the inline value. They assign unconditionally:
case "--tunnel":
args.tunnel = true;
break;
case "--no-open":
args.open = false;
break;So --tunnel=false is parsed as --tunnel. The false is discarded and the flag fires anyway.
The Problem
mcp-use dev --tunnel=falseandmcp-use start --tunnel=falseopen a public tunnel. A tunnel exposes a local dev server to the internet, so the result is the inverse of an explicit instruction, in the direction that widens exposure.- There is no diagnostic. Unknown flags throw at line 167, so a user reasonably concludes that an accepted flag was understood.
args.tunnelreaches a real tunnel:main.ts:285passes it torunStart,start.ts:172gates onoptions.tunnel === true, anddev.ts:1017callstunnelManager.start(port).- The same defect affects
--no-open,--no-inspector,--with-inspector,--source-maps,--inline,--helpand--version. - The docstring advertises
--flag valueand--flag=valueas generally supported, without excluding boolean switches.
Reproduced on main at 2ef6367. Unit level:
parseArgs(["dev", "--tunnel=false"]).tunnel // true
parseArgs(["dev", "--no-open=false"]).open // false
parseArgs(["build", "--source-maps=false"]).sourceMaps // trueEnd to end through main(), with only @mcp-use/tunnel stubbed at its module boundary so no real tunnel is created:
main(["start", "--path", cwd, "--port", "4567", "--tunnel=false"])
// resolves 0
// createTunnelManager called once
// tunnelManager.start called with 4567
// stdout: "mcp-use public MCP URL: https://public-test.local.mcp-use.run/mcp"Existing coverage in tests/bin-start.test.ts:227-274 exercises these flags in bare form only; =value is tested on string and number flags only (--port=8080, --mcp-dir=src/mcp).
Proposed fix
Reject a value on a boolean switch rather than interpret it. The CLI has no truthiness parsing anywhere else, so honouring the value invites follow-up questions about --tunnel=0 and --tunnel=no. takeValue records that it consumed the inline value; any flag reaching the end of the loop with an unconsumed inline value is an error.
let inlineConsumed = false;
const takeValue = (): string => {
if (inline !== undefined) {
inlineConsumed = true;
return inline;
}
// ...unchanged
};
switch (flag) { /* ...unchanged... */ }
if (inline !== undefined && !inlineConsumed) {
throw new Error(`${flag} does not take a value`);
}--tunnel=false then exits with --tunnel does not take a value. Bare booleans, --flag value, and --flag=value on value-taking flags are unaffected.
Happy to switch to honouring the value instead if you would prefer that direction.
Source: mcp-use/mcp-use