Skip to content

Commit cc97b29

Browse files
committed
list tools
1 parent faad89b commit cc97b29

8 files changed

Lines changed: 145 additions & 65 deletions

File tree

README.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,6 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
475475
- [`list_console_messages`](docs/tool-reference.md#list_console_messages)
476476
- [`take_screenshot`](docs/tool-reference.md#take_screenshot)
477477
- [`take_snapshot`](docs/tool-reference.md#take_snapshot)
478-
- **In-page tools** (1 tools)
479-
- [`list_in_page_tools`](docs/tool-reference.md#list_in_page_tools)
480478

481479
<!-- END AUTO GENERATED TOOLS -->
482480

@@ -568,11 +566,6 @@ The Chrome DevTools MCP server supports the following configuration option:
568566
- **Type:** boolean
569567
- **Default:** `true`
570568

571-
- **`--categoryInPageTools`/ `--category-in-page-tools`**
572-
Set to true to enable tools exposed by the inspected page itself
573-
- **Type:** boolean
574-
- **Default:** `false`
575-
576569
- **`--performanceCrux`/ `--performance-crux`**
577570
Set to false to disable sending URLs from performance traces to CrUX API to get field performance data.
578571
- **Type:** boolean

docs/tool-reference.md

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
- [`list_console_messages`](#list_console_messages)
3838
- [`take_screenshot`](#take_screenshot)
3939
- [`take_snapshot`](#take_snapshot)
40-
- **[In-page tools](#in-page-tools)** (1 tools)
41-
- [`list_in_page_tools`](#list_in_page_tools)
4240

4341
## Input automation
4442

@@ -399,15 +397,3 @@ in the DevTools Elements panel (if any).
399397
- **verbose** (boolean) _(optional)_: Whether to include all possible information available in the full a11y tree. Default is false.
400398

401399
---
402-
403-
## In-page tools
404-
405-
### `list_in_page_tools`
406-
407-
**Description:** Lists all in-page-tools the page exposes for providing runtime information.
408-
In-page-tools are exposed on the page via the 'window.\_\_dtmcp.executeTool(toolName, params)'
409-
function where they can be called by '[`evaluate_script`](#evaluate_script)'.
410-
411-
**Parameters:** None
412-
413-
---

src/bin/chrome-devtools-mcp-cli-options.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ export const cliOptions = {
219219
categoryInPageTools: {
220220
type: 'boolean',
221221
hidden: true,
222-
default: false,
223222
describe:
224223
'Set to true to enable tools exposed by the inspected page itself',
225224
},

src/tools/pages.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const listPages = defineTool(args => {
2727
schema: {},
2828
handler: async (_request, response) => {
2929
response.setIncludePages(true);
30+
response.setListInPageTools();
3031
},
3132
};
3233
});
@@ -53,6 +54,7 @@ export const selectPage = defineTool({
5354
const page = context.getPageById(request.params.pageId);
5455
context.selectPage(page);
5556
response.setIncludePages(true);
57+
response.setListInPageTools();
5658
if (request.params.bringToFront) {
5759
await page.pptrPage.bringToFront();
5860
}
@@ -82,6 +84,7 @@ export const closePage = defineTool({
8284
}
8385
}
8486
response.setIncludePages(true);
87+
response.setListInPageTools();
8588
},
8689
});
8790

@@ -275,6 +278,7 @@ export const navigatePage = definePageTool({
275278
}
276279

277280
response.setIncludePages(true);
281+
response.setListInPageTools();
278282
},
279283
});
280284

tests/McpResponse.test.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ import {describe, it} from 'node:test';
1313
import sinon from 'sinon';
1414

1515
import type {ParsedArguments} from '../src/bin/chrome-devtools-mcp-cli-options.js';
16+
import type {McpContext} from '../src/McpContext.js';
17+
import type {McpResponse} from '../src/McpResponse.js';
18+
import {
19+
closePage,
20+
listPages,
21+
navigatePage,
22+
selectPage,
23+
} from '../src/tools/pages.js';
1624
import type {InsightName} from '../src/trace-processing/parse.js';
1725
import {
1826
parseRawTraceBuffer,
@@ -1091,4 +1099,93 @@ describe('inPage tools', () => {
10911099
{categoryInPageTools: true} as ParsedArguments,
10921100
);
10931101
});
1102+
1103+
async function testIncludesInPageTools(
1104+
handlerAction: (
1105+
response: McpResponse,
1106+
context: McpContext,
1107+
) => Promise<void>,
1108+
toolName: string,
1109+
) {
1110+
await withMcpContext(
1111+
async (response, context) => {
1112+
const mcpPage = context.getSelectedMcpPage();
1113+
stubToolDiscovery(mcpPage.pptrPage);
1114+
1115+
const initScript = `
1116+
window.__dtmcp = {
1117+
toolGroup: {
1118+
name: 'In-Page group',
1119+
description: 'Test tools',
1120+
tools: [
1121+
{
1122+
name: 'inPageTool',
1123+
description: 'A test tool',
1124+
inputSchema: {
1125+
type: 'object',
1126+
properties: {},
1127+
},
1128+
execute: () => 'result',
1129+
},
1130+
],
1131+
},
1132+
};
1133+
window.addEventListener('devtoolstooldiscovery', (e) => {
1134+
e.respondWith(window.__dtmcp?.toolGroup);
1135+
});
1136+
`;
1137+
await mcpPage.pptrPage.evaluateOnNewDocument(initScript);
1138+
await mcpPage.pptrPage.evaluate(initScript);
1139+
1140+
await handlerAction(response, context);
1141+
1142+
const {content} = await response.handle(toolName, context);
1143+
const responseText = getTextContent(content[0]);
1144+
assert.ok(
1145+
responseText.includes('inPageTool'),
1146+
`Should include in-page tool name in the ${toolName} response`,
1147+
);
1148+
},
1149+
undefined,
1150+
{categoryInPageTools: true} as ParsedArguments,
1151+
);
1152+
}
1153+
1154+
it('includes in-page tools in list_pages response', async () => {
1155+
await testIncludesInPageTools(async (response, context) => {
1156+
const listPagesDef = listPages({
1157+
categoryInPageTools: true,
1158+
} as ParsedArguments);
1159+
await listPagesDef.handler({params: {}}, response, context);
1160+
}, 'list_pages');
1161+
});
1162+
1163+
it('includes in-page tools in select_page response', async () => {
1164+
await testIncludesInPageTools(async (response, context) => {
1165+
const pageId =
1166+
context.getPageId(context.getSelectedMcpPage().pptrPage) ?? 1;
1167+
await selectPage.handler({params: {pageId}}, response, context);
1168+
}, 'select_page');
1169+
});
1170+
1171+
it('includes in-page tools in close_page response', async () => {
1172+
await testIncludesInPageTools(async (response, context) => {
1173+
const pageId =
1174+
context.getPageId(context.getSelectedMcpPage().pptrPage) ?? 1;
1175+
await closePage.handler({params: {pageId}}, response, context);
1176+
}, 'close_page');
1177+
});
1178+
1179+
it('includes in-page tools in navigate_page response', async () => {
1180+
await testIncludesInPageTools(async (response, context) => {
1181+
await navigatePage.handler(
1182+
{
1183+
params: {type: 'url', url: 'about:blank'},
1184+
page: context.getSelectedMcpPage(),
1185+
},
1186+
response,
1187+
context,
1188+
);
1189+
}, 'navigate_page');
1190+
});
10941191
});

tests/cli.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ describe('cli args parsing', () => {
2323
performanceCrux: true,
2424
'usage-statistics': true,
2525
usageStatistics: true,
26-
'category-in-page-tools': false,
27-
categoryInPageTools: false,
2826
};
2927

3028
it('parses with default args', async () => {

tests/index.test.ts

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -72,52 +72,47 @@ describe('e2e', () => {
7272
});
7373

7474
it('has all tools', async () => {
75-
await withClient(
76-
async client => {
77-
const {tools} = await client.listTools();
78-
const exposedNames = tools.map(t => t.name).sort();
79-
const files = fs.readdirSync('build/src/tools');
80-
const definedNames = [];
81-
for (const file of files) {
82-
if (
83-
file === 'ToolDefinition.js' ||
84-
file === 'tools.js' ||
85-
file === 'slim'
86-
) {
87-
continue;
88-
}
89-
const fileTools = await import(`../src/tools/${file}`);
90-
for (const maybeTool of Object.values<unknown>(fileTools)) {
91-
if (typeof maybeTool === 'function') {
92-
const tool = (maybeTool as (val: boolean) => ToolDefinition)(
93-
false,
94-
);
95-
if (tool && typeof tool === 'object' && 'name' in tool) {
96-
if (tool.annotations?.conditions) {
97-
continue;
98-
}
99-
definedNames.push(tool.name);
100-
}
101-
continue;
102-
}
103-
if (
104-
typeof maybeTool === 'object' &&
105-
maybeTool !== null &&
106-
'name' in maybeTool
107-
) {
108-
const tool = maybeTool as ToolDefinition;
75+
await withClient(async client => {
76+
const {tools} = await client.listTools();
77+
const exposedNames = tools.map(t => t.name).sort();
78+
const files = fs.readdirSync('build/src/tools');
79+
const definedNames = [];
80+
for (const file of files) {
81+
if (
82+
file === 'ToolDefinition.js' ||
83+
file === 'tools.js' ||
84+
file === 'slim'
85+
) {
86+
continue;
87+
}
88+
const fileTools = await import(`../src/tools/${file}`);
89+
for (const maybeTool of Object.values<unknown>(fileTools)) {
90+
if (typeof maybeTool === 'function') {
91+
const tool = (maybeTool as (val: boolean) => ToolDefinition)(false);
92+
if (tool && typeof tool === 'object' && 'name' in tool) {
10993
if (tool.annotations?.conditions) {
11094
continue;
11195
}
11296
definedNames.push(tool.name);
11397
}
98+
continue;
99+
}
100+
if (
101+
typeof maybeTool === 'object' &&
102+
maybeTool !== null &&
103+
'name' in maybeTool
104+
) {
105+
const tool = maybeTool as ToolDefinition;
106+
if (tool.annotations?.conditions) {
107+
continue;
108+
}
109+
definedNames.push(tool.name);
114110
}
115111
}
116-
definedNames.sort();
117-
assert.deepStrictEqual(exposedNames, definedNames);
118-
},
119-
['--category-in-page-tools'],
120-
);
112+
}
113+
definedNames.sort();
114+
assert.deepStrictEqual(exposedNames, definedNames);
115+
});
121116
});
122117

123118
it('has experimental in-Page tools', async () => {

tests/tools/inPage.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ describe('inPage', () => {
8686
const result = await response.handle('list_in_page_tools', context);
8787
assert.ok('inPageTools' in result.structuredContent);
8888
assert.deepEqual(
89-
(result.structuredContent as {inPageTools: ToolGroup<ToolDefinition>}).inPageTools,
89+
(
90+
result.structuredContent as {
91+
inPageTools: ToolGroup<ToolDefinition>;
92+
}
93+
).inPageTools,
9094
{},
9195
);
9296
},
@@ -110,7 +114,11 @@ describe('inPage', () => {
110114
const result = await response.handle('list_in_page_tools', context);
111115
assert.ok('inPageTools' in result.structuredContent);
112116
assert.strictEqual(
113-
(result.structuredContent as {inPageTools: ToolGroup<ToolDefinition>}).inPageTools,
117+
(
118+
result.structuredContent as {
119+
inPageTools: ToolGroup<ToolDefinition>;
120+
}
121+
).inPageTools,
114122
undefined,
115123
);
116124
},

0 commit comments

Comments
 (0)