mcpField
C
chrome-devtools-mcp

chrome-devtools-mcp

github.com/gsmlg-dev测试与质量040 次安装3 周前更新
代码仓库

关于 chrome-devtools-mcp

chrome-devtools-mcp 是用于通过 Chrome DevTools 操作和检查浏览器的 MCP 服务,面向浏览器自动化与测试工作。它提供页面快照、交互、脚本执行、截图及性能和无障碍检查,并可选启用扩展和内存工具。

主要功能

  1. 01导航并等待页面加载
  2. 02读取页面结构并交互
  3. 03执行脚本检查页面状态
  4. 04截取视口截图
  5. 05检查性能、布局与无障碍问题
  6. 06可选启用扩展和内存工具

适用场景

  1. 01自动化网页操作与数据读取
  2. 02检查页面错误和网络失败
  3. 03测试不同视口下的响应式布局
  4. 04验证浏览器扩展的页面行为

MCP 相关

它作为 MCP 服务向 MCP 客户端提供 Chrome 浏览器控制与检查工具。客户端可按页面 ID 定位页面,并通过配置参数启用扩展或内存相关工具。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gsmlg-dev/code-agent --skill chrome-devtools-mcp

安装后在 Claude Code 中输入/chrome-devtools-mcp确认已加载。

详细介绍

核心概念

浏览器生命周期:首次调用工具时,浏览器会使用持久化的 Chrome 配置文件自动启动。通过 MCP 服务配置中的 CLI 参数进行设置:npx chrome-devtools-mcp@latest --help。

提供以下标志即可启用其他工具:

  • 如需扩展工具,请使用 --categoryExtensions 标志。
  • 如需内存工具,请使用 --memoryDebugging 标志。

页面定位:页面范围的工具需要 pageId 参数来定位特定页面。使用 list_pages 查看可用页面及其 ID(例如 pageId: 1),或者使用通过 new_page 创建页面时返回的 ID。 注意:使用 evaluate_script 时,定位页面必须提供 pageId。不过,启用 --categoryExtensions 后,pageId 是可选的,因此可以改为传入 serviceWorkerId,在扩展后台服务工作线程中执行操作。

元素交互:使用 take_snapshot 获取页面结构及元素 uid。每个元素都有用于交互的唯一 uid。如果找不到某个元素,请重新获取快照——该元素可能已被移除,或者页面可能已更改。

工作流模式

与页面交互前
  1. 导航:navigate_page 或 new_page
  2. 等待:如果知道要查找什么,请使用 wait_for 确保内容已加载。
  3. 获取快照:使用 take_snapshot 和 pageId 了解页面结构
  4. 交互:使用快照中的元素 uid 执行 click、fill 等操作,并传入相应的 pageId。
高效获取数据
  • 对于大型输出(屏幕截图、快照、跟踪记录),使用 filePath 参数
  • 使用分页(pageIdx、pageSize)和筛选(types)来减少数据量
  • 除非需要更新后的页面状态,否则在输入操作中设置 includeSnapshot: false
工具选择
  • 自动化/交互:take_snapshot(基于文本,速度更快,更适合自动化)
  • 视觉检查:take_screenshot(用户需要查看视觉状态时)
  • 更多详情:使用 evaluate_script 获取无障碍树中没有的数据
并行执行

可以并行发送多个工具调用,但需保持正确顺序:导航 → 等待 → 快照 → 交互。

测试扩展

扩展工具(install_extension、list_extensions 等)仅在 MCP 服务使用 --categoryExtensions 标志启动时可用。如果这些工具不可用,请停止操作,并要求用户更新 MCP 服务配置并重启 MCP 服务(或 AI 客户端)。

  1. 安装:使用 install_extension 并提供已解压扩展的路径。
  2. 识别:从响应中获取扩展 ID,或调用 list_extensions 获取。
  3. 触发操作:如果适用,使用 trigger_extension_action 打开弹出窗口或侧边面板。
  4. 验证服务工作线程:使用 evaluate_script 和 serviceWorkerId(省略 pageId 和 args)检查扩展状态或触发后台操作。在页面中执行时,传入 pageId(省略 serviceWorkerId)。
  5. 验证页面行为:导航至扩展会运行的页面,并使用 take_snapshot 检查内容脚本是否注入元素,或是否正确修改了页面。

故障排除

如果 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 使用方法

重要限制:屏幕截图尺寸上限

API 提交内容的任一尺寸上限为 8000px。整页屏幕截图经常会超出此限制。

解决方案:默认始终仅截取视口
// ✓ 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 })
需要整页屏幕截图时

先检查页面高度:

const height = execute_script('return document.documentElement.scrollHeight')
if (height > 8000) {
  take_screenshot({ fullPage: false, path: './screenshot.png' })
} else {
  take_screenshot({ fullPage: true })
}

替代方案:通过滚动截取多张视口屏幕截图:

take_screenshot({ fullPage: false, path: './top.png' })
execute_script('window.scrollBy(0, window.innerHeight)')
take_screenshot({ fullPage: false, path: './middle.png' })

导航与计时

导航后务必等待,以便 JS 执行和页面渲染:

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();
  });
`)

错误检测模式

控制台错误
const errors = execute_script(`
  return performance.getEntriesByType('navigation')[0].type === 'reload'
    ? []
    : (window.__consoleErrors || []);
`)
网络故障
const failed = execute_script(`
  return performance.getEntriesByType('resource')
    .filter(r => r.transferSize === 0 && r.duration > 0)
    .map(r => ({ url: r.name, duration: r.duration }));
`)
布局问题
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;
`)

响应式测试

高效测试多个视口:

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`
  });
}

组件状态测试

无需用户交互即可测试交互状态:

// 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' });

性能指标

收集 Web Vitals 和性能数据:

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)
  };
`);

无障碍检查

基本无障碍验证:

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;
`);

标准审计工作流

使用此模式系统地审计页面:

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
  };
}

错误处理

截图尺寸错误

如果使用 fullPage: false 后仍遇到尺寸错误,页面可能使用了特殊的视口设置。请改为保存到文件:

try {
  take_screenshot({ fullPage: false });
} catch (error) {
  if (error.includes('8000 pixels')) {
    take_screenshot({ fullPage: false, path: './fallback.png' });
  }
}
导航超时
try {
  navigate(url);
  wait(5000);
} catch (error) {
  // Log failure and continue
  console.log(`Failed to load: ${url}`);
}
元素缺失
const exists = execute_script(`return !!document.querySelector('#target')`);
if (!exists) {
  take_screenshot({ fullPage: false, path: './missing-element.png' });
  // Handle accordingly
}

重要提示

  1. 始终默认使用 fullPage: false,以避免尺寸错误
  2. 尽可能将截图保存到文件系统,而不是通过 API 提交
  3. 导航后等待,以便 JS 执行(至少等待 1000ms)
  4. 使用 execute_script 查询 DOM,而不是使用脆弱的基于选择器的方法
  5. 对响应式应用测试多个视口
  6. 尽早采集证据——在元素状态发生变化前截图
  7. 先检查页面尺寸,再决定截图策略

其他工具类别

提供以下标志即可启用其他工具:

  • 要启用扩展工具,请使用 --categoryExtensions 标志。
  • 要启用内存工具,请使用 --memoryDebugging 标志。
测试扩展

继续操作前请注意:扩展工具(install_extension、list_extensions 等)仅在 MCP 服务启动时使用 --categoryExtensions 标志才可用。如果工具列表中没有这些工具,请停止操作,并要求用户更新其 MCP 服务配置:

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "npx",
      "args": ["chrome-devtools-mcp@latest", "--categoryExtensions"]
    }
  }
}

更新后,用户必须重启 MCP 服务(或其 AI 客户端),更改才能生效。

  1. 安装:使用 install_extension 并指定已解压扩展的路径。
  2. 识别:从响应中获取扩展 ID,或调用 list_extensions 获取。
  3. 触发操作:在适用时,使用 trigger_extension_action 打开弹出窗口或侧边栏。
  4. 验证 Service Worker:使用 evaluate_script 和 serviceWorkerId 检查扩展状态或触发后台操作。
  5. 验证页面行为:导航到扩展运行的页面,并使用 take_snapshot 检查内容脚本是否注入了元素,或是否正确修改了页面。

评论

支持 Markdown