关于 ParallelSandbox
ParallelSandbox 的 stdio 适配器让编码 Agent 通过 MCP 操作远程 Linux 沙箱,支持 OAuth 登录,并可在本机与沙箱间同步文件。适用于需要在隔离环境中运行和检查代码的开发流程。
主要功能
- 01通过 OAuth 连接沙箱与日志工具
- 02上传本地工作目录到沙箱
- 03将沙箱文件下载回本机
- 04同步时比较差异并可预览
- 05支持人工接管与代码审查
适用场景
- 01将未提交的工作目录上传到沙箱测试
- 02取回沙箱生成的构建产物
- 03让人工检查沙箱中的工作
- 04查看沙箱命令日志
MCP 相关
它通过 stdio 连接到 ParallelSandbox MCP 服务,提供沙箱和日志工具,并在本地实现 sandbox_sync 与 sandbox_pull。也可直接通过 HTTP 连接服务,但这两项本地文件工具不可用。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://mcp.parallelsandbox.com/mcpclaude mcp add --transport http com-parallelsandbox-parallelsandbox https://mcp.parallelsandbox.com/mcp{"mcpServers":{"com-parallelsandbox-parallelsandbox":{"type":"http","url":"https://mcp.parallelsandbox.com/mcp"}}}在 Cursor 中打开{"servers":{"com-parallelsandbox-parallelsandbox":{"type":"http","url":"https://mcp.parallelsandbox.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"com-parallelsandbox-parallelsandbox":{"type":"http","url":"https://mcp.parallelsandbox.com/mcp"}}}{"mcpServers":{"com-parallelsandbox-parallelsandbox":{"serverUrl":"https://mcp.parallelsandbox.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
https://mcp.parallelsandbox.com/mcp需要授权工具
详细介绍
parallelsandbox-mcp
ParallelSandbox MCP 服务的 stdio 适配器。它通过 OAuth 登录,并提供与 https://mcp.parallelsandbox.com/mcp 相同的工具(sandbox_*、logs_*),同时在本地实现 sandbox_sync 和 sandbox_pull:Agent 可以将工作目录上传到沙盒,而无需提交更改;也可以将沙盒中的文件写回本机。0.4.0 及更高版本会打开浏览器以登录并授权连接。无需 API 密钥。
使用
npx -y parallelsandbox-mcp
Claude Code:
claude mcp add parallelsandbox -- npx -y parallelsandbox-mcp
其他 MCP 客户端:将上述命令作为 stdio 服务运行。
首次连接会立即启动,随后打开浏览器进行 OAuth 登录。登录完成前,parallelsandbox_connect 工具会返回登录链接。之后,适配器会公布其沙盒和日志工具;不重新加载工具列表的客户端需要重新连接一次。再次调用 parallelsandbox_connect 可检查状态,或重试已取消的登录。登录等待五分钟后,需要重试。
令牌文件位于 ~/.parallelsandbox 中,每个 MCP 端点各自独立,权限模式为 0600。多个对话会共用此登录,并通过文件锁串行刷新令牌。若刷新响应丢失,则需要重新登录,以确保不会再次使用已用过的刷新令牌。现有的 PARALLELSANDBOX_API_KEY 配置仍可继续使用。
如果不需要 sandbox_sync 或 sandbox_pull,请跳过此软件包,直接通过 HTTP 连接并使用 OAuth 登录(之后在 Claude Code 中运行 /mcp;无需密钥)。通过普通 HTTP 使用时,这两个工具会返回错误,因为它们会读写本机上的文件:
claude mcp add --transport http parallelsandbox https://mcp.parallelsandbox.com/mcp
环境
| 变量 | 默认值 | 用途 |
|---|---|---|
PARALLELSANDBOX_API_KEY | 未设置 | 可选的现有 API 密钥;设置后跳过 OAuth |
PARALLELSANDBOX_AUTH_DIR | ~/.parallelsandbox | OAuth 令牌文件和锁 |
PARALLELSANDBOX_NO_BROWSER | 未设置 | 设置为 1,仅获取登录链接,不打开浏览器 |
PARALLELSANDBOX_MCP_URL | https://mcp.parallelsandbox.com/mcp | MCP 端点 |
PARALLELSANDBOX_API_URL | https://api.parallelsandbox.com | sandbox_sync 使用的 REST 基础地址 |
PSBX_TOOL_TIMEOUT_SEC | 60 | MCP 主机配置的工具绝对截止时间,单位为秒;用于确定安全的审查等待时间(默认 25 秒,最长 1800 秒) |
PSBX_ADAPTER_SILENCE_MS | 75000 | 某次调用的连接在适配器放弃前可保持静默的时长(参见超时) |
PSBX_FEEDBACK_HOST | 未设置 | 开发反馈桥接:claude-code 或 codex;普通 MCP 连接不受影响 |
PSBX_CODEX_CLI | 主机上的 codex 进程 | 用于通过 codex queue 传递反馈的 codex 可执行文件绝对路径(也用于显式配对的 App Server) |
PSBX_FEEDBACK_DIR | ~/.cache/parallelsandbox/feedback | 反馈工单、邮箱和中继状态 |
PSBX_HOOK_HOLD_SEC | 1200 | 请求审查后,Cursor 和 Gemini CLI 的回合结束钩子等待的时长 |
PSBX_CODEX_HOST_SOCKET | 未设置 | 该现有 App Server 的私有控制套接字绝对路径;不支持 Desktop IPC |
PSBX_CODEX_FEEDBACK_DIR | ~/.cache/parallelsandbox/codex-feedback | 由 Codex 钩子和适配器共享的私有绑定工单 |
使用开发端点时,请将 PARALLELSANDBOX_MCP_URL 和 PARALLELSANDBOX_API_URL 都设置为对应的开发地址。
sandbox_sync
{"id": "<box id>", "localPath": "/abs/path/to/repo", "dest": "repo"} 会将 localPath 同步到沙箱中的 /work/<dest>。
dest 是相对于 /work 的路径(用 repo,而不是 /work/repo;开头的 /work/ 会被去掉,其他绝对路径会在上传任何内容之前被拒绝)。
请传入绝对路径:相对路径会相对于此适配器的工作目录解析(即 MCP 客户端启动时所在的目录),该目录不一定是 Agent 的工作目录。在 Git 工作树中,它会获取已跟踪文件,以及 .gitignore 未排除的未跟踪文件,然后询问沙箱其中哪些文件与 dest 中现有文件不同,并且只上传这些文件,因此编辑后再次同步时只会发送该编辑内容。在沙箱中更改的文件也会被视为不同,并被本地版本覆盖,除非有 "exclude" glob 匹配该文件(例如 ["capacitor.config.ts", "renderer/dist-win"]:这些路径既不会发送,也不会进行比较,沙箱中的副本也不会被列为过期文件或被清理)。在 Git 之外,以及使用 commit 时,比较和发送方式相同;在 Git 之外,会获取除 node_modules、.git、dist、build、coverage、.venv 等目录以外的所有文件。不会发送 .git。
如果同步将要发送的内容超过 100 MB(磁盘占用大小),则不会发送任何内容,并会列出最大的文件夹;如果该大小符合预期,可通过 "maxMB" 提高限制。"dryRun": true 会与沙箱进行比较,并报告将要发送的内容,但不会发送或删除任何内容。运行期间,适配器每 10 秒向请求进度的客户端报告进度(哈希计算、比较、已上传的兆字节)。如果上传遇到 fetch failed、连接重置或 HTTP 502/504,则会再发送一次,并在 notes 中说明;如果两分钟内没有任何进展,或者沙箱收到全部内容后十分钟内没有响应,则会失败,并显示指出该步骤的消息。
结果会说明执行情况:sentPaths(已发送文件中的前 50 个;sentFiles 是文件数)、changedOnBox(沙箱实际重写的文件)、remotePath,以及在工作树中提供的 uncommitted(与 HEAD 不同的路径)。如果其他会话共用该检出目录,这些可能是它们尚未完成的工作;请传入 "commit": "HEAD",并通过 "alsoPaths" 列出你自己的文件。commit 接受任意版本;若该版本不存在则会失败。不传入 commit 时,alsoPaths 仅发送其中列出的路径。
本地删除或重命名的文件会保留在沙箱中,并列在 staleInDest 中,但会排除被忽略规则跳过的路径(node_modules、构建输出、.env)。"prune": true 会删除这些文件。如果 localPath 是单个文件,该文件会写入 dest 本身("dest": "renderer/.env" 会写入 /work/renderer/.env),除非 dest 以 / 结尾,或它在沙箱中已经是一个文件夹。
不会发送 node_modules,因此如果包含 package-lock.json、pnpm-lock.yaml 或 yarn.lock 的文件夹在沙箱中没有 node_modules,或者对于 npm,已安装的包与 lockfile 不同,notes(以及 deps)会说明这一点,并提供要在沙箱中运行的命令。首次同步到某个 dest 时,notes 还会列出被忽略规则排除的构建设置(tsconfig.json、.env.local),并说明如何发送;如果发送的 gradlew、mvnw 或 *.sh 脚本以 #! 开头但没有可执行权限,也会指出这一点。
子模块:不传入 commit 时,已初始化的子模块会作为普通目录发送,其中包含磁盘上的所有内容。git archive 不会包含子模块,因此使用 commit 时,请传入 "submodules": true,以添加每个已初始化子模块,并使用树中记录的提交。"baseline": "origin/main" 还会将该提交发送到 <dest>-baseline,这样就可以在两边运行失败的测试,查看它是否原本就会失败;如果 dest 中有 node_modules,会将其复制到 baseline,缺少的文件使用硬链接("baselineDeps": false 可跳过此操作),并排除 Vite 缓存,以免两棵目录树共用同一份缓存。同步失败时,没有任何新内容到达沙箱;该沙箱上的下一次 sandbox_exec 会附带提醒。
sandbox_pull
{"id": "<box id>", "path": "<path under /work>", "localPath": "/abs/path/on/your/machine"} 会从 box 下载文件或目录。文件会写入 localPath。目录内容会直接解压到 localPath 中,这与 sandbox_sync 相反:path 为 app/dist、localPath 为 /abs/dist 时,得到的是 /abs/dist/index.html,而不是 /abs/dist/dist/index.html(0.3.3 之前的版本会多出这一层)。结果会返回 files(写入的文件数)和 paths(其中前 50 个文件的路径)。传入 "extract": false 可将 tar.gz 保留为单个文件;其中目录本身是顶层条目。相对路径的解析方式与 sandbox_sync 相同;dest 也可用作 localPath 的别名。只会保留本地副本:ParallelSandbox 一侧的交接副本会在约一天后删除。
解压会与 localPath 中已有内容合并。"clean": true 会让其内容与 box 中的目录完全一致:归档会先解压到旁边,只有成功后才会替换;结果中的 removed 统计被移除的本地文件数。对于 git checkout、你的主目录、adapter 的工作目录及其父目录,系统会拒绝执行 clean。box 在打包目录时仍在写入的文件会列在 changedWhileReading 中。下载会报告进度,在两分钟没有数据后放弃;如果第一个下载链接被拒绝,则会重新获取一个链接。
哪个对话正在使用 box
普通 MCP 连接会在 adapter 启动时选择一个随机 id,并在每次调用时将其作为 X-Psbx-Agent 发送。已注册的原生会话会在所有轮次中保持同一个由 supervisor 管理的 id;supervisor 会一直维护其在线状态,直到停止。首次调用工具后,每分钟会报告一次;对话结束时(stdin 结束,或收到 SIGTERM、SIGINT 或 SIGHUP),会报告 /v1/agents/<id>/leave。使用下方的反馈中继时,中继会为该机器上账号的每个运行中的 adapter 每分钟发送一次 /v1/agents/heartbeat(每个 adapter 都会用自己的 id 和进程信息保留一个小型在线状态文件);否则,每个 adapter 会自行报告 /v1/agents/<id>/heartbeat。应用会利用这些信息,区分 AI 仍在使用的 box,以及对话结束时未调用 sandbox_review 或 sandbox_stop 的 box;如果对话被直接终止(没有 leave),则在上次心跳三分钟后视为已结束。不会发送其他内容:没有提示词,也没有转录文本。
重启客户端会启动一个带有新 id 的 adapter,因此,对话重启前使用过的 box 会显示 agent.state 为 left,直到再次被使用;重启后的对话可以直接继续使用该 box。
超时
sandbox_takeover 会一直阻塞,直到有人交还沙箱,最长 30 分钟。sandbox_review 会立即创建供用户审核的卡片,然后等待对方在调用方声明的时限内提交报告或完成审核。默认适配器和未知的 HTTP 客户端最多等待 25 秒;明确支持的客户端最多等待 30 分钟。显式设置的 waitSec 不得超过此时限与准备审核所用时间所允许的范围。结果中包含生效的 waitSec 和 callerWaitMaxSec。最终结果返回前,其进度信息会包含审核 ID 和入口 URL。使用 waitSec: 0 可显式移交而不等待;若要恢复超时的审核轮次,请使用 reviewId,而不是通过 what 创建另一张卡片。适配器对接管和审核等待 31 分钟,对其他调用等待 65 分钟(前台 sandbox_exec 最多运行 60 分钟)。
取消客户端调用也会取消其控制连接,但不会删除审核或反馈。
每个前台 sandbox_exec 都会携带由适配器选择的 execId。如果结果在返回途中丢失(75 秒内没有数据,或流在结果返回前结束),命令会继续在沙箱中运行,错误信息会指出
sandbox_procs {action: "wait", bgId: <execId>};命令结束后,该操作会返回其退出代码和输出末尾内容。
适配器还会每隔 10 分钟检查一次服务端的工具列表,并在列表发生变化时发送 notifications/tools/list_changed,以免较长的对话一直使用旧架构。
等待工具的路由仅在该调用处于活动状态期间有效。已注册的原生会话使用下方的监督程序,在一轮结束后继续运行。
AI 完成后继续运行
parallelsandbox-agent 会为已注册的原生 Claude Code、Codex 或 Gemini CLI 会话运行持久监督程序。首次提示词和后续每条提示词都会使用相应提供方的原生对话历史记录。在该会话中创建的审核,会向同一个监督程序注册其沙箱和审核。提交 App 报告后,监督程序会接收该报告,等待当前原生轮次退出,然后恢复精确保存的原生会话 UUID。恢复后的 AI 会通过其原生 MCP 连接调用 sandbox_report,接收文本、图像、录音和带时间戳的转录内容。只有成功完成且已读取该报告的原生轮次,才能确认已送达。提交后,App 回执会独立轮询;“已接收”并不表示所请求的更改已完成。
npx -y --package parallelsandbox-mcp parallelsandbox-agent start \
--provider claude-code --cli /absolute/path/to/claude --cwd /absolute/path/to/project \
--prompt "Work on this project and use sandbox_review when it is ready to try."
在同一条命令中,使用原生 Codex 可执行文件选择 codex,或使用原生 Gemini 可执行文件选择 gemini。
命令会返回准确的会话目录。之后的提示词请使用 send --session <directory> --prompt <text>,使用 status --session <directory> 读取结果,并使用 stop --session <directory> 停止该监督程序。必须提供提供方运行时凭据:ANTHROPIC_API_KEY、CODEX_API_KEY/OPENAI_API_KEY,或指向有效提供方端点的 GEMINI_API_KEY。运行程序使用私有的原生配置目录;不会自动继承全局 CLI OAuth 登录状态。有关配置、恢复和权限配置文件,请参阅 SESSION_FEEDBACK.md。
原始会话通过此运行程序启动时即完成注册。较早的实验性 Claude Channel 和配对式 Codex App Server 桥接仍是独立的可选集成;它们并非已注册原生运行程序的交付机制。
将反馈返回原始对话(Codex、Claude Code、Cursor、Gemini CLI)
sandbox_review 成功后,针对该评审的 App 反馈会返回到发起评审请求的同一对话。sandbox_draft、sandbox_architecture 或 sandbox_schema 绘制的每个版本也一样:用户在 App 中圈出的内容及其反馈,会返回到绘制它的对话。设计属于账号和该对话,而非某个框:设计工具不需要框的 id,反馈也会以同样方式路由,无需提供框的 id。
适配器会写入一个工单(评审、sandbox_review 卡片对应的框,以及适配器自己的 Agent id,不含凭据),并为每个账号启动一个小型本地中继。中继会为该对话注册一个反馈接收器,认领已提交的报告(对这台机器上的所有对话进行一次长轮询,/v1/feedback-consumers/claim;较旧的服务器会对每个对话分别轮询),并向对话发送一条简短的后续提示,告知它使用 sandbox_report 读取哪份报告;读取后,App 回执会标记为已读。各主机的区别仅在于后续提示如何进入对话:
| 主机 | 钩子 | 对话接收提示的方式 |
|---|---|---|
| Codex(桌面端、CLI、IDE) | 无 | 对话线程来自 Codex 的工具调用元数据;中继会运行主机自带的 codex queue --thread。空闲线程会开始一个轮次;忙碌线程则会在当前轮次结束后收到提示。 |
| Claude Code(CLI、桌面端) | install claude-code | 后台 asyncRewake 钩子会唤醒空闲会话;忙碌会话会在当前工具调用后读取提示。钩子会在会话自己的 CLI 进程中等待,因此未运行的会话无法接收提示:在 CLI 中恢复会话(claude --resume <session id>)后,会接收期间到达的所有内容。Claude Desktop 会在内存不足时停止空闲会话,仅在应用中打开这样的会话并不会重新启动它:向它发送一条消息(任何消息均可),应用便会恢复会话并交付反馈。在此之前,App 回执会说明原对话未在运行,并请用户执行该操作。claude -p "<prompt>" 会在前台运行钩子,因此在这种情况下,打开评审的调用会等待报告,而 sandbox_report 会立即返回。 |
| Cursor | install cursor | afterMCPExecution 会附加评审;stop 钩子会以 followup_message 的形式返回评审。尚未通过真实的 Cursor Agent 完成端到端验证。 |
| Gemini CLI | install gemini | AfterTool 会附加评审;AfterAgent 钩子会通过 decision: "block" 返回评审。 |
无需用户手动设置。如果机器上缺少客户端的钩子,适配器的服务器说明会告知 AI 在对话中征求用户同意,为其客户端运行这条命令(npx -y parallelsandbox-mcp install <client>;该命令会修改用户设置),而 sandbox_review 结果会说明评审尚未路由回来。用户同意后,AI 会在首次评审前运行该命令(或者运行该命令后,使用 reviewId 和 waitSec: 0 再次请求评审)。Claude Code 和 Cursor 会将通过这种方式添加的钩子应用到正在运行的对话;Gemini CLI 会在启动时加载钩子,因此首次评审会通过该框上的下一次 sandbox_status 或 sandbox_review 交付,之后的会话则会自动处理。install 会合并到客户端的用户设置中(Claude Code 会遵循 CLAUDE_CONFIG_DIR),保留其他所有内容,并为之前的文件写入 .psbx-backup 备份。Cursor 默认也会运行 Claude Code 的钩子;Claude Code 钩子只会在运行它的 Claude Code 会话内生效(CLAUDE_CODE_SESSION_ID),因此绝不会阻塞或错误路由 Cursor 对话。
Cursor 和 Gemini CLI 无法唤醒空闲对话。它们的轮次结束钩子会在请求评审后立即等待最多 20 分钟(PSBX_HOOK_HOLD_SEC);其他情况下,则会在该对话的下一轮结束时交付等待中的反馈。
状态保存在 ~/.cache/parallelsandbox/feedback 中(可通过 PSBX_FEEDBACK_DIR 覆盖),权限模式为 0600,保留 7 天。
报告绝不会交给其他对话,绝不会重复排队;如果钩子的宿主进程已退出,钩子就不会接收任何内容。无法注册的评审(服务端只允许发起评审的对话接收该评审的反馈)只会记录一次并搁置;不会阻碍其他评审的反馈,临时服务端或网络错误则会通过退避重试。使用其他对话中的现有 reviewId 调用 sandbox_review,或在适配器重启后调用,都会保留该评审原有的路由。只有在适配器无法找到宿主 codex 进程时(例如在 Windows 上),才设置 PSBX_CODEX_CLI。
如要在 Codex 中等待完整的 30 分钟,请为此 MCP 服务设置 tool_timeout_sec = 1920,并在该服务的适配器环境中设置 PSBX_TOOL_TIMEOUT_SEC = "1920",然后使用适配器 0.4.2 或更高版本重启或重新连接服务。其他宿主需要设置等效的绝对工具超时时间。两项设置缺一不可:仅增加 waitSec 或仅增加适配器设置都无法延长宿主的截止时间。现有缓存的适配器进程会继续使用旧设置,直到重启。本软件包不会自动更改客户端配置。
sandbox_report 会通过 reportId 读取账户所有的报告;对于 sandbox_review 卡片上的报告,还需提供卡片的 id(设计上的报告只需提供 reportId),内容包括媒体 URL、带时间戳的转录和带注释的帧。它可以重放先前已由工具返回的报告,不会认领该卡片,也不会消耗其他待处理消息。报告和媒体会保留 7 天。回执记录的是完整工具结果的准备情况,而不是 AI 是否理解或完成了所请求的更改。
调用运行期间,服务端每 20 秒(sandbox_takeover 为每 15 秒)在连接上发送一行“仍在运行”消息。如果客户端请求了进度,适配器会将这些消息转发为 MCP 进度通知,因此在一段时间没有响应后会取消调用的客户端(Claude Code 会在 30 分钟后取消)可以继续等待长时间的构建。如果连接在返回结果前结束,或在 PSBX_ADAPTER_SILENCE_MS 指定的时间内没有收到任何内容,适配器会立即返回错误,而不是一直等到超时。可安全重放的工具(sandbox_report、sandbox_list、sandbox_get、logs_* 工具等)会先重试一次。其他情况下,错误会说明调用可能已在卡片上运行甚至完成:再次运行前,请检查 sandbox_status(其 steps[] 会列出已运行的步骤)。sandbox_status 可以转交一次待处理的人工反馈,因此在结果丢失后不会自动重试;请使用应用中的报告 ID 调用 sandbox_report,以取回该报告。
故障排除
- 客户端在启动服务时超时(MCP
initialize超过 60 秒),且没有显示适配器错误。npx仍在下载软件包,因此适配器尚未启动。请查看~/.npm/_logs/中最新的文件。registry.npmjs.org出现ENETUNREACH(或ETIMEDOUT)通常表示机器解析到了无法访问的 IPv6 地址:在客户端的 MCP 设置中,将"NODE_OPTIONS": "--dns-result-order=ipv4first"添加到服务的env,或者先通过npm i -g parallelsandbox-mcp安装,再运行parallelsandbox-mcp,而不是使用npx。 the result never came back (connection from this computer to ParallelSandbox (...) failed: fetch failed (ENOTFOUND ...))。 这台计算机与 ParallelSandbox 之间的连接中断了(DNS、代理、VPN、Wi-Fi 问题),而不是卡片自身的网络问题。括号中的代码是 Node 报告的原因。卡片与您的环境之间的连接可在sandbox_status的environment.connections[]中查看。
源代码和问题
源代码:https://github.com/parallel-sandbox/parallelsandbox-mcp。请在那里提交问题报告,或在会话中使用 sandbox_feedback 工具提交。采用 MIT 许可证。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。