chrome-devtools-mcp 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -2
- package/build/src/McpContext.js +11 -0
- package/build/src/McpResponse.js +4 -1
- package/build/src/browser.js +2 -7
- package/build/src/cli.js +8 -7
- package/build/src/formatters/snapshotFormatter.js +14 -47
- package/build/src/main.js +11 -24
- package/build/src/tools/input.js +57 -20
- package/build/src/tools/pages.js +2 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -53,6 +53,16 @@ Add the following config to your MCP client:
|
|
|
53
53
|
|
|
54
54
|
### MCP Client configuration
|
|
55
55
|
|
|
56
|
+
<details>
|
|
57
|
+
<summary>Amp</summary>
|
|
58
|
+
Follow https://ampcode.com/manual#mcp and use the config provided above. You can also install the Chrome DevTools MCP server using the CLI:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
amp mcp add chrome-devtools -- npx chrome-devtools-mcp@latest
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
</details>
|
|
65
|
+
|
|
56
66
|
<details>
|
|
57
67
|
<summary>Claude Code</summary>
|
|
58
68
|
Use the Claude Code CLI to add the Chrome DevTools MCP server (<a href="https://docs.anthropic.com/en/docs/claude-code/mcp">guide</a>):
|
|
@@ -177,6 +187,15 @@ The same way chrome-devtools-mcp can be configured for JetBrains Junie in `Setti
|
|
|
177
187
|
|
|
178
188
|
</details>
|
|
179
189
|
|
|
190
|
+
<details>
|
|
191
|
+
<summary>Kiro</summary>
|
|
192
|
+
|
|
193
|
+
In **Kiro Settings**, go to `Configure MCP` > `Open Workspace or User MCP Config` > Use the configuration snippet provided above.
|
|
194
|
+
|
|
195
|
+
Or, from the IDE **Activity Bar** > `Kiro` > `MCP Servers` > `Click Open MCP Config`. Use the configuration snippet provided above.
|
|
196
|
+
|
|
197
|
+
</details>
|
|
198
|
+
|
|
180
199
|
<details>
|
|
181
200
|
<summary>Visual Studio</summary>
|
|
182
201
|
|
|
@@ -291,6 +310,10 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
291
310
|
If enabled, ignores errors relative to self-signed and expired certificates. Use with caution.
|
|
292
311
|
- **Type:** boolean
|
|
293
312
|
|
|
313
|
+
- **`--chromeArg`**
|
|
314
|
+
Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.
|
|
315
|
+
- **Type:** array
|
|
316
|
+
|
|
294
317
|
<!-- END AUTO GENERATED OPTIONS -->
|
|
295
318
|
|
|
296
319
|
Pass them via the `args` property in the JSON configuration. For example:
|
|
@@ -336,7 +359,7 @@ Here is a step-by-step guide on how to connect to a running Chrome Stable instan
|
|
|
336
359
|
|
|
337
360
|
**Step 1: Configure the MCP client**
|
|
338
361
|
|
|
339
|
-
Add the `--browser-url` option to your MCP client configuration. The value of this option should be the URL of the running Chrome instance. `http://
|
|
362
|
+
Add the `--browser-url` option to your MCP client configuration. The value of this option should be the URL of the running Chrome instance. `http://127.0.0.1:9222` is a common default.
|
|
340
363
|
|
|
341
364
|
```json
|
|
342
365
|
{
|
|
@@ -345,7 +368,7 @@ Add the `--browser-url` option to your MCP client configuration. The value of th
|
|
|
345
368
|
"command": "npx",
|
|
346
369
|
"args": [
|
|
347
370
|
"chrome-devtools-mcp@latest",
|
|
348
|
-
"--browser-url=http://
|
|
371
|
+
"--browser-url=http://127.0.0.1:9222"
|
|
349
372
|
]
|
|
350
373
|
}
|
|
351
374
|
}
|
package/build/src/McpContext.js
CHANGED
|
@@ -201,6 +201,9 @@ export class McpContext {
|
|
|
201
201
|
const page = this.getSelectedPage();
|
|
202
202
|
return page.getDefaultNavigationTimeout();
|
|
203
203
|
}
|
|
204
|
+
getAXNodeByUid(uid) {
|
|
205
|
+
return this.#textSnapshot?.idToNode.get(uid);
|
|
206
|
+
}
|
|
204
207
|
async getElementByUid(uid) {
|
|
205
208
|
if (!this.#textSnapshot?.idToNode.size) {
|
|
206
209
|
throw new Error(`No snapshot found. Use ${takeSnapshot.name} to capture one.`);
|
|
@@ -253,6 +256,14 @@ export class McpContext {
|
|
|
253
256
|
? node.children.map(child => assignIds(child))
|
|
254
257
|
: [],
|
|
255
258
|
};
|
|
259
|
+
// The AXNode for an option doesn't contain its `value`.
|
|
260
|
+
// Therefore, set text content of the option as value.
|
|
261
|
+
if (node.role === 'option') {
|
|
262
|
+
const optionText = node.name;
|
|
263
|
+
if (optionText) {
|
|
264
|
+
nodeWithId.value = optionText.toString();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
256
267
|
idToNode.set(nodeWithId.id, nodeWithId);
|
|
257
268
|
return nodeWithId;
|
|
258
269
|
};
|
package/build/src/McpResponse.js
CHANGED
|
@@ -117,8 +117,11 @@ export class McpResponse {
|
|
|
117
117
|
}
|
|
118
118
|
const dialog = context.getDialog();
|
|
119
119
|
if (dialog) {
|
|
120
|
+
const defaultValueIfNeeded = dialog.type() === 'prompt'
|
|
121
|
+
? ` (default value: "${dialog.defaultValue()}")`
|
|
122
|
+
: '';
|
|
120
123
|
response.push(`# Open dialog
|
|
121
|
-
${dialog.type()}: ${dialog.message()}
|
|
124
|
+
${dialog.type()}: ${dialog.message()}${defaultValueIfNeeded}.
|
|
122
125
|
Call ${handleDialog.name} to handle it before continuing.`);
|
|
123
126
|
}
|
|
124
127
|
if (this.#includePages) {
|
package/build/src/browser.js
CHANGED
|
@@ -42,7 +42,7 @@ export async function ensureBrowserConnected(options) {
|
|
|
42
42
|
return browser;
|
|
43
43
|
}
|
|
44
44
|
export async function launch(options) {
|
|
45
|
-
const { channel, executablePath,
|
|
45
|
+
const { channel, executablePath, headless, isolated } = options;
|
|
46
46
|
const profileDirName = channel && channel !== 'stable'
|
|
47
47
|
? `chrome-profile-${channel}`
|
|
48
48
|
: 'chrome-profile';
|
|
@@ -57,9 +57,6 @@ export async function launch(options) {
|
|
|
57
57
|
...(options.args ?? []),
|
|
58
58
|
'--hide-crash-restore-bubble',
|
|
59
59
|
];
|
|
60
|
-
if (customDevTools) {
|
|
61
|
-
args.push(`--custom-devtools-frontend=file://${customDevTools}`);
|
|
62
|
-
}
|
|
63
60
|
if (headless) {
|
|
64
61
|
args.push('--screen-info={3840x2160}');
|
|
65
62
|
}
|
|
@@ -104,9 +101,7 @@ export async function launch(options) {
|
|
|
104
101
|
}
|
|
105
102
|
catch (error) {
|
|
106
103
|
if (userDataDir &&
|
|
107
|
-
|
|
108
|
-
error.message.includes('Target closed') ||
|
|
109
|
-
error.message.includes('Connection closed'))) {
|
|
104
|
+
error.message.includes('The browser is already running')) {
|
|
110
105
|
throw new Error(`The browser is already running for ${userDataDir}. Use --isolated to run multiple browser instances.`, {
|
|
111
106
|
cause: error,
|
|
112
107
|
});
|
package/build/src/cli.js
CHANGED
|
@@ -39,13 +39,6 @@ export const cliOptions = {
|
|
|
39
39
|
description: 'If specified, creates a temporary user-data-dir that is automatically cleaned up after the browser is closed.',
|
|
40
40
|
default: false,
|
|
41
41
|
},
|
|
42
|
-
customDevtools: {
|
|
43
|
-
type: 'string',
|
|
44
|
-
description: 'Path to custom DevTools.',
|
|
45
|
-
hidden: true,
|
|
46
|
-
conflicts: 'browserUrl',
|
|
47
|
-
alias: 'd',
|
|
48
|
-
},
|
|
49
42
|
channel: {
|
|
50
43
|
type: 'string',
|
|
51
44
|
description: 'Specify a different Chrome channel that should be used. The default is the stable channel version.',
|
|
@@ -86,6 +79,10 @@ export const cliOptions = {
|
|
|
86
79
|
describe: 'Whether to enable automation over DevTools targets',
|
|
87
80
|
hidden: true,
|
|
88
81
|
},
|
|
82
|
+
chromeArg: {
|
|
83
|
+
type: 'array',
|
|
84
|
+
describe: 'Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.',
|
|
85
|
+
},
|
|
89
86
|
};
|
|
90
87
|
export function parseArguments(version, argv = process.argv) {
|
|
91
88
|
const yargsInstance = yargs(hideBin(argv))
|
|
@@ -114,6 +111,10 @@ export function parseArguments(version, argv = process.argv) {
|
|
|
114
111
|
'$0 --viewport 1280x720',
|
|
115
112
|
'Launch Chrome with the initial viewport size of 1280x720px',
|
|
116
113
|
],
|
|
114
|
+
[
|
|
115
|
+
`$0 --chrome-arg='--no-sandbox' --chrome-arg='--disable-setuid-sandbox'`,
|
|
116
|
+
'Launch Chrome without sandboxes. Use with caution.',
|
|
117
|
+
],
|
|
117
118
|
]);
|
|
118
119
|
return yargsInstance
|
|
119
120
|
.wrap(Math.min(120, yargsInstance.terminalWidth()))
|
|
@@ -14,61 +14,28 @@ function getAttributes(serializedAXNodeRoot) {
|
|
|
14
14
|
serializedAXNodeRoot.role,
|
|
15
15
|
`"${serializedAXNodeRoot.name || ''}"`, // Corrected: Added quotes around name
|
|
16
16
|
];
|
|
17
|
-
|
|
18
|
-
const valueProperties = [
|
|
19
|
-
'value',
|
|
20
|
-
'valuetext',
|
|
21
|
-
'valuemin',
|
|
22
|
-
'valuemax',
|
|
23
|
-
'level',
|
|
24
|
-
'autocomplete',
|
|
25
|
-
'haspopup',
|
|
26
|
-
'invalid',
|
|
27
|
-
'orientation',
|
|
28
|
-
'description',
|
|
29
|
-
'keyshortcuts',
|
|
30
|
-
'roledescription',
|
|
31
|
-
];
|
|
32
|
-
for (const property of valueProperties) {
|
|
33
|
-
if (property in serializedAXNodeRoot &&
|
|
34
|
-
serializedAXNodeRoot[property] !== undefined) {
|
|
35
|
-
attributes.push(`${property}="${serializedAXNodeRoot[property]}"`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
// Boolean properties that also have an 'able' attribute
|
|
17
|
+
const excluded = new Set(['id', 'role', 'name', 'elementHandle', 'children']);
|
|
39
18
|
const booleanPropertyMap = {
|
|
40
19
|
disabled: 'disableable',
|
|
41
20
|
expanded: 'expandable',
|
|
42
21
|
focused: 'focusable',
|
|
43
22
|
selected: 'selectable',
|
|
44
23
|
};
|
|
45
|
-
for (const
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
if (serializedAXNodeRoot[property]) {
|
|
49
|
-
attributes.push(property);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const booleanProperties = [
|
|
54
|
-
'modal',
|
|
55
|
-
'multiline',
|
|
56
|
-
'readonly',
|
|
57
|
-
'required',
|
|
58
|
-
'multiselectable',
|
|
59
|
-
];
|
|
60
|
-
for (const property of booleanProperties) {
|
|
61
|
-
if (property in serializedAXNodeRoot && serializedAXNodeRoot[property]) {
|
|
62
|
-
attributes.push(property);
|
|
24
|
+
for (const attr of Object.keys(serializedAXNodeRoot).sort()) {
|
|
25
|
+
if (excluded.has(attr)) {
|
|
26
|
+
continue;
|
|
63
27
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
attributes.push(property);
|
|
69
|
-
if (serializedAXNodeRoot[property]) {
|
|
70
|
-
attributes.push(`${property}="${serializedAXNodeRoot[property]}"`);
|
|
28
|
+
const value = serializedAXNodeRoot[attr];
|
|
29
|
+
if (typeof value === 'boolean') {
|
|
30
|
+
if (booleanPropertyMap[attr]) {
|
|
31
|
+
attributes.push(booleanPropertyMap[attr]);
|
|
71
32
|
}
|
|
33
|
+
if (value) {
|
|
34
|
+
attributes.push(attr);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (typeof value === 'string' || typeof value === 'number') {
|
|
38
|
+
attributes.push(`${attr}="${value}"`);
|
|
72
39
|
}
|
|
73
40
|
}
|
|
74
41
|
return attributes;
|
package/build/src/main.js
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import './polyfill.js';
|
|
7
|
-
import assert from 'node:assert';
|
|
8
|
-
import fs from 'node:fs';
|
|
9
|
-
import path from 'node:path';
|
|
10
7
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
8
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
9
|
import { SetLevelRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
@@ -25,36 +22,24 @@ import * as performanceTools from './tools/performance.js';
|
|
|
25
22
|
import * as screenshotTools from './tools/screenshot.js';
|
|
26
23
|
import * as scriptTools from './tools/script.js';
|
|
27
24
|
import * as snapshotTools from './tools/snapshot.js';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
const json = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
36
|
-
assert.strict(json['name'], 'chrome-devtools-mcp');
|
|
37
|
-
return json;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const version = readPackageJson().version ?? 'unknown';
|
|
44
|
-
export const args = parseArguments(version);
|
|
25
|
+
// If moved update release-please config
|
|
26
|
+
// x-release-please-start-version
|
|
27
|
+
const VERSION = '0.8.1';
|
|
28
|
+
// x-release-please-end
|
|
29
|
+
export const args = parseArguments(VERSION);
|
|
45
30
|
const logFile = args.logFile ? saveLogsToFile(args.logFile) : undefined;
|
|
46
|
-
logger(`Starting Chrome DevTools MCP Server v${
|
|
31
|
+
logger(`Starting Chrome DevTools MCP Server v${VERSION}`);
|
|
47
32
|
const server = new McpServer({
|
|
48
33
|
name: 'chrome_devtools',
|
|
49
34
|
title: 'Chrome DevTools MCP server',
|
|
50
|
-
version,
|
|
35
|
+
version: VERSION,
|
|
51
36
|
}, { capabilities: { logging: {} } });
|
|
52
37
|
server.server.setRequestHandler(SetLevelRequestSchema, () => {
|
|
53
38
|
return {};
|
|
54
39
|
});
|
|
55
40
|
let context;
|
|
56
41
|
async function getContext() {
|
|
57
|
-
const extraArgs = [];
|
|
42
|
+
const extraArgs = (args.chromeArg ?? []).map(String);
|
|
58
43
|
if (args.proxyServer) {
|
|
59
44
|
extraArgs.push(`--proxy-server=${args.proxyServer}`);
|
|
60
45
|
}
|
|
@@ -67,7 +52,6 @@ async function getContext() {
|
|
|
67
52
|
: await ensureBrowserLaunched({
|
|
68
53
|
headless: args.headless,
|
|
69
54
|
executablePath: args.executablePath,
|
|
70
|
-
customDevTools: args.customDevtools,
|
|
71
55
|
channel: args.channel,
|
|
72
56
|
isolated: args.isolated,
|
|
73
57
|
logFile,
|
|
@@ -140,6 +124,9 @@ const tools = [
|
|
|
140
124
|
...Object.values(scriptTools),
|
|
141
125
|
...Object.values(snapshotTools),
|
|
142
126
|
];
|
|
127
|
+
tools.sort((a, b) => {
|
|
128
|
+
return a.name.localeCompare(b.name);
|
|
129
|
+
});
|
|
143
130
|
for (const tool of tools) {
|
|
144
131
|
registerTool(tool);
|
|
145
132
|
}
|
package/build/src/tools/input.js
CHANGED
|
@@ -68,6 +68,55 @@ export const hover = defineTool({
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
});
|
|
71
|
+
// The AXNode for an option doesn't contain its `value`. We set text content of the option as value.
|
|
72
|
+
// If the form is a combobox, we need to find the correct option by its text value.
|
|
73
|
+
// To do that, loop through the children while checking which child's text matches the requested value (requested value is actually the text content).
|
|
74
|
+
// When the correct option is found, use the element handle to get the real value.
|
|
75
|
+
async function selectOption(handle, aXNode, value) {
|
|
76
|
+
let optionFound = false;
|
|
77
|
+
for (const child of aXNode.children) {
|
|
78
|
+
if (child.role === 'option' && child.name === value && child.value) {
|
|
79
|
+
optionFound = true;
|
|
80
|
+
const childHandle = await child.elementHandle();
|
|
81
|
+
if (childHandle) {
|
|
82
|
+
try {
|
|
83
|
+
const childValueHandle = await childHandle.getProperty('value');
|
|
84
|
+
try {
|
|
85
|
+
const childValue = await childValueHandle.jsonValue();
|
|
86
|
+
if (childValue) {
|
|
87
|
+
await handle.asLocator().fill(childValue.toString());
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
void childValueHandle.dispose();
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
void childHandle.dispose();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!optionFound) {
|
|
102
|
+
throw new Error(`Could not find option with text "${value}"`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function fillFormElement(uid, value, context) {
|
|
106
|
+
const handle = await context.getElementByUid(uid);
|
|
107
|
+
try {
|
|
108
|
+
const aXNode = context.getAXNodeByUid(uid);
|
|
109
|
+
if (aXNode && aXNode.role === 'combobox') {
|
|
110
|
+
await selectOption(handle, aXNode, value);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
await handle.asLocator().fill(value);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
void handle.dispose();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
71
120
|
export const fill = defineTool({
|
|
72
121
|
name: 'fill',
|
|
73
122
|
description: `Type text into a input, text area or select an option from a <select> element.`,
|
|
@@ -82,17 +131,11 @@ export const fill = defineTool({
|
|
|
82
131
|
value: z.string().describe('The value to fill in'),
|
|
83
132
|
},
|
|
84
133
|
handler: async (request, response, context) => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
response.appendResponseLine(`Successfully filled out the element`);
|
|
91
|
-
response.setIncludeSnapshot(true);
|
|
92
|
-
}
|
|
93
|
-
finally {
|
|
94
|
-
void handle.dispose();
|
|
95
|
-
}
|
|
134
|
+
await context.waitForEventsAfterAction(async () => {
|
|
135
|
+
await fillFormElement(request.params.uid, request.params.value, context);
|
|
136
|
+
});
|
|
137
|
+
response.appendResponseLine(`Successfully filled out the element`);
|
|
138
|
+
response.setIncludeSnapshot(true);
|
|
96
139
|
},
|
|
97
140
|
});
|
|
98
141
|
export const drag = defineTool({
|
|
@@ -141,15 +184,9 @@ export const fillForm = defineTool({
|
|
|
141
184
|
},
|
|
142
185
|
handler: async (request, response, context) => {
|
|
143
186
|
for (const element of request.params.elements) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
await handle.asLocator().fill(element.value);
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
finally {
|
|
151
|
-
void handle.dispose();
|
|
152
|
-
}
|
|
187
|
+
await context.waitForEventsAfterAction(async () => {
|
|
188
|
+
await fillFormElement(element.uid, element.value, context);
|
|
189
|
+
});
|
|
153
190
|
}
|
|
154
191
|
response.appendResponseLine(`Successfully filled out the form`);
|
|
155
192
|
response.setIncludeSnapshot(true);
|
package/build/src/tools/pages.js
CHANGED
|
@@ -133,8 +133,8 @@ export const navigatePageHistory = defineTool({
|
|
|
133
133
|
await page.goForward(options);
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
-
catch {
|
|
137
|
-
response.appendResponseLine(`Unable to navigate ${request.params.navigate} in currently selected page
|
|
136
|
+
catch (error) {
|
|
137
|
+
response.appendResponseLine(`Unable to navigate ${request.params.navigate} in currently selected page. ${error.message}`);
|
|
138
138
|
}
|
|
139
139
|
response.setIncludePages(true);
|
|
140
140
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-devtools-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "MCP server for Chrome DevTools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./build/src/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test:only:no-build": "node --require ./build/tests/setup.js --no-warnings=ExperimentalWarning --test-reporter spec --test-force-exit --test --test-only \"build/tests/**/*.test.js\"",
|
|
21
21
|
"test:update-snapshots": "npm run build && node --require ./build/tests/setup.js --no-warnings=ExperimentalWarning --test-force-exit --test --test-update-snapshots \"build/tests/**/*.test.js\"",
|
|
22
22
|
"prepare": "node --experimental-strip-types scripts/prepare.ts",
|
|
23
|
-
"
|
|
23
|
+
"verify-server-json-version": "node --experimental-strip-types scripts/verify-server-json-version.ts"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"build/src",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp#readme",
|
|
38
38
|
"mcpName": "io.github.ChromeDevTools/chrome-devtools-mcp",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@modelcontextprotocol/sdk": "1.
|
|
41
|
-
"core-js": "3.
|
|
40
|
+
"@modelcontextprotocol/sdk": "1.20.0",
|
|
41
|
+
"core-js": "3.46.0",
|
|
42
42
|
"debug": "4.4.3",
|
|
43
|
-
"puppeteer-core": "^24.24.
|
|
43
|
+
"puppeteer-core": "^24.24.1",
|
|
44
44
|
"yargs": "18.0.0",
|
|
45
45
|
"zod": "^3.25.76"
|
|
46
46
|
},
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"eslint-plugin-import": "^2.32.0",
|
|
61
61
|
"globals": "^16.4.0",
|
|
62
62
|
"prettier": "^3.6.2",
|
|
63
|
-
"puppeteer": "24.24.
|
|
63
|
+
"puppeteer": "24.24.1",
|
|
64
64
|
"sinon": "^21.0.0",
|
|
65
65
|
"typescript": "^5.9.2",
|
|
66
66
|
"typescript-eslint": "^8.43.0"
|