@cotestdev/mcp_playwright 0.0.51 → 0.0.53

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.
Files changed (71) hide show
  1. package/lib/mcp/browser/browserContextFactory.js +11 -6
  2. package/lib/mcp/browser/browserServerBackend.js +2 -4
  3. package/lib/mcp/browser/config.js +71 -47
  4. package/lib/mcp/browser/context.js +65 -4
  5. package/lib/mcp/browser/logFile.js +96 -0
  6. package/lib/mcp/browser/response.js +107 -104
  7. package/lib/mcp/browser/sessionLog.js +1 -1
  8. package/lib/mcp/browser/tab.js +73 -18
  9. package/lib/mcp/browser/tools/config.js +41 -0
  10. package/lib/mcp/browser/tools/console.js +6 -2
  11. package/lib/mcp/browser/tools/cookies.js +152 -0
  12. package/lib/mcp/browser/tools/install.js +1 -0
  13. package/lib/mcp/browser/tools/network.js +25 -11
  14. package/lib/mcp/browser/tools/pdf.js +3 -4
  15. package/lib/mcp/browser/tools/route.js +140 -0
  16. package/lib/mcp/browser/tools/runCode.js +0 -2
  17. package/lib/mcp/browser/tools/screenshot.js +6 -7
  18. package/lib/mcp/browser/tools/storage.js +3 -4
  19. package/lib/mcp/browser/tools/tracing.js +10 -9
  20. package/lib/mcp/browser/tools/utils.js +0 -6
  21. package/lib/mcp/browser/tools/video.js +31 -13
  22. package/lib/mcp/browser/tools/webstorage.js +223 -0
  23. package/lib/mcp/browser/tools.js +11 -3
  24. package/lib/mcp/extension/cdpRelay.js +7 -7
  25. package/lib/mcp/extension/extensionContextFactory.js +4 -2
  26. package/lib/mcp/program.js +20 -12
  27. package/lib/mcp/terminal/cli.js +23 -2
  28. package/lib/mcp/terminal/command.js +34 -30
  29. package/lib/mcp/terminal/commands.js +329 -46
  30. package/lib/mcp/terminal/daemon.js +25 -39
  31. package/lib/mcp/terminal/helpGenerator.js +27 -7
  32. package/lib/mcp/terminal/program.js +495 -200
  33. package/lib/mcp/terminal/socketConnection.js +17 -2
  34. package/lib/mcpBundleImpl/index.js +27 -27
  35. package/package.json +2 -2
  36. package/lib/common/config.js +0 -281
  37. package/lib/common/configLoader.js +0 -344
  38. package/lib/common/esmLoaderHost.js +0 -104
  39. package/lib/common/expectBundle.js +0 -43
  40. package/lib/common/expectBundleImpl.js +0 -407
  41. package/lib/common/fixtures.js +0 -302
  42. package/lib/common/globals.js +0 -58
  43. package/lib/common/ipc.js +0 -60
  44. package/lib/common/poolBuilder.js +0 -85
  45. package/lib/common/process.js +0 -132
  46. package/lib/common/suiteUtils.js +0 -140
  47. package/lib/common/test.js +0 -322
  48. package/lib/common/testLoader.js +0 -101
  49. package/lib/common/testType.js +0 -298
  50. package/lib/common/validators.js +0 -68
  51. package/lib/mcp/browser/actions.d.js +0 -16
  52. package/lib/mcp/browser/codegen.js +0 -66
  53. package/lib/mcp/browser/processUtils.js +0 -102
  54. package/lib/mcp/browser/tools/script.js +0 -60
  55. package/lib/mcp/sdk/bundle.js +0 -75
  56. package/lib/mcp/sdk/mdb.js +0 -208
  57. package/lib/mcp/sdk/proxyBackend.js +0 -128
  58. package/lib/mcp/vscode/host.js +0 -187
  59. package/lib/mcp/vscode/main.js +0 -77
  60. package/lib/mcpBundleImpl.js +0 -41
  61. package/lib/third_party/pirates.js +0 -62
  62. package/lib/third_party/tsconfig-loader.js +0 -103
  63. package/lib/transform/babelBundle.js +0 -43
  64. package/lib/transform/babelBundleImpl.js +0 -461
  65. package/lib/transform/babelHighlightUtils.js +0 -63
  66. package/lib/transform/compilationCache.js +0 -272
  67. package/lib/transform/esmLoader.js +0 -103
  68. package/lib/transform/portTransport.js +0 -67
  69. package/lib/transform/transform.js +0 -296
  70. package/lib/utilsBundleImpl/index.js +0 -218
  71. package/lib/utilsBundleImpl.js +0 -103
@@ -23,24 +23,53 @@ __export(commands_exports, {
23
23
  module.exports = __toCommonJS(commands_exports);
24
24
  var import_mcpBundle = require("../../mcpBundle");
25
25
  var import_command = require("./command");
26
+ const numberArg = import_mcpBundle.z.preprocess((val, ctx) => {
27
+ const number = Number(val);
28
+ if (Number.isNaN(number)) {
29
+ ctx.issues.push({
30
+ code: "custom",
31
+ message: `expected number, received '${val}'`,
32
+ input: val
33
+ });
34
+ }
35
+ return number;
36
+ }, import_mcpBundle.z.number());
26
37
  const open = (0, import_command.declareCommand)({
27
38
  name: "open",
28
- description: "Open URL",
39
+ description: "Open the browser",
29
40
  category: "core",
30
41
  args: import_mcpBundle.z.object({
31
- url: import_mcpBundle.z.string().describe("The URL to navigate to")
42
+ url: import_mcpBundle.z.string().optional().describe("The URL to navigate to")
43
+ }),
44
+ options: import_mcpBundle.z.object({
45
+ browser: import_mcpBundle.z.string().optional().describe("Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge."),
46
+ config: import_mcpBundle.z.string().optional().describe("Path to the configuration file, defaults to .playwright/cli.config.json"),
47
+ extension: import_mcpBundle.z.boolean().optional().describe("Connect to browser extension"),
48
+ headed: import_mcpBundle.z.boolean().optional().describe("Run browser in headed mode"),
49
+ persistent: import_mcpBundle.z.boolean().optional().describe("Use persistent browser profile"),
50
+ profile: import_mcpBundle.z.string().optional().describe("Use persistent browser profile, store profile in specified directory.")
32
51
  }),
33
52
  toolName: "browser_navigate",
34
- toolParams: ({ url }) => ({ url })
53
+ toolParams: ({ url }) => ({ url: url || "about:blank" })
35
54
  });
36
55
  const close = (0, import_command.declareCommand)({
37
56
  name: "close",
38
- description: "Close the page",
57
+ description: "Close the browser",
39
58
  category: "core",
40
59
  args: import_mcpBundle.z.object({}),
41
60
  toolName: "",
42
61
  toolParams: () => ({})
43
62
  });
63
+ const goto = (0, import_command.declareCommand)({
64
+ name: "goto",
65
+ description: "Navigate to a URL",
66
+ category: "core",
67
+ args: import_mcpBundle.z.object({
68
+ url: import_mcpBundle.z.string().describe("The URL to navigate to")
69
+ }),
70
+ toolName: "browser_navigate",
71
+ toolParams: ({ url }) => ({ url })
72
+ });
44
73
  const goBack = (0, import_command.declareCommand)({
45
74
  name: "go-back",
46
75
  description: "Go back to the previous page",
@@ -113,8 +142,8 @@ const mouseMove = (0, import_command.declareCommand)({
113
142
  description: "Move mouse to a given position",
114
143
  category: "mouse",
115
144
  args: import_mcpBundle.z.object({
116
- x: import_mcpBundle.z.number().describe("X coordinate"),
117
- y: import_mcpBundle.z.number().describe("Y coordinate")
145
+ x: numberArg.describe("X coordinate"),
146
+ y: numberArg.describe("Y coordinate")
118
147
  }),
119
148
  toolName: "browser_mouse_move_xy",
120
149
  toolParams: ({ x, y }) => ({ x, y })
@@ -144,8 +173,8 @@ const mouseWheel = (0, import_command.declareCommand)({
144
173
  description: "Scroll mouse wheel",
145
174
  category: "mouse",
146
175
  args: import_mcpBundle.z.object({
147
- dx: import_mcpBundle.z.number().describe("Y delta"),
148
- dy: import_mcpBundle.z.number().describe("X delta")
176
+ dx: numberArg.describe("Y delta"),
177
+ dy: numberArg.describe("X delta")
149
178
  }),
150
179
  toolName: "browser_mouse_wheel",
151
180
  toolParams: ({ dx: deltaY, dy: deltaX }) => ({ deltaY, deltaX })
@@ -186,9 +215,6 @@ const drag = (0, import_command.declareCommand)({
186
215
  startRef: import_mcpBundle.z.string().describe("Exact source element reference from the page snapshot"),
187
216
  endRef: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
188
217
  }),
189
- options: import_mcpBundle.z.object({
190
- headed: import_mcpBundle.z.boolean().default(false).describe("Run browser in headed mode")
191
- }),
192
218
  toolName: "browser_drag",
193
219
  toolParams: ({ startRef, endRef }) => ({ startRef, endRef })
194
220
  });
@@ -302,8 +328,8 @@ const resize = (0, import_command.declareCommand)({
302
328
  description: "Resize the browser window",
303
329
  category: "core",
304
330
  args: import_mcpBundle.z.object({
305
- w: import_mcpBundle.z.number().describe("Width of the browser window"),
306
- h: import_mcpBundle.z.number().describe("Height of the browser window")
331
+ w: numberArg.describe("Width of the browser window"),
332
+ h: numberArg.describe("Height of the browser window")
307
333
  }),
308
334
  toolName: "browser_resize",
309
335
  toolParams: ({ w: width, h: height }) => ({ width, height })
@@ -341,7 +367,7 @@ const tabClose = (0, import_command.declareCommand)({
341
367
  description: "Close a browser tab",
342
368
  category: "tabs",
343
369
  args: import_mcpBundle.z.object({
344
- index: import_mcpBundle.z.number().optional().describe("Tab index. If omitted, current tab is closed.")
370
+ index: numberArg.optional().describe("Tab index. If omitted, current tab is closed.")
345
371
  }),
346
372
  toolName: "browser_tabs",
347
373
  toolParams: ({ index }) => ({ action: "close", index })
@@ -351,11 +377,226 @@ const tabSelect = (0, import_command.declareCommand)({
351
377
  description: "Select a browser tab",
352
378
  category: "tabs",
353
379
  args: import_mcpBundle.z.object({
354
- index: import_mcpBundle.z.number().describe("Tab index")
380
+ index: numberArg.describe("Tab index")
355
381
  }),
356
382
  toolName: "browser_tabs",
357
383
  toolParams: ({ index }) => ({ action: "select", index })
358
384
  });
385
+ const stateLoad = (0, import_command.declareCommand)({
386
+ name: "state-load",
387
+ description: "Loads browser storage (authentication) state from a file",
388
+ category: "storage",
389
+ args: import_mcpBundle.z.object({
390
+ filename: import_mcpBundle.z.string().describe("File name to load the storage state from.")
391
+ }),
392
+ toolName: "browser_set_storage_state",
393
+ toolParams: ({ filename }) => ({ filename })
394
+ });
395
+ const stateSave = (0, import_command.declareCommand)({
396
+ name: "state-save",
397
+ description: "Saves the current storage (authentication) state to a file",
398
+ category: "storage",
399
+ args: import_mcpBundle.z.object({
400
+ filename: import_mcpBundle.z.string().optional().describe("File name to save the storage state to.")
401
+ }),
402
+ toolName: "browser_storage_state",
403
+ toolParams: ({ filename }) => ({ filename })
404
+ });
405
+ const cookieList = (0, import_command.declareCommand)({
406
+ name: "cookie-list",
407
+ description: "List all cookies (optionally filtered by domain/path)",
408
+ category: "storage",
409
+ args: import_mcpBundle.z.object({}),
410
+ options: import_mcpBundle.z.object({
411
+ domain: import_mcpBundle.z.string().optional().describe("Filter cookies by domain"),
412
+ path: import_mcpBundle.z.string().optional().describe("Filter cookies by path")
413
+ }),
414
+ toolName: "browser_cookie_list",
415
+ toolParams: ({ domain, path }) => ({ domain, path })
416
+ });
417
+ const cookieGet = (0, import_command.declareCommand)({
418
+ name: "cookie-get",
419
+ description: "Get a specific cookie by name",
420
+ category: "storage",
421
+ args: import_mcpBundle.z.object({
422
+ name: import_mcpBundle.z.string().describe("Cookie name")
423
+ }),
424
+ toolName: "browser_cookie_get",
425
+ toolParams: ({ name }) => ({ name })
426
+ });
427
+ const cookieSet = (0, import_command.declareCommand)({
428
+ name: "cookie-set",
429
+ description: "Set a cookie with optional flags",
430
+ category: "storage",
431
+ args: import_mcpBundle.z.object({
432
+ name: import_mcpBundle.z.string().describe("Cookie name"),
433
+ value: import_mcpBundle.z.string().describe("Cookie value")
434
+ }),
435
+ options: import_mcpBundle.z.object({
436
+ domain: import_mcpBundle.z.string().optional().describe("Cookie domain"),
437
+ path: import_mcpBundle.z.string().optional().describe("Cookie path"),
438
+ expires: numberArg.optional().describe("Cookie expiration as Unix timestamp"),
439
+ httpOnly: import_mcpBundle.z.boolean().optional().describe("Whether the cookie is HTTP only"),
440
+ secure: import_mcpBundle.z.boolean().optional().describe("Whether the cookie is secure"),
441
+ sameSite: import_mcpBundle.z.enum(["Strict", "Lax", "None"]).optional().describe("Cookie SameSite attribute")
442
+ }),
443
+ toolName: "browser_cookie_set",
444
+ toolParams: ({ name, value, domain, path, expires, httpOnly, secure, sameSite }) => ({ name, value, domain, path, expires, httpOnly, secure, sameSite })
445
+ });
446
+ const cookieDelete = (0, import_command.declareCommand)({
447
+ name: "cookie-delete",
448
+ description: "Delete a specific cookie",
449
+ category: "storage",
450
+ args: import_mcpBundle.z.object({
451
+ name: import_mcpBundle.z.string().describe("Cookie name")
452
+ }),
453
+ toolName: "browser_cookie_delete",
454
+ toolParams: ({ name }) => ({ name })
455
+ });
456
+ const cookieClear = (0, import_command.declareCommand)({
457
+ name: "cookie-clear",
458
+ description: "Clear all cookies",
459
+ category: "storage",
460
+ args: import_mcpBundle.z.object({}),
461
+ toolName: "browser_cookie_clear",
462
+ toolParams: () => ({})
463
+ });
464
+ const localStorageList = (0, import_command.declareCommand)({
465
+ name: "localstorage-list",
466
+ description: "List all localStorage key-value pairs",
467
+ category: "storage",
468
+ args: import_mcpBundle.z.object({}),
469
+ toolName: "browser_localstorage_list",
470
+ toolParams: () => ({})
471
+ });
472
+ const localStorageGet = (0, import_command.declareCommand)({
473
+ name: "localstorage-get",
474
+ description: "Get a localStorage item by key",
475
+ category: "storage",
476
+ args: import_mcpBundle.z.object({
477
+ key: import_mcpBundle.z.string().describe("Key to get")
478
+ }),
479
+ toolName: "browser_localstorage_get",
480
+ toolParams: ({ key }) => ({ key })
481
+ });
482
+ const localStorageSet = (0, import_command.declareCommand)({
483
+ name: "localstorage-set",
484
+ description: "Set a localStorage item",
485
+ category: "storage",
486
+ args: import_mcpBundle.z.object({
487
+ key: import_mcpBundle.z.string().describe("Key to set"),
488
+ value: import_mcpBundle.z.string().describe("Value to set")
489
+ }),
490
+ toolName: "browser_localstorage_set",
491
+ toolParams: ({ key, value }) => ({ key, value })
492
+ });
493
+ const localStorageDelete = (0, import_command.declareCommand)({
494
+ name: "localstorage-delete",
495
+ description: "Delete a localStorage item",
496
+ category: "storage",
497
+ args: import_mcpBundle.z.object({
498
+ key: import_mcpBundle.z.string().describe("Key to delete")
499
+ }),
500
+ toolName: "browser_localstorage_delete",
501
+ toolParams: ({ key }) => ({ key })
502
+ });
503
+ const localStorageClear = (0, import_command.declareCommand)({
504
+ name: "localstorage-clear",
505
+ description: "Clear all localStorage",
506
+ category: "storage",
507
+ args: import_mcpBundle.z.object({}),
508
+ toolName: "browser_localstorage_clear",
509
+ toolParams: () => ({})
510
+ });
511
+ const sessionStorageList = (0, import_command.declareCommand)({
512
+ name: "sessionstorage-list",
513
+ description: "List all sessionStorage key-value pairs",
514
+ category: "storage",
515
+ args: import_mcpBundle.z.object({}),
516
+ toolName: "browser_sessionstorage_list",
517
+ toolParams: () => ({})
518
+ });
519
+ const sessionStorageGet = (0, import_command.declareCommand)({
520
+ name: "sessionstorage-get",
521
+ description: "Get a sessionStorage item by key",
522
+ category: "storage",
523
+ args: import_mcpBundle.z.object({
524
+ key: import_mcpBundle.z.string().describe("Key to get")
525
+ }),
526
+ toolName: "browser_sessionstorage_get",
527
+ toolParams: ({ key }) => ({ key })
528
+ });
529
+ const sessionStorageSet = (0, import_command.declareCommand)({
530
+ name: "sessionstorage-set",
531
+ description: "Set a sessionStorage item",
532
+ category: "storage",
533
+ args: import_mcpBundle.z.object({
534
+ key: import_mcpBundle.z.string().describe("Key to set"),
535
+ value: import_mcpBundle.z.string().describe("Value to set")
536
+ }),
537
+ toolName: "browser_sessionstorage_set",
538
+ toolParams: ({ key, value }) => ({ key, value })
539
+ });
540
+ const sessionStorageDelete = (0, import_command.declareCommand)({
541
+ name: "sessionstorage-delete",
542
+ description: "Delete a sessionStorage item",
543
+ category: "storage",
544
+ args: import_mcpBundle.z.object({
545
+ key: import_mcpBundle.z.string().describe("Key to delete")
546
+ }),
547
+ toolName: "browser_sessionstorage_delete",
548
+ toolParams: ({ key }) => ({ key })
549
+ });
550
+ const sessionStorageClear = (0, import_command.declareCommand)({
551
+ name: "sessionstorage-clear",
552
+ description: "Clear all sessionStorage",
553
+ category: "storage",
554
+ args: import_mcpBundle.z.object({}),
555
+ toolName: "browser_sessionstorage_clear",
556
+ toolParams: () => ({})
557
+ });
558
+ const routeMock = (0, import_command.declareCommand)({
559
+ name: "route",
560
+ description: "Mock network requests matching a URL pattern",
561
+ category: "network",
562
+ args: import_mcpBundle.z.object({
563
+ pattern: import_mcpBundle.z.string().describe('URL pattern to match (e.g., "**/api/users")')
564
+ }),
565
+ options: import_mcpBundle.z.object({
566
+ status: numberArg.optional().describe("HTTP status code (default: 200)"),
567
+ body: import_mcpBundle.z.string().optional().describe("Response body (text or JSON string)"),
568
+ ["content-type"]: import_mcpBundle.z.string().optional().describe("Content-Type header"),
569
+ 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)'),
570
+ ["remove-header"]: import_mcpBundle.z.string().optional().describe("Comma-separated header names to remove")
571
+ }),
572
+ toolName: "browser_route",
573
+ toolParams: ({ pattern, status, body, ["content-type"]: contentType, header: headers, ["remove-header"]: removeHeaders }) => ({
574
+ pattern,
575
+ status,
576
+ body,
577
+ contentType,
578
+ headers,
579
+ removeHeaders
580
+ })
581
+ });
582
+ const routeList = (0, import_command.declareCommand)({
583
+ name: "route-list",
584
+ description: "List all active network routes",
585
+ category: "network",
586
+ args: import_mcpBundle.z.object({}),
587
+ toolName: "browser_route_list",
588
+ toolParams: () => ({})
589
+ });
590
+ const unroute = (0, import_command.declareCommand)({
591
+ name: "unroute",
592
+ description: "Remove routes matching a pattern (or all routes)",
593
+ category: "network",
594
+ args: import_mcpBundle.z.object({
595
+ pattern: import_mcpBundle.z.string().optional().describe("URL pattern to unroute (omit to remove all)")
596
+ }),
597
+ toolName: "browser_unroute",
598
+ toolParams: ({ pattern }) => ({ pattern })
599
+ });
359
600
  const screenshot = (0, import_command.declareCommand)({
360
601
  name: "screenshot",
361
602
  description: "screenshot of the current page or element",
@@ -441,54 +682,71 @@ const videoStop = (0, import_command.declareCommand)({
441
682
  toolParams: ({ filename }) => ({ filename })
442
683
  });
443
684
  const sessionList = (0, import_command.declareCommand)({
444
- name: "session-list",
445
- description: "List all sessions",
446
- category: "session",
685
+ name: "list",
686
+ description: "List browser sessions",
687
+ category: "browsers",
447
688
  args: import_mcpBundle.z.object({}),
689
+ options: import_mcpBundle.z.object({
690
+ all: import_mcpBundle.z.boolean().optional().describe("List all browser sessions across all workspaces")
691
+ }),
448
692
  toolName: "",
449
693
  toolParams: () => ({})
450
694
  });
451
- const sessionStop = (0, import_command.declareCommand)({
452
- name: "session-stop",
453
- description: "Stop session",
454
- category: "session",
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
- }),
695
+ const sessionCloseAll = (0, import_command.declareCommand)({
696
+ name: "close-all",
697
+ description: "Close all browser sessions",
698
+ category: "browsers",
458
699
  toolName: "",
459
700
  toolParams: () => ({})
460
701
  });
461
- const sessionStopAll = (0, import_command.declareCommand)({
462
- name: "session-stop-all",
463
- description: "Stop all sessions",
464
- category: "session",
702
+ const killAll = (0, import_command.declareCommand)({
703
+ name: "kill-all",
704
+ description: "Forcefully kill all browser sessions (for stale/zombie processes)",
705
+ category: "browsers",
465
706
  toolName: "",
466
707
  toolParams: () => ({})
467
708
  });
468
- const sessionDelete = (0, import_command.declareCommand)({
469
- name: "session-delete",
709
+ const deleteData = (0, import_command.declareCommand)({
710
+ name: "delete-data",
470
711
  description: "Delete session data",
471
- category: "session",
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
- }),
712
+ category: "core",
475
713
  toolName: "",
476
- toolParams: ({ name }) => ({ name })
714
+ toolParams: () => ({})
477
715
  });
478
- const config = (0, import_command.declareCommand)({
479
- name: "config",
480
- description: "Restart session with new config, defaults to `playwright-cli.json`",
716
+ const configPrint = (0, import_command.declareCommand)({
717
+ name: "config-print",
718
+ description: "Print the final resolved config after merging CLI options, environment variables and config file.",
481
719
  category: "config",
482
- args: import_mcpBundle.z.object({
483
- config: import_mcpBundle.z.string().optional().describe("Path to the configuration file")
720
+ hidden: true,
721
+ toolName: "browser_get_config",
722
+ toolParams: () => ({})
723
+ });
724
+ const install = (0, import_command.declareCommand)({
725
+ name: "install",
726
+ description: "Initialize workspace",
727
+ category: "install",
728
+ args: import_mcpBundle.z.object({}),
729
+ options: import_mcpBundle.z.object({
730
+ skills: import_mcpBundle.z.boolean().optional().describe("Install skills for Claude / GitHub Copilot")
484
731
  }),
485
732
  toolName: "",
486
733
  toolParams: () => ({})
487
734
  });
735
+ const installBrowser = (0, import_command.declareCommand)({
736
+ name: "install-browser",
737
+ description: "Install browser",
738
+ category: "install",
739
+ options: import_mcpBundle.z.object({
740
+ browser: import_mcpBundle.z.string().optional().describe("Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge")
741
+ }),
742
+ toolName: "browser_install",
743
+ toolParams: () => ({})
744
+ });
488
745
  const commandsArray = [
489
746
  // core category
490
747
  open,
491
748
  close,
749
+ goto,
492
750
  type,
493
751
  click,
494
752
  doubleClick,
@@ -506,6 +764,7 @@ const commandsArray = [
506
764
  dialogDismiss,
507
765
  resize,
508
766
  runCode,
767
+ deleteData,
509
768
  // navigation category
510
769
  goBack,
511
770
  goForward,
@@ -527,8 +786,33 @@ const commandsArray = [
527
786
  tabNew,
528
787
  tabClose,
529
788
  tabSelect,
530
- // config
531
- config,
789
+ // storage category
790
+ stateLoad,
791
+ stateSave,
792
+ cookieList,
793
+ cookieGet,
794
+ cookieSet,
795
+ cookieDelete,
796
+ cookieClear,
797
+ localStorageList,
798
+ localStorageGet,
799
+ localStorageSet,
800
+ localStorageDelete,
801
+ localStorageClear,
802
+ sessionStorageList,
803
+ sessionStorageGet,
804
+ sessionStorageSet,
805
+ sessionStorageDelete,
806
+ sessionStorageClear,
807
+ // network category
808
+ routeMock,
809
+ routeList,
810
+ unroute,
811
+ // config category
812
+ configPrint,
813
+ // install category
814
+ install,
815
+ installBrowser,
532
816
  // devtools category
533
817
  networkRequests,
534
818
  tracingStart,
@@ -537,9 +821,8 @@ const commandsArray = [
537
821
  videoStop,
538
822
  // session category
539
823
  sessionList,
540
- sessionStop,
541
- sessionStopAll,
542
- sessionDelete
824
+ sessionCloseAll,
825
+ killAll
543
826
  ];
544
827
  const commands = Object.fromEntries(commandsArray.map((cmd) => [cmd.name, cmd]));
545
828
  // 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(socketPath, serverBackendFactory, daemonVersion) {
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
- await backend.initialize?.({
68
+ const clientInfo = {
67
69
  name: "playwright-cli",
68
- version: "1.0.0",
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, daemonVersion);
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,23 +111,18 @@ 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}`);
115
118
  }
116
119
  } catch (e) {
117
120
  daemonDebug("command failed", e);
118
- await connection.send({ id, error: e.message });
121
+ const error = process.env.PWDEBUGIMPL ? e.stack || e.message : e.message;
122
+ await connection.send({ id, error });
119
123
  }
120
124
  };
121
125
  });
122
- backend.onBrowserContextClosed = () => {
123
- daemonDebug("browser closed, shutting down daemon");
124
- server.close();
125
- (0, import_utils.gracefullyProcessExitDoNotHang)(0);
126
- };
127
126
  return new Promise((resolve, reject) => {
128
127
  server.on("error", (error) => {
129
128
  daemonDebug(`server error: ${error.message}`);
@@ -146,19 +145,6 @@ function parseCliCommand(args) {
146
145
  throw new Error("Command is required");
147
146
  return (0, import_command.parseCommand)(command, args);
148
147
  }
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
148
  // Annotate the CommonJS export names for ESM import in node:
163
149
  0 && (module.exports = {
164
150
  startMcpDaemonServer
@@ -23,6 +23,7 @@ __export(helpGenerator_exports, {
23
23
  generateReadme: () => generateReadme
24
24
  });
25
25
  module.exports = __toCommonJS(helpGenerator_exports);
26
+ var import_mcpBundle = require("../../mcpBundle");
26
27
  var import_commands = require("./commands");
27
28
  function commandArgs(command) {
28
29
  const args = [];
@@ -68,18 +69,24 @@ const categories = [
68
69
  { name: "export", title: "Save as" },
69
70
  { name: "tabs", title: "Tabs" },
70
71
  { name: "storage", title: "Storage" },
72
+ { name: "network", title: "Network" },
71
73
  { name: "devtools", title: "DevTools" },
74
+ { name: "install", title: "Install" },
72
75
  { name: "config", title: "Configuration" },
73
- { name: "session", title: "Sessions" }
76
+ { name: "browsers", title: "Browser sessions" }
74
77
  ];
75
78
  function generateHelp() {
76
79
  const lines = [];
77
80
  lines.push("Usage: playwright-cli <command> [args] [options]");
81
+ lines.push("Usage: playwright-cli -s=<session> <command> [args] [options]");
78
82
  const commandsByCategory = /* @__PURE__ */ new Map();
79
83
  for (const c of categories)
80
84
  commandsByCategory.set(c.name, []);
81
- for (const command of Object.values(import_commands.commands))
85
+ for (const command of Object.values(import_commands.commands)) {
86
+ if (command.hidden)
87
+ continue;
82
88
  commandsByCategory.get(command.category).push(command);
89
+ }
83
90
  for (const c of categories) {
84
91
  const cc = commandsByCategory.get(c.name);
85
92
  if (!cc.length)
@@ -90,11 +97,7 @@ ${c.title}:`);
90
97
  lines.push(generateHelpEntry(command));
91
98
  }
92
99
  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
100
  lines.push(formatWithGap(" --help [command]", "print help"));
97
- lines.push(formatWithGap(" --session", "run command in the scope of a specific session"));
98
101
  lines.push(formatWithGap(" --version", "print version"));
99
102
  return lines.join("\n");
100
103
  }
@@ -132,12 +135,29 @@ function generateReadmeEntry(command) {
132
135
  const suffix = "# " + command.description.toLowerCase();
133
136
  return formatWithGap(prefix, suffix, 40);
134
137
  }
138
+ function unwrapZodType(schema) {
139
+ if ("unwrap" in schema && typeof schema.unwrap === "function")
140
+ return unwrapZodType(schema.unwrap());
141
+ return schema;
142
+ }
135
143
  function generateHelpJSON() {
144
+ const booleanOptions = /* @__PURE__ */ new Set();
145
+ for (const command of Object.values(import_commands.commands)) {
146
+ if (!command.options)
147
+ continue;
148
+ const optionsShape = command.options.shape;
149
+ for (const [name, schema] of Object.entries(optionsShape)) {
150
+ const innerSchema = unwrapZodType(schema);
151
+ if (innerSchema instanceof import_mcpBundle.z.ZodBoolean)
152
+ booleanOptions.add(name);
153
+ }
154
+ }
136
155
  const help = {
137
156
  global: generateHelp(),
138
157
  commands: Object.fromEntries(
139
158
  Object.entries(import_commands.commands).map(([name, command]) => [name, generateCommandHelp(command)])
140
- )
159
+ ),
160
+ booleanOptions: [...booleanOptions]
141
161
  };
142
162
  return help;
143
163
  }