mcpField
D
Devloop

Devloop

本地服务
devloop.build开发工具21 天前更新

关于 Devloop

Devloop 为编码 Agent 和开发者整合浏览器或 Expo/React Native 应用操作与开发服务器日志,并按统一时间线呈现相关事件。它提供 MCP 工具,可用于操作页面、采集日志并定位同一时刻发生的问题。

主要功能

  1. 01统一关联浏览器与服务端日志
  2. 02操作浏览器页面并采集网络信息
  3. 03支持 Expo/React Native 原生目标
  4. 04生成页面快照与错误复现信息
  5. 05通过 stdio 或 HTTP/SSE 提供服务

适用场景

  1. 01对照浏览器错误与服务端堆栈
  2. 02驱动浏览器完成页面测试
  3. 03排查 Expo 或 React Native 应用问题
  4. 04导出网络记录与错误报告

MCP 相关

Devloop 通过 MCP 暴露开发服务器、浏览器控制、日志和复现等工具。可用 stdio 启动,也可通过 HTTP/SSE 连接共享的 daemon 或桌面 Cockpit;原生设备控制需 Cockpit。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"devloop": {
"command": "npx",
"args": [
"-y",
"devloop-mcp"
]
}
}
}
启动命令npx -y devloop-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmdevloop-mcp0.13.0

工具

46

收录的工具列表 · 更新于 2 周前

参数类型必填说明
urlstring是要加载的绝对 URL(例如 http://localhost:3000/path)。

详细介绍

Devloop

为 AI Agent 和开发者提供浏览器控制与开发服务器日志,并将两者关联到同一时间线上。

npm CI Glama 评分 MIT 许可证 Biome 约定式提交

Devloop 控制台:浏览器窗格旁边是统一且可筛选的时间线,其中关联了服务器和浏览器日志


一款统一的开发循环工具:它可以操作浏览器和你的开发服务器,将两端的数据写入同一个带时间戳的缓冲区,方便你将浏览器控制台错误与同一时刻的后端堆栈跟踪关联起来。它基于共享核心提供两种运行方式:

  • 无头模式(stdio) — 通过 Puppeteer 操作 Chrome,并通过 stdio 提供服务。这是 Claude Code 每个会话都会启动的轻量模式。运行 devloop-mcp daemon,即可改为通过 HTTP/SSE 提供一个共享的长期运行实例,供多个 Agent/会话连接(参见守护进程模式)。
  • 控制台(Electron) — 一个桌面窗口:包含多个标签页的浏览器窗格(由 CDP 驱动的内嵌 WebContentsView),带有浏览器栏(后退/前进/重新加载 + 地址栏),旁边是可折叠侧边栏,可在日志和复现构建器之间切换。支持项目选择器、自动导航和弹出目标。渲染器使用 React 19 + Tailwind v4 + Radix + lucide-react。通过 HTTP 提供相同的工具。

由于每个事件(浏览器控制台/网络/页面错误以及服务器 stdout/stderr)都共享同一个单调时钟,get_logs_around / repro 会返回关联的跨来源时间线片段。

原生目标 — Expo / React Native(iOS + Android)

该控制台也支持 Expo/React Native 项目,而不仅限于 Web。打开一个原生项目后,你会看到一个面板,其中包含 Web · iOS · Android 目标切换器、一个与 Build 按钮分开的 bundler 开关(Metro),以及以下功能(expo run:ios / expo run:android,并通过 @expo/fingerprint 检测过时状态):

  • 通过 Metro 的 Hermes 检查器经由 CDP 获取 JS 控制台 + 错误(两个平台均支持),堆栈带有 源码映射(你的打包文件 index.bundle:1:… 会解析到原始 .tsx 文件)。
  • RN 网络捕获 — 注入的 XMLHttpRequest 钩子会将应用的 fetch/XHR 流量转换为与 Web 相同的 network 时间线条目(因此 get_network / export_har / 网络标记在原生应用中也可用)。
  • 原生设备日志以 native 来源合并到时间线上 — iOS 使用 simctl log stream,Android 使用 logcat。
  • 面板中嵌入 实时交互式设备 — iOS 通过 serve-sim(MJPEG,可点击/滚动/输入),Android 通过轮询 screencap 镜像(约 2fps),支持点击转触控 + 按键输入。两个平台都支持截图。
  • 可由 Agent 驱动的交互 — browser_snapshot 可读取原生无障碍树(iOS 通过 idb 的 UIKit a11y 树;Android 通过 uiautomator dump),browser_click/type/scroll/press 可通过元素的 pt:x,y 引用(来自快照)或其标签来操作设备 — 可通过 repro 重放,也可通过 MCP 使用 native_open / native_build 打开。同一套 Agent 工具映射到原生环境。

所有内容都会按应用范围汇入同一条关联时间线 — 为原生应用提供 Web 开发循环体验。(嵌入式 iOS 模拟器需要 macOS + Apple Silicon;只要有 Android SDK + 模拟器,Android 即可运行。)

iOS 交互需要 idb: brew install facebook/fb/idb-companion 和 pipx install fb-idb(请使用 Python <3.14 — 较新的 Python 会导致 fb-idb 无法运行)。Android 交互需要 Android SDK platform-tools(adb)+ 已启动的模拟器。控制台的 Settings → native readiness 会运行各平台的预检(iOS:idb · companion · 已启动的模拟器;Android:adb · 已启动的设备),并显示缺少项目的具体修复方法;无需交互工具也可以查看信息(日志/截图)。

serve-sim 已随控制台一同提供,并通过 Electron 自带的 Node 运行,因此嵌入式模拟器开箱即用 — 无需联网,无需 bun/node/npx,也无需首次运行时下载。(从源码运行时会使用 node_modules 中的副本。)

架构

三个 传输层 共用一个 核心,核心驱动多个 底层环境(真实浏览器,或在控制台中使用原生设备)。所有内容都会推送到同一条带时间戳的 时间线。

%%{init: {"flowchart": {"wrappingWidth": 700}}}%%
flowchart TD
  clients["<b>MCP clients</b><br/>Claude Code · agents · mcporter"]
  clients --> stdio & daemon & cockpit

  stdio["<b>stdio</b><br/><i>spawned per session</i>"]
  daemon["<b>daemon</b><br/><i>HTTP/SSE · one shared instance</i>"]
  cockpit["<b>cockpit</b><br/><i>HTTP/SSE · Electron app</i>"]

  stdio --> mcp
  daemon --> mcp
  cockpit --> mcp
  mcp(["<b>MCP Server</b><br/><i>stdio transport, or HTTP/SSE for the daemon + cockpit</i>"])
  mcp --> core

  core["<b>shared core</b> · <i>transport- and substrate-agnostic</i><br/>the MCP tool layer + one unified, correlated timeline"]

  core --> iface(["<b>IBrowserController · IBrowserManager · ITargetController</b><br/><i>capability-gated by the active target</i>"])
  iface --> pup & elec & rn

  pup["<b>web</b> · Puppeteer / Chrome<br/><i>stdio + daemon</i>"]
  elec["<b>web</b> · Electron CDP panes<br/><i>cockpit · per-project partitions</i>"]
  rn["<b>native</b> · React Native (Hermes)<br/><i>JS + network over Metro CDP</i>"]

  rn -->|"idb / adb"| nd["<b>NativeDriver</b><br/>iOS idb · Android adb<br/>taps · snapshot · screens · logs"]

工具层完全不关心底层是什么 — Puppeteer 还是 Electron,stdio 还是 HTTP,Web 页面还是原生应用。它只在启动时接线一次。浏览器位于单一的 IBrowserController 接口之后;控制台的面板管理器实现了功能更丰富的 IBrowserManager(管理多个面板,将 browser_* 调用委托给当前活动面板 — 或在打开 iOS/Android 目标时委托给原生控制器)。能力层会根据当前活动目标限制工具,因此 Agent 会收到清晰的说明,而不是底层环境错误。

stdio 模式下,stdout 专用于 MCP 协议;所有面向用户的输出都会发送到 stderr。

各层
  • 传输层 — 通过两种协议提供的三个入口:stdio(每个会话对应一个服务)和 HTTP/SSE(长期运行的守护进程和 cockpit)。它们都会构建同一个绑定到工具层的 MCP 服务;只有 HTTP 传输支持多个客户端(每个连接的客户端都有自己的会话,共用一个后端)。
  • 共享核心 — 工具层(MCP 工具 + 受能力门控的分发器),构建在统一且相互关联的时间线之上(服务端输出、浏览器控制台/网络/错误、本机日志),并由独立的全量捕获网络环形缓冲区提供支持。工具所提供的横切功能——项目注册表、错误诊断、源映射解析、HAR 导出和错误报告包——也位于此处。
  • 浏览器底层 — 共享控制器接口,包含两个 Web 实现(无头模式使用 Puppeteer/Chrome;cockpit 中的 Electron WebContentsView 窗格通过 CDP 运行)和一个原生实现(通过 Hermes/Metro 运行的 React Native)。共享的页面操作 + 无障碍快照逻辑,以及设备/限流模拟功能位于其上层。
  • 原生目标 — RN 控制器(通过 Metro CDP 获取 JS/错误/网络信息)将点按 + 快照操作委托给 NativeDriver(iOS 上使用 idb,Android 上使用 adb);此外还包括原生日志(simctl / logcat)、截图 + 实时镜像、构建编排(expo run)以及就绪状态预检。
  • 状态与隔离 — 磁盘上的注册表(项目 / 会话 / 窗格)、每个项目独立的会话分区,以及 Chrome 扩展管理。
  • Cockpit(Electron) — 桌面外壳:窗格管理器(每个项目独立的分区、原生路由)、React UI(时间线、浏览器栏、复现流程构建器、目标切换、Android 镜像)、随附的 serve-sim iOS 镜像、应用商店内的“Add to Devloop”注入功能,以及应用内更新器。

安装

无头 MCP(stdio) — 无需克隆,向 Claude Code 注册即可:

claude mcp add devloop --scope user -- npx -y devloop-mcp

(在 npm 上以 devloop-mcp 发布;Puppeteer 会在首次安装时下载 Chromium。)

Cockpit(桌面应用) — 从 发布版本 下载适用于你操作系统的安装程序(.dmg / .exe / .AppImage)。macOS 提供 Apple Silicon(arm64)和 Intel(x64)版本。应用启动时会检查 GitHub 上是否有更新版本,并在下载或安装前提示你;也可以从设置 → 更新 → 检查更新手动触发。

从源代码安装(开发)— 需要 bun:

bun install
bun run app          # build + launch the Electron cockpit
bun run start        # or run the stdio MCP directly

在编码 Agent 中使用

注册完成后,将以下内容添加到你的 CLAUDE.md(或任何 Agent 的规则文件)中,让 Agent 通过 Devloop 驱动功能并实时验证,而不是只根据代码进行推断:

## Devloop — use it for any web/mobile feature work

When you build, test, or debug a feature that runs in a **browser** or an **Expo /
React Native** app, drive it through **devloop** instead of reasoning from the code
alone. It puts the dev-server logs and the live browser/device on one correlated
timeline, so you can see what actually happened.

- **Start the loop:** `dev_start` (auto-detects the dev command), then
  `browser_navigate` to the page — or `native_open` for an iOS/Android target.
- **Act, then verify — don't assume:** after a change, reproduce it with `repro`
  (a navigate/click/type sequence) and read the result. Never claim a fix works
  without exercising it in the running app.
- **Find/target elements** with `browser_snapshot` (returns clickable `ref`
  selectors) — prefer it over screenshots.
- **When something breaks:** `diagnose` first (groups errors + failed requests),
  then `get_logs_around` a timestamp to line up the browser console error with the
  matching server stack trace from the same moment. `get_network` / `export_har`
  for request detail.
- **Definition of done:** the feature is verified live in devloop — no console or
  page errors, the expected network calls succeeded, the UI reflects the change —
  not just "the code looks right."
- **Setup stays yours:** if a native build needs a toolchain that isn't installed,
  devloop tells you exactly what's missing and the command to fix it — it
  **diagnoses, it never installs or touches your toolchain.** Run the fix, then rebuild.

Register once: `claude mcp add devloop --scope user -- npx -y devloop-mcp`

工具(46)

开发服务器 — 运行时工具,无需为每个项目单独注册

  • dev_start({ project?, cmd?, cwd? }) — 启动开发服务器并转发其日志。可通过三种方式指定:已保存的注册表 project;显式指定 cmd+cwd;或者两者都不指定(cwd 默认为服务器目录,cmd 会根据 package.json 脚本自动检测:dev/develop/web/start/serve)。
  • dev_stop() — 停止服务器。会终止整个进程组(因此 next dev/metro 的子进程也会退出)。
  • dev_status() — 查询是否正在运行,以及 cmd/cwd/pid。 原生目标平台 — Expo/React Native(仅限控制台;需要 Electron 和模拟器/仿真器)
  • native_open({ platform }) — 为当前窗格打开 iOS 模拟器或 Android 设备镜像;随后使用 browser_* 操控原生应用(idb/adb),JS 和原生日志会流式传输到时间线。如果设备/工具尚未就绪,则返回带有原因的 ok:false。
  • native_close() — 返回窗格中的网页内容。
  • native_build({ platform, cwd? }) — 运行 expo run:ios / expo run:android,并将输出流式传输到时间线(cwd 默认为当前窗格的项目目录)。如果尚未配置 SDK/JDK,Android 会返回工具链检查清单,而不是进行构建。
  • native_doctor() — 重新检查原生就绪状态,不会进行构建或打开:分别检查 iOS 和 Android 交互,以及 Android 构建工具链;每项都以 ✓/✗ 清单形式列出,并说明缺失项目的修复方法。安装缺失的工具后运行此命令,以确认问题已解决。
  • 在无头 stdio/守护进程模式下,这些工具会提示需要控制台(Puppeteer 仅支持网页)。

浏览器控制 — 操控当前窗格

  • browser_navigate({ url })
  • browser_back() · browser_forward() · browser_reload({ hard? }) — 历史记录导航和重新加载(浏览器栏中的 ←/→/⟲;hard 表示忽略缓存)。
  • browser_screenshot({ fullPage? }) → PNG 图像
  • browser_click({ selector })
  • browser_type({ selector, text })
  • browser_hover({ selector }) · browser_scroll({ selector? | x?, y? }) · browser_select({ selector, value }) · browser_press({ key, selector? }) — 可用按键包括 Enter/Escape/Tab/ArrowDown。
  • browser_wait_for_idle({ idleMs?, timeoutMs? }) — 等待网络请求完成。
  • browser_clear_storage({ allOrigins? }) — 清除当前源(或整个会话)的 cookies / localStorage / IndexedDB / cache / service workers — 可用于退出登录 / 测试新用户。
  • browser_emulate({ device? | width?, height?, mobile?, deviceScaleFactor?, userAgent?, reset? }) — 模拟设备/视口(device:iphone/ipad/pixel,或自定义;reset → 桌面端)。
  • browser_throttle({ profile }) — 网络状况:slow-3g / fast-3g / offline / none。
  • browser_eval({ expression }) — 在页面上下文中运行(不受 CSP 限制)
  • browser_snapshot() — 结构化页面快照:包含 url、title 和交互式/地标元素(role、无障碍名称、值/状态、标题级别),每个元素都带有可供 browser_click/browser_type 使用的 CSS 选择器 ref。查找/定位元素时,优先使用此功能,而不是截图。
  • browser_wait_for({ selector?, text?, timeoutMs? }) — 等待选择器出现或文本存在(例如导航后/异步渲染后)。返回 { ok, waitedMs }。 日志与关联
  • get_logs({ source?, stream?, grep?, app?, sinceSeq?, limit? }) — 统一查看最新日志。source 为 server|browser;stream 为 stdout/stderr/console/network/pageerror。app 可限定查看某个项目的日志 — 它匹配窗格的 标签(项目名称)或 ID(参见 pane_list),并筛选该窗格的服务器端和浏览器日志,无论当前激活的是哪个窗格。将上次的 seq 作为 sinceSeq 传入,即可增量查看最新日志。
  • get_logs_around({ ts, windowMs?, source?, app? }) — 关联工具:按时间顺序返回时间戳前后 windowMs 范围内来自两个来源的所有事件(可选限定到某个 app)。
  • 时间线显示失败或状态 ≥ DEVLOOP_NET_THRESHOLD 的网络事件(将其设为 0 可在行内显示所有事件),并在所有底层平台(Puppeteer / CDP / React Native)上附带丰富的 detail:方法、状态、资源类型、MIME、耗时、请求和响应标头,以及经过长度限制的请求和响应正文。
  • get_network({ grep?, app?, limit? }) — 完整采集环形缓冲区中的每个请求,不受阈值影响(而 get_logs 只显示经过筛选的时间线)。如果你关心的快速 200 请求未显示在时间线上,就使用此工具。
  • export_har({ app? }) — 将完整网络环形缓冲区导出为 HAR 1.2 文档(可导入 Chrome DevTools / Charles);不受阈值影响,内容完整。也可以限定到某个 app。
  • diagnose({ windowMs?, app? }) — 排查当前故障:对重复错误(控制台 / 页面 / 服务器端)分组并去重,附上计数;列出失败及 4xx-5xx 网络请求,并返回一行摘要。深入查看 get_logs 之前,请先从这里开始。
  • 页面错误包含 resolvedStack — 浏览器的压缩堆栈跟踪会通过 bundle 的源映射还原为原始源代码(浏览器只会在其 DevTools 界面中反混淆;error.stack 仍是编译后的内容,因此我们会为你还原)。位于条目的 detail 中。
  • export_bundle({ app?, windowMs? }) — 可分享的 错误报告包(JSON):包含诊断摘要、时间线、屏幕截图、HAR 和复现信息。Cockpit 的 report 按钮会将其保存为独立的 HTML 页面。
  • clear_logs() — 在复现问题之前重置日志。
  • repro({ actions | action, waitFor?, settleMs?, stepSettleMs?, idleMs?, timeoutMs?, continueOnError?, clear? }) — 复现并关联:清空缓冲区,执行一个操作或一系列操作,等待后返回整个操作序列中两端发生的所有情况 — 包含逐步结果(steps[])、byStream 计数和预筛选的 errors 列表。
    • actions: [{kind, ...}] — 支持的类型:navigate/click/type/hover/scroll/select/press/eval/wait/none。action(单数)是执行单步操作的便捷方式。
    • 每步之间等待 stepSettleMs(默认 300),最后一步之后等待 settleMs(默认 1000)。waitFor: "networkidle" 会等待网络活动停止 idleMs(默认 500),最长等待 timeoutMs(默认 10000)— 用于处理缓慢或流式响应(Expo 首次 Web bundle 需要约 12s)。超时后仍会返回已获取的内容,并附带 waitNote。
    • continueOnError(默认 false)— 否则会在失败步骤处停止(stoppedAtStep)。

项目注册表 — 已保存的项目,持久化到 ~/.devloop/projects.json

  • project_list() — 列出已保存的项目(名称、cwd、cmd、url、steps)。
  • project_add({ name, cwd, cmd?, url?, steps? }) — 保存或替换项目(包括已保存的复现 steps 序列),以便按名称执行 dev_start({ project })。
  • project_remove({ name })。 窗格 — 多目标(仅限驾驶舱;stdio 模式为单窗格,并会报告此情况)
  • pane_list() — 每个窗格:{ id, url, active, popped }。当前活动窗格是 browser_*/repro 的目标;事件会标记其窗格 id。
  • pane_new({ url? }) — 打开新窗格并将其设为活动窗格。
  • pane_select({ id }) — 将指定窗格设为活动窗格。
  • pane_close({ id })。
  • pane_pop({ id }) — 将窗格分离到独立窗口中(并排显示目标)。
  • pane_set_label({ id, label }) — 重命名窗格(与双击标签页的效果相同)。

扩展程序 — Chrome 扩展程序管理(仅限驾驶舱)

  • ext_list() — 已安装的扩展程序:{ id, name, version, enabled }。
  • ext_install({ idOrUrl }) — 通过 Chrome 网上应用店 ID/URL 安装。
  • ext_remove({ id }) — 卸载。
  • ext_set_enabled({ id, enabled }) — 启用/停用,而不卸载。
控制台参数

捕获 console.log(obj) 时,会将参数解析为实际值(例如 [log] user {"id":7}),而不是 JSHandle@object。Electron 底层会根据 CDP 预览同步渲染这些参数;Puppeteer 底层采用 先预留再填充 的模式(到达时同步标记 seq/ts,之后再补入已解析的参数),因此顺序与发出顺序一致,并能与服务器日志正确交错。

无头模式(stdio)

在用户级别注册一次 — 适用于每个项目:

claude mcp add devloop --scope user -- npx -y devloop-mcp

然后,在任意项目中使用:“dev_start and repro a navigate to /projects”。dev_start 默认将 cwd 设为当前所在项目,并自动检测命令。

变量默认值含义
DEVLOOP_HEADLESSfalse"true" 时以无头模式运行 Chrome;默认为有头模式,方便你查看。
DEVLOOP_CHROME_PATH(bundled)Chrome 可执行文件的显式路径。
DEVLOOP_NET_THRESHOLD400记录状态码 >= 此值的网络响应(失败项始终会记录)。
DEVLOOP_ACTION_TIMEOUT10000交互的上限(ms)——页面卡住时会快速失败,而不是一直等待。
DEVLOOP_NAV_TIMEOUT30000导航的上限(ms)。
DEVLOOP_LOG_CAPACITY5000缓冲事件的最大数量。
DEVLOOP_NET_RING3000完整捕获网络环形缓冲区(get_network / export_har)中保留的最大请求数,不受 DEVLOOP_NET_THRESHOLD 影响。
DEVLOOP_DEV_CMD / DEVLOOP_DEV_CWD(none)可选的启动时自动启动开发服务器设置(通常使用 dev_start)。
DEVLOOP_HOME~/.devloop注册表位置。

守护进程模式(共享 HTTP/SSE)

自行运行一个长期运行的守护进程(stdio 启动时已按项目执行此操作;参见下文的 共享模式),所有客户端都通过 HTTP/SSE 连接到该守护进程——多个客户端共用一个 Devloop 实例(一个浏览器、一个开发服务器、一条关联时间线):

devloop-mcp daemon                 # headless; serves MCP at http://localhost:7333/mcp
# then point any number of MCP clients at it:
claude mcp add --transport http devloop http://localhost:7333/mcp

后端与环境变量和 stdio 模式相同(默认无头;设置 DEVLOOP_HEADLESS=false 即可查看),并会从 DEVLOOP_HTTP_PORT 自动选择一个空闲端口(默认为 7333)。每个客户端都有自己的 MCP 会话,但共享同一后端,因此一个 Agent 的 dev_start / 导航会显示在另一个 Agent 的 get_logs 中。(Electron 驾驶舱也通过完全相同的 HTTP 传输提供服务——守护进程只是它的无头版本。)

管理守护进程的生命周期:

devloop-mcp daemon --status        # is one running? (pid + url)
devloop-mcp daemon --stop          # SIGTERM the running daemon
DEVLOOP_DAEMON_IDLE_MS=60000 devloop-mcp daemon   # auto-exit 60s after the last client disconnects
共享模式 — 默认对 stdio 启用

你无需自行运行守护进程。普通的 stdio 启动(npx -y devloop-mcp)会连接到该项目的守护进程:它会连接到该目录中已运行的守护进程;如果没有,则会启动一个并将其分离。因此,重启 Claude Code、重新连接 /mcp,以及在同一仓库中启动新会话,都会复用同一个 Chrome,而不会再打开一个。两个仓库同时打开时,会使用各自独立的守护进程,因此其开发服务器和时间线不会相互干扰。

stdio 进程会变成一个轻量代理:它通过 stdio 与客户端通信,并通过 HTTP 将工具调用转发给守护进程。只有首次使用浏览器工具时才会打开 Chrome,不会仅仅因为会话启动就打开。自动启动的守护进程会显示 stdio 的浏览器(设置 DEVLOOP_HEADLESS=true 可将其隐藏),在项目目录中运行,并且在最后一个会话断开 10 分钟后退出(设置 DEVLOOP_DAEMON_IDLE_MS 可更改此时长)。在项目目录中运行 devloop-mcp daemon --status / --stop,即可管理该项目的守护进程。如果出现任何问题(例如守护进程无法启动),会话会回退到普通本地实例,不会直接退出。

npx -y devloop-mcp --shared   # or DEVLOOP_DAEMON=1: one global daemon shared by every project
npx -y devloop-mcp --local    # or DEVLOOP_DAEMON=0: the old behavior, one browser per session

全局守护进程会在 $DEVLOOP_HOME/daemon.json 中声明自身,项目级守护进程则会声明在 $DEVLOOP_HOME/daemons/ 中。

MCP 受阻时(企业沙盒)——通过 mcporter 驱动 Devloop

某些沙盒或企业环境不允许 Agent 注册或启动 MCP 服务(或会阻止 MCP 传输),但确实允许运行 shell 命令。[mcporter](https://www.npmjs.com/package/mcporter) 可以解决这个问题:它将任意 MCP 服务的工具作为普通 CLI 命令调用,因此 Agent 可以通过 Bash 而非 MCP 客户端来调用 Devloop。

稳妥的做法是使用 守护进程 + mcporter over HTTP——运行一个 Devloop 守护进程(运行一次,在沙盒外部或旁边运行),然后通过 shell 命令调用其工具:

devloop-mcp daemon                                          # one shared instance on :7333

# point mcporter at it ad-hoc (no config); --allow-http since it's localhost cleartext
npx mcporter list  --allow-http --http-url http://localhost:7333/mcp --name devloop
npx mcporter call  --allow-http --http-url http://localhost:7333/mcp 'devloop.dev_start(cwd: "/repo")'
npx mcporter call  --allow-http --http-url http://localhost:7333/mcp 'devloop.browser_navigate(url: "http://localhost:3000")'
npx mcporter call  --allow-http --http-url http://localhost:7333/mcp 'devloop.diagnose()'

或者跳过守护进程,让 mcporter 在每次调用时启动 stdio 服务(前提是允许启动进程):

npx mcporter list --stdio "npx devloop-mcp" --name devloop
npx mcporter call --stdio "npx devloop-mcp" 'devloop.get_logs(limit: 50)'

注意:

  • 将其持久化,这样就不必重复填写描述符:将 Devloop 添加到 ~/.mcporter/mcporter.json(或传入 --persist)。mcporter 也会自动导入已在 Claude Code/Desktop、Cursor、Codex 等客户端中配置的服务。因此,之前执行的 claude mcp add devloop … 会被自动识别,你可以直接运行 npx mcporter call devloop.<tool> …。
  • npx mcporter list devloop --schema 会列出所有工具及其 TypeScript 风格的签名,方便 Agent 查找参数。
  • 如需使用完全独立的 CLI,npx mcporter generate-cli devloop 会生成独立二进制文件;mcporter serve 会将服务重新暴露为一个桥接端点。请参阅 mcporter 文档。

(具体的临时标志可能因 mcporter 版本而异——请以 npx mcporter --help 为准。)

Agent 技能:skills/devloop/SKILL.md 将这些内容打包成可安装的 Agent 技能——将其放入(cp -r skills/devloop ~/.claude/skills/,或放入项目的 .claude/skills/),Agent 便会知道在 MCP 受阻时如何通过 mcporter 驱动 Devloop,其中内置了守护进程设置和工具用法示例。

Cockpit 模式(Electron)

bun run app          # build + launch the cockpit
bun run app:selftest # headless integration test (no visible windows)

单窗口(React 19 + Tailwind v4,使用 @theme tokens + Radix Dialog/Tooltip + lucide-react 图标),布局如下:

  • 顶栏 — 窗格标签页,然后是当前窗格的开发控件和窗口切换项:
    • 开发控件(作用于当前窗格):状态标记(运行时显示绿色 ● project,非零退出码时显示红色 ✗ exited (code N),否则显示 dev: stopped/not configured)、▶/⏹ 启动或停止开发服务器、⟳ 重启服务器(Power)、📷 将窗格截图保存到时间线。
    • ⚙ 设置 · ⤢ 将当前窗格弹出到独立窗口。
    • 标签页根据项目自动命名(取 package.json 的 name,否则取文件夹基本名称);窗格的服务器运行时显示绿色运行圆点,弹出后显示 ⤢;单击切换(时间线会跟随当前窗格),双击重命名,× 关闭,+ pane 添加窗格。窗格通过 UI 或 Claude 发生变化时,标签页会实时更新。
  • 浏览器栏(窗格上方)— ←/→ 后退/前进(无历史记录时禁用)、⟲ 重新加载、⤓ 强制重新加载(忽略缓存)、⌫ 清除站点数据(cookies/localStorage + 重新加载),以及显示当前窗格实时 URL 的地址栏 — 随链接点击和 SPA 路由变化更新(管理器监听 did-navigate);接受纯端口号(3000 → http://localhost:3000)或任何 http(s):// URL;按 Enter 导航(⌘L 聚焦地址栏)。
  • 浏览器区域 — 当前窗格:通过 CDP 驱动的真实 Chromium WebContentsView。其他窗格会在后台继续运行(日志持续流入);当前窗格会定位在此区域上方,并在折叠面板或调整大小时重新排布。
  • 设置(位于 ⚙ 后方,默认折叠以保持顶栏简洁)— 标签行:
    • project — 已保存项目的下拉列表;选择项目后立即打开(填入 cmd/cwd/url + 复现步骤,然后启动开发服务器并导航)。💾 save 将当前窗格保存为项目,名称取其标签名(在标签页上重命名)。
    • dev — cmd(留空 = 自动检测)+ 📁 文件夹选择器 + cwd。失焦时自动保存到当前窗格(选择文件夹时也会保存)— 无需单独的“应用”按钮;之后,顶栏的 ▶ 已配置就绪。
    • ext — 将 Chrome 扩展加载到窗格中(React/Redux DevTools,或开发期间使用你自己的扩展):通过 Chrome Web Store id/URL 安装,或 📁 加载未打包扩展文件夹。扩展会持久保存并在启动时重新加载,且运行于窗格的会话中(与驾驶舱 UI 隔离)。由 electron-chrome-web-store 提供支持;Electron 的扩展 API 仅部分可用(大多数 MV3 功能可用;部分 chrome.* 功能存在缺失)。
  • 侧边面板(可折叠)— 分段式 日志 / 复现控件:
    • 日志 — 实时事件列表(按来源着色、时间戳、窗格标签、点击展开长条目、截图缩略图 → Radix Dialog 灯箱)。网络条目按状态等级着色(2xx/3xx/4xx/5xx),展开后可查看方法/状态/耗时,以及请求/响应的标头和正文。固定的筛选栏:子串筛选 + 筛选标签(server/console/network/errors/repro)、↓ latest 标记、HAR 导出和 clear。始终限定为当前窗格。
    • 复现 — 复现构建器(+ step / pick / run);pick 可让你点击页面中的元素,将稳定选择器直接捕获到点击步骤中;结果会显示在日志时间线中(自动切换到该视图),并包含逐步 ✓/✗ 状态和关联错误列表。
    • 点击面板标题中的 › 折叠;将鼠标悬停在右侧边缘的小型悬停把手上即可重新展开。将当前窗格弹出到独立窗口后,时间线会填充腾出的空间。拖动分隔线可调整大小。
  • 弹出窗口 — ⤢(URL 栏右侧)可将当前窗格分离到独立浏览器窗口,并带有自己的工具栏(后退/前进/重新加载/强制重新加载/地址栏/截图),并通过窗格 ID 控制该窗格;实时 URL 会跟踪导航,⌘R 重新加载页面。关闭窗口后,窗格会重新停靠。
  • 键盘: ⌘L 地址栏 · ⌘R/⌘⇧R 重新加载/强制重新加载 · ⌘K 清除 · ⌘B 切换面板 · ⌘, 设置 · ⌘1–9 切换窗格。 按窗格划分项目: 每个窗格都有自己的开发服务器和配置(cmd/cwd),因此不同窗格可以同时运行不同项目(使用不同端口),控件会作用于当前活动窗格。

自动导航: 启动开发服务器(或打开项目)时,工作台会监听该窗格的服务器输出,并在窗格中打开服务器公布的第一个 http://localhost:PORT 地址——无需手动输入端口。

持久化与恢复: 打开的窗格(每个窗格的 URL、项目标签和开发配置)会保存到 ~/.devloop/panes.json,并在重新启动时恢复;表单状态(复现步骤 + 所选项目)会保存到 ~/.devloop/session.json。恢复时不会假定开发服务器正在运行——保存的 URL 为开发环境(localhost)URL 的窗格会显示“按 ▶ 启动”占位提示(同时保留其真实 URL),按下 ▶ 即可启动服务器并自动导航。

工作台还通过 MCP-over-HTTP 提供相同的工具(有状态会话)。它会从 DEVLOOP_HTTP_PORT 开始自动选择可用端口(默认值为 7333),并记录 URL。将 Claude 指向正在运行的工作台:

claude mcp add --transport http devloop-cockpit http://localhost:7333/mcp

(仅在 bun run app 运行期间连接。)

彻底清理: 关闭窗口(或退出 / SIGTERM / SIGINT)会清理所有内容——开发服务器进程组、所有浏览器窗格和 HTTP 服务器;如果正常退出卡住,还会强制退出。开发服务器还会受父进程 PID 看门狗监控,因此即使工作台崩溃或收到 SIGKILL,也不会遗留孤儿进程(不会有 next dev 占用 :3000)。

仅供工作台使用的环境变量:DEVLOOP_HTTP_PORT(默认值为 7333),以及共享变量 DEVLOOP_NET_THRESHOLD / DEVLOOP_ACTION_TIMEOUT / DEVLOOP_LOG_CAPACITY / DEVLOOP_HOME。

项目布局

src/
  logBuffer.ts          source-aware, timestamped ring buffer (+ live onPush)
  devServer.ts          runtime dev-server manager (process-group kill) + detectDevCommand
  registry.ts           persisted project registry
  browserController.ts  IBrowserController + IBrowserManager interfaces
  browser.ts            PuppeteerBrowserController (headless/stdio)
  electronBrowser.ts    ElectronBrowserController (cockpit; CDP debugger)
  toolLayer.ts          TOOLS + handleTool, bound via configureTools(deps)
  index.ts              stdio entry (Puppeteer + stdio)
cockpit/
  main.ts               Electron main: windows, BrowserManager, MCP-over-HTTP, lifecycle
  browserManager.ts     multi-pane manager (IBrowserManager)
  preload.ts            contextBridge IPC surface
  renderer/             React UI — main.tsx (app) + global.d.ts (IPC types) +
                        styles.css (Tailwind v4 @theme) + index.html
  build.ts              Bun build for main/preload/renderer + Tailwind CLI step

测试与检查

CI 会在每次推送和 PR 时执行门禁检查——lint/format、types、unit、smoke、daemon、mcporter CLI、工作台自检以及GUI 端到端测试。运行 bun run test:all 可在本地执行全部检查,也可以分项运行:

bun run check           # Biome lint + format check (the CI gate; `bun run format` to auto-fix)
bun run typecheck       # tsc across core + renderer + gui
bun test                # unit tests (pure logic)
bun run test-smoke.ts   # headless Puppeteer: structured args, networkidle, repro sequence, abort
bun run test:daemon     # HTTP/SSE daemon: two clients sharing one backend
bun run test:mcporter   # the mcporter CLI path: `mcporter call devloop.<tool>` over HTTP
bun run app:selftest    # headless Electron: substrate→buffer, tool layer, MCP-over-HTTP,
                        # renderer IPC, registry, multi-target panes + pop-out, auto-navigate,
                        # derived project name, per-pane dev (server-log tagging), app-scoped
                        # get_logs, inline repro builder, pane persistence/restore, teardown
bun run mcp-drive.ts    # live smoke test: drives a RUNNING cockpit over its MCP-over-HTTP
                        # endpoint (start dev server → auto-navigate → verify the live app via
                        # browser_eval → app-scoped get_logs → screenshot). Cockpit must be up.

新功能采用针对该测试框架的测试优先方式开发。代码使用 Biome 执行 lint 和格式化(bun run check / bun run format),提交遵循 Conventional Commits 规范。完整工作流请参阅 CONTRIBUTING.md;报告漏洞请参阅 SECURITY.md。发布历史记录在 CHANGELOG.md 中。

实战中总结的注意事项

  • 端口冲突会导致浏览器显示 500。 在端口 8081 已被占用时连接 Expo 应用,会导致浏览器端出现 500;但服务器日志显示 Expo 跳过了启动。请为每个应用指定一个空闲端口——这也很好地说明了统一时间线的作用。
  • bun run dev 会将真正的服务器作为孙进程启动。 杀掉 shell 会导致 next dev/metro 成为孤儿进程;因此,开发服务器会以分离模式启动,并通过进程组停止。
  • 交互使用时不要设置 CI=1——它会禁用 Metro watch/HMR。

接下来可以做什么

  • EAS Build 备用方案 — 在没有本地工具链时,提供用于原生构建的 eas build 路径(尤其是 Android),并在 Settings → 原生就绪状态 预检中显示。
  • 可配置的快照深度 — 允许 browser_snapshot 覆盖 250 个元素的上限,以适应密集 UI(数据表格、长表单)。

已完成:统一的浏览器 + 服务时间线 · get_logs_around 关联 · repro 一次性执行 + 操作序列(结果内联呈现) · waitFor: networkidle · 结构化控制台参数 · 有限时长的交互超时 · 自愈式重新获取(Puppeteer 和 Electron 窗格——从渲染进程崩溃中恢复) · 网络请求/响应正文(有上限,对已记录的 Electron 条目进行 Base64 解码) · 项目注册表(含已保存的复现步骤) · 会话持久化 · 单窗口 Electron 控制台——带标签页的窗格、可折叠工具栏 + 时间线、弹出窗口、以项目命名的标签页 · 每个窗格独立的开发服务,一次配置(自动保存) · 根据日志自动导航 · 窗格持久化 + 恢复(不再“假定正在运行”) · React 19 + Tailwind v4 + Radix + lucide-react 渲染器 · 浏览器栏(后退/前进/重新加载 + 实时地址) · 分段式日志/复现面板 · 带独立浏览器框架的弹出窗口 · 截图 → 时间线(缩略图 + 灯箱) · 开发失败状态指示器 · 项目选择器(选中即打开)+ 文件夹浏览 · 可视化复现构建器 · 基于 HTTP 的 MCP · 干净的进程组清理 + 崩溃监控 · 禁用 Electron 安全警告 · 原生目标(Expo / React Native iOS) — Web·iOS 切换器、独立的打包器/构建流程(使用 @expo/fingerprint 检测 expo run:ios 的过时状态)、通过 CDP 获取带源映射的 Hermes JS 日志、在时间线上显示 simctl 原生设备日志,以及嵌入窗格的自带离线实时交互式 iOS 模拟器 · 由 Agent 驱动的原生交互 — 使用 browser_snapshot 获取 UIKit a11y 树,并通过 idb 执行 browser_click/type/scroll/press(通过 pt:x,y 引用或标签),可通过 repro 重放,并提供 Settings → 原生就绪状态 预检 · 每个窗格独立加载/切换 Chrome 扩展 + 商店内的 “Add to Devloop” 安装按钮 · 应用内更新横幅(下载进度 + 重启) · Android 目标(Web·iOS·Android 切换器、通过 uiautomator 由 adb 驱动的快照/点击、时间线上的 logcat、实时 screencap 镜像、expo run:android) · RN 网络捕获(注入 XHR 钩子 → network 行) · 完整网络捕获环形缓冲区(完整 HAR + get_network,不受阈值影响) · 视口/节流选择器 UI · 每个项目独立的会话分区(同源隔离) · 共享 HTTP/SSE 守护进程(devloop-mcp daemon——多个 Agent,共用一个实例) · 通过 MCP 打开/构建原生应用(native_open/native_close/native_build) · 共享模式下 stdio 自动连接(stdio 入口连接到正在运行的守护进程——或启动一个——并在必要时回退到本地实例) · 完整的 MCP 功能对等(扩展管理 ext_*、browser_back/forward/reload、pane_set_label)。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。