title: 将Playwright MCP集成到Hermes Agent:完整踩坑实录与23个工具全功能验证
date: 2026-05-05
categories: [AI, 工具链]
tags: [Playwright, MCP, Hermes, 浏览器自动化, AI Agent]

将Playwright MCP集成到Hermes Agent:完整踩坑实录与23个工具全功能验证

前言

最近在折腾 Hermes Agent(一个 CLI 端的 AI 代理框架),想要给它加上浏览器自动化能力。最自然的选择就是 Playwright MCP——通过 MCP(Model Context Protocol)协议,让 AI 代理能直接操控浏览器。

这篇文章记录了从零开始集成 @playwright/mcp 的全过程:环境搭建、踩过的坑、以及最终的 23 个工具全功能验证。希望能给同样在折腾 MCP + 浏览器的同学一些参考。

什么是 Playwright MCP?

Playwright 是微软出品的浏览器自动化工具,支持 Chromium、Firefox、WebKit 三引擎。MCP(Model Context Protocol)是 Anthropic 推出的一种让 AI 模型与外部工具交互的开放协议。

@playwright/mcp 就是两者的结合——一个 MCP 服务器,将 Playwright 的浏览器操控能力封装成 23 个标准工具,AI 代理可以通过 MCP 协议直接调用。

环境概览

  • 操作系统: WSL2(Windows Subsystem for Linux)
  • Hermes Agent: 最新版
  • Playwright MCP: @playwright/mcp@latest
  • Chromium: Chrome for Testing v148(revision 1222)
  • Node.js: 通过 npx 运行时自动管理

第一步:下载 Chromium

Playwright 需要特定版本的 Chromium,不是日常用的 Chrome 浏览器。用的是 Google 的 Chrome for Testing,需要从 Google CDN 手动下载。

下载链接格式:

https://storage.googleapis.com/chrome-for-testing-public/{版本号}/linux64/chrome-linux64.zip

踩坑记录:直接通过 npm / npx 自动下载极其缓慢,国内网络经常中断。建议手动下载 zip 包后解压。

# 创建 Playwright 期望的目录结构
mkdir -p ~/.cache/ms-playwright/chromium-1222/

# 解压已下载的 zip 包
python3 -c "
import zipfile, os
zip_path = '/mnt/d/cc/Downloads/chrome-linux64.zip'
target = os.path.expanduser('~/.cache/ms-playwright/chromium-1222')
with zipfile.ZipFile(zip_path, 'r') as zf:
    zf.extractall(target)
os.chmod(f'{target}/chrome-linux64/chrome', 0o755)
"

第二步:安装系统依赖

Chromium 在 Linux 下需要一堆系统库,缺一个就启动失败。好在 apt 能解决:

sudo apt-get install -y libnspr4 libnss3 libatk1.0-0t64 libatk-bridge2.0-0t64 \
  libcups2t64 libdrm2 libdbus-1-3 libxkbcommon0 libxcomposite1 libxdamage1 \
  libxfixes3 libxrandr2 libgbm1 libpango-1.0-0 libcairo2 libasound2t64

第三步:配置符号链接

@playwright/mcp 默认查找 /opt/google/chrome/chrome 作为浏览器路径。我们可以创建一个符号链接指向手动下载的 Chromium:

sudo mkdir -p /opt/google/chrome
sudo ln -sf ~/.cache/ms-playwright/chromium-1222/chrome-linux64/chrome /opt/google/chrome/chrome

这样就不用每次启动都传 --executable-path 参数了。当然,也可以直接传参覆盖,灵活选择。

第四步:编写包装脚本

这里有一个关键问题:@playwright/mcp 作为 MCP 服务器,需要长时间运行在后端。但直接运行 npx 命令会有几个问题:

  1. 多实例冲突:多次启动会导致多个 MCP 服务器进程
  2. crash 后不会自动重启:进程意外退出后需要手动拉起
  3. 超时配置:默认超时对复杂页面不够用

所以写了一个包装脚本来解决这些问题:

#!/bin/bash
# playwright-mcp-wrapper.sh

set -euo pipefail

NAME="playwright-mcp"
LOCK_DIR="/tmp/${NAME}.lock"
CHROMIUM_PATH="/home/cc/.cache/ms-playwright/chromium-1222/chrome-linux64/chrome"
MAX_RESTARTS=5
RESTART_DELAY=2

# PID 文件锁定——防止多实例冲突
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
    EXISTING_PID=$(cat "$LOCK_DIR/pid" 2>/dev/null || echo "unknown")
    echo "[${NAME}] ERROR: Already running (pid $EXISTING_PID). Exiting." >&2
    exit 1
fi
echo $$ > "$LOCK_DIR/pid"

cleanup() { rm -rf "$LOCK_DIR"; }
trap cleanup EXIT

# 子进程启动函数
start_server() {
    exec npx -y "@playwright/mcp@latest" \
        --headless \
        --no-sandbox \
        --executable-path "$CHROMIUM_PATH" \
        --timeout-action 10000 \
        --timeout-navigation 120000 \
        --output-mode stdout \
        --isolated \
        "$@"
}

# Chrome 就绪检查
if [ ! -x "$CHROMIUM_PATH" ]; then
    echo "[${NAME}] ERROR: Chromium not found at $CHROMIUM_PATH" >&2
    exit 1
fi

# 守护循环——crash后最多自动重启5次
RESTART_COUNT=0
while true; do
    echo "[${NAME}] Starting (attempt $((RESTART_COUNT + 1)))..." >&2
    start_server || true
    EXIT_CODE=$?
    # 正常退出不重启
    if [ $EXIT_CODE -eq 0 ] || [ $EXIT_CODE -eq 130 ] || [ $EXIT_CODE -eq 143 ]; then
        exit 0
    fi
    RESTART_COUNT=$((RESTART_COUNT + 1))
    if [ "$RESTART_COUNT" -ge "$MAX_RESTARTS" ]; then
        echo "[${NAME}] Too many restarts, giving up." >&2
        exit 1
    fi
    sleep "$RESTART_DELAY"
done

这个脚本的核心设计:

  • PID 文件锁:通过 mkdir 的原子性保证只有一个实例在运行
  • exec 替代 fork:子进程直接替换父进程,避免僵尸进程
  • 守护循环:非正常退出时自动重启,最多 5 次
  • trap cleanup:退出时自动清理锁文件

第五步:配置 Hermes

将 Playwright MCP 添加到 Hermes 的配置文件 ~/.hermes/config.yaml

mcp_servers:
  playwright:
    command: /home/cc/.local/bin/playwright-mcp-wrapper.sh
    args: []
    timeout: 120
    connect_timeout: 60

这里有个小坑:timeout 默认值 30 秒对于浏览器操作来说太短了,导航复杂页面很容易超时。我把 timeout 调到了 120 秒,connect_timeout 设到 60 秒。

第六步:启动与连接测试

# 启动包装脚本
bash ~/.local/bin/playwright-mcp-wrapper.sh &

# 测试连接
hermes mcp test playwright

成功输出:

Testing 'playwright'...
  Transport: stdio → /home/cc/.local/bin/playwright-mcp-wrapper.sh
  ✓ Connected (2911ms)
  ✓ Tools discovered: 23

23 个工具全部发现!比预想的多。具体包括:

类别 工具列表
导航 browser_navigate, browser_navigate_back
DOM browser_snapshot
截图 browser_take_screenshot
点击交互 browser_click, browser_hover, browser_drag
输入 browser_type, browser_fill_form, browser_select_option, browser_press_key
JS执行 browser_evaluate, browser_run_code_unsafe
网络 browser_network_requests, browser_network_request
控制台 browser_console_messages
对话框 browser_handle_dialog
文件 browser_file_upload, browser_drop
标签页 browser_tabs
窗口 browser_resize
等待 browser_wait_for
关闭 browser_close

踩坑记录

坑1:参数名与直觉不符(最坑)

这是最大的坑。@playwright/mcp 的某些工具参数名和直观理解不一样,用错了就报 validation error。

browser_evaluate

# ❌ 错误——参数是 expression?不是!
session.call_tool("browser_evaluate", {"expression": "document.title"})

# ✅ 正确——参数是 function,必须传箭头函数
session.call_tool("browser_evaluate", {"function": "() => { return document.title; }"})

browser_run_code_unsafe

# ❌ 错误——普通函数不行
session.call_tool("browser_run_code_unsafe", {"code": "return page.title()"})

# ✅ 正确——必须传 async 函数,接收 page 参数
session.call_tool("browser_run_code_unsafe", {
    "code": "async (page) => { return await page.title(); }"
})

browser_tabs

# ❌ 错误——没有 "switch" 这个 action
session.call_tool("browser_tabs", {"action": "switch", "index": 0})

# ✅ 正确——用 "select"
session.call_tool("browser_tabs", {"action": "select", "index": 0})

browser_network_request

# ❌ 错误——index 不是 0-based
session.call_tool("browser_network_request", {"index": 0})

# ✅ 正确——1-based
session.call_tool("browser_network_request", {"index": 1})

这类错误的调试方法是直接用 list_tools() 打印每个工具的完整 inputSchema:

tools = await session.list_tools()
for tool in tools.tools:
    print(tool.name, json.dumps(tool.inputSchema, indent=2))

坑2:文件上传需要模态状态

browser_file_upload 这个工具必须在文件选择器弹出后才能使用,不能像 Playwright 原生 API 那样直接 set_input_files()

# ❌ 直接调用报错:"can only be used when there is related modal state present"
session.call_tool("browser_file_upload", {"paths": ["/tmp/file.txt"]})

# 需要用 run_code_unsafe 替代
session.call_tool("browser_run_code_unsafe", {
    "code": """async (page) => {
        const fi = page.locator('input[type=file]');
        const [fileChooser] = await Promise.all([
            page.waitForEvent('filechooser'),
            fi.click()
        ]);
        await fileChooser.setFiles('/tmp/file.txt');
        return 'done';
    }"""
})

而且上传后如果状态没清理,后续工具调用会报 “does not handle the modal state”,需要通过关闭页面或重新导航来重置。

坑3:选择器 strict mode

使用 text= 选择器时,如果匹配到多个元素会报 strict mode violation:

Error: strict mode violation: locator('text=暴力破解') resolved to 2 elements

解决方案:用更精确的选择器,如 role=link[name="精准文本"] 或直接在 snapshot 中取 ref。

另外,snapshot 中的 @eN ref 编号只在当次 snapshot 有效,跨操作使用会报 “Ref not found”。

坑4:example.com 页面已更新

测试时发现 example.com 的链接文本已经从 “More information…” 变成了 “Learn more”。这么经典的页面也会悄无声息地改版,写测试用例的时候要注意。

坑5:连接稳定性

长时间运行或连续快速调用后,MCP 连接可能进入 unreachable 状态。恢复方法:

hermes mcp test playwright

如果还不行,需要先杀掉旧进程、清理 PID 锁文件,再重新启动:

ps aux | grep playwright-mcp | grep -v grep | awk '{print $2}' | xargs kill
rm -rf /tmp/playwright-mcp.lock
bash ~/.local/bin/playwright-mcp-wrapper.sh &
hermes mcp test playwright

全功能测试结果

最终用 Python MCP 客户端写了一个完整的测试脚本,对全部 23 个工具做了 40 项功能测试。结果:

📊 测试总结
  总测试项: 40
  ✅ 通过: 39
  ❌ 失败: 1
  通过率: 97%

唯一失败的是 browser_file_upload 的模态状态问题(坑2),属于工具的设计限制,有明确的替代方案。

测试覆盖的功能点

功能 测试内容 结果
页面导航 example.com + 多级子页面
无障碍树 获取YAML格式快照(含ref)
全页截图 fullPage模式, 876KB
元素点击 文本选择器点击链接
页面后退 navigate_back
窗口缩放 800×600 / 375×667 / 1920×1080
JS执行 document.title / 链接统计 / Cookie / localStorage
输入框 目标输入文本
表单填充 多字段填充
下拉选择 select option values
键盘事件 Tab / Enter
元素悬停 hover交互
控制台 info / error 级别过滤
网络请求 列表 + 单请求详情(状态码/headers)
多标签 新建 / 列表 / 选中 / 关闭
等待机制 文本等待 / 时间等待
拖放 元素间拖放
对话框 alert自动接受
MIME拖放 data对象拖放
代码注入 page.title / locator.count / 多步操作 / 截图
页面关闭 资源释放

最终配置清单

总结一下,一个可用的 Playwright MCP 集成需要以下组件:

~/.cache/ms-playwright/chromium-1222/chrome-linux64/chrome  ← Chromium二进制 (276MB)
/opt/google/chrome/chrome → .../chrome-linux64/chrome        ← 符号链接
~/.local/bin/playwright-mcp-wrapper.sh                       ← 包装脚本(含PID锁+守护)
~/.hermes/config.yaml → mcp_servers.playwright               ← Hermes配置

启动流程:

bash ~/.local/bin/playwright-mcp-wrapper.sh &   # 后台启动
hermes mcp test playwright                       # 验证连接

结语

@playwright/mcp 为 AI Agent 提供了完整的浏览器操控能力,23 个工具覆盖了从导航、交互到网络分析的全部需求。虽然有一些小坑(参数名、文件上传状态),但核心功能稳定可用,是 AI 自动化流程中浏览器能力的优秀选择。

最大的感受:MCP 协议让工具与 AI 模型的解耦变得简单——不需要为每个 AI 框架单独适配,一次集成,到处可用。


如果你也在折腾 MCP 相关的集成,欢迎交流。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐