- Multi-tab: browser_new_page / browser_list_pages / browser_switch_page / browser_close_page in playwright_mcp.py; each new page gets a fresh Playwright context, so cookies and storage are isolated between pages. Single-page tools act on the current page; switching to a missing index is an error, not a crash; closing the last page is an error (use browser_close). - Navigation allowlist: BROWSER_ALLOWED_HOSTS (comma list, leading-dot suffix match, case/port-insensitive) checked in _check_allowed_url before launching Chromium; unset (or empty) means no check, the old behaviour. file:// always allowed; localhost/127.0.0.1 have no special treatment. - Close cleanup: browser_close closes all pages and best-effort removes cwd browser-live.png / browser-live.json; custom screenshot files are untouched. list_pages needs no launch. - Egress filter: 10 programming-source Tinyproxy BASIC rules (python.org, nodejs.org, go.dev, pkg.go.dev, rust-lang.org, developer.mozilla.org, crates.io, stackoverflow.com, cve.mitre.org, nvd.nist.gov); already-present github.com / pypi.org / npmjs.org not duplicated; searx.diante.me stays exact-only, no diante.me wildcard. - Allowlist worker wiring: _docker_task_context now passes a set, non-empty BROWSER_ALLOWED_HOSTS from the worker env into [mcp_servers.playwright.env] in the tenant config, so the MCP process actually sees it (container -e alone does not reach MCP subprocesses, 2026-10-30). Unset/empty writes nothing and never overwrites; the value never goes into logs; it is not added to the websearch env block or the container env. ensure_playwright_mcp_env now returns False without rewriting when the result would be identical (canonical join: one blank line before the block), so a second prep leaves an unchanged tenant config alone; other sections untouched. - Skill + docs: browser-automation SKILL.md multi-tab/allowlist section; docs/platform-browser.md comparison doc (new file). - Tests (mock/fake only, no network, no real Chromium, no real credentials): cloud.tests.test_playwright + cloud.tests.test_websearch_worker, 48 tests OK, including 6 new wiring tests (switch off passes no variable, switch on reaches MCP env verbatim, empty never written, old-tenant merge idempotent + no-rewrite, ensure no-op when identical, allowlist enforces only after wiring). - NOT done (see PR body): no persistent profile, no credential vault, no approval card, no CAPTCHA bypass, in-page link navigation does not pass the allowlist, no real-Chromium live verification, host tinyproxy filter not reloaded.
5.2 KiB
name, description
| name | description |
|---|---|
| browser-automation | Use when a task needs a real browser: pages that render with JavaScript, clicking through pagination or forms, filling and submitting input, or taking a screenshot of what a page actually looks like. For a plain static page or a quick fact, use web_fetch / web_search first; open the browser only when static fetch cannot see the content. |
工具
browser_navigate(打开 URL,返回最终 URL 与标题)、
browser_snapshot(当前页标题、URL、正文,超 8000 字截断并标记)、
browser_click(按 CSS 选择器或 text=... 点击)、
browser_fill(按选择器填表)、
browser_evaluate(在页内跑 JS 表达式,返回字符串,限 4000 字)、
browser_screenshot(把当前页存成工作区内的 PNG,返回绝对路径与字节数)、
browser_click_at(按视口坐标点击,坐标系为 1280x800、原点左上角,
是 live 视图里用户点击的落点)、
browser_live_shot(把当前画面存成固定文件 browser-live.png,
附带 browser-live.json 状态:URL、标题、时间戳,供 watcher 轮询)、
browser_close(关闭浏览器,可重复调用)。
浏览器是单页的:一次 navigate,之后 snapshot / click / fill / screenshot 都针对同一页;要换页再 navigate。
live 视图(第一期)
有人在看浏览器时,每次 navigate / click / fill / click_at 之后
都要调一次 browser_live_shot,让 browser-live.png 保持最新;
不要只在最后截图一次。用户在 live 图上点的坐标会以 x/y 到达
browser_click_at,点完必须再 snapshot 一次确认变化,再调
browser_live_shot 刷新画面。
远控接管(第二期)
用户可以在控制台接管浏览器:接管期间(holder=user)你的 所有 browser_* 工具都会直接报错“user holds browser control”, 不要重试、不要 close 浏览器,停下来等用户交还;交还后 (holder 回到 agent)下一条继续消息会让你续跑,续跑前先 snapshot 一次看清用户改动到哪了。
新工具:browser_snapshot_refs(带 ref 的元素清单,点
browser_click_ref 比 CSS 选择器稳,页面重渲染后先重新
snapshot_refs 再点);browser_mouse_move / browser_key_press /
browser_type_text(键盘与鼠标,远控输入与 agent 工具同源)。
规则
- 先 navigate,再 snapshot 看实际渲染结果;click / fill 后 必须再 snapshot 一次确认变化,不要凭猜测汇报。
- 截图产出后用 shell / PIL 重新打开验证(格式、尺寸、非 0 字节)再交给用户;失败时贴出工具报错,不要换一张别的图顶替。
- 网络走 egress 代理:不在 Tinyproxy 白名单里的域名会报 代理 403,这时如实说明,不要绕过白名单。
- file:// URL 可用于打开工作区内已写好的测试页(验证 JS 执行、表单行为),是比外网更可靠的自测手段。
- 不要用浏览器做静态抓取能做的事;不要用 evaluate 绕过 click / fill 的正常路径去改页面状态,除非 snapshot 已证明 正常路径走不通。
多页与域名白名单(本期新增)
多页工具:browser_new_page(开新页并切到它,每次
new_page 都是全新 Playwright context,cookie 与存储天然
隔离,适合同时登录两个账号或对照两个页面)、
browser_list_pages(列出全部页:index、URL、标题、
哪一页是当前页;浏览器未启动时不启动,只返回空列表)、
browser_switch_page(按 index 切到指定页,之后
navigate / snapshot / click / fill / screenshot 都针对该页;
切到不存在的 index 会明确报错,不会崩掉 MCP,当前页不变;
切换后旧页的 snapshot_refs 全部失效,要重新 snapshot_refs)、
browser_close_page(关一页,缺省关当前页;关当前页后
自动切到上一页;关最后一页会明确报错,改用
browser_close 关整个浏览器)。
域名白名单:环境变量 BROWSER_ALLOWED_HOSTS(逗号列表,
如 example.com,.python.org)。未设置时行为完全不变,
只靠 egress 代理白名单;设置后 navigate 在启动浏览器之前
就检查:file:// 一律放行,http(s) 的 host 必须命中列表
(前导点条目做后缀匹配:.python.org 同时放行
python.org 与 docs.python.org,不放行
notpython.org),大小写与端口不影响匹配,未命中直接
报错且不启动 Chromium。localhost / 127.0.0.1 没有
特殊待遇:本地开发服务器要自己把它列进变量,否则会被挡。
清理:browser_close 会关掉全部页,并尽力删除工作区里的
browser-live.png 与 browser-live.json(删不掉也不报错),
所以 close 之后不要再拿旧 live 文件当“当前画面”汇报;
单个截图(browser_screenshot 的 shot-*.png)不受影响。
不在本轨范围:下载没有落盘清单(下载仍只落工作区文件, 无统一清单可查);没有持久 profile(每次 MCP 进程结束 cookie 即丢);没有登录保险库(账号密码仍不进浏览器工具)。 需要这些时不要假装已有,先如实说明缺口。