feat: add runtime permission granting tools and --grant-all-permissions flag
New tools for managing browser permissions at runtime (no restart needed): - browser_grant_permissions: Grant specific or ALL permissions at runtime - Supports `all: true` to grant all common permissions at once - browser_clear_permissions: Revoke all granted permissions - browser_set_geolocation: Set geolocation coordinates at runtime New CLI flag: - --grant-all-permissions: Start with all permissions pre-granted - PLAYWRIGHT_MCP_GRANT_ALL_PERMISSIONS env var support Permissions granted with `all: true` or --grant-all-permissions: - geolocation, notifications, camera, microphone - clipboard-read, clipboard-write - accelerometer, gyroscope, magnetometer - midi, background-sync, ambient-light-sensor - accessibility-events
This commit is contained in:
parent
5e5123d1ac
commit
0031d17f32
55
README.md
55
README.md
@ -181,6 +181,9 @@ Playwright MCP server supports following arguments. They can be provided in the
|
||||
--no-isolated use a persistent browser profile. Enables
|
||||
features like Push API that require
|
||||
non-incognito mode.
|
||||
--grant-all-permissions grant all browser permissions (geolocation,
|
||||
camera, microphone, clipboard, etc.) at
|
||||
startup.
|
||||
--image-responses <mode> whether to send image responses to the client.
|
||||
Can be "allow" or "omit", Defaults to "allow".
|
||||
--no-snapshots disable automatic page snapshots after
|
||||
@ -556,6 +559,14 @@ http.createServer(async (req, res) => {
|
||||
|
||||
<!-- NOTE: This has been generated via update-readme.js -->
|
||||
|
||||
- **browser_clear_permissions**
|
||||
- Title: Clear all browser permissions
|
||||
- Description: Revoke all previously granted permissions for the current browser context. Sites will need to request permissions again.
|
||||
- Parameters: None
|
||||
- Read-only: **false**
|
||||
|
||||
<!-- NOTE: This has been generated via update-readme.js -->
|
||||
|
||||
- **browser_clear_requests**
|
||||
- Title: Clear captured requests
|
||||
- Description: Clear all captured HTTP request data from memory. Useful for freeing up memory during long sessions or when starting fresh analysis.
|
||||
@ -835,6 +846,39 @@ This is the FIRST conversational browser automation MCP server!
|
||||
|
||||
<!-- NOTE: This has been generated via update-readme.js -->
|
||||
|
||||
- **browser_grant_permissions**
|
||||
- Title: Grant browser permissions at runtime
|
||||
- Description: Grant browser permissions at runtime without restarting the browser. This is faster than using browser_configure which requires a browser restart.
|
||||
|
||||
**Quick option:** Use `all: true` to grant all common permissions at once!
|
||||
|
||||
**Available permissions:**
|
||||
- geolocation - Access user location
|
||||
- notifications - Show browser notifications
|
||||
- camera - Access camera/webcam
|
||||
- microphone - Access microphone
|
||||
- clipboard-read - Read from clipboard
|
||||
- clipboard-write - Write to clipboard
|
||||
- accelerometer - Access motion sensors
|
||||
- gyroscope - Access orientation sensors
|
||||
- magnetometer - Access compass
|
||||
- accessibility-events - Accessibility automation
|
||||
- midi - MIDI device access
|
||||
- midi-sysex - MIDI system exclusive messages
|
||||
- background-sync - Background sync API
|
||||
- ambient-light-sensor - Light sensor access
|
||||
- payment-handler - Payment request API
|
||||
- storage-access - Storage access API
|
||||
|
||||
**Note:** Some permissions may require user interaction (like camera/microphone device selection) even after being granted.
|
||||
- Parameters:
|
||||
- `permissions` (array, optional): List of permissions to grant (e.g., ["geolocation", "camera", "microphone"])
|
||||
- `all` (boolean, optional): Grant ALL common permissions at once (geolocation, notifications, camera, microphone, clipboard, sensors, midi)
|
||||
- `origin` (string, optional): Origin to grant permissions for (e.g., "https://example.com"). If not specified, grants for all origins.
|
||||
- Read-only: **false**
|
||||
|
||||
<!-- NOTE: This has been generated via update-readme.js -->
|
||||
|
||||
- **browser_handle_dialog**
|
||||
- Title: Handle a dialog
|
||||
- Description: Handle a dialog. Returns page snapshot after handling dialog (configurable via browser_configure_snapshots).
|
||||
@ -1101,6 +1145,17 @@ Full API: See MODEL-COLLABORATION-API.md
|
||||
|
||||
<!-- NOTE: This has been generated via update-readme.js -->
|
||||
|
||||
- **browser_set_geolocation**
|
||||
- Title: Set geolocation at runtime
|
||||
- Description: Set the browser's geolocation at runtime without restarting. Automatically grants geolocation permission.
|
||||
- Parameters:
|
||||
- `latitude` (number): Latitude coordinate (-90 to 90)
|
||||
- `longitude` (number): Longitude coordinate (-180 to 180)
|
||||
- `accuracy` (number, optional): Accuracy in meters (default: 100)
|
||||
- Read-only: **false**
|
||||
|
||||
<!-- NOTE: This has been generated via update-readme.js -->
|
||||
|
||||
- **browser_set_offline**
|
||||
- Title: Set browser offline mode
|
||||
- Description: Toggle browser offline mode on/off (equivalent to DevTools offline checkbox)
|
||||
|
||||
@ -34,6 +34,7 @@ export type CLIOptions = {
|
||||
consoleOutputFile?: string;
|
||||
device?: string;
|
||||
executablePath?: string;
|
||||
grantAllPermissions?: boolean;
|
||||
headless?: boolean;
|
||||
host?: string;
|
||||
ignoreHttpsErrors?: boolean;
|
||||
@ -191,6 +192,25 @@ export function configFromCLIOptions(cliOptions: CLIOptions): Config {
|
||||
if (cliOptions.blockServiceWorkers)
|
||||
contextOptions.serviceWorkers = 'block';
|
||||
|
||||
// Grant all permissions if requested
|
||||
if (cliOptions.grantAllPermissions) {
|
||||
contextOptions.permissions = [
|
||||
'geolocation',
|
||||
'notifications',
|
||||
'camera',
|
||||
'microphone',
|
||||
'clipboard-read',
|
||||
'clipboard-write',
|
||||
'accelerometer',
|
||||
'gyroscope',
|
||||
'magnetometer',
|
||||
'midi',
|
||||
'background-sync',
|
||||
'ambient-light-sensor',
|
||||
'accessibility-events',
|
||||
];
|
||||
}
|
||||
|
||||
const result: Config = {
|
||||
browser: {
|
||||
browserName,
|
||||
@ -236,6 +256,7 @@ function configFromEnv(): Config {
|
||||
options.config = envToString(process.env.PLAYWRIGHT_MCP_CONFIG);
|
||||
options.device = envToString(process.env.PLAYWRIGHT_MCP_DEVICE);
|
||||
options.executablePath = envToString(process.env.PLAYWRIGHT_MCP_EXECUTABLE_PATH);
|
||||
options.grantAllPermissions = envToBoolean(process.env.PLAYWRIGHT_MCP_GRANT_ALL_PERMISSIONS);
|
||||
options.headless = envToBoolean(process.env.PLAYWRIGHT_MCP_HEADLESS);
|
||||
options.host = envToString(process.env.PLAYWRIGHT_MCP_HOST);
|
||||
options.ignoreHttpsErrors = envToBoolean(process.env.PLAYWRIGHT_MCP_IGNORE_HTTPS_ERRORS);
|
||||
|
||||
@ -46,6 +46,7 @@ program
|
||||
.option('--ignore-https-errors', 'ignore https errors')
|
||||
.option('--isolated', 'keep the browser profile in memory, do not save it to disk. This is the default.')
|
||||
.option('--no-isolated', 'use a persistent browser profile. Enables features like Push API that require non-incognito mode.')
|
||||
.option('--grant-all-permissions', 'grant all browser permissions (geolocation, camera, microphone, clipboard, etc.) at startup.')
|
||||
.option('--image-responses <mode>', 'whether to send image responses to the client. Can be "allow" or "omit", Defaults to "allow".')
|
||||
.option('--no-snapshots', 'disable automatic page snapshots after interactive operations like clicks. Use browser_snapshot tool for explicit snapshots.')
|
||||
.option('--max-snapshot-tokens <tokens>', 'maximum number of tokens allowed in page snapshots before truncation. Use 0 to disable truncation. Default is 10000.', parseInt)
|
||||
|
||||
@ -235,10 +235,158 @@ const clearNotifications = defineTool({
|
||||
},
|
||||
});
|
||||
|
||||
// All commonly-used permissions that can be granted
|
||||
const ALL_PERMISSIONS = [
|
||||
'geolocation',
|
||||
'notifications',
|
||||
'camera',
|
||||
'microphone',
|
||||
'clipboard-read',
|
||||
'clipboard-write',
|
||||
'accelerometer',
|
||||
'gyroscope',
|
||||
'magnetometer',
|
||||
'midi',
|
||||
'background-sync',
|
||||
'ambient-light-sensor',
|
||||
'accessibility-events',
|
||||
];
|
||||
|
||||
/**
|
||||
* Grant permissions at runtime without restarting the browser.
|
||||
* More flexible than browser_configure which requires a restart.
|
||||
*/
|
||||
const grantPermissions = defineTool({
|
||||
capability: 'core',
|
||||
|
||||
schema: {
|
||||
name: 'browser_grant_permissions',
|
||||
title: 'Grant browser permissions at runtime',
|
||||
description: `Grant browser permissions at runtime without restarting the browser. This is faster than using browser_configure which requires a browser restart.
|
||||
|
||||
**Quick option:** Use \`all: true\` to grant all common permissions at once!
|
||||
|
||||
**Available permissions:**
|
||||
- geolocation - Access user location
|
||||
- notifications - Show browser notifications
|
||||
- camera - Access camera/webcam
|
||||
- microphone - Access microphone
|
||||
- clipboard-read - Read from clipboard
|
||||
- clipboard-write - Write to clipboard
|
||||
- accelerometer - Access motion sensors
|
||||
- gyroscope - Access orientation sensors
|
||||
- magnetometer - Access compass
|
||||
- accessibility-events - Accessibility automation
|
||||
- midi - MIDI device access
|
||||
- midi-sysex - MIDI system exclusive messages
|
||||
- background-sync - Background sync API
|
||||
- ambient-light-sensor - Light sensor access
|
||||
- payment-handler - Payment request API
|
||||
- storage-access - Storage access API
|
||||
|
||||
**Note:** Some permissions may require user interaction (like camera/microphone device selection) even after being granted.`,
|
||||
inputSchema: z.object({
|
||||
permissions: z.array(z.string()).optional().describe('List of permissions to grant (e.g., ["geolocation", "camera", "microphone"])'),
|
||||
all: z.boolean().optional().describe('Grant ALL common permissions at once (geolocation, notifications, camera, microphone, clipboard, sensors, midi)'),
|
||||
origin: z.string().optional().describe('Origin to grant permissions for (e.g., "https://example.com"). If not specified, grants for all origins.'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
handle: async (context, params, response) => {
|
||||
const browserContext = await context.existingBrowserContext();
|
||||
if (!browserContext)
|
||||
throw new Error('No browser context available. Navigate to a page first.');
|
||||
|
||||
// Determine which permissions to grant
|
||||
let permissionsToGrant: string[];
|
||||
if (params.all) {
|
||||
permissionsToGrant = ALL_PERMISSIONS;
|
||||
} else if (params.permissions && params.permissions.length > 0) {
|
||||
permissionsToGrant = params.permissions;
|
||||
} else {
|
||||
throw new Error('Either specify "permissions" array or set "all: true" to grant all permissions.');
|
||||
}
|
||||
|
||||
const grantOptions = params.origin ? { origin: params.origin } : undefined;
|
||||
|
||||
await browserContext.grantPermissions(permissionsToGrant, grantOptions);
|
||||
|
||||
const scope = params.origin ? `for ${params.origin}` : 'for all origins';
|
||||
const header = params.all ? '✅ Granted ALL permissions' : '✅ Granted permissions';
|
||||
response.addResult(`${header} ${scope}:\n${permissionsToGrant.map(p => ` • ${p}`).join('\n')}`);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Clear all granted permissions.
|
||||
*/
|
||||
const clearPermissions = defineTool({
|
||||
capability: 'core',
|
||||
|
||||
schema: {
|
||||
name: 'browser_clear_permissions',
|
||||
title: 'Clear all browser permissions',
|
||||
description: 'Revoke all previously granted permissions for the current browser context. Sites will need to request permissions again.',
|
||||
inputSchema: z.object({}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
handle: async (context, _params, response) => {
|
||||
const browserContext = await context.existingBrowserContext();
|
||||
if (!browserContext)
|
||||
throw new Error('No browser context available. Navigate to a page first.');
|
||||
|
||||
await browserContext.clearPermissions();
|
||||
|
||||
response.addResult('✅ All permissions have been cleared. Sites will need to request permissions again.');
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Set geolocation at runtime.
|
||||
*/
|
||||
const setGeolocation = defineTool({
|
||||
capability: 'core',
|
||||
|
||||
schema: {
|
||||
name: 'browser_set_geolocation',
|
||||
title: 'Set geolocation at runtime',
|
||||
description: 'Set the browser\'s geolocation at runtime without restarting. Automatically grants geolocation permission.',
|
||||
inputSchema: z.object({
|
||||
latitude: z.number().min(-90).max(90).describe('Latitude coordinate (-90 to 90)'),
|
||||
longitude: z.number().min(-180).max(180).describe('Longitude coordinate (-180 to 180)'),
|
||||
accuracy: z.number().optional().describe('Accuracy in meters (default: 100)'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
handle: async (context, params, response) => {
|
||||
const browserContext = await context.existingBrowserContext();
|
||||
if (!browserContext)
|
||||
throw new Error('No browser context available. Navigate to a page first.');
|
||||
|
||||
// Grant geolocation permission first
|
||||
await browserContext.grantPermissions(['geolocation']);
|
||||
|
||||
// Set the geolocation
|
||||
await browserContext.setGeolocation({
|
||||
latitude: params.latitude,
|
||||
longitude: params.longitude,
|
||||
accuracy: params.accuracy || 100,
|
||||
});
|
||||
|
||||
response.addResult(`✅ Geolocation set to:\n • Latitude: ${params.latitude}\n • Longitude: ${params.longitude}\n • Accuracy: ${params.accuracy || 100}m\n\nGeolocation permission has been automatically granted.`);
|
||||
},
|
||||
});
|
||||
|
||||
export default [
|
||||
configureNotifications,
|
||||
listNotifications,
|
||||
handleNotification,
|
||||
waitForNotification,
|
||||
clearNotifications,
|
||||
grantPermissions,
|
||||
clearPermissions,
|
||||
setGeolocation,
|
||||
];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user