| name | chrome-devtools-mcp |
| description | Chrome DevTools MCP server — agent-controlled browser via MCP. take_snapshot (accessibility tree + uids), click/fill/navigate automation, screenshot, evaluate_script, console/network inspection. 41k+ stars. Sources: ChromeDevTools/chrome-devtools-mcp (Apache-2.0). |
/chrome-devtools-mcp
When to Use
- AI agent needs to control a live Chrome browser (click, fill forms, navigate)
- Debugging a web page: console errors, network requests, accessibility tree
- Performance analysis: LCP traces, Lighthouse audits (use [[chrome-devtools-lcp-debug]])
- Memory leak investigation (use [[chrome-devtools-memory-leak]])
Do NOT use for
- Headless scraping at scale (use Playwright/Puppeteer directly)
--slim mode sessions (reduced tool set — see slim-tool-reference)
- Firefox or Safari (only Chrome / Chrome for Testing officially supported)
MCP config
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"]
}
}
}
{ "args": ["-y", "chrome-devtools-mcp@latest", "--slim", "--headless"] }
Core workflow pattern
1. navigate_page → go to URL
2. wait_for → wait for selector/network-idle if needed
3. take_snapshot → get accessibility tree with element uids
4. click/fill → interact using uid from snapshot
5. take_snapshot → verify updated state (only when needed)
await mcp.call("navigate_page", { url: "https://example.com/login" });
const snapshot = await mcp.call("take_snapshot", {});
await mcp.call("fill_form", {
elements: [
{ uid: "a1b2", value: "user@example.com" },
{ uid: "c3d4", value: "password123" },
{ uid: "e5f6", value: "true" },
]
});
await mcp.call("click", { uid: "g7h8" });
await mcp.call("wait_for", { selector: "[data-testid='dashboard']" });
Tool selection guide
Goal Tool
──────────────────────────── ─────────────────────────────────────────────
Understand page structure take_snapshot (accessibility tree, faster)
See visual state take_screenshot (when human needs to see)
Get extra data evaluate_script (data not in accessibility tree)
Fill multiple form fields fill_form (one call > multiple fill calls)
Check errors list_console_messages (types: ["error"])
Check network list_network_requests / get_network_request
Run Lighthouse audit lighthouse_audit
Efficient data retrieval patterns
await mcp.call("take_screenshot", { filePath: "/tmp/screenshot.png" });
await mcp.call("take_snapshot", { filePath: "/tmp/snapshot.json" });
await mcp.call("list_console_messages", {
types: ["error", "warning"],
pageSize: 20,
pageIdx: 0,
includePreservedMessages: true,
});
await mcp.call("list_network_requests", {
urlFilter: "/api/",
pageSize: 10,
});
await mcp.call("evaluate_script", {
script: "JSON.stringify(window.__APP_STATE__)"
});
Parallel tool calls
Rules:
1. navigate → wait → snapshot → interact (must be sequential — each depends on prior)
2. Independent reads can run in parallel:
[list_console_messages, list_network_requests] — parallel OK
[take_screenshot, evaluate_script] — parallel OK
3. NEVER parallelize writes (click, fill) — order matters
Extension testing workflow
const { extensionId } = await mcp.call("install_extension", {
path: "/path/to/extension"
});
await mcp.call("trigger_extension_action", { extensionId });
await mcp.call("evaluate_script", {
serviceWorkerId: extensionId,
script: "self.registration.scope"
});
await mcp.call("navigate_page", { url: "https://example.com" });
const snapshot = await mcp.call("take_snapshot", {});
Anti-Fake-Pass Checklist
❌ Taking a screenshot when take_snapshot suffices → screenshot costs more tokens; use for visual-only needs
❌ Multiple fill calls instead of fill_form → 3-5x more tool calls for the same form
❌ Reading snapshot after every action → only re-snapshot when you need the updated state
❌ Not using filePath for large outputs → raw screenshot/trace data floods context
❌ Assuming Chrome is already open → browser starts automatically on first tool call; no pre-launch needed
❌ Using slim mode without knowing its limitations → slim mode lacks performance/memory/extension tools