mirror of
				https://github.com/microsoft/playwright-mcp.git
				synced 2025-10-12 00:25:14 +03:00 
			
		
		
		
	chore: add support for device (#300)
Fixes https://github.com/microsoft/playwright-mcp/issues/294
This commit is contained in:
		
							
								
								
									
										17
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								README.md
									
									
									
									
									
								
							| @@ -16,7 +16,7 @@ A Model Context Protocol (MCP) server that provides browser automation capabilit | ||||
| - General-purpose browser interaction for agents | ||||
|  | ||||
| <!-- | ||||
| // Generate using?: | ||||
| // Generate using: | ||||
| node utils/generate_links.js | ||||
| --> | ||||
|  | ||||
| @@ -72,6 +72,7 @@ The Playwright MCP server supports the following command-line options: | ||||
| - `--cdp-endpoint <endpoint>`: CDP endpoint to connect to | ||||
| - `--executable-path <path>`: Path to the browser executable | ||||
| - `--headless`: Run browser in headless mode (headed by default) | ||||
| - `--device`: Emulate mobile device | ||||
| - `--user-data-dir <path>`: Path to the user data directory | ||||
| - `--port <port>`: Port to listen on for SSE transport | ||||
| - `--host <host>`: Host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces. | ||||
| @@ -100,27 +101,29 @@ The Playwright MCP server can be configured using a JSON configuration file. Her | ||||
|   browser?: { | ||||
|     // Browser type to use (chromium, firefox, or webkit) | ||||
|     browserName?: 'chromium' | 'firefox' | 'webkit'; | ||||
|      | ||||
|  | ||||
|     // Path to user data directory for browser profile persistence | ||||
|     userDataDir?: string; | ||||
|      | ||||
|  | ||||
|     // Browser launch options (see Playwright docs) | ||||
|     // @see https://playwright.dev/docs/api/class-browsertype#browser-type-launch | ||||
|     launchOptions?: { | ||||
|       channel?: string;        // Browser channel (e.g. 'chrome') | ||||
|       headless?: boolean;      // Run in headless mode | ||||
|       executablePath?: string; // Path to browser executable | ||||
|       // ... other Playwright launch options | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     // Browser context options | ||||
|     // @see https://playwright.dev/docs/api/class-browser#browser-new-context | ||||
|     contextOptions?: { | ||||
|       viewport?: { width: number, height: number }; | ||||
|       // ... other Playwright context options | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     // CDP endpoint for connecting to existing browser | ||||
|     cdpEndpoint?: string; | ||||
|      | ||||
|  | ||||
|     // Remote Playwright server endpoint | ||||
|     remoteEndpoint?: string; | ||||
|   }, | ||||
| @@ -166,8 +169,6 @@ npx @playwright/mcp@latest --config path/to/config.json | ||||
|  | ||||
| ### Running on Linux | ||||
|  | ||||
| When running headless without DISPLAY, pass `--headless` command line argument. | ||||
|  | ||||
| When running headed browser on system w/o display or from worker processes of the IDEs, | ||||
| run the MCP server from environment with the DISPLAY and pass the `--port` flag to enable SSE transport. | ||||
|  | ||||
|   | ||||
| @@ -18,11 +18,12 @@ import fs from 'fs'; | ||||
| import net from 'net'; | ||||
| import os from 'os'; | ||||
| import path from 'path'; | ||||
| import { devices } from 'playwright'; | ||||
|  | ||||
| import { sanitizeForFilePath } from './tools/utils'; | ||||
|  | ||||
| import type { Config, ToolCapability } from '../config'; | ||||
| import type { LaunchOptions } from 'playwright'; | ||||
| import type { BrowserContextOptions, LaunchOptions } from 'playwright'; | ||||
|  | ||||
| export type CLIOptions = { | ||||
|   browser?: string; | ||||
| @@ -30,6 +31,7 @@ export type CLIOptions = { | ||||
|   cdpEndpoint?: string; | ||||
|   executablePath?: string; | ||||
|   headless?: boolean; | ||||
|   device?: string; | ||||
|   userDataDir?: string; | ||||
|   port?: number; | ||||
|   host?: string; | ||||
| @@ -93,11 +95,14 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Conf | ||||
|   if (browserName === 'chromium') | ||||
|     (launchOptions as any).webSocketPort = await findFreePort(); | ||||
|  | ||||
|   const contextOptions: BrowserContextOptions | undefined = cliOptions.device ? devices[cliOptions.device] : undefined; | ||||
|  | ||||
|   return { | ||||
|     browser: { | ||||
|       browserName, | ||||
|       userDataDir: cliOptions.userDataDir ?? await createUserDataDir({ browserName, channel }), | ||||
|       launchOptions, | ||||
|       contextOptions, | ||||
|       cdpEndpoint: cliOptions.cdpEndpoint, | ||||
|     }, | ||||
|     server: { | ||||
|   | ||||
| @@ -306,7 +306,7 @@ ${code.join('\n')} | ||||
| async function launchPersistentContext(browserConfig: Config['browser']): Promise<playwright.BrowserContext> { | ||||
|   try { | ||||
|     const browserType = browserConfig?.browserName ? playwright[browserConfig.browserName] : playwright.chromium; | ||||
|     return await browserType.launchPersistentContext(browserConfig?.userDataDir || '', browserConfig?.launchOptions); | ||||
|     return await browserType.launchPersistentContext(browserConfig?.userDataDir || '', { ...browserConfig?.launchOptions, ...browserConfig?.contextOptions }); | ||||
|   } catch (error: any) { | ||||
|     if (error.message.includes('Executable doesn\'t exist')) | ||||
|       throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`); | ||||
|   | ||||
| @@ -33,6 +33,7 @@ program | ||||
|     .option('--cdp-endpoint <endpoint>', 'CDP endpoint to connect to.') | ||||
|     .option('--executable-path <path>', 'Path to the browser executable.') | ||||
|     .option('--headless', 'Run browser in headless mode, headed by default') | ||||
|     .option('--device <device>', 'Device to emulate, for example: "iPhone 15"') | ||||
|     .option('--user-data-dir <path>', 'Path to the user data directory') | ||||
|     .option('--port <port>', 'Port to listen on for SSE transport.') | ||||
|     .option('--host <host>', 'Host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.') | ||||
|   | ||||
							
								
								
									
										43
									
								
								tests/device.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								tests/device.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| import { test, expect } from './fixtures'; | ||||
|  | ||||
| test('browser_take_screenshot (viewport)', async ({ startClient, server }) => { | ||||
|   const client = await startClient({ | ||||
|     args: ['--device', 'iPhone 15'], | ||||
|   }); | ||||
|  | ||||
|   server.route('/', (req, res) => { | ||||
|     res.writeHead(200, { 'Content-Type': 'text/html' }); | ||||
|     res.end(` | ||||
|       <head> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|       </head> | ||||
|       <body></body> | ||||
|       <script> | ||||
|         document.body.textContent = window.innerWidth + "x" + window.innerHeight; | ||||
|       </script> | ||||
|     `); | ||||
|   }); | ||||
|  | ||||
|   expect(await client.callTool({ | ||||
|     name: 'browser_navigate', | ||||
|     arguments: { | ||||
|       url: server.PREFIX, | ||||
|     }, | ||||
|   })).toContainTextContent(`393x659`); | ||||
| }); | ||||
							
								
								
									
										6
									
								
								utils/generate_links.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								utils/generate_links.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| const config = JSON.stringify({ name: 'playwright', command: 'npx', args: ["@playwright/mcp@latest"] }); | ||||
| const urlForWebsites = `vscode:mcp/install?${encodeURIComponent(config)}`; | ||||
| // Github markdown does not allow linking to `vscode:` directly, so you can use our redirect: | ||||
| const urlForGithub = `https://insiders.vscode.dev/redirect?url=${encodeURIComponent(urlForWebsites)}`; | ||||
|  | ||||
| console.log(urlForGithub); | ||||
		Reference in New Issue
	
	Block a user
	 Pavel Feldman
					Pavel Feldman