用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Aradotso/mcp-skills --skill playwright-mcp-server命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | playwright-mcp-server |
| description | Browser automation MCP server using Playwright's accessibility tree for LLM-friendly web interaction |
| triggers | ["automate a web browser","interact with a web page","use playwright mcp","navigate to a website","click on an element","fill out a form","take a screenshot with playwright","get page accessibility tree"] |
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.
Add to your MCP client configuration:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
Configure via args in your MCP config:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--allowed-hosts", "example.com,*.trusted-domain.com",
"--browser", "chromium",
"--headless", "false"
]
}
}
}
Common options:
--allowed-hosts <hosts...>: Comma-separated hosts (or * to disable check). Env: PLAYWRIGHT_MCP_ALLOWED_HOSTS--browser <browser>: Choose chromium, firefox, or webkit--headless <true|false>: Run browser in headless mode--timeout <ms>: Default timeout for operationsThe MCP server exposes these tools to LLM agents:
playwright_navigateNavigate to a URL and get accessibility snapshot.
Parameters:
url (string, required): URL to navigate toExample usage:
// Agent will call this tool
{
"url": "https://example.com"
}
Returns: Accessibility tree snapshot of the page
playwright_clickClick an element identified by its accessibility role and name.
Parameters:
selector (string, required): Element selector (role, text, or CSS)button (string, optional): left, right, or middle (default: left)Example usage:
{
"selector": "button[name='Submit']",
"button": "left"
}
playwright_fillFill an input field with text.
Parameters:
selector (string, required): Input field selectorvalue (string, required): Text to fillExample usage:
{
"selector": "input[name='email']",
"value": "user@example.com"
}
playwright_screenshotTake a screenshot of the page or element.
Parameters:
selector (string, optional): Element to screenshot (defaults to full page)path (string, optional): File path to save screenshotExample usage:
{
"selector": "div.main-content",
"path": "./screenshots/content.png"
}
playwright_evaluateExecute JavaScript in the page context.
Parameters:
expression (string, required): JavaScript to executeExample usage:
{
"expression": "document.title"
}
playwright_snapshotGet current accessibility snapshot without navigation.
Example usage:
{}
// 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 login
// 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
}))
`
});
// 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"
});
// 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 accessibility
Playwright MCP uses accessible selectors. Prefer:
// 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"
Accessibility snapshots are structured representations of the page:
// 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:
Error: Host not allowed: example.com
Solution: Add to allowed hosts:
{
"args": [
"@playwright/mcp@latest",
"--allowed-hosts", "example.com,*.example.com"
]
}
Or disable checks (development only):
{
"args": ["@playwright/mcp@latest", "--allowed-hosts", "*"]
}
Error: Element not found: button[name='Submit']
Solutions:
Get current snapshot to see available elements:
const snapshot = await playwright_snapshot({});
Use more flexible selectors:
// Instead of exact match
"button[name*='submit']" // Contains 'submit'
"text=/submit/i" // Case-insensitive regex
Wait for element by evaluating:
await playwright_evaluate({
expression: `
new Promise(resolve => {
const check = () => {
if (document.querySelector('button[name="Submit"]')) {
resolve(true);
} else {
setTimeout(check, 100);
}
};
check();
})
`
});
Error: Timeout waiting for element
Solution: Increase timeout:
{
"args": ["@playwright/mcp@latest", "--timeout", "60000"]
}
Or wait explicitly:
await playwright_evaluate({
expression: "new Promise(r => setTimeout(r, 2000))"
});
Error: Failed to launch browser
Solutions:
Check browser installation:
npx playwright install chromium
Try different browser:
{
"args": ["@playwright/mcp@latest", "--browser", "firefox"]
}
Run in headed mode for debugging:
{
"args": ["@playwright/mcp@latest", "--headless", "false"]
}
Use environment variables for secrets:
// Never hardcode credentials
await playwright_fill({
selector: "input[type='password']",
value: process.env.PASSWORD
});
Take snapshots for debugging:
// 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:
// Robust to UI changes
"button[name='Save']"
// vs fragile CSS
"div.container > div:nth-child(2) > button.primary"
Handle navigation timing:
await playwright_navigate({ url: "https://example.com" });
// Snapshot after navigate includes wait for load
const snapshot = await playwright_snapshot({});
Combine tools for complex workflows:
// Navigate → Inspect → Act → Verify
await playwright_navigate({ url: });
structure = ({});
({ ... });
({ ... });
result = ({});
Use Playwright MCP when:
Use Playwright CLI + SKILLS when: