使用说明
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 |
获取视频录制路径 |
稳定测试的最佳实践
遵循这些做法将确保您的测试具有弹性、可维护性,并且不易出现漏洞。查看完整 最佳实践指南 以获取详细示例。
核心原则
-
使用语义化、面向用户的定位器
- 基于角色的定位器最可靠:
getByRole('button', { name: 'Submit' }) - 避免使用CSS选择器和XPath——当样式更改时,它们会中断
- 优先级:角色→ 标签→ 占位符→ Text → TestId→ CSS(最后手段)
- 基于角色的定位器最可靠:
-
使用定位器链接和过滤
- 链接定位器以缩小搜索范围:
page.getByRole('listitem').filter({ hasText: 'Product 2' }) - 按文本或其他定位器筛选动态内容
- 这减少了严格模式违规,提高了清晰度
- 链接定位器以缩小搜索范围:
-
始终使用Web优先断言
- 使用
expect()自动等待的断言:await expect(page.getByText('Success')).toBeVisible() - 不要使用像这样的直接检查
isVisible()没有期望 - 断言在失败前最多等待5秒(可配置)
- 使用
-
避免常见陷阱
- ❌
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);
});
定位器优先级
与元素交互时,首选面向用户的定位器(最可靠的第一个):
- 角色 ⭐ -
element_click(locatorType: 'role', role: 'button', name: 'Submit') - 标签 ⭐ -
element_fill(locatorType: 'label', value: 'Email', text: '...') - 文本 -
element_click(locatorType: 'text', value: 'Learn more') - 占位符 -
element_fill(locatorType: 'placeholder', value: 'Search...') - 测试 ID -
element_click(locatorType: 'testid', value: 'submit-btn') - 选择器 -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 文件 |
| 治愈者 | 测试失败 | 修复测试文件 |
用法
- 规划师:在中探索应用程序并创建测试计划
specs/ - 发电机:将计划转化为剧作家测试
- 治愈者:调试并修复失败的测试
代理定义在 .github/agents/ 有提示 .github/prompts/.
安全
- URL验证:只有
http://和https://允许的协议 - UUID验证:所有会话/页面ID均已验证
- 速率限制:可配置
MAX_SESSIONS_PER_MINUTE - 会话隔离:每个浏览器上下文都是隔离的
- 脚本限制:仅安全、只读的JavaScript评估
贡献
- 分叉存储库
- 创建要素分支(
git checkout -b feature/amazing-feature) - 遵循中的编码标准
.github/copilot-instructions.md - 运行linting和类型检查(
npm run lint && npm run type-check) - 确保测试通过(
npm test) - 提交您的更改(
git commit -m 'Add amazing feature') - 推到分支(
git push origin feature/amazing-feature) - 打开拉取请求
添加新工具
- 将方法添加到中的操作类
src/playwright/actions/ - 在处理程序文件中注册
src/server/handlers/ - 将架构添加到
schemas.ts如果需要新的输入形状 - 为新功能添加测试
许可证
此项目根据MIT许可证获得许可-请参阅 许可证 文件以获取详细信息。
