一个最小且健壮的 Playwright MCP(模型上下文协议)服务器,通过简单的 API 暴露核心浏览器自动化能力。
# 直接从 GitHub 安装
pip install git+https://github.com/alexrwilliam/playwright-mcp-server.git
# 安装 Playwright 浏览器
playwright install
# 克隆仓库
git clone https://github.com/alexrwilliam/playwright-mcp-server.git
cd playwright-mcp-server
# 开发模式安装
pip install -e .
# 安装浏览器
playwright install
安装后,可以从任何地方使用:
# 使用 stdio 传输运行(适用于 MCP 客户端)
playwright-mcp stdio
# 使用 HTTP 传输运行
playwright-mcp http --port 8000
# 在有头模式下运行(默认是无头模式)
playwright-mcp stdio --headed
# 运行 MCP 服务器
playwright-mcp stdio
# 使用可见浏览器
playwright-mcp stdio --headed
# 运行 HTTP 服务器
playwright-mcp http --port 8000
# 使用不同的浏览器
playwright-mcp stdio --browser firefox
playwright-mcp stdio --browser webkit
# 使用真实的 Chrome 而不是捆绑的 Chromium
playwright-mcp stdio --channel chrome
# 使用真实 Chrome 和你的配置文件(Cookies、扩展程序、历史记录)
playwright-mcp stdio --channel chrome --user-data-dir "/Users/you/Library/Application Support/Google/Chrome"
# 调整响应预算(默认:4k 内联,400 字符预览)
playwright-mcp stdio --max-response-chars 6000 --preview-chars 600
# 选择溢出工件写入的位置
playwright-mcp stdio --artifact-dir /tmp/playwright-artifacts
# 控制每个工件片段返回内联的数量
playwright-mcp stdio --artifact-chunk-size 8192
# 其他 Chrome 渠道
playwright-mcp stdio --channel chrome-beta
playwright-mcp stdio --channel chrome-dev
添加到你的 claude_desktop_config.json:
{
"mcpServers": {
"playwright": {
"command": "playwright-mcp",
"args": ["stdio"]
}
}
}
# 安装并运行 MCP inspector
uv run mcp dev src/playwright_mcp/server.py
高容量工具(evaluate、get_accessibility_snapshot、get_network_requests、get_network_responses、get_html等)遵守共享响应预算。当序列化负载超过 --max-response-chars:
truncated: true。preview(默认 400 字符)快照保留的内容。tmp/playwright_mcp),并返回 overflow_path 加上原始大小 overflow_characters。read_artifact 工具(或本地打开文件)检索保存的负载。二进制工件读取时回退到 base64。--artifact-max-age-seconds,--artifact-max-files)。二进制密集型工具(screenshot、pdf、非文本负载的 get_response_body)现在默认为工件响应。它们返回元数据(大小、哈希、预览)加上 artifact_path。当你确实需要完整的 base64 内联时,传递 inline=True。
当你需要比内联预览更多时,使用 read_artifact_chunk 流式传输二进制/文本工件的可管理切片(默认切片大小可通过 --artifact-chunk-size 配置)。
每次运行时调整限制 --max-response-chars、--preview-chars 和 --artifact-dir 或覆盖工具暴露的调用限制。
navigate(url: str) - 导航到 URLreload() - 重新加载当前页面go_back() - 后退go_forward() - 前进get_current_url() - 获取当前页面 URL 及其解析组件和查询参数wait_for_url(url_pattern: str, timeout: int) - 等待 URL 匹配模式wait_for_load_state(state: str, timeout: int) - 等待页面加载状态(domcontentloaded、load、networkidle)set_viewport_size(width: int, height: int) - 设置视口尺寸list_pages() - 列出所有打开的浏览器页面/标签页及其 ID、URL 和标题switch_page(page_id: str) - 通过 ID 切换到不同的页面/标签页close_page(page_id: str) - 关闭特定页面/标签页(不能关闭最后一个)wait_for_popup(timeout: int) - 等待并捕获新弹出窗口/标签页switch_to_latest_page() - 切换到最近打开的页面click(selector: str) - 点击元素type_text(selector: str, text: str) - 输入文本到元素fill(selector: str, value: str) - 填充输入字段clear_text(selector: str) - 清除输入字段文本select_option(selector: str, value: str) - 选择选项hover(selector: str) - 悬停在元素上scroll(selector: str, x: int, y: int) - 滚动元素press_key(key: str) - 按键盘键check_checkbox(selector: str) - 勾选复选框uncheck_checkbox(selector: str) - 取消勾选复选框upload_file(selector: str, file_path: str) - 上传文件到输入query_selector(selector: str, max_text_length: int | None = None) - 查询单个元素(可选每调用文本限制覆盖)query_selector_all(selector: str, max_elements: int | None = None, max_text_length: int | None = None) - 查询所有匹配的元素(可选每调用覆盖)query_selector_meta(selector: str, preview_length: int = 200, max_elements: int | None = None) - 快速元数据预览(标签、角色、短文本、关键属性)truncated / returned_count 元数据。is_visible(selector: str) - 检查元素是否可见is_enabled(selector: str) - 检查元素是否启用wait_for_element(selector: str, timeout: int) - 等待元素出现get_element_bounding_box(selector: str) - 获取元素位置和大小get_element_attributes(selector: str) - 获取所有元素属性get_computed_style(selector: str, property: str) - 获取 CSS 计算样式evaluate(script: str) - 在页面上下文中执行 JavaScript(结果尊重共享响应预算,并根据需要发出溢出元数据)get_network_requests(url_pattern: str | None = None) - 检查捕获的请求;大型结果集溢出到工件中带有预览get_network_responses(url_pattern: str | None = None) - 检查捕获的响应,具有相同的预算行为read_artifact(path: str) - 加载之前响应中引用的溢出工件的第一个切片(返回文本或 base64 内容)read_artifact_chunk(path: str, offset: int = 0, limit: int | None = None) - 流式传输附加工件数据的有界切片get_response_body(url_pattern: str) - 获取最新匹配的响应正文;文本预算内联,二进制负载自动保存到工件get_html() - 获取页面 HTMLget_accessibility_snapshot(interesting_only: bool = True, root_selector: str | None = None, max_nodes: int | None = None) - 获取可访问性树,带可选过滤器和每调用节点限制truncated、max_nodes 和 node_count 元数据。screenshot(selector: str | None = None, full_page: bool = False, inline: bool = False) - 捕获页面或元素;默认情况下将 PNG 存储为带有元数据预览的工件pdf(inline: bool = False) - 生成 PDF 并返回工件元数据,除非明确请求内联模式evaluate(script: str) - 在页面上下文中执行 JavaScriptwait_for_network_idle(timeout: int) - 等待网络活动平息get_page_errors() - 获取页面中的 JavaScript 错误get_console_logs() - 获取页面的控制台输出get_network_requests(url_pattern: str) - 检索捕获的网络请求,带过滤get_network_responses(url_pattern: str) - 检索捕获的网络响应,带过滤clear_network_logs() - 清除所有捕获的网络请求/响应日志intercept_route(url_pattern: str, action: str, ...) - 拦截并处理网络请求unroute_all() - 移除所有路由拦截器wait_for_response(url_pattern: str, timeout: int) - 等待特定网络响应get_response_body(url_pattern: str) - 从网络调用中提取响应正文内容get_cookies(urls: List[str]) - 获取浏览器 Cookie,带可选 URL 过滤add_cookies(cookies: List[Dict]) - 将 Cookie 添加到浏览器上下文中clear_cookies(name: str, domain: str) - 清除 Cookie,带可选过滤get_local_storage(origin: str) - 访问 localStorage 数据set_local_storage(key: str, value: str) - 设置 localStorage 项get_session_storage() - 访问 sessionStorage 数据set_session_storage(key: str, value: str) - 设置 sessionStorage 项clear_storage(storage_type: str) - 清除 localStorage 和/或 sessionStorageset_extra_headers(headers: Dict) - 为所有请求添加自定义 HTTP 标头set_user_agent(user_agent: str) - 更改浏览器 User-Agent 字符串服务器会自动跟踪所有浏览器页面/标签页:
# 示例:点击打开新标签页的链接
1. navigate("https://example.com")
2. click("a[target='_blank']") # 打开新标签页
3. list_pages() # 显示所有打开的标签页及其 ID
4. switch_to_latest_page() # 切换到新标签页
5. get_current_url() # 获取新标签页的 URL
6. switch_page(original_page_id) # 切换回原页面
# 示例:处理 JavaScript 弹出窗口
1. evaluate("window.open('https://example.com', '_blank')")
2. wait_for_popup(timeout=5000) # 等待并捕获弹出窗口
3. list_pages() # 查看所有页面,包括弹出窗口
4. close_page(popup_id) # 关闭弹出窗口
所有现有工具都自动工作在当前激活的页面上。当你切换页面时,后续操作应用于新的激活页面。
服务器接受以下配置选项:
--headed / --headless - 在有头或无头模式下运行浏览器--browser - 浏览器类型(chromium、firefox、webkit)--channel - 浏览器通道(chrome、chrome-beta、msedge 等)用于真实浏览器--user-data-dir - 浏览器配置文件目录路径,用于持久化上下文--port - HTTP 传输端口--timeout - 操作的默认超时时间(毫秒)--max-elements - 查询工具返回的 DOM 节点最大数量(默认:20)--max-element-text-length - 元素文本和属性值返回的最大字符数(默认:2000)--max-accessibility-nodes - get_accessibility_snapshot 返回的最大可访问性树节点数(默认:500)--max-response-chars - 在结果溢出到工件文件之前返回内联的最大序列化字符数(默认:4000)--preview-chars - 当发生裁剪时内联预览中包含的最大字符数(默认:400)--artifact-dir - 溢出工件写入的目录(默认:./tmp/playwright_mcp)--artifact-max-age-seconds - 工件在被清理前的最大年龄(默认:7200 秒)--artifact-max-files - 目录中保留的最大工件文件数(默认:200)--artifact-chunk-size - 每次 read_artifact_chunk 调用返回的默认字节数(默认:4096)所有限制接受 0 或负值以完全禁用裁剪。当发生裁剪时,工具响应包含 truncated 标志和元数据,以便客户端可以选择重新发出更窄的请求。
默认情况下,Playwright 使用捆绑的 Chromium。对于需要真实 Chrome 功能的网络抓取:
使用 --channel chrome 来使用已安装的 Google Chrome:
使用 --user-data-dir 来访问真实配置文件:
macOS 示例:
playwright-mcp stdio --channel chrome --user-data-dir "/Users/$(whoami)/Library/Application Support/Google/Chrome"
Linux 示例:
playwright-mcp stdio --channel chrome --user-data-dir "/home/$(whoami)/.config/google-chrome"
# 克隆仓库
git clone <repo-url>
cd playwright-mcp
# 安装依赖
uv sync --dev
# 运行测试
uv run pytest
# 格式化代码
uv run black src/
uv run ruff check src/
# 类型检查
uv run mypy src/
MIT