Loading...
Loading...
VSCode extension for Browser DevTools MCP Server enabling AI-driven browser automation, debugging, and testing via Playwright and Model Context Protocol
npx skill4agent add aradotso/devtools-skills browser-devtools-mcp-vscodeSkill by ara.so — Devtools Skills collection.
browser-devtools-mcp# VS Code
code --install-extension serkan-ozal.browser-devtools-mcp-vscode
# Cursor
cursor --install-extension serkan-ozal.browser-devtools-mcp-vscode# VS Code
code --install-extension browser-devtools-mcp-vscode-x.x.x.vsix
# Cursor
cursor --install-extension browser-devtools-mcp-vscode-x.x.x.vsixCtrl+Shift+PCmd+Shift+PbrowserDevtoolsMcp.install.chromiumtruebrowserDevtoolsMcp.install.firefoxfalsebrowserDevtoolsMcp.install.webkitfalseCtrl+,Cmd+,Browser DevTools MCP: Open Settings{
"browserDevtoolsMcp.enable": true,
"browserDevtoolsMcp.telemetry.enable": true,
"browserDevtoolsMcp.platform": "browser" // "browser" or "node"
}{
"browserDevtoolsMcp.browser.headless": true,
"browserDevtoolsMcp.browser.persistent": false,
"browserDevtoolsMcp.browser.userDataDir": "",
"browserDevtoolsMcp.browser.useSystemBrowser": false,
"browserDevtoolsMcp.browser.executablePath": "",
"browserDevtoolsMcp.browser.locale": "en-US"
}{
"browserDevtoolsMcp.browser.cdp.enable": false,
"browserDevtoolsMcp.browser.cdp.endpointUrl": "" // e.g., "http://localhost:9222"
}{
"browserDevtoolsMcp.network.proxy": "", // e.g., "http://proxy.example.com:8080"
"browserDevtoolsMcp.network.bypassProxy": "",
"browserDevtoolsMcp.network.ignoreHTTPSErrors": false
}{
"browserDevtoolsMcp.debug.enable": false,
"browserDevtoolsMcp.debug.screenshots": false,
"browserDevtoolsMcp.debug.traces": false,
"browserDevtoolsMcp.debug.videos": false,
"browserDevtoolsMcp.debug.outputDir": ""
}{
"browserDevtoolsMcp.otel.enable": false,
"browserDevtoolsMcp.otel.exporterUrl": "", // e.g., "http://localhost:4318/v1/traces"
"browserDevtoolsMcp.otel.serviceName": "browser-devtools-mcp",
"browserDevtoolsMcp.otel.propagationHeaderName": "traceparent"
}"Navigate to example.com and take a screenshot"
"Run accessibility audit on the current page"
"Measure Core Web Vitals for https://example.com"
"Click the submit button and capture network requests"
"Mock the /api/users endpoint to return test data"vscode.lm.registerMcpServerDefinitionProvider// Navigate to URL
{
"url": "https://example.com",
"waitUntil": "networkidle" // "load" | "domcontentloaded" | "networkidle"
}// Click element by selector
{
"selector": "button.submit",
"timeout": 30000
}// Fill form input
{
"selector": "input[name='email']",
"value": "test@example.com"
}// Type text with keyboard simulation
{
"selector": "textarea",
"text": "Hello world",
"delay": 100 // ms between keystrokes
}// Select dropdown option
{
"selector": "select[name='country']",
"values": ["US"]
}// Capture screenshot
{
"fullPage": true,
"selector": null, // or specific element selector
"path": "/tmp/screenshot.png" // optional
}// Get accessibility tree
{
"selector": "main" // optional, default entire page
}// Run accessibility audit
{
"includeWarnings": true,
"selector": null
}// Measure Core Web Vitals
{
"url": "https://example.com"
}// Get network request log
{
"filter": {
"url": "/api/*",
"method": "GET",
"status": 200
}
}// Mock API endpoint
{
"pattern": "**/api/users",
"response": {
"status": 200,
"body": { "users": [{"id": 1, "name": "Test User"}] },
"headers": { "Content-Type": "application/json" }
}
}// Remove mock
{
"pattern": "**/api/users"
}// Inspect React component
{
"selector": "div.App"
}// Get full component tree
{}// Non-blocking breakpoint with logging
{
"source": "app.js",
"line": 42,
"condition": "user.id === 123",
"logMessage": "User: {user.name}"
}// Inject console.log
{
"source": "utils.js",
"line": 15,
"message": "Value: {myVariable}"
}// Watch expression value
{
"expression": "this.state.count",
"source": "Counter.jsx"
}// Execute multiple operations
{
"code": `
// Navigate
await callTool('navigate', { url: 'https://example.com' });
// Fill form
await page.fill('input[name="search"]', 'test query');
// Click and wait
await page.click('button[type="submit"]');
await page.waitForLoadState('networkidle');
// Capture screenshot
const screenshot = await callTool('screenshot', { fullPage: true });
return { screenshot };
`
}// AI prompt: "Test the login flow and capture results"
// 1. Navigate to login page
await callTool('navigate', { url: 'https://app.example.com/login' });
// 2. Fill credentials (use environment variables)
await callTool('fill', {
selector: 'input[name="username"]',
value: process.env.TEST_USERNAME
});
await callTool('fill', {
selector: 'input[name="password"]',
value: process.env.TEST_PASSWORD
});
// 3. Submit form
await callTool('click', { selector: 'button[type="submit"]' });
// 4. Wait for navigation
await callTool('wait', { selector: '.dashboard', timeout: 5000 });
// 5. Capture evidence
const screenshot = await callTool('screenshot', { fullPage: true });
// 6. Run accessibility audit
const audit = await callTool('accessibility_audit', {});// AI prompt: "Measure performance of the homepage"
const vitals = await callTool('web_vitals', {
url: 'https://example.com'
});
// vitals contains: LCP, INP, CLS, TTFB, FCP
console.log(`LCP: ${vitals.LCP}ms`);
console.log(`CLS: ${vitals.CLS}`);// AI prompt: "Mock the user API and test the profile page"
// 1. Set up mock
await callTool('mock_route', {
pattern: '**/api/user/profile',
response: {
status: 200,
body: {
id: 1,
name: 'Test User',
email: 'test@example.com'
}
}
});
// 2. Navigate and test
await callTool('navigate', { url: 'https://app.example.com/profile' });
// 3. Verify UI
await callTool('screenshot', { selector: '.profile-card' });
// 4. Clean up
await callTool('unmock_route', { pattern: '**/api/user/profile' });// AI prompt: "Debug the checkout flow without stopping execution"
// Set tracepoint at critical function
await callTool('set_tracepoint', {
source: 'checkout.js',
line: 78,
condition: 'cart.total > 1000',
logMessage: 'High value cart: {cart.total}, items: {cart.items.length}'
});
// Watch state changes
await callTool('watch_expression', {
expression: 'this.state.checkoutStep',
source: 'CheckoutComponent.jsx'
});
// Execute checkout flow
await callTool('navigate', { url: 'https://shop.example.com/checkout' });
// ... interact with page// AI prompt: "Inspect the React component structure of the dashboard"
// Get full component tree
const tree = await callTool('react_get_component_tree', {});
// Inspect specific component
const component = await callTool('react_inspect_element', {
selector: 'div[data-testid="dashboard"]'
});
// component contains: props, state, hooks, children// AI prompt: "Monitor API calls during user signup"
// Navigate to signup
await callTool('navigate', { url: 'https://app.example.com/signup' });
// Fill and submit form
await callTool('fill', { selector: 'input[name="email"]', value: 'test@example.com' });
await callTool('click', { selector: 'button.signup' });
// Get network requests
const requests = await callTool('network_requests', {
filter: {
url: '/api/*',
method: 'POST'
}
});
// Analyze response times and status codes
requests.forEach(req => {
console.log(`${req.method} ${req.url}: ${req.status} (${req.duration}ms)`);
});// AI prompt: "Run complete E2E test with multiple assertions"
const result = await callTool('execute', {
code: `
// Navigate to app
await callTool('navigate', { url: 'https://app.example.com' });
// Check accessibility
const audit = await callTool('accessibility_audit', { includeWarnings: false });
if (audit.violations.length > 0) {
throw new Error('Accessibility violations found');
}
// Measure performance
const vitals = await callTool('web_vitals', { url: 'https://app.example.com' });
if (vitals.LCP > 2500) {
console.warn('LCP exceeds threshold');
}
// Interact with UI
await page.click('button.start-tour');
await page.waitForSelector('.tour-step-1');
// Capture state
const screenshot = await callTool('screenshot', { fullPage: true });
return {
audit: audit.violations.length === 0,
performance: vitals,
screenshot
};
`
});{
"browserDevtoolsMcp.browser.useSystemBrowser": true
}{
"browserDevtoolsMcp.browser.executablePath": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
}export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
code # or cursor{
"browserDevtoolsMcp.network.proxy": "http://proxy.company.com:8080"
}npx playwright install chromium{
"browserDevtoolsMcp.enable": true
}{
"browserDevtoolsMcp.browser.headless": false
}{
"browserDevtoolsMcp.network.ignoreHTTPSErrors": true
}{
"browserDevtoolsMcp.browser.persistent": true,
"browserDevtoolsMcp.browser.userDataDir": "/path/to/userdata"
}await callTool('click', {
selector: 'button',
timeout: 60000 // 60 seconds
});{
"browserDevtoolsMcp.debug.screenshots": false,
"browserDevtoolsMcp.debug.videos": false
}{
"browserDevtoolsMcp.telemetry.enable": false
}export TELEMETRY_ENABLE=false~/.browser-devtools-mcp/config.json{
"telemetryEnabled": false
}{
"browserDevtoolsMcp.otel.enable": true,
"browserDevtoolsMcp.otel.exporterUrl": "http://localhost:4318/v1/traces",
"browserDevtoolsMcp.otel.serviceName": "browser-automation",
"browserDevtoolsMcp.otel.propagationHeaderName": "traceparent"
}{
"browserDevtoolsMcp.browser.persistent": true,
"browserDevtoolsMcp.browser.userDataDir": "${workspaceFolder}/.browser-data"
}{
"browserDevtoolsMcp.browser.cdp.enable": true,
"browserDevtoolsMcp.browser.cdp.endpointUrl": "http://localhost:9222"
}google-chrome --remote-debugging-port=9222{
"browserDevtoolsMcp.browser.locale": "tr-TR"
}await callTool('fill', {
selector: 'input[name="apiKey"]',
value: process.env.API_KEY
});{
"browserDevtoolsMcp.debug.enable": true,
"browserDevtoolsMcp.debug.outputDir": "${workspaceFolder}/debug-output"
}executepagemock_route