@cotestdev/mcp_playwright 0.0.47 → 0.0.49
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/lib/mcp/browser/browserContextFactory.js +1 -1
- package/lib/mcp/browser/browserServerBackend.js +3 -5
- package/lib/mcp/browser/config.js +4 -2
- package/lib/mcp/browser/context.js +1 -0
- package/lib/mcp/browser/response.js +21 -38
- package/lib/mcp/browser/tools/console.js +1 -1
- package/lib/mcp/browser/tools/network.js +1 -1
- package/lib/mcp/browser/tools/pdf.js +1 -1
- package/lib/mcp/browser/tools/runCode.js +3 -1
- package/lib/mcp/browser/tools/screenshot.js +1 -1
- package/lib/mcp/browser/tools/storage.js +68 -0
- package/lib/mcp/browser/tools/tracing.js +2 -2
- package/lib/mcp/browser/tools/video.js +71 -0
- package/lib/mcp/browser/tools.js +7 -3
- package/lib/mcp/extension/cdpRelay.js +3 -0
- package/lib/mcp/program.js +15 -12
- package/lib/mcp/terminal/command.js +13 -0
- package/lib/mcp/terminal/commands.js +32 -12
- package/lib/mcp/terminal/daemon.js +41 -7
- package/lib/mcp/terminal/helpGenerator.js +1 -0
- package/lib/mcp/terminal/program.js +187 -193
- package/lib/mcp/terminal/socketConnection.js +9 -3
- package/package.json +2 -2
|
@@ -38,7 +38,7 @@ const close = (0, import_command.declareCommand)({
|
|
|
38
38
|
description: "Close the page",
|
|
39
39
|
category: "core",
|
|
40
40
|
args: import_mcpBundle.z.object({}),
|
|
41
|
-
toolName: "
|
|
41
|
+
toolName: "",
|
|
42
42
|
toolParams: () => ({})
|
|
43
43
|
});
|
|
44
44
|
const goBack = (0, import_command.declareCommand)({
|
|
@@ -308,6 +308,16 @@ const resize = (0, import_command.declareCommand)({
|
|
|
308
308
|
toolName: "browser_resize",
|
|
309
309
|
toolParams: ({ w: width, h: height }) => ({ width, height })
|
|
310
310
|
});
|
|
311
|
+
const runCode = (0, import_command.declareCommand)({
|
|
312
|
+
name: "run-code",
|
|
313
|
+
description: "Run Playwright code snippet",
|
|
314
|
+
category: "devtools",
|
|
315
|
+
args: import_mcpBundle.z.object({
|
|
316
|
+
code: import_mcpBundle.z.string().describe("A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction.")
|
|
317
|
+
}),
|
|
318
|
+
toolName: "browser_run_code",
|
|
319
|
+
toolParams: ({ code }) => ({ code })
|
|
320
|
+
});
|
|
311
321
|
const tabList = (0, import_command.declareCommand)({
|
|
312
322
|
name: "tab-list",
|
|
313
323
|
description: "List all tabs",
|
|
@@ -396,16 +406,6 @@ const networkRequests = (0, import_command.declareCommand)({
|
|
|
396
406
|
toolName: ({ clear }) => clear ? "browser_network_clear" : "browser_network_requests",
|
|
397
407
|
toolParams: ({ static: includeStatic, clear }) => clear ? {} : { includeStatic }
|
|
398
408
|
});
|
|
399
|
-
const runCode = (0, import_command.declareCommand)({
|
|
400
|
-
name: "run-code",
|
|
401
|
-
description: "Run Playwright code snippet",
|
|
402
|
-
category: "devtools",
|
|
403
|
-
args: import_mcpBundle.z.object({
|
|
404
|
-
code: import_mcpBundle.z.string().describe("A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction.")
|
|
405
|
-
}),
|
|
406
|
-
toolName: "browser_run_code",
|
|
407
|
-
toolParams: ({ code }) => ({ code })
|
|
408
|
-
});
|
|
409
409
|
const tracingStart = (0, import_command.declareCommand)({
|
|
410
410
|
name: "tracing-start",
|
|
411
411
|
description: "Start trace recording",
|
|
@@ -422,6 +422,24 @@ const tracingStop = (0, import_command.declareCommand)({
|
|
|
422
422
|
toolName: "browser_stop_tracing",
|
|
423
423
|
toolParams: () => ({})
|
|
424
424
|
});
|
|
425
|
+
const videoStart = (0, import_command.declareCommand)({
|
|
426
|
+
name: "video-start",
|
|
427
|
+
description: "Start video recording",
|
|
428
|
+
category: "devtools",
|
|
429
|
+
args: import_mcpBundle.z.object({}),
|
|
430
|
+
toolName: "browser_start_video",
|
|
431
|
+
toolParams: () => ({})
|
|
432
|
+
});
|
|
433
|
+
const videoStop = (0, import_command.declareCommand)({
|
|
434
|
+
name: "video-stop",
|
|
435
|
+
description: "Stop video recording",
|
|
436
|
+
category: "devtools",
|
|
437
|
+
options: import_mcpBundle.z.object({
|
|
438
|
+
filename: import_mcpBundle.z.string().optional().describe("Filename to save the video.")
|
|
439
|
+
}),
|
|
440
|
+
toolName: "browser_stop_video",
|
|
441
|
+
toolParams: ({ filename }) => ({ filename })
|
|
442
|
+
});
|
|
425
443
|
const sessionList = (0, import_command.declareCommand)({
|
|
426
444
|
name: "session-list",
|
|
427
445
|
description: "List all sessions",
|
|
@@ -487,6 +505,7 @@ const commandsArray = [
|
|
|
487
505
|
dialogAccept,
|
|
488
506
|
dialogDismiss,
|
|
489
507
|
resize,
|
|
508
|
+
runCode,
|
|
490
509
|
// navigation category
|
|
491
510
|
goBack,
|
|
492
511
|
goForward,
|
|
@@ -512,9 +531,10 @@ const commandsArray = [
|
|
|
512
531
|
config,
|
|
513
532
|
// devtools category
|
|
514
533
|
networkRequests,
|
|
515
|
-
runCode,
|
|
516
534
|
tracingStart,
|
|
517
535
|
tracingStop,
|
|
536
|
+
videoStart,
|
|
537
|
+
videoStop,
|
|
518
538
|
// session category
|
|
519
539
|
sessionList,
|
|
520
540
|
sessionStop,
|
|
@@ -51,7 +51,7 @@ async function socketExists(socketPath) {
|
|
|
51
51
|
}
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
54
|
-
async function startMcpDaemonServer(socketPath, serverBackendFactory) {
|
|
54
|
+
async function startMcpDaemonServer(socketPath, serverBackendFactory, daemonVersion) {
|
|
55
55
|
if (import_os.default.platform() !== "win32" && await socketExists(socketPath)) {
|
|
56
56
|
daemonDebug(`Socket already exists, removing: ${socketPath}`);
|
|
57
57
|
try {
|
|
@@ -75,21 +75,38 @@ async function startMcpDaemonServer(socketPath, serverBackendFactory) {
|
|
|
75
75
|
await import_promises.default.mkdir(import_path.default.dirname(socketPath), { recursive: true });
|
|
76
76
|
const server = import_net.default.createServer((socket) => {
|
|
77
77
|
daemonDebug("new client connection");
|
|
78
|
-
const connection = new import_socketConnection.SocketConnection(socket);
|
|
78
|
+
const connection = new import_socketConnection.SocketConnection(socket, daemonVersion);
|
|
79
79
|
connection.onclose = () => {
|
|
80
80
|
daemonDebug("client disconnected");
|
|
81
81
|
};
|
|
82
|
+
connection.onversionerror = (id, e) => {
|
|
83
|
+
if (daemonVersion === "undefined-for-test")
|
|
84
|
+
return false;
|
|
85
|
+
if (semverGreater(daemonVersion, e.received)) {
|
|
86
|
+
connection.send({ id, error: `Client is too old: daemon is ${daemonVersion}, client is ${e.received}.` }).catch((e2) => console.error(e2));
|
|
87
|
+
} else {
|
|
88
|
+
(0, import_utils.gracefullyProcessExitDoNotHang)(0, async () => {
|
|
89
|
+
await connection.send({ id, error: `Daemon is too old: daemon is ${daemonVersion}, client is ${e.received}. Stopping it.` }).catch((e2) => console.error(e2));
|
|
90
|
+
server.close();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
};
|
|
82
95
|
connection.onmessage = async (message) => {
|
|
83
96
|
const { id, method, params } = message;
|
|
84
97
|
try {
|
|
85
98
|
daemonDebug("received command", method);
|
|
86
99
|
if (method === "stop") {
|
|
87
100
|
daemonDebug("stop command received, shutting down");
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
(0, import_utils.gracefullyProcessExitDoNotHang)(0, async () => {
|
|
102
|
+
await connection.send({ id, result: "ok" }).catch(() => {
|
|
103
|
+
});
|
|
104
|
+
server.close();
|
|
105
|
+
});
|
|
91
106
|
} else if (method === "run") {
|
|
92
107
|
const { toolName, toolParams } = parseCliCommand(params.args);
|
|
108
|
+
if (params.cwd)
|
|
109
|
+
toolParams._meta = { cwd: params.cwd };
|
|
93
110
|
const response = await backend.callTool(toolName, toolParams, () => {
|
|
94
111
|
});
|
|
95
112
|
await connection.send({ id, result: formatResult(response) });
|
|
@@ -102,6 +119,11 @@ async function startMcpDaemonServer(socketPath, serverBackendFactory) {
|
|
|
102
119
|
}
|
|
103
120
|
};
|
|
104
121
|
});
|
|
122
|
+
backend.onBrowserContextClosed = () => {
|
|
123
|
+
daemonDebug("browser closed, shutting down daemon");
|
|
124
|
+
server.close();
|
|
125
|
+
(0, import_utils.gracefullyProcessExitDoNotHang)(0);
|
|
126
|
+
};
|
|
105
127
|
return new Promise((resolve, reject) => {
|
|
106
128
|
server.on("error", (error) => {
|
|
107
129
|
daemonDebug(`server error: ${error.message}`);
|
|
@@ -116,8 +138,7 @@ async function startMcpDaemonServer(socketPath, serverBackendFactory) {
|
|
|
116
138
|
function formatResult(result) {
|
|
117
139
|
const isError = result.isError;
|
|
118
140
|
const text = result.content[0].type === "text" ? result.content[0].text : void 0;
|
|
119
|
-
|
|
120
|
-
return { isError, text, sections };
|
|
141
|
+
return { isError, text };
|
|
121
142
|
}
|
|
122
143
|
function parseCliCommand(args) {
|
|
123
144
|
const command = import_commands.commands[args._[0]];
|
|
@@ -125,6 +146,19 @@ function parseCliCommand(args) {
|
|
|
125
146
|
throw new Error("Command is required");
|
|
126
147
|
return (0, import_command.parseCommand)(command, args);
|
|
127
148
|
}
|
|
149
|
+
function semverGreater(a, b) {
|
|
150
|
+
a = a.replace(/-next$/, "");
|
|
151
|
+
b = b.replace(/-next$/, "");
|
|
152
|
+
const aParts = a.split(".").map(Number);
|
|
153
|
+
const bParts = b.split(".").map(Number);
|
|
154
|
+
for (let i = 0; i < 4; i++) {
|
|
155
|
+
if (aParts[i] > bParts[i])
|
|
156
|
+
return true;
|
|
157
|
+
if (aParts[i] < bParts[i])
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
128
162
|
// Annotate the CommonJS export names for ESM import in node:
|
|
129
163
|
0 && (module.exports = {
|
|
130
164
|
startMcpDaemonServer
|
|
@@ -91,6 +91,7 @@ ${c.title}:`);
|
|
|
91
91
|
}
|
|
92
92
|
lines.push("\nGlobal options:");
|
|
93
93
|
lines.push(formatWithGap(" --config <path>", "create a session with custom config, defaults to `playwright-cli.json`"));
|
|
94
|
+
lines.push(formatWithGap(" --extension", "connect to a running browser instance using Playwright MCP Bridge extension"));
|
|
94
95
|
lines.push(formatWithGap(" --headed", "create a headed session"));
|
|
95
96
|
lines.push(formatWithGap(" --help [command]", "print help"));
|
|
96
97
|
lines.push(formatWithGap(" --session", "run command in the scope of a specific session"));
|