mcp-accessibility-scanner 1.0.10 → 1.1.0

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 (73) hide show
  1. package/NOTICE.md +21 -0
  2. package/Readme.md +194 -68
  3. package/cli.js +18 -0
  4. package/lib/browserContextFactory.js +228 -0
  5. package/lib/browserContextFactory.js.map +1 -0
  6. package/lib/browserServer.js +152 -0
  7. package/lib/browserServer.js.map +1 -0
  8. package/lib/config.js +190 -0
  9. package/lib/config.js.map +1 -0
  10. package/lib/connection.js +83 -0
  11. package/lib/connection.js.map +1 -0
  12. package/lib/context.js +292 -0
  13. package/lib/context.js.map +1 -0
  14. package/lib/fileUtils.js +33 -0
  15. package/lib/fileUtils.js.map +1 -0
  16. package/lib/httpServer.js +202 -0
  17. package/lib/httpServer.js.map +1 -0
  18. package/lib/index.js +37 -0
  19. package/lib/index.js.map +1 -0
  20. package/lib/javascript.js +50 -0
  21. package/lib/javascript.js.map +1 -0
  22. package/lib/manualPromise.js +112 -0
  23. package/lib/manualPromise.js.map +1 -0
  24. package/lib/package.js +21 -0
  25. package/lib/package.js.map +1 -0
  26. package/lib/pageSnapshot.js +44 -0
  27. package/lib/pageSnapshot.js.map +1 -0
  28. package/lib/program.js +72 -0
  29. package/lib/program.js.map +1 -0
  30. package/lib/server.js +49 -0
  31. package/lib/server.js.map +1 -0
  32. package/lib/tab.js +102 -0
  33. package/lib/tab.js.map +1 -0
  34. package/lib/tools/common.js +69 -0
  35. package/lib/tools/common.js.map +1 -0
  36. package/lib/tools/console.js +45 -0
  37. package/lib/tools/console.js.map +1 -0
  38. package/lib/tools/dialogs.js +53 -0
  39. package/lib/tools/dialogs.js.map +1 -0
  40. package/lib/tools/files.js +52 -0
  41. package/lib/tools/files.js.map +1 -0
  42. package/lib/tools/install.js +57 -0
  43. package/lib/tools/install.js.map +1 -0
  44. package/lib/tools/keyboard.js +47 -0
  45. package/lib/tools/keyboard.js.map +1 -0
  46. package/lib/tools/navigate.js +94 -0
  47. package/lib/tools/navigate.js.map +1 -0
  48. package/lib/tools/network.js +52 -0
  49. package/lib/tools/network.js.map +1 -0
  50. package/lib/tools/pdf.js +50 -0
  51. package/lib/tools/pdf.js.map +1 -0
  52. package/lib/tools/screenshot.js +78 -0
  53. package/lib/tools/screenshot.js.map +1 -0
  54. package/lib/tools/snapshot.js +245 -0
  55. package/lib/tools/snapshot.js.map +1 -0
  56. package/lib/tools/tabs.js +119 -0
  57. package/lib/tools/tabs.js.map +1 -0
  58. package/lib/tools/tool.js +19 -0
  59. package/lib/tools/tool.js.map +1 -0
  60. package/lib/tools/utils.js +81 -0
  61. package/lib/tools/utils.js.map +1 -0
  62. package/lib/tools/vision.js +190 -0
  63. package/lib/tools/vision.js.map +1 -0
  64. package/lib/tools/wait.js +60 -0
  65. package/lib/tools/wait.js.map +1 -0
  66. package/lib/tools.js +59 -0
  67. package/lib/tools.js.map +1 -0
  68. package/lib/transport.js +134 -0
  69. package/lib/transport.js.map +1 -0
  70. package/package.json +41 -13
  71. package/build/accessibilityChecker.js +0 -379
  72. package/build/index.js +0 -958
  73. package/build/server.js +0 -50
package/NOTICE.md ADDED
@@ -0,0 +1,21 @@
1
+ # NOTICE
2
+
3
+ ## mcp-accessibility-scanner
4
+
5
+ Copyright (c) 2024 Justas Monkev
6
+
7
+ This project is licensed under the MIT License.
8
+
9
+ ## Third-Party Code Attribution
10
+
11
+ This project includes code adapted from:
12
+
13
+ ### Microsoft Playwright MCP
14
+ - Copyright (c) Microsoft Corporation
15
+ - Licensed under the Apache License, Version 2.0
16
+ - Original source: https://github.com/microsoft/playwright-mcp
17
+
18
+ Adapted code has been modified to:
19
+ - Convert from ESM to CommonJS module format
20
+ - Integrate with axe-core accessibility scanning
21
+ - Work with existing Playwright instances rather than spawning new ones
package/Readme.md CHANGED
@@ -1,14 +1,32 @@
1
- [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/justasmonkev-mcp-accessibility-scanner-badge.png)](https://mseep.ai/app/justasmonkev-mcp-accessibility-scanner)
2
1
 
3
2
  # MCP Accessibility Scanner 🔍
4
3
 
4
+ [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/justasmonkev-mcp-accessibility-scanner-badge.png)](https://mseep.ai/app/justasmonkev-mcp-accessibility-scanner)
5
+
5
6
  A Model Context Protocol (MCP) server that provides automated web accessibility scanning using Playwright and Axe-core. This server enables LLMs to perform WCAG compliance checks, capture annotated screenshots, and generate detailed accessibility reports.
7
+ A powerful Model Context Protocol (MCP) server that provides automated web accessibility scanning and browser automation using Playwright and Axe-core. This server enables LLMs to perform WCAG compliance checks, interact with web pages, manage persistent browser sessions, and generate detailed accessibility reports with visual annotations.
6
8
 
7
9
  ## Features
8
10
 
9
- Full WCAG 2.1/2.2 compliance checking
11
+ ### Accessibility Scanning
12
+ ✅ Full WCAG 2.0/2.1/2.2 compliance checking (A, AA, AAA levels)
10
13
  🖼️ Automatic screenshot capture with violation highlighting
11
- 📄 Detailed JSON reports with remediation guidance
14
+ 📄 Detailed JSON reports with remediation guidance
15
+ 🎯 Support for specific violation categories (color contrast, ARIA, forms, keyboard navigation, etc.)
16
+
17
+ ### Browser Automation
18
+ 🖱️ Click, hover, and drag elements using accessibility snapshots
19
+ ⌨️ Type text and handle keyboard inputs
20
+ 🔍 Capture page snapshots to discover all interactive elements
21
+ 📸 Take screenshots and save PDFs
22
+ 🎯 Support for both element-based and coordinate-based interactions
23
+
24
+ ### Advanced Features
25
+ 📑 Tab management for multi-page workflows
26
+ 🌐 Monitor console messages and network requests
27
+ ⏱️ Wait for dynamic content to load
28
+ 📁 Handle file uploads and browser dialogs
29
+ 🔄 Navigate through browser history
12
30
 
13
31
  ## Installation
14
32
 
@@ -19,25 +37,6 @@ Using npm:
19
37
  npm install -g mcp-accessibility-scanner
20
38
  ```
21
39
 
22
- ### Docker Installation
23
-
24
- The project includes a Dockerfile that sets up all necessary dependencies including Node.js v22 and Python 3.13.
25
-
26
- 1. Build the Docker image:
27
- ```bash
28
- docker build -t mcp-server .
29
- ```
30
-
31
- 2. Run the container:
32
- ```bash
33
- docker run -it -e MCP_PROXY_DEBUG=true mcp-server
34
- ```
35
-
36
- You can also run it in the background:
37
- ```bash
38
- docker run -d -p 3000:3000 mcp-server
39
- ```
40
-
41
40
  ### Installation in VS Code
42
41
 
43
42
  Install the Accessibility Scanner in VS Code using the VS Code CLI:
@@ -67,72 +66,199 @@ Here's the Claude Desktop configuration:
67
66
  }
68
67
  ```
69
68
 
70
- ## Usage
69
+ ## Available Tools
70
+
71
+ The MCP server provides comprehensive browser automation and accessibility scanning tools:
72
+
73
+ ### Core Accessibility Tool
74
+
75
+ #### `scan_page`
76
+ Performs a comprehensive accessibility scan on the current page using Axe-core.
77
+
78
+ **Parameters:**
79
+ - `violationsTag`: Array of WCAG/violation tags to check
80
+
81
+ **Supported Violation Tags:**
82
+ - WCAG standards: `wcag2a`, `wcag2aa`, `wcag2aaa`, `wcag21a`, `wcag21aa`, `wcag21aaa`, `wcag22a`, `wcag22aa`, `wcag22aaa`
83
+ - Section 508: `section508`
84
+ - Categories: `cat.aria`, `cat.color`, `cat.forms`, `cat.keyboard`, `cat.language`, `cat.name-role-value`, `cat.parsing`, `cat.semantics`, `cat.sensory-and-visual-cues`, `cat.structure`, `cat.tables`, `cat.text-alternatives`, `cat.time-and-media`
85
+
86
+ ### Navigation Tools
87
+
88
+ #### `browser_navigate`
89
+ Navigate to a URL.
90
+ - Parameters: `url` (string)
91
+
92
+ #### `browser_navigate_back`
93
+ Go back to the previous page.
94
+
95
+ #### `browser_navigate_forward`
96
+ Go forward to the next page.
97
+
98
+ ### Page Interaction Tools
99
+
100
+ #### `browser_snapshot`
101
+ Capture accessibility snapshot of the current page (better than screenshot for analysis).
102
+
103
+ #### `browser_click`
104
+ Perform click on a web page element.
105
+ - Parameters: `element` (description), `ref` (element reference), `doubleClick` (optional)
106
+
107
+ #### `browser_type`
108
+ Type text into editable element.
109
+ - Parameters: `element`, `ref`, `text`, `submit` (optional), `slowly` (optional)
110
+
111
+ #### `browser_hover`
112
+ Hover over element on page.
113
+ - Parameters: `element`, `ref`
114
+
115
+ #### `browser_drag`
116
+ Perform drag and drop between two elements.
117
+ - Parameters: `startElement`, `startRef`, `endElement`, `endRef`
118
+
119
+ #### `browser_select_option`
120
+ Select an option in a dropdown.
121
+ - Parameters: `element`, `ref`, `values` (array)
122
+
123
+ #### `browser_press_key`
124
+ Press a key on the keyboard.
125
+ - Parameters: `key` (e.g., 'ArrowLeft' or 'a')
126
+
127
+ ### Screenshot & Visual Tools
128
+
129
+ #### `browser_take_screenshot`
130
+ Take a screenshot of the current page.
131
+ - Parameters: `raw` (optional), `filename` (optional), `element` (optional), `ref` (optional)
132
+
133
+ #### `browser_pdf_save`
134
+ Save page as PDF.
135
+ - Parameters: `filename` (optional, defaults to `page-{timestamp}.pdf`)
136
+
137
+ ### Browser Management
138
+
139
+ #### `browser_close`
140
+ Close the page.
141
+
142
+ #### `browser_resize`
143
+ Resize the browser window.
144
+ - Parameters: `width`, `height`
145
+
146
+ ### Tab Management
147
+
148
+ #### `browser_tab_list`
149
+ List all open browser tabs.
71
150
 
72
- The scanner exposes a single tool `scan_accessibility` that accepts:
151
+ #### `browser_tab_new`
152
+ Open a new tab.
153
+ - Parameters: `url` (optional)
73
154
 
74
- - `url`: The webpage URL to scan (required)
75
- - `violationsTag`: Array of accessibility violation tags to check (required)
76
- - `viewport`: Optional object to customize the viewport size
77
- - `width`: number (default: 1920)
78
- - `height`: number (default: 1080)
79
- - `shouldRunInHeadless`: Optional boolean to control headless mode (default: true)
155
+ #### `browser_tab_select`
156
+ Select a tab by index.
157
+ - Parameters: `index`
80
158
 
81
- **Note: When running a scan, an annotated screenshot highlighting any accessibility violations will be automatically saved to your downloads folder.**
159
+ #### `browser_tab_close`
160
+ Close a tab.
161
+ - Parameters: `index` (optional, closes current tab if not provided)
82
162
 
83
- Example usage in Claude:
163
+ ### Information & Monitoring Tools
164
+
165
+ #### `browser_console_messages`
166
+ Returns all console messages from the page.
167
+
168
+ #### `browser_network_requests`
169
+ Returns all network requests since loading the page.
170
+
171
+ ### Utility Tools
172
+
173
+ #### `browser_wait_for`
174
+ Wait for text to appear/disappear or time to pass.
175
+ - Parameters: `time` (optional), `text` (optional), `textGone` (optional)
176
+
177
+ #### `browser_handle_dialog`
178
+ Handle browser dialogs (alerts, confirms, prompts).
179
+ - Parameters: `accept` (boolean), `promptText` (optional)
180
+
181
+ #### `browser_file_upload`
182
+ Upload files to the page.
183
+ - Parameters: `paths` (array of absolute file paths)
184
+
185
+ ### Vision Mode Tools (Coordinate-based Interaction)
186
+
187
+ #### `browser_screen_capture`
188
+ Take a screenshot for coordinate-based interaction.
189
+
190
+ #### `browser_screen_move_mouse`
191
+ Move mouse to specific coordinates.
192
+ - Parameters: `element`, `x`, `y`
193
+
194
+ #### `browser_screen_click`
195
+ Click at specific coordinates.
196
+ - Parameters: `element`, `x`, `y`
197
+
198
+ #### `browser_screen_drag`
199
+ Drag from one coordinate to another.
200
+ - Parameters: `element`, `startX`, `startY`, `endX`, `endY`
201
+
202
+ #### `browser_screen_type`
203
+ Type text (coordinate-independent).
204
+ - Parameters: `text`, `submit` (optional)
205
+
206
+ ## Usage Examples
207
+
208
+ ### Basic Accessibility Scan
84
209
  ```
85
- Could you scan example.com for accessibility issues related to color contrast?
210
+ 1. Navigate to example.com using browser_navigate
211
+ 2. Run scan_page with violationsTag: ["wcag21aa"]
86
212
  ```
87
213
 
88
- Advanced example with custom options:
214
+ ### Color Contrast Check
89
215
  ```
90
- Could you scan example.com for accessibility issues with a viewport of 1280x720 and show the browser window?
216
+ 1. Use browser_navigate to go to example.com
217
+ 2. Run scan_page with violationsTag: ["cat.color"]
91
218
  ```
92
219
 
93
- ## Development
94
-
95
- Clone and set up the project:
96
- ```bash
97
- git clone https://github.com/JustasMonkev/mcp-accessibility-scanner.git
98
- cd mcp-accessibility-scanner
99
- npm install
220
+ ### Multi-step Workflow
100
221
  ```
101
-
102
- Start the TypeScript compiler in watch mode:
103
- ```bash
104
- npm run watch
222
+ 1. Navigate to example.com with browser_navigate
223
+ 2. Take a browser_snapshot to see available elements
224
+ 3. Click the "Sign In" button using browser_click
225
+ 4. Type "user@example.com" using browser_type
226
+ 5. Run scan_page on the login page
227
+ 6. Take a browser_take_screenshot to capture the final state
105
228
  ```
106
229
 
107
- Test the MCP server locally:
108
- ```bash
109
- npm run inspector
230
+ ### Page Analysis
231
+ ```
232
+ 1. Navigate to example.com
233
+ 2. Use browser_snapshot to capture all interactive elements
234
+ 3. Review console messages with browser_console_messages
235
+ 4. Check network activity with browser_network_requests
110
236
  ```
111
237
 
112
- ### Docker Development
113
-
114
- For development using Docker:
115
-
116
- 1. Build the development image:
117
- ```bash
118
- docker build -t mcp-server-dev .
238
+ ### Tab Management
239
+ ```
240
+ 1. Open a new tab with browser_tab_new
241
+ 2. Navigate to different pages in each tab
242
+ 3. Switch between tabs using browser_tab_select
243
+ 4. List all tabs with browser_tab_list
119
244
  ```
120
245
 
121
- 2. Run with volume mounting for live code changes:
122
- ```bash
123
- docker run -it -v $(pwd):/app -p 3000:3000 -e MCP_PROXY_DEBUG=true mcp-server-dev
246
+ ### Waiting for Dynamic Content
247
+ ```
248
+ 1. Navigate to a page
249
+ 2. Use browser_wait_for to wait for specific text to appear
250
+ 3. Interact with the dynamically loaded content
124
251
  ```
125
252
 
126
- ## Project Structure
253
+ **Note:** Most interaction tools require element references from browser_snapshot. Always capture a snapshot before attempting to interact with page elements.
127
254
 
128
- ```
129
- ├── src/ # Source code
130
- │ ├── index.ts # MCP server setup and tool definitions
131
- │ └── scanner.ts # Core scanning functionality
132
- ├── build/ # Compiled JavaScript output
133
- ├── Dockerfile # Docker configuration for containerized setup
134
- ├── package.json # Project configuration and dependencies
135
- └── tsconfig.json # TypeScript configuration
255
+ ## Development
256
+
257
+ Clone and set up the project:
258
+ ```bash
259
+ git clone https://github.com/JustasMonkev/mcp-accessibility-scanner.git
260
+ cd mcp-accessibility-scanner
261
+ npm install
136
262
  ```
137
263
 
138
264
  ## License
package/cli.js ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Copyright (c) Microsoft Corporation.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ import './lib/program.js';
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import fs from 'node:fs';
17
+ import net from 'node:net';
18
+ import path from 'node:path';
19
+ import os from 'node:os';
20
+ import debug from 'debug';
21
+ import * as playwright from 'playwright';
22
+ import { userDataDir } from './fileUtils.js';
23
+ const testDebug = debug('pw:mcp:test');
24
+ export function contextFactory(browserConfig) {
25
+ if (browserConfig.remoteEndpoint)
26
+ return new RemoteContextFactory(browserConfig);
27
+ if (browserConfig.cdpEndpoint)
28
+ return new CdpContextFactory(browserConfig);
29
+ if (browserConfig.isolated)
30
+ return new IsolatedContextFactory(browserConfig);
31
+ if (browserConfig.browserAgent)
32
+ return new BrowserServerContextFactory(browserConfig);
33
+ return new PersistentContextFactory(browserConfig);
34
+ }
35
+ class BaseContextFactory {
36
+ browserConfig;
37
+ _browserPromise;
38
+ name;
39
+ constructor(name, browserConfig) {
40
+ this.name = name;
41
+ this.browserConfig = browserConfig;
42
+ }
43
+ async _obtainBrowser() {
44
+ if (this._browserPromise)
45
+ return this._browserPromise;
46
+ testDebug(`obtain browser (${this.name})`);
47
+ this._browserPromise = this._doObtainBrowser();
48
+ void this._browserPromise.then(browser => {
49
+ browser.on('disconnected', () => {
50
+ this._browserPromise = undefined;
51
+ });
52
+ }).catch(() => {
53
+ this._browserPromise = undefined;
54
+ });
55
+ return this._browserPromise;
56
+ }
57
+ async _doObtainBrowser() {
58
+ throw new Error('Not implemented');
59
+ }
60
+ async createContext() {
61
+ testDebug(`create browser context (${this.name})`);
62
+ const browser = await this._obtainBrowser();
63
+ const browserContext = await this._doCreateContext(browser);
64
+ return { browserContext, close: () => this._closeBrowserContext(browserContext, browser) };
65
+ }
66
+ async _doCreateContext(browser) {
67
+ throw new Error('Not implemented');
68
+ }
69
+ async _closeBrowserContext(browserContext, browser) {
70
+ testDebug(`close browser context (${this.name})`);
71
+ if (browser.contexts().length === 1)
72
+ this._browserPromise = undefined;
73
+ await browserContext.close().catch(() => { });
74
+ if (browser.contexts().length === 0) {
75
+ testDebug(`close browser (${this.name})`);
76
+ await browser.close().catch(() => { });
77
+ }
78
+ }
79
+ }
80
+ class IsolatedContextFactory extends BaseContextFactory {
81
+ constructor(browserConfig) {
82
+ super('isolated', browserConfig);
83
+ }
84
+ async _doObtainBrowser() {
85
+ await injectCdpPort(this.browserConfig);
86
+ const browserType = playwright[this.browserConfig.browserName];
87
+ return browserType.launch({
88
+ ...this.browserConfig.launchOptions,
89
+ handleSIGINT: false,
90
+ handleSIGTERM: false,
91
+ }).catch(error => {
92
+ if (error.message.includes('Executable doesn\'t exist'))
93
+ throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);
94
+ throw error;
95
+ });
96
+ }
97
+ async _doCreateContext(browser) {
98
+ return browser.newContext(this.browserConfig.contextOptions);
99
+ }
100
+ }
101
+ class CdpContextFactory extends BaseContextFactory {
102
+ constructor(browserConfig) {
103
+ super('cdp', browserConfig);
104
+ }
105
+ async _doObtainBrowser() {
106
+ return playwright.chromium.connectOverCDP(this.browserConfig.cdpEndpoint);
107
+ }
108
+ async _doCreateContext(browser) {
109
+ return this.browserConfig.isolated ? await browser.newContext() : browser.contexts()[0];
110
+ }
111
+ }
112
+ class RemoteContextFactory extends BaseContextFactory {
113
+ constructor(browserConfig) {
114
+ super('remote', browserConfig);
115
+ }
116
+ async _doObtainBrowser() {
117
+ const url = new URL(this.browserConfig.remoteEndpoint);
118
+ url.searchParams.set('browser', this.browserConfig.browserName);
119
+ if (this.browserConfig.launchOptions)
120
+ url.searchParams.set('launch-options', JSON.stringify(this.browserConfig.launchOptions));
121
+ return playwright[this.browserConfig.browserName].connect(String(url));
122
+ }
123
+ async _doCreateContext(browser) {
124
+ return browser.newContext();
125
+ }
126
+ }
127
+ class PersistentContextFactory {
128
+ browserConfig;
129
+ _userDataDirs = new Set();
130
+ constructor(browserConfig) {
131
+ this.browserConfig = browserConfig;
132
+ }
133
+ async createContext() {
134
+ await injectCdpPort(this.browserConfig);
135
+ testDebug('create browser context (persistent)');
136
+ const userDataDir = this.browserConfig.userDataDir ?? await this._createUserDataDir();
137
+ this._userDataDirs.add(userDataDir);
138
+ testDebug('lock user data dir', userDataDir);
139
+ const browserType = playwright[this.browserConfig.browserName];
140
+ for (let i = 0; i < 5; i++) {
141
+ try {
142
+ const browserContext = await browserType.launchPersistentContext(userDataDir, {
143
+ ...this.browserConfig.launchOptions,
144
+ ...this.browserConfig.contextOptions,
145
+ handleSIGINT: false,
146
+ handleSIGTERM: false,
147
+ });
148
+ const close = () => this._closeBrowserContext(browserContext, userDataDir);
149
+ return { browserContext, close };
150
+ }
151
+ catch (error) {
152
+ if (error.message.includes('Executable doesn\'t exist'))
153
+ throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);
154
+ if (error.message.includes('ProcessSingleton') || error.message.includes('Invalid URL')) {
155
+ // User data directory is already in use, try again.
156
+ await new Promise(resolve => setTimeout(resolve, 1000));
157
+ continue;
158
+ }
159
+ throw error;
160
+ }
161
+ }
162
+ throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);
163
+ }
164
+ async _closeBrowserContext(browserContext, userDataDir) {
165
+ testDebug('close browser context (persistent)');
166
+ testDebug('release user data dir', userDataDir);
167
+ await browserContext.close().catch(() => { });
168
+ this._userDataDirs.delete(userDataDir);
169
+ testDebug('close browser context complete (persistent)');
170
+ }
171
+ async _createUserDataDir() {
172
+ let cacheDirectory;
173
+ if (process.platform === 'linux')
174
+ cacheDirectory = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
175
+ else if (process.platform === 'darwin')
176
+ cacheDirectory = path.join(os.homedir(), 'Library', 'Caches');
177
+ else if (process.platform === 'win32')
178
+ cacheDirectory = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
179
+ else
180
+ throw new Error('Unsupported platform: ' + process.platform);
181
+ const result = path.join(cacheDirectory, 'ms-playwright', `mcp-${this.browserConfig.launchOptions?.channel ?? this.browserConfig?.browserName}-profile`);
182
+ await fs.promises.mkdir(result, { recursive: true });
183
+ return result;
184
+ }
185
+ }
186
+ export class BrowserServerContextFactory extends BaseContextFactory {
187
+ constructor(browserConfig) {
188
+ super('persistent', browserConfig);
189
+ }
190
+ async _doObtainBrowser() {
191
+ const response = await fetch(new URL(`/json/launch`, this.browserConfig.browserAgent), {
192
+ method: 'POST',
193
+ body: JSON.stringify({
194
+ browserType: this.browserConfig.browserName,
195
+ userDataDir: this.browserConfig.userDataDir ?? await this._createUserDataDir(),
196
+ launchOptions: this.browserConfig.launchOptions,
197
+ contextOptions: this.browserConfig.contextOptions,
198
+ }),
199
+ });
200
+ const info = await response.json();
201
+ if (info.error)
202
+ throw new Error(info.error);
203
+ return await playwright.chromium.connectOverCDP(`http://localhost:${info.cdpPort}/`);
204
+ }
205
+ async _doCreateContext(browser) {
206
+ return this.browserConfig.isolated ? await browser.newContext() : browser.contexts()[0];
207
+ }
208
+ async _createUserDataDir() {
209
+ const dir = await userDataDir(this.browserConfig);
210
+ await fs.promises.mkdir(dir, { recursive: true });
211
+ return dir;
212
+ }
213
+ }
214
+ async function injectCdpPort(browserConfig) {
215
+ if (browserConfig.browserName === 'chromium')
216
+ browserConfig.launchOptions.cdpPort = await findFreePort();
217
+ }
218
+ async function findFreePort() {
219
+ return new Promise((resolve, reject) => {
220
+ const server = net.createServer();
221
+ server.listen(0, () => {
222
+ const { port } = server.address();
223
+ server.close(() => resolve(port));
224
+ });
225
+ server.on('error', reject);
226
+ });
227
+ }
228
+ //# sourceMappingURL=browserContextFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserContextFactory.js","sourceRoot":"","sources":["../src/browserContextFactory.ts"],"names":[],"mappings":"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"}