feat(args): allow configuring proxy, UA, viewport, https errors (#410)

This commit is contained in:
Pavel Feldman 2025-05-13 14:40:03 -07:00 committed by GitHub
parent ce72367208
commit 7be0c8872e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 82 additions and 34 deletions

View File

@ -110,6 +110,9 @@ Follow the MCP install [guide](https://modelcontextprotocol.io/quickstart/user),
Playwright MCP server supports following arguments. They can be provided in the JSON configuration above, as a part of the `"args"` list:
- `--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.
- `--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.
- `--block-service-workers`: Block service workers
- `--browser <browser>`: Browser or chrome channel to use. Possible values:
- `chrome`, `firefox`, `webkit`, `msedge`
- Chrome channels: `chrome-beta`, `chrome-canary`, `chrome-dev`
@ -117,18 +120,21 @@ Playwright MCP server supports following arguments. They can be provided in the
- Default: `chrome`
- `--caps <caps>`: Comma-separated list of capabilities to enable, possible values: tabs, pdf, history, wait, files, install. Default is all.
- `--cdp-endpoint <endpoint>`: CDP endpoint to connect to
- `--isolated`: Keep the browser profile in memory, do not save it to disk
- `--config <path>`: Path to the configuration file
- `--device`: Emulate mobile device
- `--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.
- `--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.
- `--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.
- `--vision`: Run server that uses screenshots (Aria snapshots are used by default)
- `--ignore-https-errors`: Ignore https errors
- `--isolated`: Keep the browser profile in memory, do not save it to disk
- `--output-dir`: Directory for output files
- `--config <path>`: Path to the configuration file
- `--port <port>`: Port to listen on for SSE transport
- `--proxy-bypass <bypass>`: Comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"'
- `--proxy-server <proxy>`: Proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"'
- `--user-agent <ua string>`: Specify user agent string
- `--user-data-dir <path>`: Path to the user data directory. If not specified, a temporary directory will be created
- `--viewport-size <size>`: Specify browser viewport size in pixels, for example "1280, 720"
- `--vision`: Run server that uses screenshots (Aria snapshots are used by default)
### User profile

View File

@ -25,23 +25,29 @@ import type { BrowserContextOptions, LaunchOptions } from 'playwright';
import { sanitizeForFilePath } from './tools/utils.js';
export type CLIOptions = {
allowedOrigins?: string[];
blockedOrigins?: string[];
blockServiceWorkers?: boolean;
browser?: string;
caps?: string;
cdpEndpoint?: string;
isolated?: boolean;
config?: string;
device?: string;
executablePath?: string;
headless?: boolean;
device?: string;
userDataDir?: string;
storageState?: string;
port?: number;
host?: string;
vision?: boolean;
config?: string;
allowedOrigins?: string[];
blockedOrigins?: string[];
outputDir?: string;
ignoreHttpsErrors?: boolean;
isolated?: boolean;
noImageResponses?: boolean;
outputDir?: string;
port?: number;
proxyBypass?: string;
proxyServer?: string;
storageState?: string;
userAgent?: string;
userDataDir?: string;
viewportSize?: string;
vision?: boolean;
};
const defaultConfig: Config = {
@ -94,6 +100,7 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Conf
channel = 'chrome';
}
// Launch options
const launchOptions: LaunchOptions = {
channel,
executablePath: cliOptions.executablePath,
@ -103,10 +110,39 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Conf
if (browserName === 'chromium')
(launchOptions as any).cdpPort = await findFreePort();
if (cliOptions.proxyServer) {
launchOptions.proxy = {
server: cliOptions.proxyServer
};
if (cliOptions.proxyBypass)
launchOptions.proxy.bypass = cliOptions.proxyBypass;
}
// Context options
const contextOptions: BrowserContextOptions = cliOptions.device ? devices[cliOptions.device] : {};
if (cliOptions.storageState)
contextOptions.storageState = cliOptions.storageState;
if (cliOptions.userAgent)
contextOptions.userAgent = cliOptions.userAgent;
if (cliOptions.viewportSize) {
try {
const [width, height] = cliOptions.viewportSize.split(',').map(n => +n);
if (isNaN(width) || isNaN(height))
throw new Error('bad values');
contextOptions.viewport = { width, height };
} catch (e) {
throw new Error('Invalid viewport size format: use "width,height", for example --viewport-size="800,600"');
}
}
if (cliOptions.ignoreHttpsErrors)
contextOptions.ignoreHTTPSErrors = true;
if (cliOptions.blockServiceWorkers)
contextOptions.serviceWorkers = 'block';
return {
browser: {
browserName,

View File

@ -25,24 +25,30 @@ import { packageJSON } from './context.js';
program
.version('Version ' + packageJSON.version)
.name(packageJSON.name)
.option('--browser <browser>', 'Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.')
.option('--caps <caps>', 'Comma-separated list of capabilities to enable, possible values: tabs, pdf, history, wait, files, install. Default is all.')
.option('--browser <browser>', 'browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.')
.option('--allowed-origins <origins>', 'semicolon-separated list of origins to allow the browser to request. Default is to allow all.', semicolonSeparatedList)
.option('--blocked-origins <origins>', 'semicolon-separated list of origins to block the browser from requesting. Blocklist is evaluated before allowlist. If used without the allowlist, requests not matching the blocklist are still allowed.', semicolonSeparatedList)
.option('--block-service-workers', 'block service workers')
.option('--caps <caps>', 'comma-separated list of capabilities to enable, possible values: tabs, pdf, history, wait, files, install. Default is all.')
.option('--cdp-endpoint <endpoint>', 'CDP endpoint to connect to.')
.option('--isolated', 'Keep the browser profile in memory, do not save it to disk.')
.option('--storage-state <path>', 'Path to the storage state file for isolated sessions.')
.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. If not specified, a temporary directory will be created.')
.option('--in-memory', 'Use in-memory storage for 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.')
.option('--allowed-origins <origins>', 'Semicolon-separated list of origins to allow the browser to request. Default is to allow all.', semicolonSeparatedList)
.option('--blocked-origins <origins>', 'Semicolon-separated list of origins to block the browser from requesting. Blocklist is evaluated before allowlist. If used without the allowlist, requests not matching the blocklist are still allowed.', semicolonSeparatedList)
.option('--config <path>', 'path to the configuration file.')
.option('--device <device>', 'device to emulate, for example: "iPhone 15"')
.option('--executable-path <path>', 'path to the browser executable.')
.option('--headless', 'run browser in headless mode, headed by default')
.option('--host <host>', 'host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.')
.option('--in-memory', 'use in-memory storage for user data directory.')
.option('--ignore-https-errors', 'ignore https errors')
.option('--isolated', 'keep the browser profile in memory, do not save it to disk.')
.option('--no-image-responses', 'do not send image responses to the client.')
.option('--output-dir <path>', 'path to the directory for output files.')
.option('--port <port>', 'port to listen on for SSE transport.')
.option('--proxy-bypass <bypass>', 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"')
.option('--proxy-server <proxy>', 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"')
.option('--storage-state <path>', 'path to the storage state file for isolated sessions.')
.option('--user-agent <ua string>', 'specify user agent string')
.option('--user-data-dir <path>', 'path to the user data directory. If not specified, a temporary directory will be created.')
.option('--viewport-size <size>', 'specify browser viewport size in pixels, for example "1280, 720"')
.option('--vision', 'Run server that uses screenshots (Aria snapshots are used by default)')
.option('--no-image-responses', 'Do not send image responses to the client.')
.option('--output-dir <path>', 'Path to the directory for output files.')
.option('--config <path>', 'Path to the configuration file.')
.action(async options => {
const config = await resolveConfig(options);
const connectionList: Connection[] = [];