chore: merge browser and channel settings (#100)

This commit is contained in:
Pavel Feldman 2025-04-01 10:26:48 -07:00 committed by GitHub
parent 9042c03faa
commit 4f16786432
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 65 additions and 12 deletions

View File

@ -59,9 +59,25 @@ code-insiders --add-mcp '{"name":"playwright","command":"npx","args":["@playwrig
After installation, the Playwright MCP server will be available for use with your GitHub Copilot agent in VS Code.
### CLI Options
The Playwright MCP server supports the following command-line options:
- `--browser <browser>`: Browser or chrome channel to use. Possible values:
- `chrome`, `firefox`, `webkit`, `msedge`
- Chrome channels: `chrome-beta`, `chrome-canary`, `chrome-dev`
- Edge channels: `msedge-beta`, `msedge-canary`, `msedge-dev`
- Default: `chrome`
- `--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)
- `--port <port>`: Port to listen on for SSE transport
- `--user-data-dir <path>`: Path to the user data directory
- `--vision`: Run server that uses screenshots (Aria snapshots are used by default)
### User data directory
Playwright MCP will launch Chrome browser with the new profile, located at
Playwright MCP will launch the browser with the new profile, located at
```
- `%USERPROFILE%\AppData\Local\ms-playwright\mcp-chrome-profile` on Windows

View File

@ -20,6 +20,7 @@ import path from 'path';
import * as playwright from 'playwright';
export type ContextOptions = {
browserName?: 'chromium' | 'firefox' | 'webkit';
userDataDir: string;
launchOptions?: playwright.LaunchOptions;
cdpEndpoint?: string;
@ -73,7 +74,7 @@ export class Context {
}
async install(): Promise<string> {
const channel = this._options.launchOptions?.channel || 'chrome';
const channel = this._options.launchOptions?.channel ?? this._options.browserName ?? 'chrome';
const cli = path.join(require.resolve('playwright/package.json'), '..', 'cli.js');
const child = fork(cli, ['install', channel], {
stdio: 'pipe',
@ -125,9 +126,11 @@ export class Context {
private async _createPage(): Promise<{ browser?: playwright.Browser, page: playwright.Page }> {
if (this._options.remoteEndpoint) {
const url = new URL(this._options.remoteEndpoint);
if (this._options.browserName)
url.searchParams.set('browser', this._options.browserName);
if (this._options.launchOptions)
url.searchParams.set('launch-options', JSON.stringify(this._options.launchOptions));
const browser = await playwright.chromium.connect(String(url));
const browser = await playwright[this._options.browserName ?? 'chromium'].connect(String(url));
const page = await browser.newPage();
return { browser, page };
}
@ -148,7 +151,8 @@ export class Context {
private async _launchPersistentContext(): Promise<playwright.BrowserContext> {
try {
return await playwright.chromium.launchPersistentContext(this._options.userDataDir, this._options.launchOptions);
const browserType = this._options.browserName ? playwright[this._options.browserName] : playwright.chromium;
return await browserType.launchPersistentContext(this._options.userDataDir, this._options.launchOptions);
} 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.`);

View File

@ -65,6 +65,7 @@ const resources: Resource[] = [
];
type Options = {
browserName?: 'chromium' | 'firefox' | 'webkit';
userDataDir?: string;
launchOptions?: LaunchOptions;
cdpEndpoint?: string;
@ -80,6 +81,7 @@ export function createServer(options?: Options): Server {
version: packageJSON.version,
tools,
resources,
browserName: options?.browserName,
userDataDir: options?.userDataDir ?? '',
launchOptions: options?.launchOptions,
cdpEndpoint: options?.cdpEndpoint,

View File

@ -35,21 +35,52 @@ const packageJSON = require('../package.json');
program
.version('Version ' + packageJSON.version)
.name(packageJSON.name)
.option('--browser <browser>', 'Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.')
.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('--port <port>', 'Port to listen on for SSE transport.')
.option('--user-data-dir <path>', 'Path to the user data directory')
.option('--vision', 'Run server that uses screenshots (Aria snapshots are used by default)')
.option('--port <port>', 'Port to listen on for SSE transport.')
.option('--cdp-endpoint <endpoint>', 'CDP endpoint to connect to.')
.option('--channel <channel>', 'Channel to use for browser, possible values: chrome, msedge, chromium. Default: chrome')
.option('--executable-path <path>', 'Path to the browser executable.')
.action(async options => {
let browserName: 'chromium' | 'firefox' | 'webkit';
let channel: string | undefined;
switch (options.browser) {
case 'chrome':
case 'chrome-beta':
case 'chrome-canary':
case 'chrome-dev':
case 'msedge':
case 'msedge-beta':
case 'msedge-canary':
case 'msedge-dev':
browserName = 'chromium';
channel = options.browser;
break;
case 'chromium':
browserName = 'chromium';
break;
case 'firefox':
browserName = 'firefox';
break;
case 'webkit':
browserName = 'webkit';
break;
default:
browserName = 'chromium';
channel = 'chrome';
}
const launchOptions: LaunchOptions = {
headless: !!options.headless,
channel: options.channel ?? 'chrome',
channel,
executablePath: options.executablePath,
};
const userDataDir = options.userDataDir ?? await createUserDataDir();
const userDataDir = options.userDataDir ?? await createUserDataDir(browserName);
const serverList = new ServerList(() => createServer({
browserName,
userDataDir,
launchOptions,
vision: !!options.vision,
@ -75,7 +106,7 @@ function setupExitWatchdog(serverList: ServerList) {
program.parse(process.argv);
async function createUserDataDir() {
async function createUserDataDir(browserName: 'chromium' | 'firefox' | 'webkit') {
let cacheDirectory: string;
if (process.platform === 'linux')
cacheDirectory = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
@ -85,7 +116,7 @@ async function createUserDataDir() {
cacheDirectory = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
else
throw new Error('Unsupported platform: ' + process.platform);
const result = path.join(cacheDirectory, 'ms-playwright', 'mcp-chrome-profile');
const result = path.join(cacheDirectory, 'ms-playwright', `mcp-${browserName}-profile`);
await fs.promises.mkdir(result, { recursive: true });
return result;
}