firefox-devtools-mcp-automation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFirefox DevTools MCP Automation
Firefox DevTools MCP 自动化
What It Does
功能介绍
Firefox DevTools MCP is a Model Context Protocol server that enables AI assistants to inspect and control Firefox browser through the Remote Debugging Protocol (WebDriver BiDi). It provides tools for:
- Page navigation and management (open, close, switch tabs)
- Element interaction (click, fill forms, hover, drag)
- Visual inspection (screenshots, snapshots with UIDs)
- Network monitoring (capture requests/responses)
- Console log access
- JavaScript execution
- Firefox management and preferences
- WebExtension installation
Firefox DevTools MCP是一款Model Context Protocol服务器,允许AI助手通过Remote Debugging Protocol(WebDriver BiDi)检查和控制Firefox浏览器。它提供以下工具:
- 页面导航与管理(打开、关闭、切换标签页)
- 元素交互(点击、填充表单、悬停、拖拽)
- 视觉检查(截图、带UID的快照)
- 网络监控(捕获请求/响应)
- 控制台日志访问
- JavaScript执行
- Firefox管理与偏好设置
- WebExtension安装
Security Considerations
安全注意事项
Always use a dedicated Firefox profile — the agent has access to cookies, sessions, and everything the browser can reach.
- Avoid visiting untrusted sites (risk of prompt injection)
- Only enable and
--enable-scriptwhen necessary--enable-privileged-context - Never run against your regular browsing profile
请始终使用专用的Firefox配置文件 —— 该Agent可以访问Cookie、会话以及浏览器能触及的所有内容。
- 避免访问不可信网站(存在提示注入风险)
- 仅在必要时启用和
--enable-script--enable-privileged-context - 切勿在常规浏览配置文件上运行
Installation
安装
Quick Start with npx (Recommended)
使用npx快速启动(推荐)
bash
undefinedbash
undefinedAdd to Claude Code
添加到Claude Code
claude mcp add firefox-devtools npx firefox-devtools-mcp@latest
claude mcp add firefox-devtools npx firefox-devtools-mcp@latest
With options
带参数启动
claude mcp add firefox-devtools npx firefox-devtools-mcp@latest -- --headless --viewport 1280x720
undefinedclaude mcp add firefox-devtools npx firefox-devtools-mcp@latest -- --headless --viewport 1280x720
undefinedManual Configuration
手动配置
Add to MCP settings JSON ( on macOS):
~/Library/Application Support/Claude/Code/mcp_settings.jsonjson
{
"mcpServers": {
"firefox-devtools": {
"command": "npx",
"args": ["-y", "firefox-devtools-mcp@latest", "--headless"],
"env": {
"START_URL": "about:home",
"FIREFOX_HEADLESS": "true"
}
}
}
}添加到MCP设置JSON文件(macOS路径:):
~/Library/Application Support/Claude/Code/mcp_settings.jsonjson
{
"mcpServers": {
"firefox-devtools": {
"command": "npx",
"args": ["-y", "firefox-devtools-mcp@latest", "--headless"],
"env": {
"START_URL": "about:home",
"FIREFOX_HEADLESS": "true"
}
}
}
}Test with MCP Inspector
使用MCP Inspector测试
bash
npx @modelcontextprotocol/inspector npx firefox-devtools-mcp@latest --start-url https://example.com --headlessbash
npx @modelcontextprotocol/inspector npx firefox-devtools-mcp@latest --start-url https://example.com --headlessConfiguration Options
配置选项
CLI Flags
CLI参数
bash
undefinedbash
undefinedBasic options
基础选项
--firefox-path /path/to/firefox # Custom Firefox binary path
--headless # Run without UI
--viewport 1280x720 # Initial window size
--profile-path /path/to/profile # Use specific Firefox profile
--start-url https://example.com # Open URL on start
--firefox-path /path/to/firefox # 自定义Firefox二进制文件路径
--headless # 无UI模式运行
--viewport 1280x720 # 初始窗口大小
--profile-path /path/to/profile # 使用特定Firefox配置文件
--start-url https://example.com # 启动时打开指定URL
Security options
安全选项
--accept-insecure-certs # Ignore TLS errors
--enable-script # Enable evaluate_script tool
--enable-privileged-context # Enable privileged tools
--accept-insecure-certs # 忽略TLS错误
--enable-script # 启用evaluate_script工具
--enable-privileged-context # 启用特权工具
Connection options
连接选项
--connect-existing # Attach to running Firefox
--marionette-port 2828 # Marionette port (default: 2828)
--connect-existing # 附加到正在运行的Firefox
--marionette-port 2828 # Marionette端口(默认:2828)
Advanced options
高级选项
--firefox-arg --arg-name # Extra Firefox arguments (repeatable)
--pref name=value # Set Firefox preference (repeatable)
undefined--firefox-arg --arg-name # 额外的Firefox参数(可重复使用)
--pref name=value # 设置Firefox偏好(可重复使用)
undefinedEnvironment Variables
环境变量
bash
FIREFOX_HEADLESS=true
START_URL=https://example.com
ACCEPT_INSECURE_CERTS=true
CONNECT_EXISTING=true
MARIONETTE_PORT=2828
ENABLE_SCRIPT=true
ENABLE_PRIVILEGED_CONTEXT=truebash
FIREFOX_HEADLESS=true
START_URL=https://example.com
ACCEPT_INSECURE_CERTS=true
CONNECT_EXISTING=true
MARIONETTE_PORT=2828
ENABLE_SCRIPT=true
ENABLE_PRIVILEGED_CONTEXT=trueCore Workflow
核心工作流程
1. Page Navigation and Management
1. 页面导航与管理
typescript
// List all open pages/tabs
list_pages()
// Returns: { pages: [{ id, url, title, isActive }] }
// Create new page
new_page({ url: "https://example.com" })
// Returns: { pageId, url }
// Navigate existing page
navigate_page({
pageId: "page-id-123",
url: "https://example.com/login"
})
// Switch active page
select_page({ pageId: "page-id-123" })
// Close page
close_page({ pageId: "page-id-123" })typescript
// 列出所有打开的页面/标签页
list_pages()
// 返回: { pages: [{ id, url, title, isActive }] }
// 创建新页面
new_page({ url: "https://example.com" })
// 返回: { pageId, url }
// 导航已有页面
navigate_page({
pageId: "page-id-123",
url: "https://example.com/login"
})
// 切换活动页面
select_page({ pageId: "page-id-123" })
// 关闭页面
close_page({ pageId: "page-id-123" })2. Snapshot and UID-Based Interaction
2. 快照与基于UID的交互
The snapshot system assigns unique UIDs to interactive elements, enabling precise interaction without CSS selectors.
typescript
// Take snapshot of current page
take_snapshot()
// Returns: {
// snapshot: "Visual representation with [uid] markers",
// elements: [{ uid, role, name, tagName, coordinates }]
// }
// Click element by UID
click_by_uid({ uid: "abc123" })
// Fill input field
fill_by_uid({
uid: "def456",
value: "user@example.com"
})
// Hover over element
hover_by_uid({ uid: "ghi789" })
// Drag and drop
drag_by_uid({
sourceUid: "drag-me",
targetUid: "drop-here"
})
// Upload file
upload_by_uid({
uid: "file-input",
filePath: "/path/to/file.pdf"
})
// Fill entire form at once
fill_form_by_uids({
fields: [
{ uid: "email-field", value: "user@example.com" },
{ uid: "password-field", value: "secure-password" },
{ uid: "submit-button", action: "click" }
]
})
// Clear UIDs after navigation
clear_uids()快照系统为交互元素分配唯一UID,无需CSS选择器即可实现精准交互。
typescript
// 拍摄当前页面快照
take_snapshot()
// 返回: {
// snapshot: "带[uid]标记的视觉表示",
// elements: [{ uid, role, name, tagName, coordinates }]
// }
// 通过UID点击元素
click_by_uid({ uid: "abc123" })
// 填充输入字段
fill_by_uid({
uid: "def456",
value: "user@example.com"
})
// 悬停在元素上
hover_by_uid({ uid: "ghi789" })
// 拖拽操作
drag_by_uid({
sourceUid: "drag-me",
targetUid: "drop-here"
})
// 文件上传
upload_by_uid({
uid: "file-input",
filePath: "/path/to/file.pdf"
})
// 一次性填充整个表单
fill_form_by_uids({
fields: [
{ uid: "email-field", value: "user@example.com" },
{ uid: "password-field", value: "secure-password" },
{ uid: "submit-button", action: "click" }
]
})
// 导航后清除UID
clear_uids()3. Visual Capture
3. 视觉捕获
typescript
// Screenshot entire page
screenshot_page()
// Returns: { screenshot: "base64-encoded-png" }
// Save to disk (recommended for Claude Code to save context)
screenshot_page({
saveTo: "/tmp/page.png"
})
// Returns: { filePath: "/tmp/page.png" }
// Screenshot specific element
screenshot_by_uid({
uid: "abc123",
saveTo: "/tmp/element.png"
})typescript
// 截取整个页面
screenshot_page()
// 返回: { screenshot: "base64编码的PNG" }
// 保存到磁盘(推荐用于Claude Code以节省上下文)
screenshot_page({
saveTo: "/tmp/page.png"
})
// 返回: { filePath: "/tmp/page.png" }
// 截取特定元素
screenshot_by_uid({
uid: "abc123",
saveTo: "/tmp/element.png"
})4. Network Monitoring
4. 网络监控
Network capture is always-on. Use ID-first approach to inspect requests:
typescript
// List all captured network requests
list_network_requests()
// Returns: {
// requests: [{
// id, method, url, status,
// contentType, responseSize, duration
// }]
// }
// Filter requests
list_network_requests({
filter: {
method: "POST",
status: 200,
urlPattern: "api.example.com"
}
})
// Get detailed request/response
get_network_request({ requestId: "req-123" })
// Returns: {
// request: { method, url, headers, body },
// response: { status, headers, body }
// }网络捕获始终处于开启状态。使用基于ID的方式检查请求:
typescript
// 列出所有捕获的网络请求
list_network_requests()
// 返回: {
// requests: [{
// id, method, url, status,
// contentType, responseSize, duration
// }]
// }
// 过滤请求
list_network_requests({
filter: {
method: "POST",
status: 200,
urlPattern: "api.example.com"
}
})
// 获取详细的请求/响应信息
get_network_request({ requestId: "req-123" })
// 返回: {
// request: { method, url, headers, body },
// response: { status, headers, body }
// }5. Console Messages
5. 控制台消息
typescript
// List console logs
list_console_messages()
// Returns: {
// messages: [{
// level, text, timestamp,
// url, lineNumber
// }]
// }
// Clear console
clear_console_messages()typescript
// 列出控制台日志
list_console_messages()
// 返回: {
// messages: [{
// level, text, timestamp,
// url, lineNumber
// }]
// }
// 清空控制台
clear_console_messages()6. JavaScript Execution
6. JavaScript执行
Requires flag
--enable-scripttypescript
// Execute JavaScript in page context
evaluate_script({
script: "document.title"
})
// Returns: { result: "Page Title" }
// Access DOM
evaluate_script({
script: `
const button = document.querySelector('.submit-btn');
return button ? button.textContent : null;
`
})
// Modify page
evaluate_script({
script: `
document.body.style.backgroundColor = 'lightblue';
return 'Background changed';
`
})需要参数
--enable-scripttypescript
// 在页面上下文中执行JavaScript
evaluate_script({
script: "document.title"
})
// 返回: { result: "页面标题" }
// 访问DOM
evaluate_script({
script: `
const button = document.querySelector('.submit-btn');
return button ? button.textContent : null;
`
})
// 修改页面
evaluate_script({
script: `
document.body.style.backgroundColor = 'lightblue';
return '背景已更改';
`
})7. Browser Utilities
7. 浏览器工具
typescript
// Navigate history
history_back()
history_forward()
// Set viewport size
set_viewport({ width: 1920, height: 1080 })
// Handle dialogs
accept_dialog({ promptText: "optional text for prompts" })
dismiss_dialog()
// Get Firefox info
get_firefox_info()
// Returns: { version, buildId, profilePath, binaryPath }
// View Firefox console output
get_firefox_output()
// Returns: { stdout, stderr }
// Restart Firefox
restart_firefox()typescript
// 历史导航
history_back()
history_forward()
// 设置视口大小
set_viewport({ width: 1920, height: 1080 })
// 处理对话框
accept_dialog({ promptText: "提示框可选文本" })
dismiss_dialog()
// 获取Firefox信息
get_firefox_info()
// 返回: { version, buildId, profilePath, binaryPath }
// 查看Firefox控制台输出
get_firefox_output()
// 返回: { stdout, stderr }
// 重启Firefox
restart_firefox()Common Patterns
常见模式
Login Flow
登录流程
typescript
// 1. Navigate to login page
navigate_page({
pageId: "page-1",
url: "https://app.example.com/login"
})
// 2. Take snapshot to get UIDs
const snap = take_snapshot()
// Inspect snap.snapshot to find email/password/submit UIDs
// 3. Fill and submit form
fill_form_by_uids({
fields: [
{ uid: "email-uid", value: process.env.USER_EMAIL },
{ uid: "password-uid", value: process.env.USER_PASSWORD },
{ uid: "submit-uid", action: "click" }
]
})
// 4. Wait and verify success
// (add delay or check for redirect)typescript
// 1. 导航到登录页面
navigate_page({
pageId: "page-1",
url: "https://app.example.com/login"
})
// 2. 拍摄快照获取UID
const snap = take_snapshot()
// 查看snap.snapshot找到邮箱/密码/提交按钮的UID
// 3. 填充并提交表单
fill_form_by_uids({
fields: [
{ uid: "email-uid", value: process.env.USER_EMAIL },
{ uid: "password-uid", value: process.env.USER_PASSWORD },
{ uid: "submit-uid", action: "click" }
]
})
// 4. 等待并验证登录成功
// (添加延迟或检查重定向)Web Scraping with Network Monitoring
结合网络监控的网页抓取
typescript
// 1. Navigate to page
navigate_page({
pageId: "page-1",
url: "https://api-site.example.com/dashboard"
})
// 2. Interact to trigger API calls
const snap = take_snapshot()
click_by_uid({ uid: "load-more-button-uid" })
// 3. Capture API responses
const requests = list_network_requests({
filter: {
urlPattern: "api.example.com/v1/data",
method: "GET"
}
})
// 4. Extract data from response
const apiData = get_network_request({
requestId: requests.requests[0].id
})
// Parse apiData.response.bodytypescript
// 1. 导航到页面
navigate_page({
pageId: "page-1",
url: "https://api-site.example.com/dashboard"
})
// 2. 触发API调用
const snap = take_snapshot()
click_by_uid({ uid: "load-more-button-uid" })
// 3. 捕获API响应
const requests = list_network_requests({
filter: {
urlPattern: "api.example.com/v1/data",
method: "GET"
}
})
// 4. 从响应中提取数据
const apiData = get_network_request({
requestId: requests.requests[0].id
})
// 解析apiData.response.bodyVisual Regression Testing
视觉回归测试
typescript
// 1. Navigate to page
navigate_page({
pageId: "page-1",
url: "https://example.com/component"
})
// 2. Take baseline screenshot
screenshot_page({ saveTo: "/tmp/baseline.png" })
// 3. Make changes via script or interaction
evaluate_script({
script: `document.querySelector('.hero').style.fontSize = '24px'`
})
// 4. Take comparison screenshot
screenshot_page({ saveTo: "/tmp/comparison.png" })
// 5. Use image diff tool externallytypescript
// 1. 导航到页面
navigate_page({
pageId: "page-1",
url: "https://example.com/component"
})
// 2. 拍摄基准截图
screenshot_page({ saveTo: "/tmp/baseline.png" })
// 3. 通过脚本或交互修改页面
evaluate_script({
script: `document.querySelector('.hero').style.fontSize = '24px'`
})
// 4. 拍摄对比截图
screenshot_page({ saveTo: "/tmp/comparison.png" })
// 5. 使用外部图片差异工具对比Form Automation
表单自动化
typescript
// Multi-step form with snapshots at each step
const pages = list_pages()
const pageId = pages.pages[0].id
// Step 1
let snap = take_snapshot()
fill_form_by_uids({
fields: [
{ uid: "first-name-uid", value: "John" },
{ uid: "last-name-uid", value: "Doe" },
{ uid: "next-btn-uid", action: "click" }
]
})
// Step 2 - take fresh snapshot after navigation
snap = take_snapshot()
fill_form_by_uids({
fields: [
{ uid: "address-uid", value: "123 Main St" },
{ uid: "city-uid", value: "Anytown" },
{ uid: "submit-uid", action: "click" }
]
})typescript
// 多步骤表单,每步拍摄快照
const pages = list_pages()
const pageId = pages.pages[0].id
// 第一步
let snap = take_snapshot()
fill_form_by_uids({
fields: [
{ uid: "first-name-uid", value: "John" },
{ uid: "last-name-uid", value: "Doe" },
{ uid: "next-btn-uid", action: "click" }
]
})
// 第二步 - 导航后获取新快照
snap = take_snapshot()
fill_form_by_uids({
fields: [
{ uid: "address-uid", value: "123 Main St" },
{ uid: "city-uid", value: "Anytown" },
{ uid: "submit-uid", action: "click" }
]
})Advanced Features
高级功能
Privileged Context (Firefox Internals)
特权上下文(Firefox内部)
Requires flag and environment variable
--enable-privileged-contextMOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1typescript
// List privileged contexts (chrome contexts)
list_privileged_contexts()
// Returns: { contexts: [{ id, type }] }
// Select privileged context
select_privileged_context({ contextId: "chrome-123" })
// Execute privileged JavaScript
evaluate_privileged_script({
script: `
Services.prefs.setIntPref("browser.cache.disk.capacity", 1024000);
return "Pref set";
`
})
// Get Firefox preferences
get_firefox_prefs({ prefNames: ["browser.cache.disk.capacity"] })
// Returns: { prefs: { "browser.cache.disk.capacity": 1024000 } }
// Set Firefox preferences
set_firefox_prefs({
prefs: {
"browser.cache.disk.capacity": 2048000,
"privacy.trackingprotection.enabled": true
}
})需要参数和环境变量
--enable-privileged-contextMOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1typescript
// 列出特权上下文(chrome上下文)
list_privileged_contexts()
// 返回: { contexts: [{ id, type }] }
// 选择特权上下文
select_privileged_context({ contextId: "chrome-123" })
// 执行特权JavaScript
evaluate_privileged_script({
script: `
Services.prefs.setIntPref("browser.cache.disk.capacity", 1024000);
return "偏好设置已修改";
`
})
// 获取Firefox偏好设置
get_firefox_prefs({ prefNames: ["browser.cache.disk.capacity"] })
// 返回: { prefs: { "browser.cache.disk.capacity": 1024000 } }
// 设置Firefox偏好设置
set_firefox_prefs({
prefs: {
"browser.cache.disk.capacity": 2048000,
"privacy.trackingprotection.enabled": true
}
})WebExtension Management
WebExtension管理
typescript
// Install extension
install_extension({
xpiPath: "/path/to/extension.xpi"
})
// Returns: { extensionId: "extension-uuid" }
// Uninstall extension
uninstall_extension({ extensionId: "extension-uuid" })
// List installed extensions (requires privileged context)
list_extensions()
// Returns: { extensions: [{ id, name, version }] }typescript
// 安装扩展
install_extension({
xpiPath: "/path/to/extension.xpi"
})
// 返回: { extensionId: "extension-uuid" }
// 卸载扩展
uninstall_extension({ extensionId: "extension-uuid" })
// 列出已安装扩展(需要特权上下文)
list_extensions()
// 返回: { extensions: [{ id, name, version }] }Connect to Existing Firefox
连接到已运行的Firefox
Automate your real browsing session with cookies and logins intact:
bash
undefined在保留Cookie和登录状态的情况下自动化真实浏览会话:
bash
undefinedTerminal 1: Start Firefox with Marionette
终端1:启动带Marionette的Firefox
firefox --marionette
firefox --marionette
Terminal 2: Connect MCP server
终端2:连接MCP服务器
npx firefox-devtools-mcp@latest --connect-existing --marionette-port 2828
**Note:** BiDi-dependent features (console/network events) are not available in connect-existing mode.npx firefox-devtools-mcp@latest --connect-existing --marionette-port 2828
**注意:** 依赖BiDi的功能(控制台/网络事件)在连接现有模式下不可用。Troubleshooting
故障排除
Firefox Not Found
Firefox未找到
bash
undefinedbash
undefinedmacOS
macOS
npx firefox-devtools-mcp@latest --firefox-path "/Applications/Firefox.app/Contents/MacOS/firefox"
npx firefox-devtools-mcp@latest --firefox-path "/Applications/Firefox.app/Contents/MacOS/firefox"
Linux
Linux
npx firefox-devtools-mcp@latest --firefox-path "/usr/bin/firefox"
npx firefox-devtools-mcp@latest --firefox-path "/usr/bin/firefox"
Windows
Windows
npx firefox-devtools-mcp@latest --firefox-path "C:\Program Files\Mozilla Firefox\firefox.exe"
undefinednpx firefox-devtools-mcp@latest --firefox-path "C:\Program Files\Mozilla Firefox\firefox.exe"
undefinedStale UIDs After Navigation
导航后UID失效
Always take a fresh snapshot after page changes:
typescript
navigate_page({ pageId: "page-1", url: "https://new-page.com" })
clear_uids() // Clear old UIDs
const snap = take_snapshot() // Get fresh UIDs页面变化后请始终拍摄新快照:
typescript
navigate_page({ pageId: "page-1", url: "https://new-page.com" })
clear_uids() // 清除旧UID
const snap = take_snapshot() // 获取新UIDWindows 10 Connection Issues
Windows 10连接问题
Wrap command with :
cmd /cjson
{
"mcpServers": {
"firefox-devtools": {
"command": "cmd",
"args": ["/c", "npx", "-y", "firefox-devtools-mcp@latest"]
}
}
}Or use absolute path to npx:
json
{
"mcpServers": {
"firefox-devtools": {
"command": "C:\\Program Files\\nodejs\\npx.cmd",
"args": ["-y", "firefox-devtools-mcp@latest"]
}
}
}使用包裹命令:
cmd /cjson
{
"mcpServers": {
"firefox-devtools": {
"command": "cmd",
"args": ["/c", "npx", "-y", "firefox-devtools-mcp@latest"]
}
}
}或使用npx的绝对路径:
json
{
"mcpServers": {
"firefox-devtools": {
"command": "C:\\Program Files\\nodejs\\npx.cmd",
"args": ["-y", "firefox-devtools-mcp@latest"]
}
}
}Debugging Connection Issues
调试连接问题
bash
undefinedbash
undefinedRun with inspector to see detailed logs
使用inspector运行以查看详细日志
npx @modelcontextprotocol/inspector npx firefox-devtools-mcp@latest --start-url about:home
npx @modelcontextprotocol/inspector npx firefox-devtools-mcp@latest --start-url about:home
Check Firefox is running
检查Firefox是否在运行
ps aux | grep firefox
ps aux | grep firefox
Verify Marionette port
验证Marionette端口
lsof -i :2828
undefinedlsof -i :2828
undefinedExample: Complete E2E Test
示例:完整端到端测试
typescript
// Create new page
const { pageId } = new_page({ url: "https://example.com" })
// Navigate to search
navigate_page({ pageId, url: "https://example.com/search" })
// Take snapshot and find search box
const snap = take_snapshot()
// Review snap.snapshot to identify UIDs
// Perform search
fill_form_by_uids({
fields: [
{ uid: "search-input-uid", value: "test query" },
{ uid: "search-button-uid", action: "click" }
]
})
// Capture results
const screenshot = screenshot_page({ saveTo: "/tmp/results.png" })
// Verify API calls
const requests = list_network_requests({
filter: { urlPattern: "example.com/api/search" }
})
const searchData = get_network_request({
requestId: requests.requests[0].id
})
// Check console for errors
const logs = list_console_messages()
const errors = logs.messages.filter(m => m.level === "error")
// Cleanup
close_page({ pageId })typescript
// 创建新页面
const { pageId } = new_page({ url: "https://example.com" })
// 导航到搜索页面
navigate_page({ pageId, url: "https://example.com/search" })
// 拍摄快照并找到搜索框
const snap = take_snapshot()
// 查看snap.snapshot识别UID
// 执行搜索
fill_form_by_uids({
fields: [
{ uid: "search-input-uid", value: "test query" },
{ uid: "search-button-uid", action: "click" }
]
})
// 捕获结果截图
const screenshot = screenshot_page({ saveTo: "/tmp/results.png" })
// 验证API调用
const requests = list_network_requests({
filter: { urlPattern: "example.com/api/search" }
})
const searchData = get_network_request({
requestId: requests.requests[0].id
})
// 检查控制台错误
const logs = list_console_messages()
const errors = logs.messages.filter(m => m.level === "error")
// 清理
close_page({ pageId })