refactor: extract category config into a seprate file (#2652)

This commit is contained in:
Nikolay Vitkov
2026-09-03 15:45:45 +00:00
committed by GitHub
parent e7ecca4d1c
commit 401a1192b6
11 changed files with 214 additions and 176 deletions
+30 -35
View File
@@ -4,6 +4,36 @@ The Chrome DevTools MCP server supports the following configuration option:
<!-- BEGIN AUTO GENERATED OPTIONS -->
- **`--categoryEmulation`/ `--category-emulation`**
Set to false to exclude tools related to emulation.
- **Type:** boolean
- **Default:** `true`
- **`--categoryPerformance`/ `--category-performance`**
Set to false to exclude tools related to performance.
- **Type:** boolean
- **Default:** `true`
- **`--categoryNetwork`/ `--category-network`**
Set to false to exclude tools related to network.
- **Type:** boolean
- **Default:** `true`
- **`--categoryExtensions`/ `--category-extensions`**
Set to true to include tools related to extensions. Note: This feature is currently only supported with a pipe connection. autoConnect, browserUrl, and wsEndpoint are not supported with this feature until 149 will be released.
- **Type:** boolean
- **Default:** `false`
- **`--categoryExperimentalThirdParty`/ `--category-experimental-third-party`**
Set to true to enable third-party developer tools exposed by the inspected page itself
- **Type:** boolean
- **Default:** `false`
- **`--categoryPwa`/ `--category-pwa`**
Set to true to include tools for automating Progressive Web Apps (install, launch, uninstall, and OS state). This feature is only supported with a pipe connection; autoConnect, browserUrl, and wsEndpoint are not supported.
- **Type:** boolean
- **Default:** `false`
- **`--autoConnect`/ `--auto-connect`**
If specified, automatically connects to a browser (Chrome 144+) running locally from the user data directory identified by the channel param (default channel is stable). Requires the remote debugging server to be started in the Chrome instance via chrome://inspect/#remote-debugging.
- **Type:** boolean
@@ -115,11 +145,6 @@ The Chrome DevTools MCP server supports the following configuration option:
- **Type:** number
- **Default:** `false`
- **`--categoryExperimentalWebmcp`/ `--category-experimental-webmcp`**
Set to true to enable debugging WebMCP tools. Requires Chrome 150+ with the following flag: `--enable-features=WebMCP`
- **Type:** boolean
- **Default:** `false`
- **`--chromeArg`/ `--chrome-arg`**
Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.
- **Type:** array
@@ -140,36 +165,6 @@ The Chrome DevTools MCP server supports the following configuration option:
- **Type:** array
- **Default:** `false`
- **`--categoryEmulation`/ `--category-emulation`**
Set to false to exclude tools related to emulation.
- **Type:** boolean
- **Default:** `true`
- **`--categoryPerformance`/ `--category-performance`**
Set to false to exclude tools related to performance.
- **Type:** boolean
- **Default:** `true`
- **`--categoryNetwork`/ `--category-network`**
Set to false to exclude tools related to network.
- **Type:** boolean
- **Default:** `true`
- **`--categoryExtensions`/ `--category-extensions`**
Set to true to include tools related to extensions. Note: This feature is currently only supported with a pipe connection. autoConnect, browserUrl, and wsEndpoint are not supported with this feature until 149 will be released.
- **Type:** boolean
- **Default:** `false`
- **`--categoryExperimentalThirdParty`/ `--category-experimental-third-party`**
Set to true to enable third-party developer tools exposed by the inspected page itself
- **Type:** boolean
- **Default:** `false`
- **`--categoryPwa`/ `--category-pwa`**
Set to true to include tools for automating Progressive Web Apps (install, launch, uninstall, and OS state). This feature is only supported with a pipe connection; autoConnect, browserUrl, and wsEndpoint are not supported.
- **Type:** boolean
- **Default:** `false`
- **`--performanceCrux`/ `--performance-crux`**
Set to false to disable sending URLs from performance traces to CrUX API to get field performance data.
- **Type:** boolean
+6 -7
View File
@@ -11,12 +11,11 @@ import {Client} from '@modelcontextprotocol/sdk/client/index.js';
import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';
import {mcpOptions, parseArguments} from '../build/src/config/mcp-options.js';
import {buildFlag} from '../build/src/index.js';
import {
labels,
ToolCategory,
OFF_BY_DEFAULT_CATEGORIES,
} from '../build/src/tools/categories.js';
isCategoryOffByDefault,
categoryToFlagName,
} from '../build/src/config/category-options.js';
import {labels, ToolCategory} from '../build/src/tools/categories.js';
import {createTools} from '../build/src/tools/tools.js';
const OUTPUT_PATH = path.join(
@@ -166,9 +165,9 @@ async function generateCli() {
let description = tool.description;
const requiredFlags: string[] = [];
const isOffByDefault = OFF_BY_DEFAULT_CATEGORIES.includes(categoryEnum);
const isOffByDefault = isCategoryOffByDefault(categoryEnum);
if (isOffByDefault) {
const categoryFlag = buildFlag(categoryEnum);
const categoryFlag = categoryToFlagName(categoryEnum);
requiredFlags.push(`--${categoryFlag}=true`);
}
+10 -11
View File
@@ -12,12 +12,11 @@ import {
mcpOptions,
type ParsedArguments,
} from '../build/src/config/mcp-options.js';
import {buildFlag} from '../build/src/ToolHandler.js';
import {
ToolCategory,
OFF_BY_DEFAULT_CATEGORIES,
labels,
} from '../build/src/tools/categories.js';
isCategoryOffByDefault,
categoryToFlagName,
} from '../build/src/config/category-options.js';
import {ToolCategory, labels} from '../build/src/tools/categories.js';
import {pageIdSchema} from '../build/src/tools/ToolDefinition.js';
import {createTools} from '../build/src/tools/tools.js';
@@ -312,8 +311,8 @@ async function generateReference(
markdown += `## ${categoryName}\n\n`;
if (OFF_BY_DEFAULT_CATEGORIES.includes(category)) {
const flagName = `--${buildFlag(category)}`;
if (isCategoryOffByDefault(category)) {
const flagName = `--${categoryToFlagName(category)}`;
markdown += `> NOTE: The ${categoryName} category is not active by default. Use the '${flagName}' flag.\n\n`;
}
@@ -330,9 +329,9 @@ async function generateReference(
const requiredFlags: string[] = [];
const isOffByDefault = OFF_BY_DEFAULT_CATEGORIES.includes(category);
const isOffByDefault = isCategoryOffByDefault(category);
if (isOffByDefault) {
const categoryFlag = buildFlag(category);
const categoryFlag = categoryToFlagName(category);
requiredFlags.push(`--${categoryFlag}=true`);
}
@@ -478,8 +477,8 @@ function getToolsAndCategories(tools: any, slim = false) {
// Sort categories using the enum order
const categoryOrder = Object.values(ToolCategory);
const sortedCategories = Object.keys(categories).sort((a, b) => {
const aOff = OFF_BY_DEFAULT_CATEGORIES.includes(a as ToolCategory);
const bOff = OFF_BY_DEFAULT_CATEGORIES.includes(b as ToolCategory);
const aOff = isCategoryOffByDefault(a);
const bOff = isCategoryOffByDefault(b);
if (aOff !== bOff) {
return aOff ? 1 : -1;
+11 -69
View File
@@ -13,8 +13,8 @@ import {SlimMcpResponse} from './SlimMcpResponse.js';
import {ClearcutLogger} from './telemetry/ClearcutLogger.js';
import type {CallToolResult} from './third_party/index.js';
import {zod} from './third_party/index.js';
import type {ToolCategory} from './tools/categories.js';
import {labels, OFF_BY_DEFAULT_CATEGORIES} from './tools/categories.js';
import {labels} from './tools/categories.js';
import {categoryToFlagName} from './config/category-options.js';
import type {
DefinedPageTool,
DevToolsData,
@@ -27,10 +27,6 @@ import type {Mutex} from './third_party/index.js';
import {fileURLToPath, pathToFileURL} from 'node:url';
import {isLocalhost} from './utils/url.js';
export function buildFlag(category: ToolCategory) {
return `category${category.charAt(0).toUpperCase() + category.slice(1)}`;
}
function buildDisabledMessage(
toolName: string,
flag: string,
@@ -43,80 +39,26 @@ function buildDisabledMessage(
return `Tool ${toolName} ${reason} is currently disabled. Enable it by running chrome-devtools start ${flag}=true. For more information check the README.`;
}
function getCategoryStatus(
category: ToolCategory,
serverArgs: ParsedArguments,
): {categoryFlag?: string; disabled: boolean} {
const categoryFlag = buildFlag(category);
const flagValue = serverArgs[categoryFlag];
const isDisabled = OFF_BY_DEFAULT_CATEGORIES.includes(category)
? !flagValue
: flagValue === false;
if (isDisabled) {
return {
categoryFlag,
disabled: true,
};
}
return {
disabled: false,
};
}
function getConditionStatus(
condition: string,
serverArgs: ParsedArguments,
): {conditionFlag?: string; disabled: boolean} {
if (condition && !serverArgs[condition]) {
return {conditionFlag: condition, disabled: true};
}
return {disabled: false};
}
function getToolStatusInfo(
tool: ToolDefinition | DefinedPageTool,
serverArgs: ParsedArguments,
): {disabled: boolean; reason?: string} {
const category = tool.annotations.category;
const categoryCheck = getCategoryStatus(category, serverArgs);
if (category && categoryCheck.disabled) {
if (!categoryCheck.categoryFlag) {
throw new Error(
'when the category is disabled there should always be a flag set',
);
if (category) {
const flag = categoryToFlagName(category);
if (!serverArgs[flag]) {
return {
disabled: true,
reason: buildDisabledMessage(tool.name, `--${flag}`, labels[category]),
};
}
return {
disabled: true,
reason: buildDisabledMessage(
tool.name,
`--${categoryCheck.categoryFlag}`,
labels[category!],
),
};
}
for (const condition of tool.annotations.conditions || []) {
const conditionCheck = getConditionStatus(condition, serverArgs);
if (conditionCheck.disabled) {
if (!conditionCheck.conditionFlag) {
throw new Error(
'when the condition is disabled there should always be a flag set',
);
}
if (!serverArgs[condition]) {
return {
disabled: true,
reason: buildDisabledMessage(
tool.name,
`--${conditionCheck.conditionFlag}`,
),
reason: buildDisabledMessage(tool.name, `--${condition}`),
};
}
}
+115
View File
@@ -0,0 +1,115 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {ToolCategory} from '../tools/categories.js';
export interface CategoryOption {
type: 'boolean';
describe: string;
default?: boolean;
hidden?: boolean;
conflicts?: string[];
}
export type CategoryFlagName<T extends ToolCategory = ToolCategory> =
`category${Capitalize<T>}`;
export type CategoryFlags = {
[K in ToolCategory as CategoryFlagName<K>]: CategoryOption;
};
const categoryOverrides: Record<
ToolCategory,
{
describe?: string;
hidden?: boolean;
conflicts?: string[];
offByDefault?: boolean;
}
> = {
[ToolCategory.INPUT]: {},
[ToolCategory.NAVIGATION]: {},
[ToolCategory.EMULATION]: {
hidden: false,
},
[ToolCategory.PERFORMANCE]: {
hidden: false,
},
[ToolCategory.NETWORK]: {
hidden: false,
},
[ToolCategory.DEBUGGING]: {},
[ToolCategory.MEMORY]: {},
[ToolCategory.WEBMCP]: {
describe:
'Set to true to enable debugging WebMCP tools. Requires Chrome 150+ with the following flag: `--enable-features=WebMCP`',
offByDefault: true,
},
[ToolCategory.EXTENSIONS]: {
describe:
'Set to true to include tools related to extensions. Note: This feature is currently only supported with a pipe connection. autoConnect, browserUrl, and wsEndpoint are not supported with this feature until 149 will be released.',
hidden: false,
offByDefault: true,
},
[ToolCategory.THIRD_PARTY]: {
describe:
'Set to true to enable third-party developer tools exposed by the inspected page itself',
hidden: false,
offByDefault: true,
},
[ToolCategory.PWA]: {
describe:
'Set to true to include tools for automating Progressive Web Apps (install, launch, uninstall, and OS state). This feature is only supported with a pipe connection; autoConnect, browserUrl, and wsEndpoint are not supported.',
conflicts: ['autoConnect', 'browserUrl', 'wsEndpoint'],
hidden: false,
offByDefault: true,
},
};
function createOption(category: ToolCategory): CategoryOption {
const overrides = categoryOverrides[category];
const describe = overrides.offByDefault
? `Set to true to include tools related to ${category}.`
: `Set to false to exclude tools related to ${category}.`;
return {
type: 'boolean',
describe,
hidden: true,
...overrides,
...(overrides.offByDefault ? {} : {default: true}),
};
}
export function categoryToFlagName(category: ToolCategory): CategoryFlagName {
return `category${category.charAt(0).toUpperCase()}${category.slice(1)}` as CategoryFlagName;
}
export function getCategoryOptions(): CategoryFlags {
const options = {} as CategoryFlags;
for (const category of Object.values(ToolCategory)) {
const flagName = categoryToFlagName(category);
options[flagName] = createOption(category);
}
return options;
}
export function isCategoryOffByDefault(category: ToolCategory): boolean {
const flagName = categoryToFlagName(category);
const option = getCategoryOptions()[flagName];
return !('default' in option) || option.default !== true;
}
export function getOffByDefaultCategories(): ToolCategory[] {
const result: ToolCategory[] = [];
for (const category of Object.values(ToolCategory)) {
if (isCategoryOffByDefault(category)) {
result.push(category);
}
}
return result;
}
+3 -40
View File
@@ -10,7 +10,10 @@ import os from 'node:os';
export const DEFAULT_FILESYSTEM_ROOT = [os.tmpdir()];
import {getCategoryOptions} from './category-options.js';
export const mcpOptions = {
...getCategoryOptions(),
autoConnect: {
type: 'boolean',
description:
@@ -226,11 +229,6 @@ export const mcpOptions = {
return value;
},
},
categoryExperimentalWebmcp: {
type: 'boolean',
describe:
'Set to true to enable debugging WebMCP tools. Requires Chrome 150+ with the following flag: `--enable-features=WebMCP`',
},
chromeArg: {
type: 'array',
describe:
@@ -253,41 +251,6 @@ export const mcpOptions = {
describe:
'Explicitly disable default arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.',
},
categoryEmulation: {
type: 'boolean',
default: true,
describe: 'Set to false to exclude tools related to emulation.',
},
categoryPerformance: {
type: 'boolean',
default: true,
describe: 'Set to false to exclude tools related to performance.',
},
categoryNetwork: {
type: 'boolean',
default: true,
describe: 'Set to false to exclude tools related to network.',
},
categoryExtensions: {
type: 'boolean',
hidden: false,
default: false,
describe:
'Set to true to include tools related to extensions. Note: This feature is currently only supported with a pipe connection. autoConnect, browserUrl, and wsEndpoint are not supported with this feature until 149 will be released.',
},
categoryExperimentalThirdParty: {
type: 'boolean',
default: false,
describe:
'Set to true to enable third-party developer tools exposed by the inspected page itself',
},
categoryPwa: {
type: 'boolean',
hidden: false,
conflicts: ['autoConnect', 'browserUrl', 'wsEndpoint'],
describe:
'Set to true to include tools for automating Progressive Web Apps (install, launch, uninstall, and OS state). This feature is only supported with a pipe connection; autoConnect, browserUrl, and wsEndpoint are not supported.',
},
performanceCrux: {
type: 'boolean',
default: true,
-2
View File
@@ -32,8 +32,6 @@ import {createTools} from './tools/tools.js';
import {logger} from './utils/logger.js';
import {VERSION} from './version.js';
export {buildFlag} from './ToolHandler.js';
puppeteer.setFollowSymlinks(false);
/**
+32
View File
@@ -405,5 +405,37 @@
{
"name": "filesystem_root_present",
"flagType": "boolean"
},
{
"name": "category_input_present",
"flagType": "boolean"
},
{
"name": "category_input",
"flagType": "boolean"
},
{
"name": "category_navigation_present",
"flagType": "boolean"
},
{
"name": "category_navigation",
"flagType": "boolean"
},
{
"name": "category_debugging_present",
"flagType": "boolean"
},
{
"name": "category_debugging",
"flagType": "boolean"
},
{
"name": "category_memory_present",
"flagType": "boolean"
},
{
"name": "category_memory",
"flagType": "boolean"
}
]
-7
View File
@@ -31,10 +31,3 @@ export const labels = {
[ToolCategory.WEBMCP]: 'WebMCP',
[ToolCategory.PWA]: 'Progressive Web Apps',
};
export const OFF_BY_DEFAULT_CATEGORIES = [
ToolCategory.EXTENSIONS,
ToolCategory.THIRD_PARTY,
ToolCategory.WEBMCP,
ToolCategory.PWA,
];
+4 -2
View File
@@ -21,11 +21,13 @@ function parseArguments(argv: string[], env: NodeJS.ProcessEnv = {}) {
describe('cli args parsing', () => {
const defaultArgs = {
categoryInput: true,
categoryNavigation: true,
categoryEmulation: true,
categoryPerformance: true,
categoryNetwork: true,
categoryExtensions: false,
categoryExperimentalThirdParty: false,
categoryDebugging: true,
categoryMemory: true,
autoConnect: undefined,
performanceCrux: true,
usageStatistics: true,
+3 -3
View File
@@ -22,8 +22,8 @@ import {
import {executablePath} from 'puppeteer';
import {mcpOptions} from '../src/config/mcp-options.js';
import {getOffByDefaultCategories} from '../src/config/category-options.js';
import type {ToolCategory} from '../src/tools/categories.js';
import {OFF_BY_DEFAULT_CATEGORIES} from '../src/tools/categories.js';
import type {ToolDefinition} from '../src/tools/ToolDefinition.js';
describe('e2e', () => {
@@ -113,7 +113,7 @@ describe('e2e', () => {
definedNames.sort();
assert.deepStrictEqual(exposedNames, definedNames);
},
OFF_BY_DEFAULT_CATEGORIES.map(category => `--category-${category}`),
getOffByDefaultCategories().map(category => `--category-${category}`),
);
});
@@ -122,7 +122,7 @@ describe('e2e', () => {
const {tools} = await client.listTools();
const exposedNames = tools.map(t => t.name).sort();
const definedNames = await getToolsWithFilteredCategories(
OFF_BY_DEFAULT_CATEGORIES,
getOffByDefaultCategories(),
);
definedNames.sort();
assert.deepStrictEqual(exposedNames, definedNames);