chromedevtools--chrome-devtools-mcp
c2d8009ff7
- `chrome-devtools-mcp.js` is the `npx chrome-devtools-mcp` - `chrome-devtools.js` is the new CLI - `-cli-options.js` is the corresponding options - all these files are in the bin folder to indicate they are executable
151 行
4.0 KiB
TypeScript
151 行
4.0 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import assert from 'node:assert';
|
|
import fs from 'node:fs';
|
|
import {describe, it} from 'node:test';
|
|
|
|
import {Client} from '@modelcontextprotocol/sdk/client/index.js';
|
|
import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
import {executablePath} from 'puppeteer';
|
|
|
|
import type {ToolDefinition} from '../src/tools/ToolDefinition';
|
|
|
|
describe('e2e', () => {
|
|
async function withClient(
|
|
cb: (client: Client) => Promise<void>,
|
|
extraArgs: string[] = [],
|
|
) {
|
|
const transport = new StdioClientTransport({
|
|
command: 'node',
|
|
args: [
|
|
'build/src/bin/chrome-devtools-mcp.js',
|
|
'--headless',
|
|
'--isolated',
|
|
'--executable-path',
|
|
executablePath(),
|
|
...extraArgs,
|
|
],
|
|
});
|
|
const client = new Client(
|
|
{
|
|
name: 'e2e-test',
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
capabilities: {},
|
|
},
|
|
);
|
|
|
|
try {
|
|
await client.connect(transport);
|
|
await cb(client);
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
}
|
|
it('calls a tool', async t => {
|
|
await withClient(async client => {
|
|
const result = await client.callTool({
|
|
name: 'list_pages',
|
|
arguments: {},
|
|
});
|
|
t.assert.snapshot?.(JSON.stringify(result.content));
|
|
});
|
|
});
|
|
|
|
it('calls a tool multiple times', async t => {
|
|
await withClient(async client => {
|
|
let result = await client.callTool({
|
|
name: 'list_pages',
|
|
arguments: {},
|
|
});
|
|
result = await client.callTool({
|
|
name: 'list_pages',
|
|
arguments: {},
|
|
});
|
|
t.assert.snapshot?.(JSON.stringify(result.content));
|
|
});
|
|
});
|
|
|
|
it('has all tools', async () => {
|
|
await withClient(async client => {
|
|
const {tools} = await client.listTools();
|
|
const exposedNames = tools.map(t => t.name).sort();
|
|
const files = fs.readdirSync('build/src/tools');
|
|
const definedNames = [];
|
|
for (const file of files) {
|
|
if (
|
|
file === 'ToolDefinition.js' ||
|
|
file === 'tools.js' ||
|
|
file === 'slim'
|
|
) {
|
|
continue;
|
|
}
|
|
const fileTools = await import(`../src/tools/${file}`);
|
|
for (const maybeTool of Object.values<unknown>(fileTools)) {
|
|
if (typeof maybeTool === 'function') {
|
|
const tool = (maybeTool as (val: boolean) => ToolDefinition)(false);
|
|
if (tool && typeof tool === 'object' && 'name' in tool) {
|
|
if (tool.annotations?.conditions) {
|
|
continue;
|
|
}
|
|
definedNames.push(tool.name);
|
|
}
|
|
continue;
|
|
}
|
|
if (
|
|
typeof maybeTool === 'object' &&
|
|
maybeTool !== null &&
|
|
'name' in maybeTool
|
|
) {
|
|
const tool = maybeTool as ToolDefinition;
|
|
if (tool.annotations?.conditions) {
|
|
continue;
|
|
}
|
|
definedNames.push(tool.name);
|
|
}
|
|
}
|
|
}
|
|
definedNames.sort();
|
|
assert.deepStrictEqual(exposedNames, definedNames);
|
|
});
|
|
});
|
|
|
|
it('has experimental extensions tools', async () => {
|
|
await withClient(
|
|
async client => {
|
|
const {tools} = await client.listTools();
|
|
const clickAt = tools.find(t => t.name === 'install_extension');
|
|
assert.ok(clickAt);
|
|
},
|
|
['--category-extensions'],
|
|
);
|
|
});
|
|
|
|
it('has experimental vision tools', async () => {
|
|
await withClient(
|
|
async client => {
|
|
const {tools} = await client.listTools();
|
|
const clickAt = tools.find(t => t.name === 'click_at');
|
|
assert.ok(clickAt);
|
|
},
|
|
['--experimental-vision'],
|
|
);
|
|
});
|
|
|
|
it('has experimental interop tools', async () => {
|
|
await withClient(
|
|
async client => {
|
|
const {tools} = await client.listTools();
|
|
const getTabId = tools.find(t => t.name === 'get_tab_id');
|
|
assert.ok(getTabId);
|
|
},
|
|
['--experimental-interop-tools'],
|
|
);
|
|
});
|
|
});
|