@wordbricks/playwright-mcp 0.1.3

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 (95) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +624 -0
  3. package/cli-wrapper.js +47 -0
  4. package/cli.js +18 -0
  5. package/config.d.ts +119 -0
  6. package/index.d.ts +23 -0
  7. package/index.js +19 -0
  8. package/lib/browserContextFactory.js +289 -0
  9. package/lib/browserServerBackend.js +82 -0
  10. package/lib/config.js +246 -0
  11. package/lib/context.js +236 -0
  12. package/lib/extension/cdpRelay.js +346 -0
  13. package/lib/extension/extensionContextFactory.js +56 -0
  14. package/lib/frameworkPatterns.js +35 -0
  15. package/lib/hooks/core.js +144 -0
  16. package/lib/hooks/eventConsumer.js +39 -0
  17. package/lib/hooks/events.js +42 -0
  18. package/lib/hooks/formatToolCallEvent.js +16 -0
  19. package/lib/hooks/frameworkStateHook.js +182 -0
  20. package/lib/hooks/grouping.js +72 -0
  21. package/lib/hooks/jsonLdDetectionHook.js +175 -0
  22. package/lib/hooks/networkFilters.js +74 -0
  23. package/lib/hooks/networkSetup.js +56 -0
  24. package/lib/hooks/networkTrackingHook.js +55 -0
  25. package/lib/hooks/pageHeightHook.js +75 -0
  26. package/lib/hooks/registry.js +39 -0
  27. package/lib/hooks/requireTabHook.js +26 -0
  28. package/lib/hooks/schema.js +75 -0
  29. package/lib/hooks/waitHook.js +33 -0
  30. package/lib/index.js +39 -0
  31. package/lib/loop/loop.js +69 -0
  32. package/lib/loop/loopClaude.js +152 -0
  33. package/lib/loop/loopOpenAI.js +141 -0
  34. package/lib/loop/main.js +60 -0
  35. package/lib/loopTools/context.js +66 -0
  36. package/lib/loopTools/main.js +51 -0
  37. package/lib/loopTools/perform.js +32 -0
  38. package/lib/loopTools/snapshot.js +29 -0
  39. package/lib/loopTools/tool.js +18 -0
  40. package/lib/mcp/inProcessTransport.js +72 -0
  41. package/lib/mcp/proxyBackend.js +115 -0
  42. package/lib/mcp/server.js +86 -0
  43. package/lib/mcp/tool.js +29 -0
  44. package/lib/mcp/transport.js +181 -0
  45. package/lib/playwrightTransformer.js +497 -0
  46. package/lib/program.js +111 -0
  47. package/lib/response.js +186 -0
  48. package/lib/sessionLog.js +121 -0
  49. package/lib/tab.js +249 -0
  50. package/lib/tools/common.js +55 -0
  51. package/lib/tools/console.js +33 -0
  52. package/lib/tools/dialogs.js +47 -0
  53. package/lib/tools/evaluate.js +53 -0
  54. package/lib/tools/extractFrameworkState.js +214 -0
  55. package/lib/tools/files.js +44 -0
  56. package/lib/tools/getSnapshot.js +37 -0
  57. package/lib/tools/getVisibleHtml.js +52 -0
  58. package/lib/tools/install.js +53 -0
  59. package/lib/tools/keyboard.js +78 -0
  60. package/lib/tools/mouse.js +99 -0
  61. package/lib/tools/navigate.js +70 -0
  62. package/lib/tools/network.js +123 -0
  63. package/lib/tools/networkDetail.js +231 -0
  64. package/lib/tools/networkSearch/bodySearch.js +141 -0
  65. package/lib/tools/networkSearch/grouping.js +28 -0
  66. package/lib/tools/networkSearch/helpers.js +32 -0
  67. package/lib/tools/networkSearch/searchHtml.js +65 -0
  68. package/lib/tools/networkSearch/types.js +1 -0
  69. package/lib/tools/networkSearch/urlSearch.js +82 -0
  70. package/lib/tools/networkSearch.js +168 -0
  71. package/lib/tools/pdf.js +40 -0
  72. package/lib/tools/repl.js +402 -0
  73. package/lib/tools/screenshot.js +79 -0
  74. package/lib/tools/scroll.js +126 -0
  75. package/lib/tools/snapshot.js +139 -0
  76. package/lib/tools/tabs.js +87 -0
  77. package/lib/tools/tool.js +33 -0
  78. package/lib/tools/utils.js +74 -0
  79. package/lib/tools/wait.js +55 -0
  80. package/lib/tools.js +67 -0
  81. package/lib/utils/codegen.js +49 -0
  82. package/lib/utils/extensionPath.js +6 -0
  83. package/lib/utils/fileUtils.js +36 -0
  84. package/lib/utils/graphql.js +258 -0
  85. package/lib/utils/guid.js +22 -0
  86. package/lib/utils/httpServer.js +39 -0
  87. package/lib/utils/log.js +21 -0
  88. package/lib/utils/manualPromise.js +111 -0
  89. package/lib/utils/networkFormat.js +12 -0
  90. package/lib/utils/package.js +20 -0
  91. package/lib/utils/result.js +2 -0
  92. package/lib/utils/sanitizeHtml.js +98 -0
  93. package/lib/utils/truncate.js +103 -0
  94. package/lib/utils/withTimeout.js +7 -0
  95. package/package.json +100 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Utilities for truncating values for display
3
+ */
4
+ /**
5
+ * Recursively truncate values for display, limiting strings, arrays, and object keys at each depth level
6
+ */
7
+ export const truncate = (value, options) => {
8
+ const { maxStringLength = 100, maxItems = 10 } = options ?? {};
9
+ if (typeof value === 'string') {
10
+ if (value.length > maxStringLength)
11
+ return value.substring(0, Math.max(0, maxStringLength - 3)) + '...';
12
+ return value;
13
+ }
14
+ if (Array.isArray(value)) {
15
+ const limited = maxItems !== undefined ? value.slice(0, maxItems) : value;
16
+ return limited.map(v => truncate(v, options));
17
+ }
18
+ if (value && typeof value === 'object') {
19
+ let entries = Object.entries(value);
20
+ if (maxItems !== undefined)
21
+ entries = entries.slice(0, maxItems);
22
+ const out = {};
23
+ for (const [key, val] of entries)
24
+ out[key] = truncate(val, options);
25
+ return out;
26
+ }
27
+ return value;
28
+ };
29
+ export const truncateStringTo = (text, max) => {
30
+ if (max <= 0)
31
+ return { text: '', truncated: text.length > 0 };
32
+ if (text.length <= max)
33
+ return { text, truncated: false };
34
+ const sliceLen = Math.max(0, max - 3);
35
+ return { text: text.slice(0, sliceLen) + '...', truncated: true };
36
+ };
37
+ /**
38
+ * Create a standardized truncation note like:
39
+ * … [truncated: showing 120/500 chars (24%)]
40
+ * Caller may optionally provide a formatter (e.g. bytes -> "8 KB") and/or units label.
41
+ */
42
+ export const formatTruncationLine = (shown, total, options) => {
43
+ const { units, formatter } = options ?? {};
44
+ const pct = total ? Math.round((shown / total) * 100) : 0;
45
+ const shownStr = formatter ? formatter(shown) : String(shown);
46
+ const totalStr = formatter ? formatter(total) : String(total);
47
+ const unitsPart = units ? ` ${units}` : '';
48
+ return `… [truncated: showing ${shownStr}/${totalStr}${unitsPart} (${pct}%)]`;
49
+ };
50
+ export const trimLeafValuesDeep = (value, maxChars) => {
51
+ if (value === null || value === undefined)
52
+ return value;
53
+ if (typeof value === 'string')
54
+ return value.length > maxChars ? value.slice(0, maxChars) + '...' : value;
55
+ if (Array.isArray(value))
56
+ return value.map(v => trimLeafValuesDeep(v, maxChars));
57
+ if (typeof value === 'object') {
58
+ const out = {};
59
+ for (const [k, v] of Object.entries(value))
60
+ out[k] = trimLeafValuesDeep(v, maxChars);
61
+ return out;
62
+ }
63
+ return value;
64
+ };
65
+ export const trimJsonLeafValues = (input, maxChars) => {
66
+ try {
67
+ const parsed = JSON.parse(input);
68
+ const trimmed = trimLeafValuesDeep(parsed, maxChars);
69
+ return JSON.stringify(trimmed);
70
+ }
71
+ catch {
72
+ return input.length > maxChars ? input.slice(0, maxChars) + '...' : input;
73
+ }
74
+ };
75
+ export const toJsonPathNormalized = (path) => {
76
+ let root = null;
77
+ if (path.startsWith('response.body.'))
78
+ root = 'response.body';
79
+ else if (path.startsWith('request.body.'))
80
+ root = 'request.body';
81
+ else
82
+ return null;
83
+ let p = path.slice(root.length + 1);
84
+ if (p.includes(' > ') || p.includes('@'))
85
+ return null;
86
+ p = p.replace(/\.\*/g, '[*]');
87
+ p = p.replace(/\.(\d+)(?=\.|$)/g, '[$1]');
88
+ return { root, jsonPath: `$.${p}` };
89
+ };
90
+ export const toJsonPathOriginal = (path) => {
91
+ let root = null;
92
+ if (path.startsWith('response.body.'))
93
+ root = 'response.body';
94
+ else if (path.startsWith('request.body.'))
95
+ root = 'request.body';
96
+ else
97
+ return null;
98
+ let p = path.slice(root.length + 1);
99
+ if (p.includes(' > ') || p.includes('@'))
100
+ return null;
101
+ p = p.replace(/\.(\d+)(?=\.|$)/g, '[$1]');
102
+ return { root, jsonPath: `$.${p}` };
103
+ };
@@ -0,0 +1,7 @@
1
+ // Helper to safely execute a promise with timeout
2
+ export const withTimeout = async (promise, ms) => {
3
+ return Promise.race([
4
+ promise,
5
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ms)),
6
+ ]);
7
+ };
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "@wordbricks/playwright-mcp",
3
+ "version": "0.1.3",
4
+ "description": "Playwright Tools for MCP",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/wordbricks/playwright-mcp.git"
9
+ },
10
+ "homepage": "https://playwright.dev",
11
+ "engines": {
12
+ "node": ">=18"
13
+ },
14
+ "author": {
15
+ "name": "Microsoft Corporation"
16
+ },
17
+ "license": "Apache-2.0",
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "build:extension": "tsc --project extension",
21
+ "dev": "concurrently --raw prefix none \"tsc --watch\" \"DEBUG=pw:mcp:* node --watch=lib cli.js --port 9224\"",
22
+ "dev:isolated": "concurrently --raw prefix none \"tsc --watch\" \"DEBUG=pw:mcp:* node --watch=lib cli.js --port 9224 --isolated --viewport-size=1280,720\"",
23
+ "dev:isolated:headless": "concurrently --raw prefix none \"tsc --watch\" \"DEBUG=pw:mcp:* node --watch=lib cli.js --port 9224 --isolated --headless --viewport-size=1280,720\"",
24
+ "dev:vision": "concurrently --raw prefix none \"tsc --watch\" \"DEBUG=pw:mcp:* node --watch=lib cli.js --port 9224 --caps=vision\"",
25
+ "start": "node cli.js --port 9224 --viewport-size=1280,720",
26
+ "start:isolated": "node cli.js --port 9224 --viewport-size=1280,720 --isolated",
27
+ "start:vision": "node cli.js --port 9224 --viewport-size=1280,720 --caps=vision",
28
+ "lint": "npm run update-readme && npm run check-deps && eslint . && tsc --noEmit",
29
+ "lint-fix": "eslint . --fix",
30
+ "check-deps": "node utils/check-deps.js",
31
+ "update-readme": "node utils/update-readme.js",
32
+ "watch": "tsc --watch",
33
+ "test": "playwright test",
34
+ "ctest": "playwright test --project=chrome",
35
+ "ftest": "playwright test --project=firefox",
36
+ "wtest": "playwright test --project=webkit",
37
+ "run-server": "node lib/browserServer.js",
38
+ "clean": "rm -rf lib && rm -rf extension/lib",
39
+ "npm-publish": "npm run clean && npm run build && npm run test && npm publish",
40
+ "ext:download": "bun src/scripts/prepare.ts"
41
+ },
42
+ "exports": {
43
+ "./package.json": "./package.json",
44
+ ".": {
45
+ "types": "./index.d.ts",
46
+ "default": "./index.js"
47
+ }
48
+ },
49
+ "dependencies": {
50
+ "@fxts/core": "^1.13.2",
51
+ "@modelcontextprotocol/sdk": "^1.16.0",
52
+ "@wordbricks/fetch-mcp": "1.2.3",
53
+ "cheerio": "1.1.2",
54
+ "commander": "^13.1.0",
55
+ "content-type": "^1.0.5",
56
+ "debug": "^4.4.1",
57
+ "dotenv": "^17.2.0",
58
+ "find-up": "^7.0.0",
59
+ "json5": "^2.2.3",
60
+ "jsonpath-plus": "^10.3.0",
61
+ "lodash": "^4.17.21",
62
+ "mime": "^4.0.7",
63
+ "ms": "^2.1.3",
64
+ "playwright": "1.55.0-alpha-2025-08-12",
65
+ "playwright-core": "1.55.0-alpha-2025-08-12",
66
+ "raw-body": "^3.0.0",
67
+ "typescript-parsec": "0.3.4",
68
+ "ws": "^8.18.1",
69
+ "zod": "^3.24.1",
70
+ "zod-to-json-schema": "^3.24.4"
71
+ },
72
+ "devDependencies": {
73
+ "@anthropic-ai/sdk": "^0.57.0",
74
+ "@eslint/eslintrc": "^3.2.0",
75
+ "@eslint/js": "^9.19.0",
76
+ "@playwright/test": "1.55.0-alpha-2025-08-12",
77
+ "@stylistic/eslint-plugin": "^3.0.1",
78
+ "@tomjs/unzip-crx": "1.1.3",
79
+ "@types/chrome": "^0.0.315",
80
+ "@types/content-type": "^1.1.9",
81
+ "@types/debug": "^4.1.12",
82
+ "@types/node": "^22.13.10",
83
+ "@types/ws": "^8.18.1",
84
+ "@typescript-eslint/eslint-plugin": "^8.26.1",
85
+ "@typescript-eslint/parser": "^8.26.1",
86
+ "@typescript-eslint/utils": "^8.26.1",
87
+ "concurrently": "^9.2.0",
88
+ "devtools-protocol": "^0.0.1498597",
89
+ "esbuild": "^0.20.1",
90
+ "eslint": "^9.19.0",
91
+ "eslint-plugin-import": "^2.31.0",
92
+ "eslint-plugin-notice": "^1.0.0",
93
+ "openai": "^5.10.2",
94
+ "typescript": "^5.8.2",
95
+ "zx": "^8.6.1"
96
+ },
97
+ "bin": {
98
+ "mcp-server-playwright": "cli-wrapper.js"
99
+ }
100
+ }