@playwright/mcp 0.0.20 → 0.0.24

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/README.md CHANGED
@@ -76,7 +76,10 @@ The Playwright MCP server supports the following command-line options:
76
76
  - `--user-data-dir <path>`: Path to the user data directory
77
77
  - `--port <port>`: Port to listen on for SSE transport
78
78
  - `--host <host>`: Host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.
79
+ - `--allowed-origins <origins>`: Semicolon-separated list of origins to allow the browser to request. Default is to allow all. Origins matching both `--allowed-origins` and `--blocked-origins` will be blocked.
80
+ - `--blocked-origins <origins>`: Semicolon-separated list of origins to block the browser to request. Origins matching both `--allowed-origins` and `--blocked-origins` will be blocked.
79
81
  - `--vision`: Run server that uses screenshots (Aria snapshots are used by default)
82
+ - `--output-dir`: Directory for output files
80
83
  - `--config <path>`: Path to the configuration file
81
84
 
82
85
  ### User profile
@@ -152,13 +155,19 @@ The Playwright MCP server can be configured using a JSON configuration file. Her
152
155
  // Directory for output files
153
156
  outputDir?: string;
154
157
 
155
- // Tool-specific configurations
156
- tools?: {
157
- browser_take_screenshot?: {
158
- // Disable base64-encoded image responses
159
- omitBase64?: boolean;
160
- }
161
- }
158
+ // Network configuration
159
+ network?: {
160
+ // List of origins to allow the browser to request. Default is to allow all. Origins matching both `allowedOrigins` and `blockedOrigins` will be blocked.
161
+ allowedOrigins?: string[];
162
+
163
+ // List of origins to block the browser to request. Origins matching both `allowedOrigins` and `blockedOrigins` will be blocked.
164
+ blockedOrigins?: string[];
165
+ };
166
+
167
+ /**
168
+ * Do not send image responses to the client.
169
+ */
170
+ noImageResponses?: boolean;
162
171
  }
163
172
  ```
164
173
 
@@ -198,7 +207,7 @@ And then in MCP client config, set the `url` to the SSE endpoint:
198
207
  "mcpServers": {
199
208
  "playwright": {
200
209
  "command": "docker",
201
- "args": ["run", "-i", "--rm", "--init", "mcp/playwright"]
210
+ "args": ["run", "-i", "--rm", "--init", "--pull=always", "mcr.microsoft.com/playwright/mcp"]
202
211
  }
203
212
  }
204
213
  }
@@ -207,7 +216,7 @@ And then in MCP client config, set the `url` to the SSE endpoint:
207
216
  You can build the Docker image yourself.
208
217
 
209
218
  ```
210
- docker build -t mcp/playwright .
219
+ docker build -t mcr.microsoft.com/playwright/mcp .
211
220
  ```
212
221
 
213
222
  ### Programmatic usage
@@ -215,16 +224,16 @@ docker build -t mcp/playwright .
215
224
  ```js
216
225
  import http from 'http';
217
226
 
218
- import { createServer } from '@playwright/mcp';
227
+ import { createConnection } from '@playwright/mcp';
219
228
  import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
220
229
 
221
230
  http.createServer(async (req, res) => {
222
231
  // ...
223
232
 
224
233
  // Creates a headless Playwright MCP server with SSE transport
225
- const mcpServer = await createServer({ headless: true });
234
+ const connection = await createConnection({ browser: { launchOptions: { headless: true } } });
226
235
  const transport = new SSEServerTransport('/messages', res);
227
- await mcpServer.connect(transport);
236
+ await connection.connect(transport);
228
237
 
229
238
  // ...
230
239
  });
@@ -264,38 +273,47 @@ X Y coordinate space, based on the provided screenshot.
264
273
  <!-- NOTE: This has been generated via update-readme.js -->
265
274
 
266
275
  - **browser_snapshot**
276
+ - Title: Page snapshot
267
277
  - Description: Capture accessibility snapshot of the current page, this is better than screenshot
268
278
  - Parameters: None
279
+ - Read-only: **true**
269
280
 
270
281
  <!-- NOTE: This has been generated via update-readme.js -->
271
282
 
272
283
  - **browser_click**
284
+ - Title: Click
273
285
  - Description: Perform click on a web page
274
286
  - Parameters:
275
287
  - `element` (string): Human-readable element description used to obtain permission to interact with the element
276
288
  - `ref` (string): Exact target element reference from the page snapshot
289
+ - Read-only: **false**
277
290
 
278
291
  <!-- NOTE: This has been generated via update-readme.js -->
279
292
 
280
293
  - **browser_drag**
294
+ - Title: Drag mouse
281
295
  - Description: Perform drag and drop between two elements
282
296
  - Parameters:
283
297
  - `startElement` (string): Human-readable source element description used to obtain the permission to interact with the element
284
298
  - `startRef` (string): Exact source element reference from the page snapshot
285
299
  - `endElement` (string): Human-readable target element description used to obtain the permission to interact with the element
286
300
  - `endRef` (string): Exact target element reference from the page snapshot
301
+ - Read-only: **false**
287
302
 
288
303
  <!-- NOTE: This has been generated via update-readme.js -->
289
304
 
290
305
  - **browser_hover**
306
+ - Title: Hover mouse
291
307
  - Description: Hover over element on page
292
308
  - Parameters:
293
309
  - `element` (string): Human-readable element description used to obtain permission to interact with the element
294
310
  - `ref` (string): Exact target element reference from the page snapshot
311
+ - Read-only: **true**
295
312
 
296
313
  <!-- NOTE: This has been generated via update-readme.js -->
297
314
 
298
315
  - **browser_type**
316
+ - Title: Type text
299
317
  - Description: Type text into editable element
300
318
  - Parameters:
301
319
  - `element` (string): Human-readable element description used to obtain permission to interact with the element
@@ -303,54 +321,67 @@ X Y coordinate space, based on the provided screenshot.
303
321
  - `text` (string): Text to type into the element
304
322
  - `submit` (boolean, optional): Whether to submit entered text (press Enter after)
305
323
  - `slowly` (boolean, optional): Whether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.
324
+ - Read-only: **false**
306
325
 
307
326
  <!-- NOTE: This has been generated via update-readme.js -->
308
327
 
309
328
  - **browser_select_option**
329
+ - Title: Select option
310
330
  - Description: Select an option in a dropdown
311
331
  - Parameters:
312
332
  - `element` (string): Human-readable element description used to obtain permission to interact with the element
313
333
  - `ref` (string): Exact target element reference from the page snapshot
314
334
  - `values` (array): Array of values to select in the dropdown. This can be a single value or multiple values.
335
+ - Read-only: **false**
315
336
 
316
337
  <!-- NOTE: This has been generated via update-readme.js -->
317
338
 
318
339
  - **browser_take_screenshot**
340
+ - Title: Take a screenshot
319
341
  - Description: Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.
320
342
  - Parameters:
321
343
  - `raw` (boolean, optional): Whether to return without compression (in PNG format). Default is false, which returns a JPEG image.
344
+ - `filename` (string, optional): File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified.
322
345
  - `element` (string, optional): Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.
323
346
  - `ref` (string, optional): Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.
347
+ - Read-only: **true**
324
348
 
325
349
  ### Vision-based Interactions
326
350
 
327
351
  <!-- NOTE: This has been generated via update-readme.js -->
328
352
 
329
353
  - **browser_screen_capture**
354
+ - Title: Take a screenshot
330
355
  - Description: Take a screenshot of the current page
331
356
  - Parameters: None
357
+ - Read-only: **true**
332
358
 
333
359
  <!-- NOTE: This has been generated via update-readme.js -->
334
360
 
335
361
  - **browser_screen_move_mouse**
362
+ - Title: Move mouse
336
363
  - Description: Move mouse to a given position
337
364
  - Parameters:
338
365
  - `element` (string): Human-readable element description used to obtain permission to interact with the element
339
366
  - `x` (number): X coordinate
340
367
  - `y` (number): Y coordinate
368
+ - Read-only: **true**
341
369
 
342
370
  <!-- NOTE: This has been generated via update-readme.js -->
343
371
 
344
372
  - **browser_screen_click**
373
+ - Title: Click
345
374
  - Description: Click left mouse button
346
375
  - Parameters:
347
376
  - `element` (string): Human-readable element description used to obtain permission to interact with the element
348
377
  - `x` (number): X coordinate
349
378
  - `y` (number): Y coordinate
379
+ - Read-only: **false**
350
380
 
351
381
  <!-- NOTE: This has been generated via update-readme.js -->
352
382
 
353
383
  - **browser_screen_drag**
384
+ - Title: Drag mouse
354
385
  - Description: Drag left mouse button
355
386
  - Parameters:
356
387
  - `element` (string): Human-readable element description used to obtain permission to interact with the element
@@ -358,143 +389,191 @@ X Y coordinate space, based on the provided screenshot.
358
389
  - `startY` (number): Start Y coordinate
359
390
  - `endX` (number): End X coordinate
360
391
  - `endY` (number): End Y coordinate
392
+ - Read-only: **false**
361
393
 
362
394
  <!-- NOTE: This has been generated via update-readme.js -->
363
395
 
364
396
  - **browser_screen_type**
397
+ - Title: Type text
365
398
  - Description: Type text
366
399
  - Parameters:
367
400
  - `text` (string): Text to type into the element
368
401
  - `submit` (boolean, optional): Whether to submit entered text (press Enter after)
402
+ - Read-only: **false**
369
403
 
370
404
  ### Tab Management
371
405
 
372
406
  <!-- NOTE: This has been generated via update-readme.js -->
373
407
 
374
408
  - **browser_tab_list**
409
+ - Title: List tabs
375
410
  - Description: List browser tabs
376
411
  - Parameters: None
412
+ - Read-only: **true**
377
413
 
378
414
  <!-- NOTE: This has been generated via update-readme.js -->
379
415
 
380
416
  - **browser_tab_new**
417
+ - Title: Open a new tab
381
418
  - Description: Open a new tab
382
419
  - Parameters:
383
420
  - `url` (string, optional): The URL to navigate to in the new tab. If not provided, the new tab will be blank.
421
+ - Read-only: **true**
384
422
 
385
423
  <!-- NOTE: This has been generated via update-readme.js -->
386
424
 
387
425
  - **browser_tab_select**
426
+ - Title: Select a tab
388
427
  - Description: Select a tab by index
389
428
  - Parameters:
390
429
  - `index` (number): The index of the tab to select
430
+ - Read-only: **true**
391
431
 
392
432
  <!-- NOTE: This has been generated via update-readme.js -->
393
433
 
394
434
  - **browser_tab_close**
435
+ - Title: Close a tab
395
436
  - Description: Close a tab
396
437
  - Parameters:
397
438
  - `index` (number, optional): The index of the tab to close. Closes current tab if not provided.
439
+ - Read-only: **false**
398
440
 
399
441
  ### Navigation
400
442
 
401
443
  <!-- NOTE: This has been generated via update-readme.js -->
402
444
 
403
445
  - **browser_navigate**
446
+ - Title: Navigate to a URL
404
447
  - Description: Navigate to a URL
405
448
  - Parameters:
406
449
  - `url` (string): The URL to navigate to
450
+ - Read-only: **false**
407
451
 
408
452
  <!-- NOTE: This has been generated via update-readme.js -->
409
453
 
410
454
  - **browser_navigate_back**
455
+ - Title: Go back
411
456
  - Description: Go back to the previous page
412
457
  - Parameters: None
458
+ - Read-only: **true**
413
459
 
414
460
  <!-- NOTE: This has been generated via update-readme.js -->
415
461
 
416
462
  - **browser_navigate_forward**
463
+ - Title: Go forward
417
464
  - Description: Go forward to the next page
418
465
  - Parameters: None
466
+ - Read-only: **true**
419
467
 
420
468
  ### Keyboard
421
469
 
422
470
  <!-- NOTE: This has been generated via update-readme.js -->
423
471
 
424
472
  - **browser_press_key**
473
+ - Title: Press a key
425
474
  - Description: Press a key on the keyboard
426
475
  - Parameters:
427
476
  - `key` (string): Name of the key to press or a character to generate, such as `ArrowLeft` or `a`
477
+ - Read-only: **false**
428
478
 
429
479
  ### Console
430
480
 
431
481
  <!-- NOTE: This has been generated via update-readme.js -->
432
482
 
433
483
  - **browser_console_messages**
484
+ - Title: Get console messages
434
485
  - Description: Returns all console messages
435
486
  - Parameters: None
487
+ - Read-only: **true**
436
488
 
437
489
  ### Files and Media
438
490
 
439
491
  <!-- NOTE: This has been generated via update-readme.js -->
440
492
 
441
493
  - **browser_file_upload**
494
+ - Title: Upload files
442
495
  - Description: Upload one or multiple files
443
496
  - Parameters:
444
497
  - `paths` (array): The absolute paths to the files to upload. Can be a single file or multiple files.
498
+ - Read-only: **false**
445
499
 
446
500
  <!-- NOTE: This has been generated via update-readme.js -->
447
501
 
448
502
  - **browser_pdf_save**
503
+ - Title: Save as PDF
449
504
  - Description: Save page as PDF
450
- - Parameters: None
505
+ - Parameters:
506
+ - `filename` (string, optional): File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.
507
+ - Read-only: **true**
451
508
 
452
509
  ### Utilities
453
510
 
454
511
  <!-- NOTE: This has been generated via update-readme.js -->
455
512
 
456
513
  - **browser_close**
514
+ - Title: Close browser
457
515
  - Description: Close the page
458
516
  - Parameters: None
517
+ - Read-only: **true**
459
518
 
460
519
  <!-- NOTE: This has been generated via update-readme.js -->
461
520
 
462
- - **browser_wait**
463
- - Description: Wait for a specified time in seconds
521
+ - **browser_wait_for**
522
+ - Title: Wait for
523
+ - Description: Wait for text to appear or disappear or a specified time to pass
464
524
  - Parameters:
465
- - `time` (number): The time to wait in seconds
525
+ - `time` (number, optional): The time to wait in seconds
526
+ - `text` (string, optional): The text to wait for
527
+ - `textGone` (string, optional): The text to wait for to disappear
528
+ - Read-only: **true**
466
529
 
467
530
  <!-- NOTE: This has been generated via update-readme.js -->
468
531
 
469
532
  - **browser_resize**
533
+ - Title: Resize browser window
470
534
  - Description: Resize the browser window
471
535
  - Parameters:
472
536
  - `width` (number): Width of the browser window
473
537
  - `height` (number): Height of the browser window
538
+ - Read-only: **true**
474
539
 
475
540
  <!-- NOTE: This has been generated via update-readme.js -->
476
541
 
477
542
  - **browser_install**
543
+ - Title: Install the browser specified in the config
478
544
  - Description: Install the browser specified in the config. Call this if you get an error about the browser not being installed.
479
545
  - Parameters: None
546
+ - Read-only: **false**
480
547
 
481
548
  <!-- NOTE: This has been generated via update-readme.js -->
482
549
 
483
550
  - **browser_handle_dialog**
551
+ - Title: Handle a dialog
484
552
  - Description: Handle a dialog
485
553
  - Parameters:
486
554
  - `accept` (boolean): Whether to accept the dialog.
487
555
  - `promptText` (string, optional): The text of the prompt in case of a prompt dialog.
556
+ - Read-only: **false**
557
+
558
+ <!-- NOTE: This has been generated via update-readme.js -->
559
+
560
+ - **browser_network_requests**
561
+ - Title: List network requests
562
+ - Description: Returns all network requests since loading the page
563
+ - Parameters: None
564
+ - Read-only: **true**
488
565
 
489
566
  ### Testing
490
567
 
491
568
  <!-- NOTE: This has been generated via update-readme.js -->
492
569
 
493
570
  - **browser_generate_playwright_test**
571
+ - Title: Generate a Playwright test
494
572
  - Description: Generate a Playwright test for given scenario
495
573
  - Parameters:
496
574
  - `name` (string): The name of the test
497
575
  - `description` (string): The description of the test
498
576
  - `steps` (array): The steps of the test
577
+ - Read-only: **true**
499
578
 
500
579
  <!--- End of generated section -->
package/config.d.ts CHANGED
@@ -40,7 +40,7 @@ export type Config = {
40
40
  *
41
41
  * This is useful for settings options like `channel`, `headless`, `executablePath`, etc.
42
42
  */
43
- launchOptions?: playwright.BrowserLaunchOptions;
43
+ launchOptions?: playwright.LaunchOptions;
44
44
 
45
45
  /**
46
46
  * Context options for the browser context.
@@ -94,20 +94,20 @@ export type Config = {
94
94
  */
95
95
  outputDir?: string;
96
96
 
97
- /**
98
- * Configuration for specific tools.
99
- */
100
- tools?: {
97
+ network?: {
98
+ /**
99
+ * List of origins to allow the browser to request. Default is to allow all. Origins matching both `allowedOrigins` and `blockedOrigins` will be blocked.
100
+ */
101
+ allowedOrigins?: string[];
102
+
101
103
  /**
102
- * Configuration for the browser_take_screenshot tool.
104
+ * List of origins to block the browser to request. Origins matching both `allowedOrigins` and `blockedOrigins` will be blocked.
103
105
  */
104
- browser_take_screenshot?: {
105
-
106
- /**
107
- * Whether to disable base64-encoded image responses to the clients that
108
- * don't support binary data or prefer to save on tokens.
109
- */
110
- omitBase64?: boolean;
111
- }
112
- }
106
+ blockedOrigins?: string[];
107
+ };
108
+
109
+ /**
110
+ * Do not send image responses to the client.
111
+ */
112
+ noImageResponses?: boolean;
113
113
  };
package/index.d.ts CHANGED
@@ -16,8 +16,14 @@
16
16
  */
17
17
 
18
18
  import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
19
-
20
19
  import type { Config } from './config';
20
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
21
+
22
+ export type Connection = {
23
+ server: Server;
24
+ connect(transport: Transport): Promise<void>;
25
+ close(): Promise<void>;
26
+ };
21
27
 
22
- export declare function createServer(config?: Config): Promise<Server>;
28
+ export declare function createConnection(config?: Config): Promise<Connection>;
23
29
  export {};
package/index.js CHANGED
@@ -15,5 +15,5 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- import { createServer } from './lib/index';
19
- export default { createServer };
18
+ import { createConnection } from './lib/index';
19
+ export { createConnection };
package/lib/config.js CHANGED
@@ -22,7 +22,6 @@ import { sanitizeForFilePath } from './tools/utils.js';
22
22
  const defaultConfig = {
23
23
  browser: {
24
24
  browserName: 'chromium',
25
- userDataDir: os.tmpdir(),
26
25
  launchOptions: {
27
26
  channel: 'chrome',
28
27
  headless: os.platform() === 'linux' && !process.env.DISPLAY,
@@ -31,6 +30,10 @@ const defaultConfig = {
31
30
  viewport: null,
32
31
  },
33
32
  },
33
+ network: {
34
+ allowedOrigins: undefined,
35
+ blockedOrigins: undefined,
36
+ },
34
37
  };
35
38
  export async function resolveConfig(cliOptions) {
36
39
  const config = await loadConfig(cliOptions.config);
@@ -69,12 +72,12 @@ export async function configFromCLIOptions(cliOptions) {
69
72
  headless: cliOptions.headless,
70
73
  };
71
74
  if (browserName === 'chromium')
72
- launchOptions.webSocketPort = await findFreePort();
75
+ launchOptions.cdpPort = await findFreePort();
73
76
  const contextOptions = cliOptions.device ? devices[cliOptions.device] : undefined;
74
77
  return {
75
78
  browser: {
76
79
  browserName,
77
- userDataDir: cliOptions.userDataDir ?? await createUserDataDir({ browserName, channel }),
80
+ userDataDir: cliOptions.userDataDir,
78
81
  launchOptions,
79
82
  contextOptions,
80
83
  cdpEndpoint: cliOptions.cdpEndpoint,
@@ -85,6 +88,11 @@ export async function configFromCLIOptions(cliOptions) {
85
88
  },
86
89
  capabilities: cliOptions.caps?.split(',').map((c) => c.trim()),
87
90
  vision: !!cliOptions.vision,
91
+ network: {
92
+ allowedOrigins: cliOptions.allowedOrigins,
93
+ blockedOrigins: cliOptions.blockedOrigins,
94
+ },
95
+ outputDir: cliOptions.outputDir,
88
96
  };
89
97
  }
90
98
  async function findFreePort() {
@@ -107,20 +115,6 @@ async function loadConfig(configFile) {
107
115
  throw new Error(`Failed to load config file: ${configFile}, ${error}`);
108
116
  }
109
117
  }
110
- async function createUserDataDir(options) {
111
- let cacheDirectory;
112
- if (process.platform === 'linux')
113
- cacheDirectory = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
114
- else if (process.platform === 'darwin')
115
- cacheDirectory = path.join(os.homedir(), 'Library', 'Caches');
116
- else if (process.platform === 'win32')
117
- cacheDirectory = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
118
- else
119
- throw new Error('Unsupported platform: ' + process.platform);
120
- const result = path.join(cacheDirectory, 'ms-playwright', `mcp-${options.channel ?? options.browserName}-profile`);
121
- await fs.promises.mkdir(result, { recursive: true });
122
- return result;
123
- }
124
118
  export async function outputFile(config, name) {
125
119
  const result = config.outputDir ?? os.tmpdir();
126
120
  await fs.promises.mkdir(result, { recursive: true });
@@ -144,11 +138,15 @@ function mergeConfig(base, overrides) {
144
138
  ...pickDefined(overrides.browser?.contextOptions),
145
139
  },
146
140
  };
147
- if (browser.browserName !== 'chromium')
141
+ if (browser.browserName !== 'chromium' && browser.launchOptions)
148
142
  delete browser.launchOptions.channel;
149
143
  return {
150
144
  ...pickDefined(base),
151
145
  ...pickDefined(overrides),
152
146
  browser,
147
+ network: {
148
+ ...pickDefined(base.network),
149
+ ...pickDefined(overrides.network),
150
+ },
153
151
  };
154
152
  }
@@ -16,11 +16,13 @@
16
16
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
17
17
  import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
18
18
  import { zodToJsonSchema } from 'zod-to-json-schema';
19
- import { Context } from './context.js';
20
- export function createServerWithTools(serverOptions, config) {
21
- const { name, version, tools } = serverOptions;
19
+ import { Context, packageJSON } from './context.js';
20
+ import { snapshotTools, screenshotTools } from './tools.js';
21
+ export async function createConnection(config) {
22
+ const allTools = config.vision ? screenshotTools : snapshotTools;
23
+ const tools = allTools.filter(tool => !config.capabilities || tool.capability === 'core' || config.capabilities.includes(tool.capability));
22
24
  const context = new Context(tools, config);
23
- const server = new Server({ name, version }, {
25
+ const server = new Server({ name: 'Playwright', version: packageJSON.version }, {
24
26
  capabilities: {
25
27
  tools: {},
26
28
  }
@@ -30,7 +32,13 @@ export function createServerWithTools(serverOptions, config) {
30
32
  tools: tools.map(tool => ({
31
33
  name: tool.schema.name,
32
34
  description: tool.schema.description,
33
- inputSchema: zodToJsonSchema(tool.schema.inputSchema)
35
+ inputSchema: zodToJsonSchema(tool.schema.inputSchema),
36
+ annotations: {
37
+ title: tool.schema.title,
38
+ readOnlyHint: tool.schema.type === 'readOnly',
39
+ destructiveHint: tool.schema.type === 'destructive',
40
+ openWorldHint: true,
41
+ },
34
42
  })),
35
43
  };
36
44
  });
@@ -54,31 +62,26 @@ export function createServerWithTools(serverOptions, config) {
54
62
  return errorResult(String(error));
55
63
  }
56
64
  });
57
- const oldClose = server.close.bind(server);
58
- server.close = async () => {
59
- await oldClose();
60
- await context.close();
61
- };
62
- return server;
65
+ const connection = new Connection(server, context);
66
+ return connection;
63
67
  }
64
- export class ServerList {
65
- _servers = [];
66
- _serverFactory;
67
- constructor(serverFactory) {
68
- this._serverFactory = serverFactory;
68
+ export class Connection {
69
+ server;
70
+ context;
71
+ constructor(server, context) {
72
+ this.server = server;
73
+ this.context = context;
69
74
  }
70
- async create() {
71
- const server = await this._serverFactory();
72
- this._servers.push(server);
73
- return server;
74
- }
75
- async close(server) {
76
- const index = this._servers.indexOf(server);
77
- if (index !== -1)
78
- this._servers.splice(index, 1);
79
- await server.close();
75
+ async connect(transport) {
76
+ await this.server.connect(transport);
77
+ await new Promise(resolve => {
78
+ this.server.oninitialized = () => resolve();
79
+ });
80
+ if (this.server.getClientVersion()?.name.includes('cursor'))
81
+ this.context.config.noImageResponses = true;
80
82
  }
81
- async closeAll() {
82
- await Promise.all(this._servers.map(server => server.close()));
83
+ async close() {
84
+ await this.server.close();
85
+ await this.context.close();
83
86
  }
84
87
  }