@mcp-b/chrome-devtools-mcp 1.8.0 → 1.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/build/src/McpContext.js +15 -0
- package/build/src/tools/pages.js +7 -0
- package/build/src/tools/script.js +31 -4
- package/package.json +1 -1
package/build/src/McpContext.js
CHANGED
|
@@ -89,6 +89,7 @@ export class McpContext {
|
|
|
89
89
|
#networkConditionsMap = new WeakMap();
|
|
90
90
|
#cpuThrottlingRateMap = new WeakMap();
|
|
91
91
|
#geolocationMap = new WeakMap();
|
|
92
|
+
#bypassCSPMap = new WeakMap();
|
|
92
93
|
#dialog;
|
|
93
94
|
#nextSnapshotId = 1;
|
|
94
95
|
#traceResults = [];
|
|
@@ -616,6 +617,20 @@ export class McpContext {
|
|
|
616
617
|
const page = this.getSelectedPage();
|
|
617
618
|
return this.#geolocationMap.get(page) ?? null;
|
|
618
619
|
}
|
|
620
|
+
async setBypassCSP(enabled) {
|
|
621
|
+
const page = this.getSelectedPage();
|
|
622
|
+
await page.setBypassCSP(enabled);
|
|
623
|
+
if (enabled) {
|
|
624
|
+
this.#bypassCSPMap.set(page, true);
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
this.#bypassCSPMap.delete(page);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
getBypassCSP() {
|
|
631
|
+
const page = this.getSelectedPage();
|
|
632
|
+
return this.#bypassCSPMap.get(page) ?? false;
|
|
633
|
+
}
|
|
619
634
|
setIsRunningPerformanceTrace(x) {
|
|
620
635
|
this.#isRunningTrace = x;
|
|
621
636
|
}
|
package/build/src/tools/pages.js
CHANGED
|
@@ -110,6 +110,10 @@ export const navigatePage = defineTool({
|
|
|
110
110
|
.boolean()
|
|
111
111
|
.optional()
|
|
112
112
|
.describe('Whether to ignore cache on reload.'),
|
|
113
|
+
bypassCSP: zod
|
|
114
|
+
.boolean()
|
|
115
|
+
.optional()
|
|
116
|
+
.describe('Bypass Content-Security-Policy on the page. Useful for injecting scripts into third-party sites during development.'),
|
|
113
117
|
...timeoutSchema,
|
|
114
118
|
},
|
|
115
119
|
handler: async (request, response, context) => {
|
|
@@ -117,6 +121,9 @@ export const navigatePage = defineTool({
|
|
|
117
121
|
const options = {
|
|
118
122
|
timeout: request.params.timeout,
|
|
119
123
|
};
|
|
124
|
+
if (request.params.bypassCSP !== undefined) {
|
|
125
|
+
await context.setBypassCSP(request.params.bypassCSP);
|
|
126
|
+
}
|
|
120
127
|
if (!request.params.type && !request.params.url) {
|
|
121
128
|
throw new Error('Either URL or a type is required.');
|
|
122
129
|
}
|
|
@@ -3,19 +3,26 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
+
import { readFile } from 'node:fs/promises';
|
|
6
7
|
import { zod } from '../third_party/index.js';
|
|
7
8
|
import { ToolCategory } from './categories.js';
|
|
8
9
|
import { defineTool } from './ToolDefinition.js';
|
|
9
10
|
export const evaluateScript = defineTool({
|
|
10
11
|
name: 'evaluate_script',
|
|
11
|
-
description: `Evaluate a JavaScript function
|
|
12
|
-
|
|
12
|
+
description: `Evaluate a JavaScript function or inject a script file into the currently selected page.
|
|
13
|
+
|
|
14
|
+
When \`function\` is provided, evaluates it and returns the result as JSON (values must be JSON-serializable).
|
|
15
|
+
When \`filePath\` is provided, reads the file from disk and injects it as a <script> tag (useful for large scripts like polyfills that are too big to pass inline).
|
|
16
|
+
Exactly one of \`function\` or \`filePath\` must be provided.`,
|
|
13
17
|
annotations: {
|
|
14
18
|
category: ToolCategory.DEBUGGING,
|
|
15
19
|
readOnlyHint: false,
|
|
16
20
|
},
|
|
17
21
|
schema: {
|
|
18
|
-
function: zod
|
|
22
|
+
function: zod
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe(`A JavaScript function declaration to be executed by the tool in the currently selected page.
|
|
19
26
|
Example without arguments: \`() => {
|
|
20
27
|
return document.title
|
|
21
28
|
}\` or \`async () => {
|
|
@@ -25,6 +32,10 @@ Example with arguments: \`(el) => {
|
|
|
25
32
|
return el.innerText;
|
|
26
33
|
}\`
|
|
27
34
|
`),
|
|
35
|
+
filePath: zod
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Absolute path to a local JavaScript file to inject into the page via <script> tag. The file is read server-side so there are no size limits or CSP/mixed-content restrictions. Use this for large scripts (polyfills, bundled tools, etc).'),
|
|
28
39
|
args: zod
|
|
29
40
|
.array(zod.object({
|
|
30
41
|
uid: zod
|
|
@@ -32,9 +43,25 @@ Example with arguments: \`(el) => {
|
|
|
32
43
|
.describe('The uid of an element on the page from the page content snapshot'),
|
|
33
44
|
}))
|
|
34
45
|
.optional()
|
|
35
|
-
.describe(`An optional list of arguments to pass to the function
|
|
46
|
+
.describe(`An optional list of arguments to pass to the function. Only used with \`function\`, not \`filePath\`.`),
|
|
36
47
|
},
|
|
37
48
|
handler: async (request, response, context) => {
|
|
49
|
+
const { filePath } = request.params;
|
|
50
|
+
// File injection mode
|
|
51
|
+
if (filePath) {
|
|
52
|
+
if (request.params.function) {
|
|
53
|
+
throw new Error('Provide either `function` or `filePath`, not both.');
|
|
54
|
+
}
|
|
55
|
+
const content = await readFile(filePath, 'utf-8');
|
|
56
|
+
const page = context.getSelectedPage();
|
|
57
|
+
await page.addScriptTag({ content });
|
|
58
|
+
response.appendResponseLine(`Injected script from \`${filePath}\` (${content.length} bytes) into page.`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Function evaluation mode (original behavior)
|
|
62
|
+
if (!request.params.function) {
|
|
63
|
+
throw new Error('Either `function` or `filePath` must be provided.');
|
|
64
|
+
}
|
|
38
65
|
const args = [];
|
|
39
66
|
try {
|
|
40
67
|
const frames = new Set();
|