playwright-mcp-server
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePlaywright MCP Server
Playwright MCP Server
Skill by ara.so — MCP Skills collection.
The Playwright MCP server provides browser automation capabilities through the Model Context Protocol. It enables LLMs to interact with web pages using Playwright's accessibility tree instead of screenshots, making it fast, lightweight, and deterministic.
由ara.so开发的Skill — MCP Skills集合。
Playwright MCP服务器通过Model Context Protocol(模型上下文协议)提供浏览器自动化能力。它让LLM能够借助Playwright的无障碍树与网页交互,而非依赖截图,兼具快速、轻量和确定性的特点。
What It Does
功能介绍
- Structured interaction: Uses accessibility snapshots instead of vision models
- Browser automation: Navigate, click, fill forms, extract data from web pages
- Multi-browser support: Chromium, Firefox, and WebKit
- LLM-optimized: Returns structured data that's easy for language models to parse
- 结构化交互:使用无障碍快照而非视觉模型
- 浏览器自动化:实现网页导航、点击、表单填写、数据提取
- 多浏览器支持:支持Chromium、Firefox和WebKit
- LLM优化:返回易于大语言模型解析的结构化数据
Installation
安装步骤
Add to your MCP client configuration:
json
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}将以下配置添加到你的MCP客户端配置文件中:
json
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}Configuration Options
配置选项
Configure via in your MCP config:
argsjson
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--allowed-hosts", "example.com,*.trusted-domain.com",
"--browser", "chromium",
"--headless", "false"
]
}
}
}Common options:
- : Comma-separated hosts (or
--allowed-hosts <hosts...>to disable check). Env:*PLAYWRIGHT_MCP_ALLOWED_HOSTS - : Choose
--browser <browser>,chromium, orfirefoxwebkit - : Run browser in headless mode
--headless <true|false> - : Default timeout for operations
--timeout <ms>
可通过MCP配置中的参数进行配置:
argsjson
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--allowed-hosts", "example.com,*.trusted-domain.com",
"--browser", "chromium",
"--headless", "false"
]
}
}
}常用选项:
- :逗号分隔的允许访问的主机(或使用
--allowed-hosts <hosts...>禁用检查)。环境变量:*PLAYWRIGHT_MCP_ALLOWED_HOSTS - :选择
--browser <browser>、chromium或firefox浏览器webkit - :以无头模式运行浏览器
--headless <true|false> - :操作的默认超时时间
--timeout <ms>
Available Tools
可用工具
The MCP server exposes these tools to LLM agents:
该MCP服务器为LLM Agent提供以下工具:
1. playwright_navigate
playwright_navigate1. playwright_navigate
playwright_navigateNavigate to a URL and get accessibility snapshot.
Parameters:
- (string, required): URL to navigate to
url
Example usage:
typescript
// Agent will call this tool
{
"url": "https://example.com"
}Returns: Accessibility tree snapshot of the page
导航至指定URL并获取无障碍快照。
参数:
- (字符串,必填):要导航的URL
url
使用示例:
typescript
// Agent将调用此工具
{
"url": "https://example.com"
}返回结果: 页面的无障碍树快照
2. playwright_click
playwright_click2. playwright_click
playwright_clickClick an element identified by its accessibility role and name.
Parameters:
- (string, required): Element selector (role, text, or CSS)
selector - (string, optional):
button,left, orright(default:middle)left
Example usage:
typescript
{
"selector": "button[name='Submit']",
"button": "left"
}通过无障碍角色和名称定位元素并点击。
参数:
- (字符串,必填):元素选择器(角色、文本或CSS选择器)
selector - (字符串,可选):点击按钮类型,可选
button、left或right(默认:middle)left
使用示例:
typescript
{
"selector": "button[name='Submit']",
"button": "left"
}3. playwright_fill
playwright_fill3. playwright_fill
playwright_fillFill an input field with text.
Parameters:
- (string, required): Input field selector
selector - (string, required): Text to fill
value
Example usage:
typescript
{
"selector": "input[name='email']",
"value": "user@example.com"
}在输入框中填充文本。
参数:
- (字符串,必填):输入框选择器
selector - (字符串,必填):要填充的文本
value
使用示例:
typescript
{
"selector": "input[name='email']",
"value": "user@example.com"
}4. playwright_screenshot
playwright_screenshot4. playwright_screenshot
playwright_screenshotTake a screenshot of the page or element.
Parameters:
- (string, optional): Element to screenshot (defaults to full page)
selector - (string, optional): File path to save screenshot
path
Example usage:
typescript
{
"selector": "div.main-content",
"path": "./screenshots/content.png"
}截取页面或指定元素的截图。
参数:
- (字符串,可选):要截图的元素(默认截取整个页面)
selector - (字符串,可选):保存截图的文件路径
path
使用示例:
typescript
{
"selector": "div.main-content",
"path": "./screenshots/content.png"
}5. playwright_evaluate
playwright_evaluate5. playwright_evaluate
playwright_evaluateExecute JavaScript in the page context.
Parameters:
- (string, required): JavaScript to execute
expression
Example usage:
typescript
{
"expression": "document.title"
}在页面上下文中执行JavaScript代码。
参数:
- (字符串,必填):要执行的JavaScript代码
expression
使用示例:
typescript
{
"expression": "document.title"
}6. playwright_snapshot
playwright_snapshot6. playwright_snapshot
playwright_snapshotGet current accessibility snapshot without navigation.
Example usage:
typescript
{}无需导航即可获取当前页面的无障碍快照。
使用示例:
typescript
{}Common Patterns
常见使用场景
Form Automation
表单自动化
typescript
// Navigate to login page
await playwright_navigate({ url: "https://app.example.com/login" });
// Fill credentials
await playwright_fill({
selector: "input[name='username']",
value: "user@example.com"
});
await playwright_fill({
selector: "input[type='password']",
value: process.env.USER_PASSWORD // Use env vars for secrets
});
// Submit form
await playwright_click({
selector: "button[type='submit']"
});
// Verify login
const snapshot = await playwright_snapshot({});
// Parse snapshot to confirm successful logintypescript
// 导航至登录页面
await playwright_navigate({ url: "https://app.example.com/login" });
// 填写凭证
await playwright_fill({
selector: "input[name='username']",
value: "user@example.com"
});
await playwright_fill({
selector: "input[type='password']",
value: process.env.USER_PASSWORD // 使用环境变量存储敏感信息
});
// 提交表单
await playwright_click({
selector: "button[type='submit']"
});
// 验证登录状态
const snapshot = await playwright_snapshot({});
// 解析快照以确认登录成功Data Extraction
数据提取
typescript
// Navigate to data page
await playwright_navigate({ url: "https://example.com/products" });
// Extract product information
const products = await playwright_evaluate({
expression: `
Array.from(document.querySelectorAll('.product')).map(p => ({
name: p.querySelector('.name')?.textContent,
price: p.querySelector('.price')?.textContent
}))
`
});typescript
// 导航至数据页面
await playwright_navigate({ url: "https://example.com/products" });
// 提取产品信息
const products = await playwright_evaluate({
expression: `
Array.from(document.querySelectorAll('.product')).map(p => ({
name: p.querySelector('.name')?.textContent,
price: p.querySelector('.price')?.textContent
}))
`
});Multi-Step Workflow
多步骤工作流
typescript
// Search flow
await playwright_navigate({ url: "https://example.com" });
await playwright_fill({
selector: "input[placeholder='Search']",
value: "playwright automation"
});
await playwright_click({
selector: "button[aria-label='Search']"
});
// Wait for results by getting snapshot
const results = await playwright_snapshot({});
// Click first result
await playwright_click({
selector: "a.result-item:first-child"
});
// Capture final page
await playwright_screenshot({
path: "./evidence/result-page.png"
});typescript
// 搜索流程
await playwright_navigate({ url: "https://example.com" });
await playwright_fill({
selector: "input[placeholder='Search']",
value: "playwright automation"
});
await playwright_click({
selector: "button[aria-label='Search']"
});
// 通过获取快照等待结果加载
const results = await playwright_snapshot({});
// 点击第一个搜索结果
await playwright_click({
selector: "a.result-item:first-child"
});
// 捕获最终页面
await playwright_screenshot({
path: "./evidence/result-page.png"
});Testing Accessibility
无障碍测试
typescript
// Navigate to page under test
await playwright_navigate({ url: "https://myapp.com/dashboard" });
// Get accessibility tree
const snapshot = await playwright_snapshot({});
// The snapshot will show:
// - Missing ARIA labels
// - Elements without proper roles
// - Navigation structure
// Parse snapshot to validate accessibilitytypescript
// 导航至待测试页面
await playwright_navigate({ url: "https://myapp.com/dashboard" });
// 获取无障碍树
const snapshot = await playwright_snapshot({});
// 快照将展示:
// - 缺失的ARIA标签
// - 未设置正确角色的元素
// - 导航结构
// 解析快照以验证无障碍性Accessibility Selectors
无障碍选择器
Playwright MCP uses accessible selectors. Prefer:
typescript
// Good: Role-based selectors
"button[name='Submit']"
"link[name='Documentation']"
"textbox[name='Email']"
// Good: ARIA attributes
"[aria-label='Close dialog']"
"[role='navigation']"
// Okay: Text content
"text=Click here"
// Last resort: CSS selectors
"div.modal > button.close"Playwright MCP使用无障碍选择器,优先选择以下类型:
typescript
// 推荐:基于角色的选择器
"button[name='Submit']"
"link[name='Documentation']"
"textbox[name='Email']"
// 推荐:ARIA属性选择器
"[aria-label='Close dialog']"
"[role='navigation']"
// 可用:文本内容选择器
"text=Click here"
// 最后选择:CSS选择器
"div.modal > button.close"Working with Snapshots
快照使用指南
Accessibility snapshots are structured representations of the page:
typescript
// Example snapshot structure
{
"role": "WebArea",
"name": "Example Page",
"children": [
{
"role": "button",
"name": "Submit",
"focusable": true
},
{
"role": "textbox",
"name": "Email",
"value": "user@example.com"
}
]
}Use snapshots to:
- Understand page structure
- Identify interactive elements
- Validate content presence
- Find navigation paths
无障碍快照是页面的结构化表示:
typescript
// 示例快照结构
{
"role": "WebArea",
"name": "Example Page",
"children": [
{
"role": "button",
"name": "Submit",
"focusable": true
},
{
"role": "textbox",
"name": "Email",
"value": "user@example.com"
}
]
}可使用快照完成以下操作:
- 理解页面结构
- 识别交互元素
- 验证内容存在性
- 查找导航路径
Troubleshooting
问题排查
Host Not Allowed
主机未被允许
Error:
Host not allowed: example.comSolution: Add to allowed hosts:
json
{
"args": [
"@playwright/mcp@latest",
"--allowed-hosts", "example.com,*.example.com"
]
}Or disable checks (development only):
json
{
"args": ["@playwright/mcp@latest", "--allowed-hosts", "*"]
}错误信息:
Host not allowed: example.com解决方案: 将主机添加到允许列表:
json
{
"args": [
"@playwright/mcp@latest",
"--allowed-hosts", "example.com,*.example.com"
]
}或禁用检查(仅开发环境使用):
json
{
"args": ["@playwright/mcp@latest", "--allowed-hosts", "*"]
}Element Not Found
元素未找到
Error:
Element not found: button[name='Submit']Solutions:
-
Get current snapshot to see available elements:typescript
const snapshot = await playwright_snapshot({}); -
Use more flexible selectors:typescript
// Instead of exact match "button[name*='submit']" // Contains 'submit' "text=/submit/i" // Case-insensitive regex -
Wait for element by evaluating:typescript
await playwright_evaluate({ expression: ` new Promise(resolve => { const check = () => { if (document.querySelector('button[name="Submit"]')) { resolve(true); } else { setTimeout(check, 100); } }; check(); }) ` });
错误信息:
Element not found: button[name='Submit']解决方案:
-
获取当前快照查看可用元素:typescript
const snapshot = await playwright_snapshot({}); -
使用更灵活的选择器:typescript
// 替代精确匹配 "button[name*='submit']" // 包含'submit'的名称 "text=/submit/i" // 不区分大小写的正则匹配 -
通过执行代码等待元素加载:typescript
await playwright_evaluate({ expression: ` new Promise(resolve => { const check = () => { if (document.querySelector('button[name="Submit"]')) { resolve(true); } else { setTimeout(check, 100); } }; check(); }) ` });
Timeout Issues
超时问题
Error:
Timeout waiting for elementSolution: Increase timeout:
json
{
"args": ["@playwright/mcp@latest", "--timeout", "60000"]
}Or wait explicitly:
typescript
await playwright_evaluate({
expression: "new Promise(r => setTimeout(r, 2000))"
});错误信息:
Timeout waiting for element解决方案: 增加超时时间:
json
{
"args": ["@playwright/mcp@latest", "--timeout", "60000"]
}或显式等待:
typescript
await playwright_evaluate({
expression: "new Promise(r => setTimeout(r, 2000))"
});Browser Not Launching
浏览器无法启动
Error:
Failed to launch browserSolutions:
-
Check browser installation:bash
npx playwright install chromium -
Try different browser:json
{ "args": ["@playwright/mcp@latest", "--browser", "firefox"] } -
Run in headed mode for debugging:json
{ "args": ["@playwright/mcp@latest", "--headless", "false"] }
错误信息:
Failed to launch browser解决方案:
-
检查浏览器安装情况:bash
npx playwright install chromium -
尝试其他浏览器:json
{ "args": ["@playwright/mcp@latest", "--browser", "firefox"] } -
以有头模式运行以便调试:json
{ "args": ["@playwright/mcp@latest", "--headless", "false"] }
Best Practices
最佳实践
-
Use environment variables for secrets:typescript
// Never hardcode credentials await playwright_fill({ selector: "input[type='password']", value: process.env.PASSWORD }); -
Take snapshots for debugging:typescript
// Before and after critical actions const beforeSnapshot = await playwright_snapshot({}); await playwright_click({ selector: "button[name='Delete']" }); const afterSnapshot = await playwright_snapshot({}); -
Prefer accessibility selectors:typescript
// Robust to UI changes "button[name='Save']" // vs fragile CSS "div.container > div:nth-child(2) > button.primary" -
Handle navigation timing:typescript
await playwright_navigate({ url: "https://example.com" }); // Snapshot after navigate includes wait for load const snapshot = await playwright_snapshot({}); -
Combine tools for complex workflows:typescript
// Navigate → Inspect → Act → Verify await playwright_navigate({ url: "..." }); const structure = await playwright_snapshot({}); await playwright_fill({ ... }); await playwright_click({ ... }); const result = await playwright_snapshot({});
-
使用环境变量存储敏感信息:typescript
// 切勿硬编码凭证 await playwright_fill({ selector: "input[type='password']", value: process.env.PASSWORD }); -
通过快照进行调试:typescript
// 在关键操作前后获取快照 const beforeSnapshot = await playwright_snapshot({}); await playwright_click({ selector: "button[name='Delete']" }); const afterSnapshot = await playwright_snapshot({}); -
优先使用无障碍选择器:typescript
// 对UI变更更鲁棒 "button[name='Save']" // 对比脆弱的CSS选择器 "div.container > div:nth-child(2) > button.primary" -
处理导航时序:typescript
await playwright_navigate({ url: "https://example.com" }); // 导航后的快照会等待页面加载完成 const snapshot = await playwright_snapshot({}); -
组合工具完成复杂工作流:typescript
// 导航 → 检查 → 操作 → 验证 await playwright_navigate({ url: "..." }); const structure = await playwright_snapshot({}); await playwright_fill({ ... }); await playwright_click({ ... }); const result = await playwright_snapshot({});
vs Playwright CLI
与Playwright CLI对比
Use Playwright MCP when:
- Building chat-based automation agents
- Need persistent browser state across tool calls
- Iterative reasoning over page structure
- Long-running autonomous workflows
Use Playwright CLI + SKILLS when:
- Working with coding agents that favor CLI tools
- Token efficiency is critical
- Managing large codebases alongside automation
- Need concise, purpose-built commands
选择Playwright MCP的场景:
- 构建基于聊天的自动化Agent
- 需要在工具调用间保持浏览器持久状态
- 需要对页面结构进行迭代推理
- 长运行的自主工作流
选择**Playwright CLI + SKILLS**的场景:
- 与偏好CLI工具的编码Agent配合使用
- 对Token效率要求较高
- 在自动化同时管理大型代码库
- 需要简洁、针对性的命令