From 3393d5e3fd0b57cd656c897e12054c73d0a8a2d7 Mon Sep 17 00:00:00 2001 From: Alex Rudenko Date: Wed, 22 Oct 2025 09:15:09 +0200 Subject: [PATCH] feat: allow configuring tool categories --- README.md | 15 +++++++++++++++ scripts/generate-docs.ts | 15 ++++++++------- src/cli.ts | 21 +++++++++++++++++++++ src/main.ts | 19 +++++++++++++++++++ src/tools/ToolDefinition.ts | 4 ++-- src/tools/categories.ts | 23 ++++++++++++++++------- src/tools/console.ts | 6 +++--- src/tools/emulation.ts | 6 +++--- src/tools/input.ts | 14 +++++++------- src/tools/network.ts | 6 +++--- src/tools/pages.ts | 18 +++++++++--------- src/tools/performance.ts | 8 ++++---- src/tools/screenshot.ts | 4 ++-- src/tools/script.ts | 4 ++-- src/tools/snapshot.ts | 6 +++--- tests/cli.test.ts | 35 +++++++++++++++++++++++++++++++++++ 16 files changed, 152 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index a4e8fab7..91faecde 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,21 @@ The Chrome DevTools MCP server supports the following configuration option: Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp. - **Type:** array +- **`--categoryEmulation`** + Set to false to exlcude tools related to emulation. + - **Type:** boolean + - **Default:** `true` + +- **`--categoryPerformance`** + Set to false to exlcude tools related to performance. + - **Type:** boolean + - **Default:** `true` + +- **`--categoryNetwork`** + Set to false to exlcude tools related to network. + - **Type:** boolean + - **Default:** `true` + Pass them via the `args` property in the JSON configuration. For example: diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index aaba4631..7466ab93 100644 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -11,7 +11,7 @@ import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js'; import type {Tool} from '@modelcontextprotocol/sdk/types.js'; import {cliOptions} from '../build/src/cli.js'; -import {ToolCategories} from '../build/src/tools/categories.js'; +import {ToolCategory, labels} from '../build/src/tools/categories.js'; const MCP_SERVER_PATH = 'build/src/index.js'; const OUTPUT_PATH = './docs/tool-reference.md'; @@ -21,7 +21,7 @@ const README_PATH = './README.md'; interface ToolWithAnnotations extends Tool { annotations?: { title?: string; - category?: ToolCategories; + category?: typeof ToolCategory; }; } @@ -67,7 +67,7 @@ function generateToolsTOC( for (const category of sortedCategories) { const categoryTools = categories[category]; - const categoryName = category; + const categoryName = labels[category]; toc += `- **${categoryName}** (${categoryTools.length} tools)\n`; // Sort tools within category for TOC @@ -209,7 +209,7 @@ async function generateToolDocumentation(): Promise { }); // Sort categories using the enum order - const categoryOrder = Object.values(ToolCategories); + const categoryOrder = Object.values(ToolCategory); const sortedCategories = Object.keys(categories).sort((a, b) => { const aIndex = categoryOrder.indexOf(a); const bIndex = categoryOrder.indexOf(b); @@ -223,8 +223,8 @@ async function generateToolDocumentation(): Promise { // Generate table of contents for (const category of sortedCategories) { const categoryTools = categories[category]; - const categoryName = category; - const anchorName = category.toLowerCase().replace(/\s+/g, '-'); + const categoryName = labels[category]; + const anchorName = categoryName.toLowerCase().replace(/\s+/g, '-'); markdown += `- **[${categoryName}](#${anchorName})** (${categoryTools.length} tools)\n`; // Sort tools within category for TOC @@ -239,8 +239,9 @@ async function generateToolDocumentation(): Promise { for (const category of sortedCategories) { const categoryTools = categories[category]; + const categoryName = labels[category]; - markdown += `## ${category}\n\n`; + markdown += `## ${categoryName}\n\n`; // Sort tools within category categoryTools.sort((a: Tool, b: Tool) => a.name.localeCompare(b.name)); diff --git a/src/cli.ts b/src/cli.ts index 54c83282..5e811ba2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -139,6 +139,21 @@ export const cliOptions = { describe: 'Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.', }, + categoryEmulation: { + type: 'boolean', + default: true, + describe: 'Set to false to exlcude tools related to emulation.', + }, + categoryPerformance: { + type: 'boolean', + default: true, + describe: 'Set to false to exlcude tools related to performance.', + }, + categoryNetwork: { + type: 'boolean', + default: true, + describe: 'Set to false to exlcude tools related to network.', + }, } satisfies Record; export function parseArguments(version: string, argv = process.argv) { @@ -185,6 +200,12 @@ export function parseArguments(version: string, argv = process.argv) { `$0 --chrome-arg='--no-sandbox' --chrome-arg='--disable-setuid-sandbox'`, 'Launch Chrome without sandboxes. Use with caution.', ], + ['$0 --no-category-emulation', 'Disable tools in the emulation category'], + [ + '$0 --no-category-performance', + 'Disable tools in the performance category', + ], + ['$0 --no-category-network', 'Disable tools in the network category'], ]); return yargsInstance diff --git a/src/main.ts b/src/main.ts index c1fb8303..44a08c71 100644 --- a/src/main.ts +++ b/src/main.ts @@ -19,6 +19,7 @@ import { type CallToolResult, SetLevelRequestSchema, } from './third_party/index.js'; +import {ToolCategory} from './tools/categories.js'; import * as consoleTools from './tools/console.js'; import * as emulationTools from './tools/emulation.js'; import * as inputTools from './tools/input.js'; @@ -96,6 +97,24 @@ Avoid sharing sensitive or personal information that you do not want to share wi const toolMutex = new Mutex(); function registerTool(tool: ToolDefinition): void { + if ( + tool.annotations.category === ToolCategory.EMULATION && + args.categoryEmulation === false + ) { + return; + } + if ( + tool.annotations.category === ToolCategory.PERFORMANCE && + args.categoryPerformance === false + ) { + return; + } + if ( + tool.annotations.category === ToolCategory.NETWORK && + args.categoryNetwork === false + ) { + return; + } server.registerTool( tool.name, { diff --git a/src/tools/ToolDefinition.ts b/src/tools/ToolDefinition.ts index d36d473d..00b85a43 100644 --- a/src/tools/ToolDefinition.ts +++ b/src/tools/ToolDefinition.ts @@ -10,7 +10,7 @@ import type {Dialog, ElementHandle, Page} from '../third_party/index.js'; import type {TraceResult} from '../trace-processing/parse.js'; import type {PaginationOptions} from '../utils/types.js'; -import type {ToolCategories} from './categories.js'; +import type {ToolCategory} from './categories.js'; export interface ToolDefinition< Schema extends zod.ZodRawShape = zod.ZodRawShape, @@ -19,7 +19,7 @@ export interface ToolDefinition< description: string; annotations: { title?: string; - category: ToolCategories; + category: ToolCategory; /** * If true, the tool does not modify its environment. */ diff --git a/src/tools/categories.ts b/src/tools/categories.ts index 084be6fe..f27a8036 100644 --- a/src/tools/categories.ts +++ b/src/tools/categories.ts @@ -4,11 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -export enum ToolCategories { - INPUT_AUTOMATION = 'Input automation', - NAVIGATION_AUTOMATION = 'Navigation automation', - EMULATION = 'Emulation', - PERFORMANCE = 'Performance', - NETWORK = 'Network', - DEBUGGING = 'Debugging', +export enum ToolCategory { + INPUT = 'input', + NAVIGATION = 'navigation', + EMULATION = 'emulation', + PERFORMANCE = 'performance', + NETWORK = 'network', + DEBUGGING = 'debugging', } + +export const labels = { + [ToolCategory.INPUT]: 'Input automation', + [ToolCategory.NAVIGATION]: 'Navigation automation', + [ToolCategory.EMULATION]: 'Emulation', + [ToolCategory.PERFORMANCE]: 'Performance', + [ToolCategory.NETWORK]: 'Network', + [ToolCategory.DEBUGGING]: 'Debugging', +}; diff --git a/src/tools/console.ts b/src/tools/console.ts index 324e04a1..7851930e 100644 --- a/src/tools/console.ts +++ b/src/tools/console.ts @@ -7,7 +7,7 @@ import {zod} from '../third_party/index.js'; import type {ConsoleMessageType} from '../third_party/index.js'; -import {ToolCategories} from './categories.js'; +import {ToolCategory} from './categories.js'; import {defineTool} from './ToolDefinition.js'; const FILTERABLE_MESSAGE_TYPES: readonly [ @@ -40,7 +40,7 @@ export const listConsoleMessages = defineTool({ description: 'List all console messages for the currently selected page since the last navigation.', annotations: { - category: ToolCategories.DEBUGGING, + category: ToolCategory.DEBUGGING, readOnlyHint: true, }, schema: { @@ -86,7 +86,7 @@ export const getConsoleMessage = defineTool({ name: 'get_console_message', description: `Gets a console message by its ID. You can get all messages by calling ${listConsoleMessages.name}.`, annotations: { - category: ToolCategories.DEBUGGING, + category: ToolCategory.DEBUGGING, readOnlyHint: true, }, schema: { diff --git a/src/tools/emulation.ts b/src/tools/emulation.ts index eceaa53b..2222e4e3 100644 --- a/src/tools/emulation.ts +++ b/src/tools/emulation.ts @@ -6,7 +6,7 @@ import {zod, PredefinedNetworkConditions} from '../third_party/index.js'; -import {ToolCategories} from './categories.js'; +import {ToolCategory} from './categories.js'; import {defineTool} from './ToolDefinition.js'; const throttlingOptions: [string, ...string[]] = [ @@ -19,7 +19,7 @@ export const emulateNetwork = defineTool({ name: 'emulate_network', description: `Emulates network conditions such as throttling or offline mode on the selected page.`, annotations: { - category: ToolCategories.EMULATION, + category: ToolCategory.EMULATION, readOnlyHint: false, }, schema: { @@ -65,7 +65,7 @@ export const emulateCpu = defineTool({ name: 'emulate_cpu', description: `Emulates CPU throttling by slowing down the selected page's execution.`, annotations: { - category: ToolCategories.EMULATION, + category: ToolCategory.EMULATION, readOnlyHint: false, }, schema: { diff --git a/src/tools/input.ts b/src/tools/input.ts index 78a1372a..9913ee56 100644 --- a/src/tools/input.ts +++ b/src/tools/input.ts @@ -8,14 +8,14 @@ import type {McpContext, TextSnapshotNode} from '../McpContext.js'; import {zod} from '../third_party/index.js'; import type {ElementHandle} from '../third_party/index.js'; -import {ToolCategories} from './categories.js'; +import {ToolCategory} from './categories.js'; import {defineTool} from './ToolDefinition.js'; export const click = defineTool({ name: 'click', description: `Clicks on the provided element`, annotations: { - category: ToolCategories.INPUT_AUTOMATION, + category: ToolCategory.INPUT, readOnlyHint: false, }, schema: { @@ -54,7 +54,7 @@ export const hover = defineTool({ name: 'hover', description: `Hover over the provided element`, annotations: { - category: ToolCategories.INPUT_AUTOMATION, + category: ToolCategory.INPUT, readOnlyHint: false, }, schema: { @@ -138,7 +138,7 @@ export const fill = defineTool({ name: 'fill', description: `Type text into a input, text area or select an option from a