Essay 009 · Agent

Chrome DevTools MCP 为什么会开新窗口:Tools、参数与窗口复用边界

基于 @async23/chrome-devtools-mcp 1.7.0 的本机硬约束构建,说明 new_page 如何固定使用默认 BrowserContext 后台创建页面,以及这一做法仍受现有 Window 状态限制的边界。

首版:梳理 Tools、BrowserContext、Window 与 new_page 硬约束

Version 1.0

一句话结论:本机硬约束版本的 new_page 只接收 url 和可选 timeout,MCP 内部固定使用 background: true 与默认 BrowserContext;已有可用 Window 时会创建后台 Tab,但当前 API 仍不能在所有浏览器状态下硬性禁止新 Window。

适用版本:基于 @async23/chrome-devtools-mcp 1.7.0 的本机硬约束构建 673fcb1、Puppeteer 25.5.0、Chrome 151.0.7922.138。tool schema 按 --browserUrl=http://127.0.0.1:9222 和默认类别配置重新获取,共 29 个 Tools。

1. MCP 暴露的全部 Tools

以下列表来自本机新启动的 @async23/chrome-devtools-mcp 1.7.0 硬约束构建 673fcb1 实际暴露的默认 tool schema,共 29 个 Tools。

序号 类别 Tool 参数
1 Navigation close_page pageId: number
2 Navigation list_pages
3 Navigation navigate_page type?: url/back/forward/reloadurl?: stringignoreCache?: booleanhandleBeforeUnload?: accept/dismissinitScript?: stringtimeout?: number
4 Navigation new_page url: stringtimeout?: number
5 Navigation select_page pageId: numberbringToFront?: boolean
6 Navigation wait_for text: string[]timeout?: number
7 Emulation resize_page width: numberheight: number
8 Input click uid: stringdblClick?: booleanincludeSnapshot?: boolean
9 Input drag from_uid: stringto_uid: stringincludeSnapshot?: boolean
10 Input fill uid: stringvalue: stringincludeSnapshot?: boolean
11 Input fill_form elements: {uid,value}[]includeSnapshot?: boolean
12 Input hover uid: stringincludeSnapshot?: boolean
13 Input press_key key: stringincludeSnapshot?: boolean
14 Input type_text text: stringsubmitKey?: string
15 Input upload_file filePath: stringuid: stringincludeSnapshot?: boolean
16 Input handle_dialog action: accept/dismisspromptText?: string
17 Debugging take_snapshot filePath?: stringverbose?: boolean
18 Debugging take_screenshot filePath?: stringformat?: png/jpeg/webpfullPage?: booleanquality?: numberuid?: string
19 Debugging evaluate_script function: stringargs?: string[]dialogAction?: stringfilePath?: string
20 Console get_console_message msgid: number
21 Console list_console_messages includePreservedMessages?: booleanpageIdx?: numberpageSize?: numberserviceWorkerId?: stringtypes?: enum[]
22 Network get_network_request reqid?: numberrequestFilePath?: stringresponseFilePath?: string
23 Network list_network_requests includePreservedRequests?: booleanpageIdx?: numberpageSize?: numberresourceTypes?: enum[]
24 Emulation emulate colorScheme?: dark/light/autocpuThrottlingRate?: numberextraHttpHeaders?: stringgeolocation?: stringnetworkConditions?: enumuserAgent?: stringviewport?: string
25 Audit lighthouse_audit device?: desktop/mobilemode?: navigation/snapshotoutputDirPath?: string
26 Performance performance_analyze_insight insightName: stringinsightSetId: string
27 Performance performance_start_trace autoStop?: booleanfilePath?: stringreload?: boolean
28 Performance performance_stop_trace filePath?: string
29 Memory take_heapsnapshot filePath: string

2. 可能引发新窗口的 Tools

29 个 Tools 中,以下 5 个可能直接或间接导致桌面 Chrome 出现新窗口:

重点 Tools

序号 Tool 参数 开窗路径 是否依赖页面行为
1 new_page url: stringtimeout?: number MCP 固定在默认 BrowserContext 后台创建 page/target,Chrome 再决定放入已有 Window 还是新 Window 否;取决于普通 Profile 和现有 Window 状态
2 click uid: stringdblClick?: booleanincludeSnapshot?: boolean 点击 target="_blank" 链接或触发 window.open()
3 press_key key: stringincludeSnapshot?: boolean 激活链接、提交表单或触发页面键盘事件
4 type_text text: stringsubmitKey?: string submitKey 可能提交表单或触发页面脚本;单纯输入文字不会开窗
5 evaluate_script function: stringargs?: string[]dialogAction?: stringfilePath?: string 执行 window.open(),或调用页面中带有开窗行为的代码 部分依赖

重点 Tools 的参数

new_page

  • url:新 Page 要打开的 URL。
  • timeout:等待 Page 打开的最长毫秒数;0 使用默认超时。

本机硬约束构建不暴露 backgroundisolatedContext;传入这两个字段会按未知参数拒绝。

click

  • uid:要点击的元素 ID,取自最新的页面快照。
  • dblClick:是否双击;默认 false
  • includeSnapshot:操作后是否顺便返回页面的文字与控件快照;true 近似于点击后再调用 take_snapshot,默认 false,与开窗无关。

press_key

  • key:要按下的按键或组合键,如 EnterControl+A
  • includeSnapshot:操作后是否顺便返回页面的文字与控件快照;true 近似于按键后再调用 take_snapshot,默认 false,与开窗无关。

type_text

  • text:输入到当前已聚焦控件中的文字。
  • submitKey:输入后追加按下的键,如 EnterTabEscape

evaluate_script

  • function:要在当前页面执行的 JavaScript 函数。
  • args:传给函数的元素 uid 列表,按顺序对应函数参数。
  • dialogAction:脚本触发弹窗时选择 acceptdismiss,或提供 prompt 文本。
  • filePath:把执行结果写入指定文件,而不是直接返回。

3. 开窗行为的可控程度

“可控”是指:无需穷举任意网页的 HTML 和 JavaScript,仅根据 tool 参数、MCP 源码和浏览器状态,就能判断是否存在开窗行为。

序号 Tool 可控程度 原因 结论范围
1 new_page 创建 page 是 tool 的直接职责,窗口选择规则可沿 MCP、Puppeteer 和 Chrome 源码确定 作为主要研究对象
2 evaluate_script 执行的函数由我们提供,但函数仍可调用 window.open() 或页面自有代码 约束脚本内容,不尝试穷举页面代码
3 click 结果取决于目标元素、target 属性和点击事件处理器 只记录风险,不穷举页面行为
4 press_key 结果取决于当前焦点元素和页面键盘事件处理器 只记录风险,不穷举页面行为
5 type_text 结果取决于 submitKey、表单目标和页面提交逻辑 只记录风险,不穷举页面行为

new_page 是“窗口复用”问题的主要研究对象。其余 4 个 Tools 都可能间接触发窗口,但无法脱离具体页面给出穷尽式结论。

4. 术语与对象关系

核心术语

序号 术语 所属范围 定义
1 user-data-dir 磁盘 Chrome 的数据根目录,包含 Local State 以及 DefaultProfile 1 等 Profile 数据目录;目录本身不是运行实例
2 Chrome 实例 运行时 一套正在运行的 Chrome,由一个 Browser 主进程及其子进程组成,并使用一个 user-data-dir;一个实例可以加载该目录中的多个普通 Profile
3 Profile Chrome 实现 Chrome 的身份与存储对象。普通 Profile 通常持久化在 user-data-dir 的子目录中;off-the-record Profile 是运行时临时对象
4 BrowserContext Chrome/CDP/Puppeteer 身份与存储隔离范围,决定 cookies、storage 等数据是否共享;Chrome 当前使用 Profile 对象实现这些范围
5 默认 BrowserContext Chrome/CDP/Puppeteer Chrome/Puppeteer 已有、不是通过 CDP Target.createBrowserContext 创建的 Context;在本文调用链中,未传 browserContextId 时使用 Chrome 选中的普通 Profile
6 非默认 BrowserContext Chrome/CDP/Puppeteer 通过 CDP Target.createBrowserContext 创建并取得 browserContextId 的 Context;Chrome 当前为其创建独立的 off-the-record Profile
7 Window Chrome 界面 macOS 桌面上的 Chrome 窗口;一个 Window 关联一个 Profile,不能混放属于不同 Profile 的 Tab
8 Tab Chrome 界面 Window 标签栏中的标签页;new_page 创建的页面目标最终成为已有 Window 中的新 Tab,或新 Window 中的第一个 Tab

“默认 BrowserContext”和“非默认 BrowserContext”是 Chrome/CDP/Puppeteer 概念。“隔离 BrowserContext”描述非默认 BrowserContext 的隔离性质;isolatedContext 则是基础版本曾使用的 MCP 参数名。

Default 是本机 Profile 数据目录的名称;“默认 BrowserContext”是运行时/API 概念。二者在本机当前调用链中相互对应,但不是同一个术语。

new_page 涉及的对象关系

Chrome 实例(使用一个 user-data-dir)
├── 默认 BrowserContext
│   └── Chrome 选中的普通 Profile
│       └── 一个或多个 Window
│           └── 一个或多个 Tab
└── 一个或多个非默认 BrowserContext
    └── 各自的 off-the-record Profile
        └── 零个或多个 Window
            └── 零个或多个 Tab

源码与 API 术语

序号 术语 准确定义 与本文的关系
1 MCP Server 接收 tool 调用并通过 Puppeteer/CDP 控制 Chrome 的 Node.js 进程 与 Chrome 实例是两个独立进程体系
2 CDP Chrome DevTools Protocol;提供 Target.createBrowserContextTarget.createTarget 等协议方法 MCP 经 Puppeteer 调用 Chrome 的底层协议
3 browserContextId CDP 为非默认 BrowserContext 返回的匿名 ID;创建 Target 时可用它指定目标 Context Chrome 识别该 ID,不识别 MCP 自定义名称
4 isolatedContext 基础版本曾由 new_page 暴露,用于把名称映射到非默认 BrowserContext;本机硬约束构建已从公开 schema 删除该参数 不是 Chrome/CDP 参数;McpContext 仍保留内部映射能力,但公开 new_page 无法使用它创建页面
5 off-the-record Profile 不按普通 Profile 方式持久化浏览数据的临时 Profile Chrome 当前用它实现 CDP 创建的非默认 BrowserContext
6 Page Puppeteer 对页面 Target 的操作对象,表示页面内容与操作接口 new_page 调用链中对应新 Tab 内的网页,但 Page 不等同于 Tab 这个界面容器
7 Target CDP 的可调试实体,可表示 page、service worker 等多种对象 new_page 创建的是页面 Target,不是所有 Target 都是 Tab
8 Browser 主进程 管理 Profile、Window、Tab、CDP 会话及 Chrome 子进程的操作系统进程 是 Chrome 实例的核心进程
9 Renderer Chrome 用于渲染页面及 frame 的子进程;受 Site Isolation 等规则影响,与 Tab 不保证一一对应 不参与 Chrome 对新 Tab 应进入已有 Window 还是新 Window 的选择
10 前台 / 后台 新 Tab 是否成为活动 Tab,以及对应 Window 是否主动获得焦点的状态 不表示 Window 是否存在,也不等于 headless
11 headless Chrome 不显示常规桌面浏览器界面的运行模式 background: true 是不同概念
12 newWindow CDP Target.createTarget 的可选参数;当前 Chrome 中,true 要求新建 Window,显式 false 要求使用已有兼容 Window,省略时允许在没有兼容 Window 时回退为新建 Window 当前 MCP new_page 未暴露该参数
13 windowId CDP Browser.WindowID,用于查询或修改已有 Window 的状态和尺寸 Target.createTarget 不接受 windowId,因此不能用它指定新 Tab 落入哪个现有 Window

5. 本机 Chrome 环境

以下内容是 2026-08-16 22:39:24 +08:00 的检查快照。进程状态和非默认 BrowserContext 数量会随 Chrome、MCP 的运行情况变化。

磁盘:user-data-dir 与普通 Profile

~/Library/Application Support/Google 范围内,检测到 5 个包含 Local State 和 Profile 元数据的目录:

序号 目录 Local State 记录的普通 Profile 目录 检查时的运行状态 说明
1 ~/Library/Application Support/Google/Chrome Default 未运行 Chrome 默认 user-data-dir
2 ~/Library/Application Support/Google/Chrome-CDP Default 正在运行 该目录对应的 Chrome 实例监听 127.0.0.1:9222
3 ~/Library/Application Support/Google/Chrome-backup Default 未运行 结构符合 user-data-dir;可能只是备份,未确认曾用于启动 Chrome
4 自定义 user-data-dir A Default 未运行 独立数据目录;具体名称不公开
5 自定义 user-data-dir B Default 未运行 独立数据目录;具体名称不公开

这里能确定的是 5 个目录各保存了一份名为 Default 的普通 Profile 数据。由于 Chrome-backup 可能是复制出来的备份,不能仅凭目录结构断言本机实际使用过 5 个彼此独立的普通 Profile。

运行时:Chrome 实例与 BrowserContext

序号 检查项 数量或结果 说明
1 正在运行的 Chrome 实例 1 使用 Chrome-CDP,监听 9222
2 该实例当前使用的普通 Profile 数据目录 Chrome-CDP/Default user-data-dir 只记录了一个普通 Profile
3 默认 BrowserContext 1 隐式存在,不包含在 Target.getBrowserContexts 的返回列表中
4 CDP 返回的非默认 BrowserContext 6 Target.getBrowserContexts 实测;Chrome 当前以临时 off-the-record Profile 实现

非默认 BrowserContext 没有可供 --profile-directory 选择的普通 Profile 目录,也不应计入磁盘上的普通 Profile 数据数量。

6. new_page 的本机硬约束

对外 schema

Agent 只需要调用:

{
  "url": "https://example.com"
}

timeout 可选:

序号 参数 类型 / 必填 作用
1 url string / 是 新 Page 要加载的 URL
2 timeout number / 否 等待 Page 打开的最长毫秒数;0 使用默认超时

backgroundisolatedContext 不在 schema 中。调用方传入其中任一字段时,ToolHandler 会按未知参数拒绝请求,不会创建 Page。

MCP 内部固定行为

src/tools/pages.ts 的 handler 固定调用:

context.newPage(true, undefined);
序号 内部参数 固定值 结果
1 background true 新 Page 不主动成为前台 Tab,也不主动前置 Window
2 isolatedContextName undefined 使用默认 BrowserContext,不通过 new_page 创建非默认 BrowserContext

前后台与 Context 的选择已经从 Agent 输入移到 MCP 执行层,不再依赖提示词约束。

Window 复用条件

默认 BrowserContext 对应的普通 Profile 已有可用 Window 时,新 Page 会成为该 Window 中的后台 Tab。检查快照中已有的 6 个非默认 BrowserContext 不参与这次调用。

如果默认 BrowserContext 没有可用 Window,Chrome 仍可能创建一个不主动获得焦点的新 Window。硬约束固定的是 MCP 参数,不改变 Chrome 在无可复用 Window 时的回退行为。

运行时验证

2026-08-16 22:42:27 +08:00 通过本机 current 入口执行端到端验证:

序号 检查项 结果
1 默认暴露的 Tool 数量 29
2 new_page 对外参数 urltimeout
3 url 必填状态 必填
4 background 参数 按未知参数拒绝,未创建 Page
5 isolatedContext 参数 按未知参数拒绝,未创建 Page 或 BrowserContext
6 合法 new_page 调用 在默认 BrowserContext 创建 Page
7 Window 数量 调用前后均为 1,复用现有 Window
8 非默认 BrowserContext 数量 调用前后均为 6,没有创建新 Context
9 验证 Page 验证后已关闭

API 能力边界

new_page 没有暴露 CDP 的 newWindow 参数。CDP Target.createTarget 本身也不接受 windowId,所以当前调用链无法指定新 Tab 必须进入某个现有 Window。

必须绝对禁止新 Window 时,不调用 new_page,改用 list_pagesselect_page({bringToFront: false})navigate_page 复用现有 Tab。

7. 参考资料

  1. Async23 Chrome DevTools MCP 本机硬约束源码(commit 673fcb1
  2. ChromeDevTools Chrome DevTools MCP 官方仓库
  3. Chrome DevTools MCP 本机硬约束 Tool Reference
  4. 本机硬约束版本的 new_page Tool 定义
  5. MCP BrowserContext 映射与 newPage 实现
  6. Puppeteer 25.5.0 BrowserContext API
  7. Chrome DevTools Protocol:Target Domain
  8. Chromium 151.0.7922.138:CDP Target Handler
  9. Chromium 151.0.7922.138:Chrome DevTools Manager Delegate
查看本文修订记录(1)
  1. v1.0 · 2026.08.17 首次发布。