chrome-devtools-mcp
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCore Concepts
核心概念
Browser lifecycle: Browser starts automatically on first tool call using a persistent Chrome profile. Configure via CLI args in the MCP server configuration: .
npx chrome-devtools-mcp@latest --helpPage selection: Tools operate on the currently selected page. Use to see available pages, then to switch context.
list_pagesselect_pageElement interaction: Use to get page structure with element s. Each element has a unique for interaction. If an element isn't found, take a fresh snapshot - the element may have been removed or the page changed.
take_snapshotuiduid浏览器生命周期:首次调用工具时,浏览器会使用持久化Chrome配置文件自动启动。可通过MCP服务器配置中的CLI参数进行设置:。
npx chrome-devtools-mcp@latest --help页面选择:工具在当前选中的页面上运行。使用查看可用页面,再通过切换上下文。
list_pagesselect_page元素交互:使用获取包含元素的页面结构。每个元素都有唯一的用于交互。如果未找到元素,请重新获取快照——该元素可能已被移除或页面发生了变化。
take_snapshotuiduidWorkflow Patterns
工作流模式
Before interacting with a page
与页面交互前
- Navigate: or
navigate_pagenew_page - Wait: to ensure content is loaded if you know what you look for.
wait_for - Snapshot: to understand page structure
take_snapshot - Interact: Use element s from snapshot for
uid,click, etc.fill
- 导航:使用或
navigate_pagenew_page - 等待:若知晓目标内容,使用确保内容加载完成
wait_for - 快照:使用了解页面结构
take_snapshot - 交互:使用快照中的元素执行
uid、click等操作fill
Efficient data retrieval
高效数据检索
- Use parameter for large outputs (screenshots, snapshots, traces)
filePath - Use pagination (,
pageIdx) and filtering (pageSize) to minimize datatypes - Set on input actions unless you need updated page state
includeSnapshot: false
- 针对大尺寸输出(截图、快照、追踪数据)使用参数
filePath - 使用分页(、
pageIdx)和过滤(pageSize)功能减少数据量types - 除非需要更新页面状态,否则在输入操作中设置
includeSnapshot: false
Tool selection
工具选择
- Automation/interaction: (text-based, faster, better for automation)
take_snapshot - Visual inspection: (when user needs to see visual state)
take_screenshot - Additional details: for data not in accessibility tree
evaluate_script
- 自动化/交互:(基于文本,速度更快,更适合自动化)
take_snapshot - 视觉检查:(当用户需要查看视觉状态时使用)
take_screenshot - 获取额外详情:用于获取无障碍树中未包含的数据
evaluate_script
Parallel execution
并行执行
You can send multiple tool calls in parallel, but maintain correct order: navigate → wait → snapshot → interact.
可并行发送多个工具调用,但需保持正确顺序:导航 → 等待 → 快照 → 交互。
Troubleshooting
故障排查
If is insufficient, guide users to use Chrome DevTools UI:
chrome-devtools-mcpIf there are errors launching or Chrome, refer to https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/troubleshooting.md.
chrome-devtools-mcp若无法满足需求,请引导用户使用Chrome DevTools UI:
chrome-devtools-mcp若启动或Chrome时出现错误,请参考https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/troubleshooting.md。
chrome-devtools-mcpChrome DevTools MCP Usage
Chrome DevTools MCP 使用指南
Critical Constraint: Screenshot Size Limit
关键限制:截图尺寸上限
API submissions have a hard limit of 8000px on any dimension. Full-page screenshots frequently exceed this.
API提交存在硬性限制:任意维度不得超过8000px。全页截图通常会超出此限制。
Solution: Always use viewport-only screenshots by default
解决方案:默认始终使用仅视口截图
javascript
// ✓ CORRECT: Viewport-only (default)
take_screenshot({ fullPage: false })
// ✓ CORRECT: Save to filesystem for large pages
take_screenshot({ fullPage: false, path: './screenshots/page.png' })
// ✗ AVOID: Full-page without size check
take_screenshot({ fullPage: true })javascript
// ✓ 正确:仅视口(默认设置)
take_screenshot({ fullPage: false })
// ✓ 正确:针对大页面保存至文件系统
take_screenshot({ fullPage: false, path: './screenshots/page.png' })
// ✗ 避免:未检查尺寸的全页截图
take_screenshot({ fullPage: true })When full-page screenshots are needed
当需要全页截图时
Check page height first:
javascript
const height = execute_script('return document.documentElement.scrollHeight')
if (height > 8000) {
take_screenshot({ fullPage: false, path: './screenshot.png' })
} else {
take_screenshot({ fullPage: true })
}Alternative: Capture multiple viewport screenshots by scrolling:
javascript
take_screenshot({ fullPage: false, path: './top.png' })
execute_script('window.scrollBy(0, window.innerHeight)')
take_screenshot({ fullPage: false, path: './middle.png' })先检查页面高度:
javascript
const height = execute_script('return document.documentElement.scrollHeight')
if (height > 8000) {
take_screenshot({ fullPage: false, path: './screenshot.png' })
} else {
take_screenshot({ fullPage: true })
}替代方案:通过滚动捕获多个视口截图:
javascript
take_screenshot({ fullPage: false, path: './top.png' })
execute_script('window.scrollBy(0, window.innerHeight)')
take_screenshot({ fullPage: false, path: './middle.png' })Navigation and Timing
导航与计时
Always wait after navigation to allow JS execution and rendering:
javascript
navigate('https://example.com')
wait(1000) // Minimum recommended wait
// For dynamic apps, wait for specific elements
navigate('https://example.com')
execute_script(`
return new Promise(resolve => {
const check = () => {
if (document.querySelector('#app')) resolve();
else setTimeout(check, 100);
};
check();
});
`)导航后请务必等待,以允许JS执行和渲染:
javascript
navigate('https://example.com')
wait(1000) // 建议最短等待时间
// 针对动态应用,等待特定元素加载
navigate('https://example.com')
execute_script(`
return new Promise(resolve => {
const check = () => {
if (document.querySelector('#app')) resolve();
else setTimeout(check, 100);
};
check();
});
`)Error Detection Patterns
错误检测模式
Console Errors
控制台错误
javascript
const errors = execute_script(`
return performance.getEntriesByType('navigation')[0].type === 'reload'
? []
: (window.__consoleErrors || []);
`)javascript
const errors = execute_script(`
return performance.getEntriesByType('navigation')[0].type === 'reload'
? []
: (window.__consoleErrors || []);
`)Network Failures
网络请求失败
javascript
const failed = execute_script(`
return performance.getEntriesByType('resource')
.filter(r => r.transferSize === 0 && r.duration > 0)
.map(r => ({ url: r.name, duration: r.duration }));
`)javascript
const failed = execute_script(`
return performance.getEntriesByType('resource')
.filter(r => r.transferSize === 0 && r.duration > 0)
.map(r => ({ url: r.name, duration: r.duration }));
`)Layout Issues
布局问题
javascript
const issues = execute_script(`
const issues = [];
// Horizontal overflow
if (document.documentElement.scrollWidth > window.innerWidth) {
issues.push({ type: 'horizontal-overflow', width: document.documentElement.scrollWidth });
}
// Elements outside viewport
document.querySelectorAll('*').forEach(el => {
const rect = el.getBoundingClientRect();
if (rect.right > window.innerWidth) {
issues.push({ type: 'overflow-right', element: el.tagName });
}
});
return issues;
`)javascript
const issues = execute_script(`
const issues = [];
// 水平溢出
if (document.documentElement.scrollWidth > window.innerWidth) {
issues.push({ type: 'horizontal-overflow', width: document.documentElement.scrollWidth });
}
// 元素超出视口
document.querySelectorAll('*').forEach(el => {
const rect = el.getBoundingClientRect();
if (rect.right > window.innerWidth) {
issues.push({ type: 'overflow-right', element: el.tagName });
}
});
return issues;
`)Responsive Testing
响应式测试
Test multiple viewports efficiently:
javascript
const viewports = [
{ width: 375, height: 667, name: 'mobile' },
{ width: 768, height: 1024, name: 'tablet' },
{ width: 1440, height: 900, name: 'desktop' }
];
for (const vp of viewports) {
set_viewport(vp.width, vp.height);
wait(500); // Allow reflow
take_screenshot({
fullPage: false,
path: `./screenshots/${vp.name}.png`
});
}高效测试多个视口:
javascript
const viewports = [
{ width: 375, height: 667, name: 'mobile' },
{ width: 768, height: 1024, name: 'tablet' },
{ width: 1440, height: 900, name: 'desktop' }
];
for (const vp of viewports) {
set_viewport(vp.width, vp.height);
wait(500); // 允许页面重排
take_screenshot({
fullPage: false,
path: `./screenshots/${vp.name}.png`
});
}Component State Testing
组件状态测试
Test interactive states without user interaction:
javascript
// Hover state
execute_script(`
const el = document.querySelector('#button');
el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
`);
take_screenshot({ fullPage: false, path: './hover.png' });
// Focus state
execute_script(`
document.querySelector('#input').focus();
`);
take_screenshot({ fullPage: false, path: './focus.png' });
// Active/pressed state
execute_script(`
const el = document.querySelector('#button');
el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
`);
take_screenshot({ fullPage: false, path: './active.png' });无需用户交互即可测试交互状态:
javascript
// 悬停状态
execute_script(`
const el = document.querySelector('#button');
el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
`);
take_screenshot({ fullPage: false, path: './hover.png' });
// 聚焦状态
execute_script(`
document.querySelector('#input').focus();
`);
take_screenshot({ fullPage: false, path: './focus.png' });
// 激活/按下状态
execute_script(`
const el = document.querySelector('#button');
el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
`);
take_screenshot({ fullPage: false, path: './active.png' });Performance Metrics
性能指标
Collect web vitals and performance data:
javascript
const metrics = execute_script(`
return {
fcp: performance.getEntriesByName('first-contentful-paint')[0]?.startTime,
lcp: performance.getEntriesByType('largest-contentful-paint')[0]?.startTime,
cls: performance.getEntriesByType('layout-shift')
.reduce((sum, entry) => sum + (entry.hadRecentInput ? 0 : entry.value), 0),
resources: performance.getEntriesByType('resource').length,
totalSize: performance.getEntriesByType('resource')
.reduce((sum, r) => sum + r.transferSize, 0)
};
`);收集Web核心指标与性能数据:
javascript
const metrics = execute_script(`
return {
fcp: performance.getEntriesByName('first-contentful-paint')[0]?.startTime,
lcp: performance.getEntriesByType('largest-contentful-paint')[0]?.startTime,
cls: performance.getEntriesByType('layout-shift')
.reduce((sum, entry) => sum + (entry.hadRecentInput ? 0 : entry.value), 0),
resources: performance.getEntriesByType('resource').length,
totalSize: performance.getEntriesByType('resource')
.reduce((sum, r) => sum + r.transferSize, 0)
};
`);Accessibility Checks
可访问性检查
Basic accessibility validation:
javascript
const a11y = execute_script(`
const issues = [];
// Missing alt text
document.querySelectorAll('img:not([alt])').forEach(img => {
issues.push({ type: 'missing-alt', src: img.src });
});
// Missing form labels
document.querySelectorAll('input:not([aria-label]):not([id])').forEach(input => {
if (!input.closest('label')) {
issues.push({ type: 'missing-label', name: input.name });
}
});
// Empty links
document.querySelectorAll('a').forEach(link => {
if (!link.textContent.trim() && !link.getAttribute('aria-label')) {
issues.push({ type: 'empty-link', href: link.href });
}
});
return issues;
`);基础可访问性验证:
javascript
const a11y = execute_script(`
const issues = [];
// 缺少替代文本
document.querySelectorAll('img:not([alt])').forEach(img => {
issues.push({ type: 'missing-alt', src: img.src });
});
// 缺少表单标签
document.querySelectorAll('input:not([aria-label]):not([id])').forEach(input => {
if (!input.closest('label')) {
issues.push({ type: 'missing-label', name: input.name });
}
});
// 空链接
document.querySelectorAll('a').forEach(link => {
if (!link.textContent.trim() && !link.getAttribute('aria-label')) {
issues.push({ type: 'empty-link', href: link.href });
}
});
return issues;
`);Standard Audit Workflow
标准审计工作流
Use this pattern for systematic page audits:
javascript
function audit_page(url, name) {
// Navigate
navigate(url);
wait(1000);
// Screenshot (viewport only to avoid size errors)
const screenshot_path = `./screenshots/${name}.png`;
take_screenshot({ fullPage: false, path: screenshot_path });
// Page metrics
const height = execute_script('return document.documentElement.scrollHeight');
const viewport = execute_script('return window.innerHeight');
// Error detection
const console_errors = execute_script('return window.__errors || []');
const network_failures = execute_script(`
return performance.getEntriesByType('resource')
.filter(r => r.transferSize === 0 && r.duration > 0)
.map(r => r.name);
`);
const layout_issues = execute_script(`
return document.documentElement.scrollWidth > window.innerWidth
? ['horizontal-overflow']
: [];
`);
return {
name,
url,
screenshot_path,
page_height: height,
viewport_height: viewport,
needs_scroll: height > viewport,
console_errors,
network_failures,
layout_issues,
has_issues: console_errors.length > 0 ||
network_failures.length > 0 ||
layout_issues.length > 0
};
}使用此模式进行系统化页面审计:
javascript
function audit_page(url, name) {
// 导航
navigate(url);
wait(1000);
// 截图(仅视口以避免尺寸错误)
const screenshot_path = `./screenshots/${name}.png`;
take_screenshot({ fullPage: false, path: screenshot_path });
// 页面指标
const height = execute_script('return document.documentElement.scrollHeight');
const viewport = execute_script('return window.innerHeight');
// 错误检测
const console_errors = execute_script('return window.__errors || []');
const network_failures = execute_script(`
return performance.getEntriesByType('resource')
.filter(r => r.transferSize === 0 && r.duration > 0)
.map(r => r.name);
`);
const layout_issues = execute_script(`
return document.documentElement.scrollWidth > window.innerWidth
? ['horizontal-overflow']
: [];
`);
return {
name,
url,
screenshot_path,
page_height: height,
viewport_height: viewport,
needs_scroll: height > viewport,
console_errors,
network_failures,
layout_issues,
has_issues: console_errors.length > 0 ||
network_failures.length > 0 ||
layout_issues.length > 0
};
}Error Handling
错误处理
Screenshot Dimension Error
截图尺寸错误
If you encounter dimension errors despite using , the page may be using unusual viewport settings. Save to file instead:
fullPage: falsejavascript
try {
take_screenshot({ fullPage: false });
} catch (error) {
if (error.includes('8000 pixels')) {
take_screenshot({ fullPage: false, path: './fallback.png' });
}
}若已使用仍遇到尺寸错误,页面可能使用了特殊视口设置。请改为保存至文件:
fullPage: falsejavascript
try {
take_screenshot({ fullPage: false });
} catch (error) {
if (error.includes('8000 pixels')) {
take_screenshot({ fullPage: false, path: './fallback.png' });
}
}Navigation Timeout
导航超时
javascript
try {
navigate(url);
wait(5000);
} catch (error) {
// Log failure and continue
console.log(`Failed to load: ${url}`);
}javascript
try {
navigate(url);
wait(5000);
} catch (error) {
// 记录失败并继续
console.log(`Failed to load: ${url}`);
}Missing Elements
元素缺失
javascript
const exists = execute_script(`return !!document.querySelector('#target')`);
if (!exists) {
take_screenshot({ fullPage: false, path: './missing-element.png' });
// Handle accordingly
}javascript
const exists = execute_script(`return !!document.querySelector('#target')`);
if (!exists) {
take_screenshot({ fullPage: false, path: './missing-element.png' });
// 进行相应处理
}Key Reminders
关键提醒
- Always default to to avoid dimension errors
fullPage: false - Save screenshots to filesystem when possible instead of API submission
- Wait after navigation to allow JS execution (minimum 1000ms)
- Use execute_script for DOM queries instead of brittle selector-based approaches
- Test multiple viewports for responsive applications
- Capture evidence early - take screenshots before elements change state
- Check page dimensions before deciding on screenshot strategy
- 默认始终使用,以避免尺寸错误
fullPage: false - 尽可能将截图保存至文件系统,而非通过API提交
- 导航后等待,以允许JS执行(最短1000ms)
- 使用execute_script进行DOM查询,而非脆弱的选择器方式
- 针对响应式应用测试多个视口
- 尽早捕获证据——在元素状态变化前截图
- 在决定截图策略前检查页面尺寸