fix: warn on unknown CLI args (#2577)

This commit is contained in:
Nikolay Vitkov
2026-08-14 10:35:24 +00:00
committed by GitHub
parent ec014d178f
commit e45036953d
4 changed files with 41 additions and 54 deletions
+5 -5
View File
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import type {parseArguments} from './bin/chrome-devtools-mcp-cli-options.js';
import type {ParsedArguments} from './bin/chrome-devtools-mcp-cli-options.js';
import type {McpContext} from './McpContext.js';
import type {McpPage} from './McpPage.js';
import type {DataFormat} from './McpResponse.js';
@@ -46,7 +46,7 @@ function buildDisabledMessage(
function getCategoryStatus(
category: ToolCategory,
serverArgs: ReturnType<typeof parseArguments>,
serverArgs: ParsedArguments,
): {categoryFlag?: string; disabled: boolean} {
const categoryFlag = buildFlag(category);
@@ -70,7 +70,7 @@ function getCategoryStatus(
function getConditionStatus(
condition: string,
serverArgs: ReturnType<typeof parseArguments>,
serverArgs: ParsedArguments,
): {conditionFlag?: string; disabled: boolean} {
if (condition && !serverArgs[condition]) {
return {conditionFlag: condition, disabled: true};
@@ -81,7 +81,7 @@ function getConditionStatus(
function getToolStatusInfo(
tool: ToolDefinition | DefinedPageTool,
serverArgs: ReturnType<typeof parseArguments>,
serverArgs: ParsedArguments,
): {disabled: boolean; reason?: string} {
const category = tool.annotations.category;
const categoryCheck = getCategoryStatus(category, serverArgs);
@@ -224,7 +224,7 @@ export class ToolHandler {
constructor(
private readonly tool: ToolDefinition | DefinedPageTool,
private readonly serverArgs: ReturnType<typeof parseArguments>,
private readonly serverArgs: ParsedArguments,
private readonly getContext: () => Promise<McpContext>,
private readonly toolMutex: Mutex,
) {
+22 -14
View File
@@ -384,23 +384,14 @@ export function parser(
argv = process.argv,
env = process.env,
) {
// Preserve yargs' mixed camel/kebab-case expansion under strict validation.
const kebabCaseAliases: Record<string, string> = {};
for (const option of Object.keys(cliOptions)) {
const alias = option.replace(
/[A-Z]/g,
letter => `-${letter.toLowerCase()}`,
);
if (alias !== option) {
kebabCaseAliases[option] = alias;
}
}
const yargsInstance = yargs(hideBin(argv))
.scriptName('npx chrome-devtools-mcp@latest')
.parserConfiguration({
'strip-aliased': true,
'strip-dashed': true,
})
.options(cliOptions)
.alias(kebabCaseAliases)
.strictOptions()
.showHelpOnFail(false, 'Specify --help for available options')
.middleware(args => {
// We can't set default in the options else
// Yargs will complain
@@ -418,6 +409,23 @@ export function parser(
);
args.usageStatistics = false;
}
const cliOptionsAllowedArgs = [
...Object.keys(cliOptions),
// Yargs populated with positional args
'_',
'$0',
];
const unknownArgs = Object.keys(args).filter(
arg => !cliOptionsAllowedArgs.includes(arg),
);
if (unknownArgs.length > 0) {
console.error(
`Unknown arguments: ${unknownArgs.map(arg => `--${arg}`)}`,
);
}
})
.example([
[
+3 -3
View File
@@ -6,7 +6,7 @@
import type fs from 'node:fs';
import type {parseArguments} from './bin/chrome-devtools-mcp-cli-options.js';
import {type ParsedArguments} from './bin/chrome-devtools-mcp-cli-options.js';
import type {Channel} from './browser.js';
import {ensureBrowserConnected, ensureBrowserLaunched} from './browser.js';
import {loadIssueDescriptions} from './devtools/issueDescriptions.js';
@@ -41,7 +41,7 @@ export {buildFlag} from './ToolHandler.js';
const ROOTS_REQUEST_TIMEOUT = 5_000;
export async function createMcpServer(
serverArgs: ReturnType<typeof parseArguments>,
serverArgs: ParsedArguments,
options: {
logFile?: fs.WriteStream;
},
@@ -230,7 +230,7 @@ export async function createMcpServer(
return {server};
}
export const logDisclaimers = (args: ReturnType<typeof parseArguments>) => {
export const logDisclaimers = (args: ParsedArguments) => {
console.error(
`chrome-devtools-mcp exposes content of the browser instance to the MCP clients allowing them to inspect,
debug, and modify any data in the browser or DevTools.
+11 -32
View File
@@ -17,25 +17,15 @@ function parseArguments(argv: string[], env: NodeJS.ProcessEnv = {}) {
describe('cli args parsing', () => {
const defaultArgs = {
'category-emulation': true,
categoryEmulation: true,
'category-performance': true,
categoryPerformance: true,
'category-network': true,
categoryNetwork: true,
'category-extensions': false,
categoryExtensions: false,
'category-experimental-third-party': false,
categoryExperimentalThirdParty: false,
'auto-connect': undefined,
autoConnect: undefined,
'performance-crux': true,
performanceCrux: true,
'usage-statistics': true,
usageStatistics: true,
'redact-network-headers': false,
redactNetworkHeaders: false,
'allow-unrestricted-paths': false,
allowUnrestrictedPaths: false,
};
@@ -57,17 +47,22 @@ describe('cli args parsing', () => {
_: [],
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
'browser-url': 'http://localhost:3000',
browserUrl: 'http://localhost:3000',
u: 'http://localhost:3000',
});
});
it('rejects unknown options', async () => {
assert.throws(
() => parseArguments(['--browserURL', 'http://localhost:3000']),
/Unknown argument: browserURL/,
);
let output = '';
const originalError = console.error;
console.error = (msg: string) => {
output += msg;
};
try {
parseArguments(['--browserURL', 'http://localhost:3000']);
assert.match(output, /Unknown arguments: --browserURL/);
} finally {
console.error = originalError;
}
});
it('parses mixed-form option names', async () => {
@@ -84,7 +79,6 @@ describe('cli args parsing', () => {
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
channel: 'stable',
'user-data-dir': '/tmp/chrome-profile',
userDataDir: '/tmp/chrome-profile',
});
});
@@ -96,9 +90,7 @@ describe('cli args parsing', () => {
_: [],
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
'browser-url': undefined,
browserUrl: undefined,
u: undefined,
channel: 'stable',
});
});
@@ -110,8 +102,6 @@ describe('cli args parsing', () => {
_: [],
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
'executable-path': '/tmp/test 123/chrome',
e: '/tmp/test 123/chrome',
executablePath: '/tmp/test 123/chrome',
});
});
@@ -142,7 +132,6 @@ describe('cli args parsing', () => {
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
channel: 'stable',
'chrome-arg': ['--no-sandbox', '--disable-setuid-sandbox'],
chromeArg: ['--no-sandbox', '--disable-setuid-sandbox'],
});
});
@@ -158,10 +147,6 @@ describe('cli args parsing', () => {
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
channel: 'stable',
'ignore-default-chrome-arg': [
'--disable-extensions',
'--disable-cancel-all-touches',
],
ignoreDefaultChromeArg: [
'--disable-extensions',
'--disable-cancel-all-touches',
@@ -179,9 +164,7 @@ describe('cli args parsing', () => {
_: [],
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
'ws-endpoint': 'ws://127.0.0.1:9222/devtools/browser/abc123',
wsEndpoint: 'ws://127.0.0.1:9222/devtools/browser/abc123',
w: 'ws://127.0.0.1:9222/devtools/browser/abc123',
});
});
@@ -195,9 +178,7 @@ describe('cli args parsing', () => {
_: [],
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
'ws-endpoint': 'wss://example.com:9222/devtools/browser/abc123',
wsEndpoint: 'wss://example.com:9222/devtools/browser/abc123',
w: 'wss://example.com:9222/devtools/browser/abc123',
});
});
@@ -222,7 +203,6 @@ describe('cli args parsing', () => {
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
channel: 'stable',
'category-emulation': false,
categoryEmulation: false,
});
});
@@ -234,7 +214,6 @@ describe('cli args parsing', () => {
headless: false,
$0: 'npx chrome-devtools-mcp@latest',
channel: 'stable',
'auto-connect': true,
autoConnect: true,
});
});