浏览器自动化服务器

一个基于Playwright的MCP服务器,提供多浏览器支持、自动化测试、辅助功能检查等浏览器自动化功能。

  • by j0hanz
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 j0hanz/playwright-mcp

使用说明

MCP编剧服务器

全面 模型上下文协议(MCP)服务器 使用Playwright实现浏览器自动化。该服务器使AI助手能够通过MCP协议控制浏览器,为web测试、可访问性审计和浏览器自动化提供强大的工具。

特性

  • 🌐 多浏览器支持 -Chromium、Firefox和WebKit
  • 🔧 50+浏览器自动化工具 -导航、交互、断言、屏幕截图
  • ♿ 可访问性测试 -内置斧头核心集成WCAG合规性检查
  • 🔒 会话管理 -具有速率限制的孤立浏览器上下文
  • 📸 目视检测 -屏幕截图、视频录制和跟踪
  • 🧪 AI测试代理 -自动化测试计划、生成和修复

技术栈

类别 技术
运行时 Node.js 18+
语言 TypeScript 5.8
浏览器自动化 剧作家1.52+
协议 模型上下文协议(MCP)SDK
验证 佐德
无障碍 @axe core/剧作家
日志记录 温斯顿
测试 @剧作家/测试
代码检查 ESLint 9,更漂亮

建筑

AI Client → MCP Protocol → Tool Handler → BrowserManager → Action Module → Playwright API
                                ↑
                         SessionManager (lifecycle, rate limiting)

层职责

图层 位置 目的
参赛作品 src/index.ts Bootstrap,优雅关机
MCP服务器 src/server/mcp-server.ts 工具/资源注册、会话清理
处理人员 src/server/handlers/ 按类别分组的工具定义
浏览器管理器 src/playwright/browser-manager.ts 编排动作模块
行动 src/playwright/actions/ 特定领域的剧作家操作
会话管理器 src/playwright/session-manager.ts 会话/页面生命周期,速率限制

入门指南

先决条件

  • Node.js 18或更高版本
  • npm或纱线

安装

# Clone the repository
git clone https://github.com/j0hanz/playwright-mcp.git
cd playwright-mcp

# Install dependencies
npm install

# Install Playwright browsers
npm run install:browsers

配置

创建一个 .env 项目根目录中的文件(可选):

LOG_LEVEL=info              # debug, info, warn, error
DEFAULT_BROWSER=chromium    # chromium, firefox, webkit
HEADLESS=true               # Run headless mode
MAX_SESSIONS=5              # Concurrent sessions (1-20)
SESSION_TIMEOUT=1800000     # Session expiry in ms (30 min)
TIMEOUT_ACTION=20000        # Element action timeout in ms
TIMEOUT_NAVIGATION=30000    # Page navigation timeout in ms

运行服务器

# Development mode (with hot reload)
npm run dev

# Production build and run
npm run build
npm start

项目结构

├── src/
│   ├── index.ts                    # Application entry point
│   ├── config/
│   │   ├── server-config.ts        # Environment configuration
│   │   └── types.ts                # TypeScript type definitions
│   ├── server/
│   │   ├── mcp-server.ts           # MCP server implementation
│   │   └── handlers/               # Tool handler categories
│   │       ├── browser-tools.ts    # Browser lifecycle tools
│   │       ├── navigation-tools.ts # Navigation tools
│   │       ├── interaction-tools.ts# Click, fill, hover tools
│   │       ├── assertion-tools.ts  # Web-first assertions
│   │       ├── page-tools.ts       # Screenshots, content, a11y
│   │       ├── test-tools.ts       # Test file management
│   │       ├── advanced-tools.ts   # Network, tracing, dialogs
│   │       └── schemas.ts          # Zod validation schemas
│   ├── playwright/
│   │   ├── browser-manager.ts      # Central browser orchestration
│   │   ├── session-manager.ts      # Session lifecycle
│   │   ├── browser-launcher.ts     # Browser launch logic
│   │   └── actions/                # Domain-specific actions
│   │       ├── assertion-actions.ts
│   │       ├── interaction-actions.ts
│   │       ├── navigation-actions.ts
│   │       └── ...
│   └── utils/
│       ├── error-handler.ts        # Centralized error handling
│       └── logger.ts               # Winston logger
├── tests/                          # Playwright test files
├── specs/                          # Human-readable test plans
├── .github/
│   ├── agents/                     # AI agent definitions
│   ├── prompts/                    # Agent prompts
│   └── copilot-instructions.md     # Development guidelines
└── playwright.config.ts            # Playwright test configuration

可用工具

浏览器生命周期

工具 说明
browser_launch 启动带有可选身份验证状态的浏览器(Chromium、Firefox、WebKit)
browser_close 关闭浏览器会话
browser_tabs 列出、创建、关闭或选择浏览器选项卡
sessions_list 列出所有活动的浏览器会话
save_storage_state 保存cookies/localStorage以供身份验证重用
session_reset_state 清除会话数据以进行测试隔离

导航

工具 说明
browser_navigate 导航到URL
browser_history 历史回顾/前进
browser_reload 重新加载当前页面
handle_dialog 接受/关闭浏览器对话框

交互

工具 说明
element_click 按角色、文本、testid或选择器单击
element_fill 按标签、占位符或选择器填充输入
element_hover 将鼠标悬停在元素上
select_option 选择下拉选项
keyboard_press 按键(Enter、Tab、快捷键)
keyboard_type 逐个字符键入文本
checkbox_set 选中/取消选中复选框
file_upload 上传文件
drag_and_drop 拖放元素

断言

工具 说明
assert_element 断言状态(可见、隐藏、启用、禁用)
assert_text 断言元素文本内容
assert_value 断言输入值
assert_url 断言页面URL
assert_title 断言页面标题
assert_attribute 断言元素属性
assert_css 断言CSS属性
assert_checked 断言复选框状态
assert_count 断言元素计数

页面操作

工具 说明
page_screenshot 截图(整页、元素、区域)
page_pdf 从页面生成PDF(仅限Chromium)
page_content 获取HTML和文本内容
page_evaluate 执行JavaScript(只读)
wait_for_selector 等待元素
page_wait_for_load_state 等待页面加载
accessibility_scan 运行斧头核心可访问性审计
browser_snapshot 获取可访问性树快照

Cookie管理

工具 说明
cookies_get 从浏览器上下文中检索Cookie
cookies_set 添加Cookie(身份验证令牌、会话)
cookies_clear 清除所有或特定Cookie

高级

工具 说明
network_mock 模拟网络响应
network_unroute 删除网络模拟
tracing_start / tracing_stop 记录执行痕迹
console_capture 捕获控制台消息
har_record_start 记录HTTP存档
clock_install 测试中的控制时间
video_path 获取视频录制路径

稳定测试的最佳实践

遵循这些做法将确保您的测试具有弹性、可维护性,并且不易出现漏洞。查看完整 最佳实践指南 以获取详细示例。

核心原则

  1. 使用语义化、面向用户的定位器

    • 基于角色的定位器最可靠: getByRole('button', { name: 'Submit' })
    • 避免使用CSS选择器和XPath——当样式更改时,它们会中断
    • 优先级:角色→ 标签→ 占位符→ Text → TestId→ CSS(最后手段)
  2. 使用定位器链接和过滤

    • 链接定位器以缩小搜索范围: page.getByRole('listitem').filter({ hasText: 'Product 2' })
    • 按文本或其他定位器筛选动态内容
    • 这减少了严格模式违规,提高了清晰度
  3. 始终使用Web优先断言

    • 使用 expect() 自动等待的断言: await expect(page.getByText('Success')).toBeVisible()
    • 不要使用像这样的直接检查 isVisible() 没有期望
    • 断言在失败前最多等待5秒(可配置)
  4. 避免常见陷阱

    • ❌ waitForTimeout() --使用特定的等待
    • ❌ waitForLoadState('networkidle') --使用 'domcontentloaded' 或等待元素
    • ❌ CSS类选择器——使用角色/标签/文本定位器
    • ❌ 截图作为选择器——使用 browser_snapshot 用于查找元素
    • ❌ test.only() 或 test.skip() --提交前删除

示例:良好的测试结构

test('Add todo and verify', async ({ page }) => {
  // Navigate
  await page.goto('/');

  // Get accessibility snapshot to understand page structure
  const snapshot = await page.accessibility.snapshot();

  // Interact using semantic locators (role > label > text)
  await page.getByPlaceholder('What needs to be done?').fill('Buy groceries');
  await page.getByRole('button', { name: 'Add' }).click();

  // Verify using web-first assertions (auto-wait)
  await expect(page.getByText('Buy groceries')).toBeVisible();
  await expect(page.getByRole('listitem')).toHaveCount(1);
});

定位器优先级

与元素交互时,首选面向用户的定位器(最可靠的第一个):

  1. 角色 ⭐ - element_click(locatorType: 'role', role: 'button', name: 'Submit')
  2. 标签 ⭐ - element_fill(locatorType: 'label', value: 'Email', text: '...')
  3. 文本 - element_click(locatorType: 'text', value: 'Learn more')
  4. 占位符 - element_fill(locatorType: 'placeholder', value: 'Search...')
  5. 测试 ID - element_click(locatorType: 'testid', value: 'submit-btn')
  6. 选择器 -CSS选择器(仅作为最后手段)

开发流程

# Watch mode with hot reload
npm run dev

# Build TypeScript to dist/
npm run build

# Run ESLint
npm run lint
npm run lint:fix

# Type check without emit
npm run type-check

# Format with Prettier
npm run format

# Run tests
npm test
npm run test:ui      # Interactive UI
npm run test:headed  # Visible browser
npm run test:debug   # Debug mode

承诺前: 跑 npm run lint && npm run type-check && npm run build

编码标准

工具注册模式

server.registerTool(
  'tool_name',
  {
    title: 'Human Title',
    description: 'What this tool does',
    inputSchema: {
      /* Zod schemas */
    },
    outputSchema: {
      /* Result shape */
    },
  },
  createToolHandler(async (input) => {
    const result = await browserManager.someMethod(input);
    return {
      content: [{ type: 'text', text: 'Human readable' }],
      structuredContent: result, // Machine readable
    };
  }, 'Error prefix message')
);

动作模块模式

export class MyActions extends BaseAction {
  async myOperation(sessionId: string, pageId: string, options: Options) {
    return this.executePageOperation(
      sessionId,
      pageId,
      'My operation',
      async (page) => {
        // Playwright operations
        return { success: true, data: '...' };
      }
    );
  }
}

错误处理

import {
  ErrorCode,
  ErrorHandler,
  validateUUID,
} from '../utils/error-handler.js';

validateUUID(sessionId, 'sessionId'); // Throws on invalid
throw ErrorHandler.sessionNotFound(id); // Factory methods
throw ErrorHandler.handlePlaywrightError(e); // Maps Playwright errors

测试

测试使用 @playwright/test 框架。配置在 playwright.config.ts.

npm test                 # Run all tests
npm run test:ui          # Interactive test UI
npm run test:headed      # With visible browser
npm run test:debug       # Debug mode with inspector
npm run test:trace       # Record traces
npm run test:report      # Show HTML report

测试配置

  • 超时:每次测试30秒
  • 重试:CI上为2,本地为0
  • 浏览器:Chromium、Firefox、WebKit、移动Chrome、移动Safari
  • 视口:1366x900
  • 测试ID属性: data-testid

AI测试代理

用于自动化测试工作流程的三个AI代理:

代理 输入 输出
规划师 应用程序URL+种子测试 specs/*.md 测试计划
发电机 测试计划 tests/*.spec.ts 文件
治愈者 测试失败 修复测试文件

用法

  1. 规划师:在中探索应用程序并创建测试计划 specs/
  2. 发电机:将计划转化为剧作家测试
  3. 治愈者:调试并修复失败的测试

代理定义在 .github/agents/ 有提示 .github/prompts/.

安全

  • URL验证:只有 http:// 和 https:// 允许的协议
  • UUID验证:所有会话/页面ID均已验证
  • 速率限制:可配置 MAX_SESSIONS_PER_MINUTE
  • 会话隔离:每个浏览器上下文都是隔离的
  • 脚本限制:仅安全、只读的JavaScript评估

贡献

  1. 分叉存储库
  2. 创建要素分支(git checkout -b feature/amazing-feature)
  3. 遵循中的编码标准 .github/copilot-instructions.md
  4. 运行linting和类型检查(npm run lint && npm run type-check)
  5. 确保测试通过(npm test)
  6. 提交您的更改(git commit -m 'Add amazing feature')
  7. 推到分支(git push origin feature/amazing-feature)
  8. 打开拉取请求

添加新工具

  1. 将方法添加到中的操作类 src/playwright/actions/
  2. 在处理程序文件中注册 src/server/handlers/
  3. 将架构添加到 schemas.ts 如果需要新的输入形状
  4. 为新功能添加测试

许可证

此项目根据MIT许可证获得许可-请参阅 许可证 文件以获取详细信息。

致谢