chrome-devtools-mcp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Core 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 --help
.
Page selection: Tools operate on the currently selected page. Use
list_pages
to see available pages, then
select_page
to switch context.
Element interaction: Use
take_snapshot
to get page structure with element
uid
s. Each element has a unique
uid
for interaction. If an element isn't found, take a fresh snapshot - the element may have been removed or the page changed.
浏览器生命周期:首次调用工具时,浏览器会使用持久化Chrome配置文件自动启动。可通过MCP服务器配置中的CLI参数进行设置:
npx chrome-devtools-mcp@latest --help
页面选择:工具在当前选中的页面上运行。使用
list_pages
查看可用页面,再通过
select_page
切换上下文。
元素交互:使用
take_snapshot
获取包含元素
uid
的页面结构。每个元素都有唯一的
uid
用于交互。如果未找到元素,请重新获取快照——该元素可能已被移除或页面发生了变化。

Workflow Patterns

工作流模式

Before interacting with a page

与页面交互前

  1. Navigate:
    navigate_page
    or
    new_page
  2. Wait:
    wait_for
    to ensure content is loaded if you know what you look for.
  3. Snapshot:
    take_snapshot
    to understand page structure
  4. Interact: Use element
    uid
    s from snapshot for
    click
    ,
    fill
    , etc.
  1. 导航:使用
    navigate_page
    new_page
  2. 等待:若知晓目标内容,使用
    wait_for
    确保内容加载完成
  3. 快照:使用
    take_snapshot
    了解页面结构
  4. 交互:使用快照中的元素
    uid
    执行
    click
    fill
    等操作

Efficient data retrieval

高效数据检索

  • Use
    filePath
    parameter for large outputs (screenshots, snapshots, traces)
  • Use pagination (
    pageIdx
    ,
    pageSize
    ) and filtering (
    types
    ) to minimize data
  • Set
    includeSnapshot: false
    on input actions unless you need updated page state
  • 针对大尺寸输出(截图、快照、追踪数据)使用
    filePath
    参数
  • 使用分页(
    pageIdx
    pageSize
    )和过滤(
    types
    )功能减少数据量
  • 除非需要更新页面状态,否则在输入操作中设置
    includeSnapshot: false

Tool selection

工具选择

  • Automation/interaction:
    take_snapshot
    (text-based, faster, better for automation)
  • Visual inspection:
    take_screenshot
    (when user needs to see visual state)
  • Additional details:
    evaluate_script
    for data not in accessibility tree
  • 自动化/交互
    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
chrome-devtools-mcp
is insufficient, guide users to use Chrome DevTools UI:
If there are errors launching
chrome-devtools-mcp
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 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
fullPage: false
, the page may be using unusual viewport settings. Save to file instead:
javascript
try {
  take_screenshot({ fullPage: false });
} catch (error) {
  if (error.includes('8000 pixels')) {
    take_screenshot({ fullPage: false, path: './fallback.png' });
  }
}
若已使用
fullPage: false
仍遇到尺寸错误,页面可能使用了特殊视口设置。请改为保存至文件:
javascript
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

关键提醒

  1. Always default to
    fullPage: false
    to avoid dimension errors
  2. Save screenshots to filesystem when possible instead of API submission
  3. Wait after navigation to allow JS execution (minimum 1000ms)
  4. Use execute_script for DOM queries instead of brittle selector-based approaches
  5. Test multiple viewports for responsive applications
  6. Capture evidence early - take screenshots before elements change state
  7. Check page dimensions before deciding on screenshot strategy
  1. 默认始终使用
    fullPage: false
    ,以避免尺寸错误
  2. 尽可能将截图保存至文件系统,而非通过API提交
  3. 导航后等待,以允许JS执行(最短1000ms)
  4. 使用execute_script进行DOM查询,而非脆弱的选择器方式
  5. 针对响应式应用测试多个视口
  6. 尽早捕获证据——在元素状态变化前截图
  7. 在决定截图策略前检查页面尺寸