hangwin--mcp-chrome
8.4 KiB
8.4 KiB
静默执行(不抢焦点)方案 — background_op
本文档描述在不影响现有工具默认行为的前提下,为 Chrome MCP Server 增加“静默执行(不抢焦点)”能力的设计方案与落地细节。静默执行指:当用户正在使用页面 A 时,自动化流程可以在后台页面/标签 B 完成全流程,而不切换当前焦点、不前置窗口。
原始需求(来自业务方)
- 我正在操作 A 页面时,需要自动化去 B 页面完成“打开 URL、点击按钮、填表、截图”等动作。
- 希望这些动作在后台完成,不抢占我的焦点,不切换到 B 标签,不前置窗口。
- 同时,不能影响现有 tools 的能力与默认行为(已有脚本必须零改动可继续工作)。
范围与目标
- 目标:为主要页面相关工具提供“后台执行/不抢焦点”能力,支持在后台标签或最小化窗口中运行完整流程。
- 范围:导航、读页、交互、截图等常用工具;可选扩展到控制台与网络工具。
- 约束:默认行为保持不变;仅当显式传入新增选项时启用静默语义。
兼容性原则
- 向后兼容:不改动现有参数默认值与行为;新增参数均可选。
- 调用优先级:
tabId指定目标 > 当前活动标签(未提供tabId时才使用活动标签)。 - 便捷开关:
silent为快捷语义,不覆盖已显式传入的更细粒度参数(如activate/focusWindow)。
API 设计(仅新增可选参数)
为尽量减小侵入性,本方案仅做“参数增量”,并保证默认值与当前一致。
统一参数(适用于需要页面上下文的工具)
tabId?: number(可选)- 将操作定向到指定标签;未提供时沿用“活动标签页”。
silent?: boolean(可选,默认 false)- 静默模式快捷语义,对导航类等效于
activate:false+focusWindow:false;对读页/交互类仅表示“不会主动切换焦点”,实际行为由是否提供tabId决定。
- 静默模式快捷语义,对导航类等效于
导航工具 chrome_navigate(新增参数,默认不变)
- 新增:
activate?: boolean(默认 true)新开或复用目标标签时,是否激活该标签。focusWindow?: boolean(默认 true)是否前置包含该标签的窗口。newWindowState?: 'normal'|'minimized'(默认 'normal')新窗口状态。silent?: boolean(默认 false)为便捷开关,等效于activate:false+focusWindow:false(若同时显式传入activate/focusWindow,以显式参数为准)。
- 返回:在保持既有返回结构的基础上,补充
tabId与windowId字段,便于链式调用(已有调用可忽略该字段)。
读页与交互类
chrome_read_page、chrome_computer、chrome_click_element、chrome_fill_or_select、chrome_keyboard、chrome_screenshot:- 新增
tabId?: number,用于在后台标签执行。 - 未提供
tabId时,仍使用活动标签(与当前行为一致)。
- 新增
网络/控制台类(建议,非 MVP 必须)
chrome_console、chrome_network_capture_start/stop、chrome_network_debugger_start/stop:- 新增
tabId?: number;如参数包含url导航,则遵循activate/focusWindow/silent的语义。
- 新增
行为语义(静默模式)
静默导航
- 复用既有标签:
activate:false时不切换至该标签,不前置窗口,仅返回tabId。 - 新建标签:使用
active:false打开,且focusWindow:false时不前置窗口。 - 新建窗口(可选):使用
focused:false与newWindowState:'minimized',实现“完全后台”。
静默交互
- DOM 路径优先:在内容脚本中执行
HTMLElement.click、输入赋值并触发事件、scrollIntoView/scrollBy等,不依赖可见焦点。 - CDP 兜底:仅在 DOM 路径失败时使用 CDP 的 Input/鼠标滚轮等;完成后及时 detach,避免资源占用。
- 输入策略:优先“设置值 + dispatch 事件”,减少对真实键盘焦点的依赖。
等待与时序
- 导航等待:监听目标
tabId的tabs.onUpdated(状态complete)或使用 CDP 的Page.loadEventFired。 - 操作等待:基于 DOM 条件(元素可见、文本出现、属性匹配)替代依赖前台可见性的信号。
推荐调用范式(端到端不抢焦点)
- 后台打开 B:
{
"name": "chrome_navigate",
"args": { "url": "https://example.com/b", "silent": true }
}
响应中拿到 tabId。
- 读页:
{ "name": "chrome_read_page", "args": { "tabId": 123 } }
- 交互:
{ "name": "chrome_computer", "args": { "action": "left_click", "ref": "ref_14", "tabId": 123 } }
- 截图:
{ "name": "chrome_computer", "args": { "action": "screenshot", "tabId": 123 } }
- 关闭:
{ "name": "chrome_close_tabs", "args": { "tabIds": [123] } }
说明:若不使用
silent,也可手动设置activate:false与focusWindow:false达到相同效果。
边界与降级策略
- 需要“用户手势”的能力(文件选择对话框、系统权限弹窗、媒体自动播放、剪贴板写入等)在后台标签通常受限。
- 策略:优先 DOM 路径;如检测到受限能力,返回“需前台确认”的提示,让用户一键 bring-to-front 再继续。
- 站点基于
document.visibilityState/focus的行为门禁。- 策略:优先走后端 API/脚本方案;必要时提供“临时前置窗口(可配置时长)”可选项,或提示用户短暂聚焦继续。
- CDP 遗留差异:少数平台上 CDP 键鼠对非激活 tab 的行为差异。
- 策略:DOM 为主、CDP 兜底且重试;执行完立即 detach。
- 并发与资源:后台标签过多可能带来内存/CPU 压力。
- 策略:限制并发、执行完主动关闭标签;日志暴露执行耗时与失败原因,用于调优。
验收标准与用例
- 指标:
- A 页面始终保持活动(执行前后
activeTab未变化) - 静默流程成功率 ≥ 95%
- 静默与非静默耗时差 ≤ 10%
- A 页面始终保持活动(执行前后
- 用例:
- 新建后台标签执行完整流程(打开→读页→点击→截图→关闭)
- 复用既有标签静默执行(不切换、不前置)
- 受限能力触发“需前台确认”,前台继续后流程成功
实施分批(推荐顺序)
- P0(最小可用)
chrome_navigate增加activate/focusWindow/newWindowState/silent;返回补充tabId/windowIdchrome_read_page/chrome_computer/chrome_click_element/chrome_fill_or_select/chrome_keyboard/chrome_screenshot增加tabId- 文档与示例更新(TOOLS.md/TOOLS_zh.md)
- P1(增强)
chrome_console、chrome_network_*支持tabId与静默导航
- P2(配套)
- 录制/回放 Runner 增加
silent:true与startUrl;Builder 运行面板提供“静默执行”开关
- 录制/回放 Runner 增加
日志与监控
- 每次调用打印核心上下文:
{ tool, tabId, silent, activate, focusWindow }; - 统计:静默流程成功率、失败原因分布、自愈/兜底触发率、执行耗时分位(P50/P95)。
风险与回滚
- 发现强依赖前台可见性的站点时:允许配置“短暂前置窗口(如 2s)”应急;同时保留“完全静默”选项,避免全局退化。
- 若出现非预期聚焦变更:提供全局开关快速禁用静默路径,回滚至既有行为。
术语说明
- 静默执行:不切换当前活动标签,不前置窗口,在后台标签或最小化窗口中执行自动化。
- DOM 路径:通过内容脚本直接调用 DOM API 完成交互(更稳定且对焦依赖小)。
- CDP:Chrome DevTools Protocol,必要时用于兜底输入/滚动等行为。
附:行为片段(示意)
// Pseudocode — do not copy directly
// Navigate silently and return the new tab id
async function navigateSilently(url: string) {
// create background tab without focusing
const tab = await chrome.tabs.create({ url, active: false }); // no window focus
return tab.id;
}
// Send action to a specific background tab
async function clickByRefSilently(tabId: number, ref: string) {
// inject helper and dispatch click via DOM to avoid focus dependency
// Prefer DOM path; CDP as fallback
}
本方案仅通过“新增可选参数 + 行为分支”实现静默执行,保证默认行为与现有能力不受影响;当且仅当调用方显式传入 silent/tabId 等参数时,才启用静默路径。