@cotestdev/mcp_playwright 0.0.50 → 0.0.52
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 +11 -4
- package/lib/mcp/browser/browserServerBackend.js +2 -4
- package/lib/mcp/browser/config.js +71 -47
- package/lib/mcp/browser/context.js +65 -4
- package/lib/mcp/browser/logFile.js +96 -0
- package/lib/mcp/browser/response.js +107 -104
- package/lib/mcp/browser/sessionLog.js +1 -1
- package/lib/mcp/browser/tab.js +73 -18
- package/lib/mcp/browser/tools/config.js +41 -0
- package/lib/mcp/browser/tools/console.js +6 -2
- package/lib/mcp/browser/tools/cookies.js +152 -0
- package/lib/mcp/browser/tools/install.js +1 -0
- package/lib/mcp/browser/tools/network.js +25 -11
- package/lib/mcp/browser/tools/pdf.js +3 -4
- package/lib/mcp/browser/tools/route.js +140 -0
- package/lib/mcp/browser/tools/runCode.js +0 -2
- package/lib/mcp/browser/tools/screenshot.js +6 -7
- package/lib/mcp/browser/tools/storage.js +3 -4
- package/lib/mcp/browser/tools/tracing.js +10 -9
- package/lib/mcp/browser/tools/utils.js +0 -6
- package/lib/mcp/browser/tools/video.js +31 -13
- package/lib/mcp/browser/tools/webstorage.js +223 -0
- package/lib/mcp/browser/tools.js +11 -3
- package/lib/mcp/extension/cdpRelay.js +7 -7
- package/lib/mcp/extension/extensionContextFactory.js +4 -2
- package/lib/mcp/program.js +19 -12
- package/lib/mcp/terminal/cli.js +23 -2
- package/lib/mcp/terminal/command.js +34 -30
- package/lib/mcp/terminal/commands.js +310 -38
- package/lib/mcp/terminal/daemon.js +23 -38
- package/lib/mcp/terminal/helpGenerator.js +8 -6
- package/lib/mcp/terminal/program.js +482 -199
- package/lib/mcp/terminal/socketConnection.js +17 -2
- package/package.json +2 -2
|
@@ -25,22 +25,40 @@ var import_mcpBundle = require("../../mcpBundle");
|
|
|
25
25
|
var import_command = require("./command");
|
|
26
26
|
const open = (0, import_command.declareCommand)({
|
|
27
27
|
name: "open",
|
|
28
|
-
description: "Open
|
|
28
|
+
description: "Open the browser",
|
|
29
29
|
category: "core",
|
|
30
30
|
args: import_mcpBundle.z.object({
|
|
31
|
-
url: import_mcpBundle.z.string().describe("The URL to navigate to")
|
|
31
|
+
url: import_mcpBundle.z.string().optional().describe("The URL to navigate to")
|
|
32
|
+
}),
|
|
33
|
+
options: import_mcpBundle.z.object({
|
|
34
|
+
browser: import_mcpBundle.z.string().optional().describe("Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge."),
|
|
35
|
+
config: import_mcpBundle.z.string().optional().describe("Path to the configuration file, defaults to .playwright/cli.config.json"),
|
|
36
|
+
extension: import_mcpBundle.z.boolean().optional().describe("Connect to browser extension"),
|
|
37
|
+
headed: import_mcpBundle.z.boolean().optional().describe("Run browser in headed mode"),
|
|
38
|
+
persistent: import_mcpBundle.z.boolean().optional().describe("Use persistent browser profile"),
|
|
39
|
+
profile: import_mcpBundle.z.string().optional().describe("Use persistent browser profile, store profile in specified directory.")
|
|
32
40
|
}),
|
|
33
41
|
toolName: "browser_navigate",
|
|
34
|
-
toolParams: ({ url }) => ({ url })
|
|
42
|
+
toolParams: ({ url }) => ({ url: url || "about:blank" })
|
|
35
43
|
});
|
|
36
44
|
const close = (0, import_command.declareCommand)({
|
|
37
45
|
name: "close",
|
|
38
|
-
description: "Close the
|
|
46
|
+
description: "Close the browser",
|
|
39
47
|
category: "core",
|
|
40
48
|
args: import_mcpBundle.z.object({}),
|
|
41
49
|
toolName: "",
|
|
42
50
|
toolParams: () => ({})
|
|
43
51
|
});
|
|
52
|
+
const goto = (0, import_command.declareCommand)({
|
|
53
|
+
name: "goto",
|
|
54
|
+
description: "Navigate to a URL",
|
|
55
|
+
category: "core",
|
|
56
|
+
args: import_mcpBundle.z.object({
|
|
57
|
+
url: import_mcpBundle.z.string().describe("The URL to navigate to")
|
|
58
|
+
}),
|
|
59
|
+
toolName: "browser_navigate",
|
|
60
|
+
toolParams: ({ url }) => ({ url })
|
|
61
|
+
});
|
|
44
62
|
const goBack = (0, import_command.declareCommand)({
|
|
45
63
|
name: "go-back",
|
|
46
64
|
description: "Go back to the previous page",
|
|
@@ -186,9 +204,6 @@ const drag = (0, import_command.declareCommand)({
|
|
|
186
204
|
startRef: import_mcpBundle.z.string().describe("Exact source element reference from the page snapshot"),
|
|
187
205
|
endRef: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
|
|
188
206
|
}),
|
|
189
|
-
options: import_mcpBundle.z.object({
|
|
190
|
-
headed: import_mcpBundle.z.boolean().default(false).describe("Run browser in headed mode")
|
|
191
|
-
}),
|
|
192
207
|
toolName: "browser_drag",
|
|
193
208
|
toolParams: ({ startRef, endRef }) => ({ startRef, endRef })
|
|
194
209
|
});
|
|
@@ -356,6 +371,221 @@ const tabSelect = (0, import_command.declareCommand)({
|
|
|
356
371
|
toolName: "browser_tabs",
|
|
357
372
|
toolParams: ({ index }) => ({ action: "select", index })
|
|
358
373
|
});
|
|
374
|
+
const stateLoad = (0, import_command.declareCommand)({
|
|
375
|
+
name: "state-load",
|
|
376
|
+
description: "Loads browser storage (authentication) state from a file",
|
|
377
|
+
category: "storage",
|
|
378
|
+
args: import_mcpBundle.z.object({
|
|
379
|
+
filename: import_mcpBundle.z.string().describe("File name to load the storage state from.")
|
|
380
|
+
}),
|
|
381
|
+
toolName: "browser_set_storage_state",
|
|
382
|
+
toolParams: ({ filename }) => ({ filename })
|
|
383
|
+
});
|
|
384
|
+
const stateSave = (0, import_command.declareCommand)({
|
|
385
|
+
name: "state-save",
|
|
386
|
+
description: "Saves the current storage (authentication) state to a file",
|
|
387
|
+
category: "storage",
|
|
388
|
+
args: import_mcpBundle.z.object({
|
|
389
|
+
filename: import_mcpBundle.z.string().optional().describe("File name to save the storage state to.")
|
|
390
|
+
}),
|
|
391
|
+
toolName: "browser_storage_state",
|
|
392
|
+
toolParams: ({ filename }) => ({ filename })
|
|
393
|
+
});
|
|
394
|
+
const cookieList = (0, import_command.declareCommand)({
|
|
395
|
+
name: "cookie-list",
|
|
396
|
+
description: "List all cookies (optionally filtered by domain/path)",
|
|
397
|
+
category: "storage",
|
|
398
|
+
args: import_mcpBundle.z.object({}),
|
|
399
|
+
options: import_mcpBundle.z.object({
|
|
400
|
+
domain: import_mcpBundle.z.string().optional().describe("Filter cookies by domain"),
|
|
401
|
+
path: import_mcpBundle.z.string().optional().describe("Filter cookies by path")
|
|
402
|
+
}),
|
|
403
|
+
toolName: "browser_cookie_list",
|
|
404
|
+
toolParams: ({ domain, path }) => ({ domain, path })
|
|
405
|
+
});
|
|
406
|
+
const cookieGet = (0, import_command.declareCommand)({
|
|
407
|
+
name: "cookie-get",
|
|
408
|
+
description: "Get a specific cookie by name",
|
|
409
|
+
category: "storage",
|
|
410
|
+
args: import_mcpBundle.z.object({
|
|
411
|
+
name: import_mcpBundle.z.string().describe("Cookie name")
|
|
412
|
+
}),
|
|
413
|
+
toolName: "browser_cookie_get",
|
|
414
|
+
toolParams: ({ name }) => ({ name })
|
|
415
|
+
});
|
|
416
|
+
const cookieSet = (0, import_command.declareCommand)({
|
|
417
|
+
name: "cookie-set",
|
|
418
|
+
description: "Set a cookie with optional flags",
|
|
419
|
+
category: "storage",
|
|
420
|
+
args: import_mcpBundle.z.object({
|
|
421
|
+
name: import_mcpBundle.z.string().describe("Cookie name"),
|
|
422
|
+
value: import_mcpBundle.z.string().describe("Cookie value")
|
|
423
|
+
}),
|
|
424
|
+
options: import_mcpBundle.z.object({
|
|
425
|
+
domain: import_mcpBundle.z.string().optional().describe("Cookie domain"),
|
|
426
|
+
path: import_mcpBundle.z.string().optional().describe("Cookie path"),
|
|
427
|
+
expires: import_mcpBundle.z.number().optional().describe("Cookie expiration as Unix timestamp"),
|
|
428
|
+
httpOnly: import_mcpBundle.z.boolean().optional().describe("Whether the cookie is HTTP only"),
|
|
429
|
+
secure: import_mcpBundle.z.boolean().optional().describe("Whether the cookie is secure"),
|
|
430
|
+
sameSite: import_mcpBundle.z.enum(["Strict", "Lax", "None"]).optional().describe("Cookie SameSite attribute")
|
|
431
|
+
}),
|
|
432
|
+
toolName: "browser_cookie_set",
|
|
433
|
+
toolParams: ({ name, value, domain, path, expires, httpOnly, secure, sameSite }) => ({ name, value, domain, path, expires, httpOnly, secure, sameSite })
|
|
434
|
+
});
|
|
435
|
+
const cookieDelete = (0, import_command.declareCommand)({
|
|
436
|
+
name: "cookie-delete",
|
|
437
|
+
description: "Delete a specific cookie",
|
|
438
|
+
category: "storage",
|
|
439
|
+
args: import_mcpBundle.z.object({
|
|
440
|
+
name: import_mcpBundle.z.string().describe("Cookie name")
|
|
441
|
+
}),
|
|
442
|
+
toolName: "browser_cookie_delete",
|
|
443
|
+
toolParams: ({ name }) => ({ name })
|
|
444
|
+
});
|
|
445
|
+
const cookieClear = (0, import_command.declareCommand)({
|
|
446
|
+
name: "cookie-clear",
|
|
447
|
+
description: "Clear all cookies",
|
|
448
|
+
category: "storage",
|
|
449
|
+
args: import_mcpBundle.z.object({}),
|
|
450
|
+
toolName: "browser_cookie_clear",
|
|
451
|
+
toolParams: () => ({})
|
|
452
|
+
});
|
|
453
|
+
const localStorageList = (0, import_command.declareCommand)({
|
|
454
|
+
name: "localstorage-list",
|
|
455
|
+
description: "List all localStorage key-value pairs",
|
|
456
|
+
category: "storage",
|
|
457
|
+
args: import_mcpBundle.z.object({}),
|
|
458
|
+
toolName: "browser_localstorage_list",
|
|
459
|
+
toolParams: () => ({})
|
|
460
|
+
});
|
|
461
|
+
const localStorageGet = (0, import_command.declareCommand)({
|
|
462
|
+
name: "localstorage-get",
|
|
463
|
+
description: "Get a localStorage item by key",
|
|
464
|
+
category: "storage",
|
|
465
|
+
args: import_mcpBundle.z.object({
|
|
466
|
+
key: import_mcpBundle.z.string().describe("Key to get")
|
|
467
|
+
}),
|
|
468
|
+
toolName: "browser_localstorage_get",
|
|
469
|
+
toolParams: ({ key }) => ({ key })
|
|
470
|
+
});
|
|
471
|
+
const localStorageSet = (0, import_command.declareCommand)({
|
|
472
|
+
name: "localstorage-set",
|
|
473
|
+
description: "Set a localStorage item",
|
|
474
|
+
category: "storage",
|
|
475
|
+
args: import_mcpBundle.z.object({
|
|
476
|
+
key: import_mcpBundle.z.string().describe("Key to set"),
|
|
477
|
+
value: import_mcpBundle.z.string().describe("Value to set")
|
|
478
|
+
}),
|
|
479
|
+
toolName: "browser_localstorage_set",
|
|
480
|
+
toolParams: ({ key, value }) => ({ key, value })
|
|
481
|
+
});
|
|
482
|
+
const localStorageDelete = (0, import_command.declareCommand)({
|
|
483
|
+
name: "localstorage-delete",
|
|
484
|
+
description: "Delete a localStorage item",
|
|
485
|
+
category: "storage",
|
|
486
|
+
args: import_mcpBundle.z.object({
|
|
487
|
+
key: import_mcpBundle.z.string().describe("Key to delete")
|
|
488
|
+
}),
|
|
489
|
+
toolName: "browser_localstorage_delete",
|
|
490
|
+
toolParams: ({ key }) => ({ key })
|
|
491
|
+
});
|
|
492
|
+
const localStorageClear = (0, import_command.declareCommand)({
|
|
493
|
+
name: "localstorage-clear",
|
|
494
|
+
description: "Clear all localStorage",
|
|
495
|
+
category: "storage",
|
|
496
|
+
args: import_mcpBundle.z.object({}),
|
|
497
|
+
toolName: "browser_localstorage_clear",
|
|
498
|
+
toolParams: () => ({})
|
|
499
|
+
});
|
|
500
|
+
const sessionStorageList = (0, import_command.declareCommand)({
|
|
501
|
+
name: "sessionstorage-list",
|
|
502
|
+
description: "List all sessionStorage key-value pairs",
|
|
503
|
+
category: "storage",
|
|
504
|
+
args: import_mcpBundle.z.object({}),
|
|
505
|
+
toolName: "browser_sessionstorage_list",
|
|
506
|
+
toolParams: () => ({})
|
|
507
|
+
});
|
|
508
|
+
const sessionStorageGet = (0, import_command.declareCommand)({
|
|
509
|
+
name: "sessionstorage-get",
|
|
510
|
+
description: "Get a sessionStorage item by key",
|
|
511
|
+
category: "storage",
|
|
512
|
+
args: import_mcpBundle.z.object({
|
|
513
|
+
key: import_mcpBundle.z.string().describe("Key to get")
|
|
514
|
+
}),
|
|
515
|
+
toolName: "browser_sessionstorage_get",
|
|
516
|
+
toolParams: ({ key }) => ({ key })
|
|
517
|
+
});
|
|
518
|
+
const sessionStorageSet = (0, import_command.declareCommand)({
|
|
519
|
+
name: "sessionstorage-set",
|
|
520
|
+
description: "Set a sessionStorage item",
|
|
521
|
+
category: "storage",
|
|
522
|
+
args: import_mcpBundle.z.object({
|
|
523
|
+
key: import_mcpBundle.z.string().describe("Key to set"),
|
|
524
|
+
value: import_mcpBundle.z.string().describe("Value to set")
|
|
525
|
+
}),
|
|
526
|
+
toolName: "browser_sessionstorage_set",
|
|
527
|
+
toolParams: ({ key, value }) => ({ key, value })
|
|
528
|
+
});
|
|
529
|
+
const sessionStorageDelete = (0, import_command.declareCommand)({
|
|
530
|
+
name: "sessionstorage-delete",
|
|
531
|
+
description: "Delete a sessionStorage item",
|
|
532
|
+
category: "storage",
|
|
533
|
+
args: import_mcpBundle.z.object({
|
|
534
|
+
key: import_mcpBundle.z.string().describe("Key to delete")
|
|
535
|
+
}),
|
|
536
|
+
toolName: "browser_sessionstorage_delete",
|
|
537
|
+
toolParams: ({ key }) => ({ key })
|
|
538
|
+
});
|
|
539
|
+
const sessionStorageClear = (0, import_command.declareCommand)({
|
|
540
|
+
name: "sessionstorage-clear",
|
|
541
|
+
description: "Clear all sessionStorage",
|
|
542
|
+
category: "storage",
|
|
543
|
+
args: import_mcpBundle.z.object({}),
|
|
544
|
+
toolName: "browser_sessionstorage_clear",
|
|
545
|
+
toolParams: () => ({})
|
|
546
|
+
});
|
|
547
|
+
const routeMock = (0, import_command.declareCommand)({
|
|
548
|
+
name: "route",
|
|
549
|
+
description: "Mock network requests matching a URL pattern",
|
|
550
|
+
category: "network",
|
|
551
|
+
args: import_mcpBundle.z.object({
|
|
552
|
+
pattern: import_mcpBundle.z.string().describe('URL pattern to match (e.g., "**/api/users")')
|
|
553
|
+
}),
|
|
554
|
+
options: import_mcpBundle.z.object({
|
|
555
|
+
status: import_mcpBundle.z.number().optional().describe("HTTP status code (default: 200)"),
|
|
556
|
+
body: import_mcpBundle.z.string().optional().describe("Response body (text or JSON string)"),
|
|
557
|
+
["content-type"]: import_mcpBundle.z.string().optional().describe("Content-Type header"),
|
|
558
|
+
header: import_mcpBundle.z.union([import_mcpBundle.z.string(), import_mcpBundle.z.array(import_mcpBundle.z.string())]).optional().transform((v) => v ? Array.isArray(v) ? v : [v] : void 0).describe('Header to add in "Name: Value" format (repeatable)'),
|
|
559
|
+
["remove-header"]: import_mcpBundle.z.string().optional().describe("Comma-separated header names to remove")
|
|
560
|
+
}),
|
|
561
|
+
toolName: "browser_route",
|
|
562
|
+
toolParams: ({ pattern, status, body, ["content-type"]: contentType, header: headers, ["remove-header"]: removeHeaders }) => ({
|
|
563
|
+
pattern,
|
|
564
|
+
status,
|
|
565
|
+
body,
|
|
566
|
+
contentType,
|
|
567
|
+
headers,
|
|
568
|
+
removeHeaders
|
|
569
|
+
})
|
|
570
|
+
});
|
|
571
|
+
const routeList = (0, import_command.declareCommand)({
|
|
572
|
+
name: "route-list",
|
|
573
|
+
description: "List all active network routes",
|
|
574
|
+
category: "network",
|
|
575
|
+
args: import_mcpBundle.z.object({}),
|
|
576
|
+
toolName: "browser_route_list",
|
|
577
|
+
toolParams: () => ({})
|
|
578
|
+
});
|
|
579
|
+
const unroute = (0, import_command.declareCommand)({
|
|
580
|
+
name: "unroute",
|
|
581
|
+
description: "Remove routes matching a pattern (or all routes)",
|
|
582
|
+
category: "network",
|
|
583
|
+
args: import_mcpBundle.z.object({
|
|
584
|
+
pattern: import_mcpBundle.z.string().optional().describe("URL pattern to unroute (omit to remove all)")
|
|
585
|
+
}),
|
|
586
|
+
toolName: "browser_unroute",
|
|
587
|
+
toolParams: ({ pattern }) => ({ pattern })
|
|
588
|
+
});
|
|
359
589
|
const screenshot = (0, import_command.declareCommand)({
|
|
360
590
|
name: "screenshot",
|
|
361
591
|
description: "screenshot of the current page or element",
|
|
@@ -441,54 +671,71 @@ const videoStop = (0, import_command.declareCommand)({
|
|
|
441
671
|
toolParams: ({ filename }) => ({ filename })
|
|
442
672
|
});
|
|
443
673
|
const sessionList = (0, import_command.declareCommand)({
|
|
444
|
-
name: "
|
|
445
|
-
description: "List
|
|
446
|
-
category: "
|
|
674
|
+
name: "list",
|
|
675
|
+
description: "List browser sessions",
|
|
676
|
+
category: "browsers",
|
|
447
677
|
args: import_mcpBundle.z.object({}),
|
|
678
|
+
options: import_mcpBundle.z.object({
|
|
679
|
+
all: import_mcpBundle.z.boolean().optional().describe("List all browser sessions across all workspaces")
|
|
680
|
+
}),
|
|
448
681
|
toolName: "",
|
|
449
682
|
toolParams: () => ({})
|
|
450
683
|
});
|
|
451
|
-
const
|
|
452
|
-
name: "
|
|
453
|
-
description: "
|
|
454
|
-
category: "
|
|
455
|
-
args: import_mcpBundle.z.object({
|
|
456
|
-
name: import_mcpBundle.z.string().optional().describe("Name of the session to stop. If omitted, current session is stopped.")
|
|
457
|
-
}),
|
|
684
|
+
const sessionCloseAll = (0, import_command.declareCommand)({
|
|
685
|
+
name: "close-all",
|
|
686
|
+
description: "Close all browser sessions",
|
|
687
|
+
category: "browsers",
|
|
458
688
|
toolName: "",
|
|
459
689
|
toolParams: () => ({})
|
|
460
690
|
});
|
|
461
|
-
const
|
|
462
|
-
name: "
|
|
463
|
-
description: "
|
|
464
|
-
category: "
|
|
691
|
+
const killAll = (0, import_command.declareCommand)({
|
|
692
|
+
name: "kill-all",
|
|
693
|
+
description: "Forcefully kill all browser sessions (for stale/zombie processes)",
|
|
694
|
+
category: "browsers",
|
|
465
695
|
toolName: "",
|
|
466
696
|
toolParams: () => ({})
|
|
467
697
|
});
|
|
468
|
-
const
|
|
469
|
-
name: "
|
|
698
|
+
const deleteData = (0, import_command.declareCommand)({
|
|
699
|
+
name: "delete-data",
|
|
470
700
|
description: "Delete session data",
|
|
471
|
-
category: "
|
|
472
|
-
args: import_mcpBundle.z.object({
|
|
473
|
-
name: import_mcpBundle.z.string().optional().describe("Name of the session to delete. If omitted, current session is deleted.")
|
|
474
|
-
}),
|
|
701
|
+
category: "core",
|
|
475
702
|
toolName: "",
|
|
476
|
-
toolParams: (
|
|
703
|
+
toolParams: () => ({})
|
|
477
704
|
});
|
|
478
|
-
const
|
|
479
|
-
name: "config",
|
|
480
|
-
description: "
|
|
705
|
+
const configPrint = (0, import_command.declareCommand)({
|
|
706
|
+
name: "config-print",
|
|
707
|
+
description: "Print the final resolved config after merging CLI options, environment variables and config file.",
|
|
481
708
|
category: "config",
|
|
482
|
-
|
|
483
|
-
|
|
709
|
+
hidden: true,
|
|
710
|
+
toolName: "browser_get_config",
|
|
711
|
+
toolParams: () => ({})
|
|
712
|
+
});
|
|
713
|
+
const install = (0, import_command.declareCommand)({
|
|
714
|
+
name: "install",
|
|
715
|
+
description: "Initialize workspace",
|
|
716
|
+
category: "install",
|
|
717
|
+
args: import_mcpBundle.z.object({}),
|
|
718
|
+
options: import_mcpBundle.z.object({
|
|
719
|
+
skills: import_mcpBundle.z.boolean().optional().describe("Install skills for Claude / GitHub Copilot")
|
|
484
720
|
}),
|
|
485
721
|
toolName: "",
|
|
486
722
|
toolParams: () => ({})
|
|
487
723
|
});
|
|
724
|
+
const installBrowser = (0, import_command.declareCommand)({
|
|
725
|
+
name: "install-browser",
|
|
726
|
+
description: "Install browser",
|
|
727
|
+
category: "install",
|
|
728
|
+
options: import_mcpBundle.z.object({
|
|
729
|
+
browser: import_mcpBundle.z.string().optional().describe("Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge")
|
|
730
|
+
}),
|
|
731
|
+
toolName: "browser_install",
|
|
732
|
+
toolParams: () => ({})
|
|
733
|
+
});
|
|
488
734
|
const commandsArray = [
|
|
489
735
|
// core category
|
|
490
736
|
open,
|
|
491
737
|
close,
|
|
738
|
+
goto,
|
|
492
739
|
type,
|
|
493
740
|
click,
|
|
494
741
|
doubleClick,
|
|
@@ -506,6 +753,7 @@ const commandsArray = [
|
|
|
506
753
|
dialogDismiss,
|
|
507
754
|
resize,
|
|
508
755
|
runCode,
|
|
756
|
+
deleteData,
|
|
509
757
|
// navigation category
|
|
510
758
|
goBack,
|
|
511
759
|
goForward,
|
|
@@ -527,8 +775,33 @@ const commandsArray = [
|
|
|
527
775
|
tabNew,
|
|
528
776
|
tabClose,
|
|
529
777
|
tabSelect,
|
|
530
|
-
//
|
|
531
|
-
|
|
778
|
+
// storage category
|
|
779
|
+
stateLoad,
|
|
780
|
+
stateSave,
|
|
781
|
+
cookieList,
|
|
782
|
+
cookieGet,
|
|
783
|
+
cookieSet,
|
|
784
|
+
cookieDelete,
|
|
785
|
+
cookieClear,
|
|
786
|
+
localStorageList,
|
|
787
|
+
localStorageGet,
|
|
788
|
+
localStorageSet,
|
|
789
|
+
localStorageDelete,
|
|
790
|
+
localStorageClear,
|
|
791
|
+
sessionStorageList,
|
|
792
|
+
sessionStorageGet,
|
|
793
|
+
sessionStorageSet,
|
|
794
|
+
sessionStorageDelete,
|
|
795
|
+
sessionStorageClear,
|
|
796
|
+
// network category
|
|
797
|
+
routeMock,
|
|
798
|
+
routeList,
|
|
799
|
+
unroute,
|
|
800
|
+
// config category
|
|
801
|
+
configPrint,
|
|
802
|
+
// install category
|
|
803
|
+
install,
|
|
804
|
+
installBrowser,
|
|
532
805
|
// devtools category
|
|
533
806
|
networkRequests,
|
|
534
807
|
tracingStart,
|
|
@@ -537,9 +810,8 @@ const commandsArray = [
|
|
|
537
810
|
videoStop,
|
|
538
811
|
// session category
|
|
539
812
|
sessionList,
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
sessionDelete
|
|
813
|
+
sessionCloseAll,
|
|
814
|
+
killAll
|
|
543
815
|
];
|
|
544
816
|
const commands = Object.fromEntries(commandsArray.map((cmd) => [cmd.name, cmd]));
|
|
545
817
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -38,6 +38,7 @@ var import_path = __toESM(require("path"));
|
|
|
38
38
|
var import_url = __toESM(require("url"));
|
|
39
39
|
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
|
40
40
|
var import_utils = require("playwright-core/lib/utils");
|
|
41
|
+
var import_browserServerBackend = require("../browser/browserServerBackend");
|
|
41
42
|
var import_socketConnection = require("./socketConnection");
|
|
42
43
|
var import_commands = require("./commands");
|
|
43
44
|
var import_command = require("./command");
|
|
@@ -51,7 +52,9 @@ async function socketExists(socketPath) {
|
|
|
51
52
|
}
|
|
52
53
|
return false;
|
|
53
54
|
}
|
|
54
|
-
async function startMcpDaemonServer(
|
|
55
|
+
async function startMcpDaemonServer(config, contextFactory) {
|
|
56
|
+
const sessionConfig = config.sessionConfig;
|
|
57
|
+
const { socketPath, version } = sessionConfig;
|
|
55
58
|
if (import_os.default.platform() !== "win32" && await socketExists(socketPath)) {
|
|
56
59
|
daemonDebug(`Socket already exists, removing: ${socketPath}`);
|
|
57
60
|
try {
|
|
@@ -61,37 +64,38 @@ async function startMcpDaemonServer(socketPath, serverBackendFactory, daemonVers
|
|
|
61
64
|
throw error;
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
|
-
const backend = serverBackendFactory.create();
|
|
65
67
|
const cwd = import_url.default.pathToFileURL(process.cwd()).href;
|
|
66
|
-
|
|
68
|
+
const clientInfo = {
|
|
67
69
|
name: "playwright-cli",
|
|
68
|
-
version:
|
|
70
|
+
version: sessionConfig.version,
|
|
69
71
|
roots: [{
|
|
70
72
|
uri: cwd,
|
|
71
73
|
name: "cwd"
|
|
72
74
|
}],
|
|
73
75
|
timestamp: Date.now()
|
|
76
|
+
};
|
|
77
|
+
const { browserContext, close } = await contextFactory.createContext(clientInfo, new AbortController().signal, {});
|
|
78
|
+
browserContext.on("close", () => {
|
|
79
|
+
daemonDebug("browser closed, shutting down daemon");
|
|
80
|
+
shutdown(0);
|
|
74
81
|
});
|
|
82
|
+
const existingContextFactory = {
|
|
83
|
+
createContext: () => Promise.resolve({ browserContext, close })
|
|
84
|
+
};
|
|
85
|
+
const backend = new import_browserServerBackend.BrowserServerBackend(config, existingContextFactory, { allTools: true });
|
|
86
|
+
await backend.initialize?.(clientInfo);
|
|
75
87
|
await import_promises.default.mkdir(import_path.default.dirname(socketPath), { recursive: true });
|
|
88
|
+
const shutdown = (exitCode) => {
|
|
89
|
+
daemonDebug(`shutting down daemon with exit code ${exitCode}`);
|
|
90
|
+
server.close();
|
|
91
|
+
(0, import_utils.gracefullyProcessExitDoNotHang)(exitCode);
|
|
92
|
+
};
|
|
76
93
|
const server = import_net.default.createServer((socket) => {
|
|
77
94
|
daemonDebug("new client connection");
|
|
78
|
-
const connection = new import_socketConnection.SocketConnection(socket,
|
|
95
|
+
const connection = new import_socketConnection.SocketConnection(socket, version);
|
|
79
96
|
connection.onclose = () => {
|
|
80
97
|
daemonDebug("client disconnected");
|
|
81
98
|
};
|
|
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
|
-
};
|
|
95
99
|
connection.onmessage = async (message) => {
|
|
96
100
|
const { id, method, params } = message;
|
|
97
101
|
try {
|
|
@@ -107,8 +111,7 @@ async function startMcpDaemonServer(socketPath, serverBackendFactory, daemonVers
|
|
|
107
111
|
const { toolName, toolParams } = parseCliCommand(params.args);
|
|
108
112
|
if (params.cwd)
|
|
109
113
|
toolParams._meta = { cwd: params.cwd };
|
|
110
|
-
const response = await backend.callTool(toolName, toolParams
|
|
111
|
-
});
|
|
114
|
+
const response = await backend.callTool(toolName, toolParams);
|
|
112
115
|
await connection.send({ id, result: formatResult(response) });
|
|
113
116
|
} else {
|
|
114
117
|
throw new Error(`Unknown method: ${method}`);
|
|
@@ -119,11 +122,6 @@ async function startMcpDaemonServer(socketPath, serverBackendFactory, daemonVers
|
|
|
119
122
|
}
|
|
120
123
|
};
|
|
121
124
|
});
|
|
122
|
-
backend.onBrowserContextClosed = () => {
|
|
123
|
-
daemonDebug("browser closed, shutting down daemon");
|
|
124
|
-
server.close();
|
|
125
|
-
(0, import_utils.gracefullyProcessExitDoNotHang)(0);
|
|
126
|
-
};
|
|
127
125
|
return new Promise((resolve, reject) => {
|
|
128
126
|
server.on("error", (error) => {
|
|
129
127
|
daemonDebug(`server error: ${error.message}`);
|
|
@@ -146,19 +144,6 @@ function parseCliCommand(args) {
|
|
|
146
144
|
throw new Error("Command is required");
|
|
147
145
|
return (0, import_command.parseCommand)(command, args);
|
|
148
146
|
}
|
|
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
|
-
}
|
|
162
147
|
// Annotate the CommonJS export names for ESM import in node:
|
|
163
148
|
0 && (module.exports = {
|
|
164
149
|
startMcpDaemonServer
|
|
@@ -68,18 +68,24 @@ const categories = [
|
|
|
68
68
|
{ name: "export", title: "Save as" },
|
|
69
69
|
{ name: "tabs", title: "Tabs" },
|
|
70
70
|
{ name: "storage", title: "Storage" },
|
|
71
|
+
{ name: "network", title: "Network" },
|
|
71
72
|
{ name: "devtools", title: "DevTools" },
|
|
73
|
+
{ name: "install", title: "Install" },
|
|
72
74
|
{ name: "config", title: "Configuration" },
|
|
73
|
-
{ name: "
|
|
75
|
+
{ name: "browsers", title: "Browser sessions" }
|
|
74
76
|
];
|
|
75
77
|
function generateHelp() {
|
|
76
78
|
const lines = [];
|
|
77
79
|
lines.push("Usage: playwright-cli <command> [args] [options]");
|
|
80
|
+
lines.push("Usage: playwright-cli -s=<session> <command> [args] [options]");
|
|
78
81
|
const commandsByCategory = /* @__PURE__ */ new Map();
|
|
79
82
|
for (const c of categories)
|
|
80
83
|
commandsByCategory.set(c.name, []);
|
|
81
|
-
for (const command of Object.values(import_commands.commands))
|
|
84
|
+
for (const command of Object.values(import_commands.commands)) {
|
|
85
|
+
if (command.hidden)
|
|
86
|
+
continue;
|
|
82
87
|
commandsByCategory.get(command.category).push(command);
|
|
88
|
+
}
|
|
83
89
|
for (const c of categories) {
|
|
84
90
|
const cc = commandsByCategory.get(c.name);
|
|
85
91
|
if (!cc.length)
|
|
@@ -90,11 +96,7 @@ ${c.title}:`);
|
|
|
90
96
|
lines.push(generateHelpEntry(command));
|
|
91
97
|
}
|
|
92
98
|
lines.push("\nGlobal options:");
|
|
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"));
|
|
95
|
-
lines.push(formatWithGap(" --headed", "create a headed session"));
|
|
96
99
|
lines.push(formatWithGap(" --help [command]", "print help"));
|
|
97
|
-
lines.push(formatWithGap(" --session", "run command in the scope of a specific session"));
|
|
98
100
|
lines.push(formatWithGap(" --version", "print version"));
|
|
99
101
|
return lines.join("\n");
|
|
100
102
|
}
|