@playwright/mcp 0.0.26 → 0.0.27
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 +4 -1
- package/config.d.ts +2 -2
- package/index.js +1 -1
- package/lib/config.js +6 -14
- package/lib/connection.js +1 -2
- package/lib/context.js +8 -0
- package/lib/pageSnapshot.js +2 -5
- package/lib/program.js +1 -1
- package/lib/tools/screenshot.js +2 -2
- package/lib/tools/snapshot.js +6 -6
- package/lib/tools/utils.js +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -137,7 +137,10 @@ Playwright MCP server supports following arguments. They can be provided in the
|
|
|
137
137
|
--ignore-https-errors ignore https errors
|
|
138
138
|
--isolated keep the browser profile in memory, do not save
|
|
139
139
|
it to disk.
|
|
140
|
-
--
|
|
140
|
+
--image-responses <mode> whether to send image responses to the client.
|
|
141
|
+
Can be "allow", "omit", or "auto". Defaults to
|
|
142
|
+
"auto", which sends images if the client can
|
|
143
|
+
display them.
|
|
141
144
|
--no-sandbox disable the sandbox for all process types that
|
|
142
145
|
are normally sandboxed.
|
|
143
146
|
--output-dir <path> path to the directory for output files.
|
package/config.d.ts
CHANGED
|
@@ -117,7 +117,7 @@ export type Config = {
|
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
|
-
*
|
|
120
|
+
* Whether to send image responses to the client. Can be "allow", "omit", or "auto". Defaults to "auto", which sends images if the client can display them.
|
|
121
121
|
*/
|
|
122
|
-
|
|
122
|
+
imageResponses?: 'allow' | 'omit' | 'auto';
|
|
123
123
|
};
|
package/index.js
CHANGED
package/lib/config.js
CHANGED
|
@@ -47,6 +47,8 @@ export async function resolveCLIConfig(cliOptions) {
|
|
|
47
47
|
// Derive artifact output directory from config.outputDir
|
|
48
48
|
if (result.saveTrace)
|
|
49
49
|
result.browser.launchOptions.tracesDir = path.join(result.outputDir, 'traces');
|
|
50
|
+
if (result.browser.browserName === 'chromium')
|
|
51
|
+
result.browser.launchOptions.cdpPort = await findFreePort();
|
|
50
52
|
return result;
|
|
51
53
|
}
|
|
52
54
|
export async function configFromCLIOptions(cliOptions) {
|
|
@@ -71,9 +73,6 @@ export async function configFromCLIOptions(cliOptions) {
|
|
|
71
73
|
case 'webkit':
|
|
72
74
|
browserName = 'webkit';
|
|
73
75
|
break;
|
|
74
|
-
default:
|
|
75
|
-
browserName = 'chromium';
|
|
76
|
-
channel = 'chrome';
|
|
77
76
|
}
|
|
78
77
|
// Launch options
|
|
79
78
|
const launchOptions = {
|
|
@@ -81,13 +80,9 @@ export async function configFromCLIOptions(cliOptions) {
|
|
|
81
80
|
executablePath: cliOptions.executablePath,
|
|
82
81
|
headless: cliOptions.headless,
|
|
83
82
|
};
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// --no-sandbox was passed, disable the sandbox
|
|
88
|
-
launchOptions.chromiumSandbox = false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
83
|
+
// --no-sandbox was passed, disable the sandbox
|
|
84
|
+
if (!cliOptions.sandbox)
|
|
85
|
+
launchOptions.chromiumSandbox = false;
|
|
91
86
|
if (cliOptions.proxyServer) {
|
|
92
87
|
launchOptions.proxy = {
|
|
93
88
|
server: cliOptions.proxyServer
|
|
@@ -137,11 +132,8 @@ export async function configFromCLIOptions(cliOptions) {
|
|
|
137
132
|
},
|
|
138
133
|
saveTrace: cliOptions.saveTrace,
|
|
139
134
|
outputDir: cliOptions.outputDir,
|
|
135
|
+
imageResponses: cliOptions.imageResponses,
|
|
140
136
|
};
|
|
141
|
-
if (!cliOptions.imageResponses) {
|
|
142
|
-
// --no-image-responses was passed, disable image responses
|
|
143
|
-
result.noImageResponses = true;
|
|
144
|
-
}
|
|
145
137
|
return result;
|
|
146
138
|
}
|
|
147
139
|
async function findFreePort() {
|
package/lib/connection.js
CHANGED
|
@@ -77,8 +77,7 @@ export class Connection {
|
|
|
77
77
|
await new Promise(resolve => {
|
|
78
78
|
this.server.oninitialized = () => resolve();
|
|
79
79
|
});
|
|
80
|
-
|
|
81
|
-
this.context.config.noImageResponses = true;
|
|
80
|
+
this.context.clientVersion = this.server.getClientVersion();
|
|
82
81
|
}
|
|
83
82
|
async close() {
|
|
84
83
|
await this.server.close();
|
package/lib/context.js
CHANGED
|
@@ -31,10 +31,18 @@ export class Context {
|
|
|
31
31
|
_modalStates = [];
|
|
32
32
|
_pendingAction;
|
|
33
33
|
_downloads = [];
|
|
34
|
+
clientVersion;
|
|
34
35
|
constructor(tools, config) {
|
|
35
36
|
this.tools = tools;
|
|
36
37
|
this.config = config;
|
|
37
38
|
}
|
|
39
|
+
clientSupportsImages() {
|
|
40
|
+
if (this.config.imageResponses === 'allow')
|
|
41
|
+
return true;
|
|
42
|
+
if (this.config.imageResponses === 'omit')
|
|
43
|
+
return false;
|
|
44
|
+
return !this.clientVersion?.name.includes('cursor');
|
|
45
|
+
}
|
|
38
46
|
modalStates() {
|
|
39
47
|
return this._modalStates;
|
|
40
48
|
}
|
package/lib/pageSnapshot.js
CHANGED
|
@@ -29,9 +29,6 @@ export class PageSnapshot {
|
|
|
29
29
|
return this._text;
|
|
30
30
|
}
|
|
31
31
|
async _build() {
|
|
32
|
-
// FIXME: Rountrip evaluate to ensure _snapshotForAI works.
|
|
33
|
-
// This probably broke once we moved off locator snapshots
|
|
34
|
-
await this._page.evaluate(() => 1);
|
|
35
32
|
const snapshot = await callOnPageNoTrace(this._page, page => page._snapshotForAI());
|
|
36
33
|
this._text = [
|
|
37
34
|
`- Page Snapshot`,
|
|
@@ -40,7 +37,7 @@ export class PageSnapshot {
|
|
|
40
37
|
'```',
|
|
41
38
|
].join('\n');
|
|
42
39
|
}
|
|
43
|
-
refLocator(
|
|
44
|
-
return this._page.locator(`aria-ref=${ref}`);
|
|
40
|
+
refLocator(params) {
|
|
41
|
+
return this._page.locator(`aria-ref=${params.ref}`).describe(params.element);
|
|
45
42
|
}
|
|
46
43
|
}
|
package/lib/program.js
CHANGED
|
@@ -35,7 +35,7 @@ program
|
|
|
35
35
|
.option('--host <host>', 'host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.')
|
|
36
36
|
.option('--ignore-https-errors', 'ignore https errors')
|
|
37
37
|
.option('--isolated', 'keep the browser profile in memory, do not save it to disk.')
|
|
38
|
-
.option('--
|
|
38
|
+
.option('--image-responses <mode>', 'whether to send image responses to the client. Can be "allow", "omit", or "auto". Defaults to "auto", which sends images if the client can display them.')
|
|
39
39
|
.option('--no-sandbox', 'disable the sandbox for all process types that are normally sandboxed.')
|
|
40
40
|
.option('--output-dir <path>', 'path to the directory for output files.')
|
|
41
41
|
.option('--port <port>', 'port to listen on for SSE transport.')
|
package/lib/tools/screenshot.js
CHANGED
|
@@ -48,12 +48,12 @@ const screenshot = defineTool({
|
|
|
48
48
|
const code = [
|
|
49
49
|
`// Screenshot ${isElementScreenshot ? params.element : 'viewport'} and save it as ${fileName}`,
|
|
50
50
|
];
|
|
51
|
-
const locator = params.ref ? snapshot.refLocator(params.ref) : null;
|
|
51
|
+
const locator = params.ref ? snapshot.refLocator({ element: params.element || '', ref: params.ref }) : null;
|
|
52
52
|
if (locator)
|
|
53
53
|
code.push(`await page.${await generateLocator(locator)}.screenshot(${javascript.formatObject(options)});`);
|
|
54
54
|
else
|
|
55
55
|
code.push(`await page.screenshot(${javascript.formatObject(options)});`);
|
|
56
|
-
const includeBase64 =
|
|
56
|
+
const includeBase64 = context.clientSupportsImages();
|
|
57
57
|
const action = async () => {
|
|
58
58
|
const screenshot = locator ? await locator.screenshot(options) : await tab.page.screenshot(options);
|
|
59
59
|
return {
|
package/lib/tools/snapshot.js
CHANGED
|
@@ -50,7 +50,7 @@ const click = defineTool({
|
|
|
50
50
|
},
|
|
51
51
|
handle: async (context, params) => {
|
|
52
52
|
const tab = context.currentTabOrDie();
|
|
53
|
-
const locator = tab.snapshotOrDie().refLocator(params
|
|
53
|
+
const locator = tab.snapshotOrDie().refLocator(params);
|
|
54
54
|
const code = [
|
|
55
55
|
`// Click ${params.element}`,
|
|
56
56
|
`await page.${await generateLocator(locator)}.click();`
|
|
@@ -79,8 +79,8 @@ const drag = defineTool({
|
|
|
79
79
|
},
|
|
80
80
|
handle: async (context, params) => {
|
|
81
81
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
82
|
-
const startLocator = snapshot.refLocator(params.startRef);
|
|
83
|
-
const endLocator = snapshot.refLocator(params.endRef);
|
|
82
|
+
const startLocator = snapshot.refLocator({ ref: params.startRef, element: params.startElement });
|
|
83
|
+
const endLocator = snapshot.refLocator({ ref: params.endRef, element: params.endElement });
|
|
84
84
|
const code = [
|
|
85
85
|
`// Drag ${params.startElement} to ${params.endElement}`,
|
|
86
86
|
`await page.${await generateLocator(startLocator)}.dragTo(page.${await generateLocator(endLocator)});`
|
|
@@ -104,7 +104,7 @@ const hover = defineTool({
|
|
|
104
104
|
},
|
|
105
105
|
handle: async (context, params) => {
|
|
106
106
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
107
|
-
const locator = snapshot.refLocator(params
|
|
107
|
+
const locator = snapshot.refLocator(params);
|
|
108
108
|
const code = [
|
|
109
109
|
`// Hover over ${params.element}`,
|
|
110
110
|
`await page.${await generateLocator(locator)}.hover();`
|
|
@@ -133,7 +133,7 @@ const type = defineTool({
|
|
|
133
133
|
},
|
|
134
134
|
handle: async (context, params) => {
|
|
135
135
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
136
|
-
const locator = snapshot.refLocator(params
|
|
136
|
+
const locator = snapshot.refLocator(params);
|
|
137
137
|
const code = [];
|
|
138
138
|
const steps = [];
|
|
139
139
|
if (params.slowly) {
|
|
@@ -173,7 +173,7 @@ const selectOption = defineTool({
|
|
|
173
173
|
},
|
|
174
174
|
handle: async (context, params) => {
|
|
175
175
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
176
|
-
const locator = snapshot.refLocator(params
|
|
176
|
+
const locator = snapshot.refLocator(params);
|
|
177
177
|
const code = [
|
|
178
178
|
`// Select options [${params.values.join(', ')}] in ${params.element}`,
|
|
179
179
|
`await page.${await generateLocator(locator)}.selectOption(${javascript.formatObject(params.values)});`
|
package/lib/tools/utils.js
CHANGED
|
@@ -66,8 +66,8 @@ export function sanitizeForFilePath(s) {
|
|
|
66
66
|
return sanitize(s.substring(0, separator)) + '.' + sanitize(s.substring(separator + 1));
|
|
67
67
|
}
|
|
68
68
|
export async function generateLocator(locator) {
|
|
69
|
-
return locator.
|
|
69
|
+
return locator._generateLocatorString();
|
|
70
70
|
}
|
|
71
71
|
export async function callOnPageNoTrace(page, callback) {
|
|
72
|
-
return await page._wrapApiCall(() => callback(page), true);
|
|
72
|
+
return await page._wrapApiCall(() => callback(page), { internal: true });
|
|
73
73
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playwright/mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.27",
|
|
4
4
|
"description": "Playwright Tools for MCP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@modelcontextprotocol/sdk": "^1.11.0",
|
|
39
39
|
"commander": "^13.1.0",
|
|
40
|
-
"playwright": "1.53.0-alpha-
|
|
40
|
+
"playwright": "1.53.0-alpha-2025-05-27",
|
|
41
41
|
"zod-to-json-schema": "^3.24.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@eslint/eslintrc": "^3.2.0",
|
|
45
45
|
"@eslint/js": "^9.19.0",
|
|
46
|
-
"@playwright/test": "1.53.0-alpha-
|
|
46
|
+
"@playwright/test": "1.53.0-alpha-2025-05-27",
|
|
47
47
|
"@stylistic/eslint-plugin": "^3.0.1",
|
|
48
48
|
"@types/node": "^22.13.10",
|
|
49
49
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|