为什么需要 Puppeteer MCP
很多 MCP 解决的是"读"的问题:
Filesystem MCP → 读本地文件
GitHub MCP → 读代码
Notion MCP → 读文档
但真实世界有一大类任务卡在"浏览器":
"帮我看看这个商品页现在多少钱"
→ 页面是 JS 动态渲染 → curl 拿到的是空壳
→ 必须真浏览器执行 JS
"帮我每天填一次打卡表单"
→ 要登录、点按钮、填字段、提交
→ 读文件读不出按钮
"这个页面上线后布局错没"
→ 要看渲染后的样子,不是 HTML 源码
→ 要截图给 AI 看
Puppeteer MCP 给 AI 一个无头(或带界面)的 Chrome:能导航、能点、能填、能截图、能抓动态内容。把"看不了动态网页"这个最后一块拼图补上。
核心能力
| 工具 | 说明 |
|---|---|
| 导航 | 打开 URL,等待加载完成 |
| 点击 | 点元素(按选择器) |
| 填表 | 给 input/textarea 输入文本 |
| 提取 | 抓取页面文本/元素内容 |
| 截图 | 整页或指定元素截图(可让 AI"看") |
| 执行 JS | 在页面上下文跑自定义脚本 |
| 等待 | 等元素出现/网络空闲 |
安装与配置
Step 1:环境依赖
Puppeteer 需要 Chrome。首次运行 npx 会自动下载 Chromium,无需手动装。
Step 2:各客户端配置
Claude Desktop
{
"mcpServers": {
"puppeteer": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
}
}
}
Cursor / VS Code Continue
{
"mcpServers": {
"puppeteer": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"],
"env": {
"PUPPETEER_HEADLESS": "true"
}
}
}
}
Step 3:验证
打开 https://example.com 并截图
AI 调用浏览器导航、截图并返回图片,确认配置成功。
五个实战场景
场景 1:抓 JS 动态渲染页
你:抓 example-shop.com 的当前商品价格
AI:
1. 导航到商品页
2. 等待 .price 元素出现
3. 提取价格文本
4. 返回"¥299"
curl 抓不到(JS 渲染),Puppeteer 等渲染完再读。
场景 2:表单自动化
你:登录 oa.example.com,用户名 admin 密码 xxx,然后点"打卡"
AI:
1. 导航到登录页
2. 填 #username = admin
3. 填 #password = xxx
4. 点 #login-btn
5. 等待跳转
6. 点 #checkin-btn
7. 截图确认"打卡成功"
场景 3:视觉回归
配合截图能力,做页面视觉监控:
你:对比 example.com 首页今天和昨天的截图
AI:
1. 今天截图存 today.png
2. 读昨天 baseline.png
3. 像素级 diff
4. 标出差异区域
5. 差异 > 阈值则告警
场景 4:E2E 测试
你:测注册流程能不能跑通
AI:
1. 导航到 /register
2. 填邮箱、密码
3. 点注册
4. 断言出现"激活邮件已发送"
5. 失败则截图 + 报错
场景 5:监控告警
你:每 10 分钟检查支付页是否在线
AI(定时):
1. 导航支付页
2. 等待核心元素
3. 超时未出现 → 截图 → Slack 告警(Slack MCP)
权限管控要点
1. 无头优先
日常用 headless 模式(PUPPETEER_HEADLESS=true)
调试时才开有头模式看实际操作
2. 域名白名单
✗ 给 MCP 任意 URL 访问权 → 可能被诱导访问恶意页
✓ 在 system prompt 限定可访问域名
3. 凭证隔离
✗ 把生产账号密码写进 MCP 配置 → 泄露风险
✓ 用只读测试账号,敏感操作要二次确认
4. 执行 JS 的边界
Puppeteer 能在页面跑任意 JS
→ system prompt 约束:只在目标页执行,不注入恶意脚本
→ 不在银行/支付页执行自定义 JS
注意事项
1. 资源占用
无头 Chrome 吃内存,批量任务要控制并发:
import asyncio
async def crawl(urls, concurrency=3):
sem = asyncio.Semaphore(concurrency)
async def one(url):
async with sem:
await visit(url) # 控制并发避免 OOM
await asyncio.gather(*[one(u) for u in urls])
2. 反爬与验证码
高频访问触发反爬 → IP 被封
验证码 → Puppeteer 过不了(需要打码服务)
解决:加延迟、限频,验证码场景留给人。
3. 等待策略
✗ 固定 sleep(5) → 慢的页等不够,快的页白等
✓ 等元素出现 / 网络空闲
4. 选择器脆弱
页面改版 → .btn-submit 变成 .btn-primary → 脚本失效
解决:用 data-testid 等稳定属性,或在脚本里加容错。
5. 截图体积
整页截图可能很大,传给 AI 看时注意压缩或截关键区域。
与其他 MCP 的协作
| 组合 | 场景 |
|---|---|
| Puppeteer + Filesystem | 抓动态页存本地 |
| Puppeteer + GitHub | E2E 失败自动建 issue |
| Puppeteer + Slack | 页面异常告警团队 |
| Puppeteer + Postgres | 抓数据入库 |
与 Filesystem MCP 的区别
| 维度 | Puppeteer MCP | Filesystem MCP |
|---|---|---|
| 读什么 | 动态渲染页 | 本地文件 |
| 交互 | 点击/填表 | 读写文件 |
| 依赖 | 浏览器 | 文件系统 |
| 适合 | 网页自动化 | 本地数据处理 |
小结
Puppeteer MCP 给 AI 补上"会用浏览器"这块拼图——读得了动态页、点得了按钮、看得见截图。
记住一个原则:无头优先、域名白名单、凭证隔离。配合 Filesystem MCP(存抓取结果)、GitHub MCP(失败建 issue)、Slack MCP(异常告警),AI 的手就伸到了真实网页——从"会读文件"进化到"会操作浏览器"。