mcpField
U
upstash-box-remote-work

upstash-box-remote-work

github.com/upstash云与 DevOps34486 次安装1 天前更新
代码仓库

关于 upstash-box-remote-work

这是一项通过 Upstash 远程云端 Box 执行开发任务的工作流技能,适用于需要隔离 Linux 环境、提交 PR、公开预览或截图的工作,并说明 Box、Git、命令执行和清理流程。

主要功能

  1. 01创建和管理云端沙箱 Box
  2. 02远程运行 shell 命令和 Git 操作
  3. 03发布基于端口的预览 URL
  4. 04截取浏览器画面并上传到 Blob
  5. 05通过快照和并行 Box 扩展独立任务

适用场景

  1. 01在隔离环境中构建和测试生成或不可信代码
  2. 02创建带公开预览的拉取请求
  3. 03并行运行多个相互独立的开发任务

MCP 相关

该工作流通过 https://mcp.upstash.com/mcp 上的 Upstash 远程 MCP 服务运行。其工具用于管理 Box、执行 shell 和 Git 操作、创建预览、控制浏览器会话、管理快照及上传到 Blob。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/upstash/skills --skill upstash-box-remote-work

安装后在 Claude Code 中输入/upstash-box-remote-work确认已加载。

详细介绍

Box 是云端经过沙盒隔离的 Linux 容器,配有 shell、文件系统、git、可选的无头 Chromium,以及指向其端口的公开 URL。这里的所有操作都通过远程 Upstash MCP 服务进行。无需安装 SDK,环境中也没有 API 密钥(录制视频是例外,见下文):服务会将会话的 OAuth 令牌转发给 Box API,而截图字节会直接从 Box 传到 Blob,不经过服务。

何时将工作放入 Box

  • 用户提出要求:远程、在沙盒中、在云端、在 Box 中,而不是在我的机器上。
  • 交付内容是拉取请求、公开预览 URL,或运行结果的截图。Box 配有 GitHub 凭据、公开端口和浏览器;本地机器通常三者都不具备。
  • 工作需要隔离:不受信任或生成的代码、繁重的依赖安装、干净的检出,或本地工作树不应包含的分支。
  • 工作需要扩展:多个相互独立的任务,每个任务使用一个 Box,并行执行。

任务一旦放入 Box,就应在那里完成全部工作。Box 的文件系统与本地文件系统不同,因此在本地进行编辑、在 Box 中运行构建会作用于两个不同的检出,而且双方都不会报告这种不一致。

连接

插件已注册 https://mcp.upstash.com/mcp,Box 和 Blob 工具也属于其默认工具集。手动添加服务:

claude mcp add --scope user --transport http upstash "https://mcp.upstash.com/mcp"

首次使用时,客户端会打开 Upstash 授权页面。选择 Box 和存储桶应归属的账户或团队,并关闭只读开关:只读授权下,除列出之外的以下所有步骤都会被拒绝,并返回 403。

工具

工具操作/用途
box_manage创建、列出、获取、删除、暂停、恢复、分叉
box_exec在 Box 中运行 shell 命令(command 是 argv 数组,folder 是工作目录)
box_git克隆、查看状态、查看差异、提交、检出、推送、创建 PR
box_preview为 Box 中的端口创建、列出、删除公开 URL
box_browsergoto、content、screenshot、tabs、tab_new、tab_close、live_view
box_snapshots创建、列出、全部列出、删除、恢复(根据快照创建一个新 Box)
box_logs、box_runs查看 Box 内发生的情况及其运行历史
box_apikey为已部署的应用或 CI 列出、创建、删除 Box API 密钥(密钥的有效期会超过 OAuth 授权,因此完成后请告知用户撤销密钥)
blob_bucket列出、创建(创建时默认使用 visibility: public)
blob_upload_url获取存储桶中路径的预签名 PUT URL;对于公开存储桶,还会提供 public_url

流程:一项任务,一个 box

  1. 创建。 使用 box_manage 的 create。如果要截屏或检查页面,请设置 browser: true。对于临时工作,使用带有 ttl 的 ephemeral: true(无需付费套餐);如果预览 URL 必须在会话结束后继续有效,则使用 keep_alive: true(付费套餐)。记下返回的 id。
  2. 使用 box_git 的 clone 克隆,绝不要在 box_exec 中使用 git。克隆操作会将账户的 GitHub 凭据写入 box;没有这一步,push 和 create_pr 会因裸 500 错误而失败。检出目录位于 /workspace/home/<repo name>。之后每次调用 box_exec 和 box_git 时,都要将该路径作为 folder 传入:默认路径是工作区根目录,并非仓库。
  3. 工作。 使用 box_exec 执行安装、构建、测试和运行应用。每次调用都会等待命令结束,因此要将服务器放到后台运行: ["sh", "-c", "( pnpm preview --host 0.0.0.0 --port 4321 > /workspace/home/app.log 2>&1 & )"], 然后在第二次调用中用 curl 轮询端口。使用 shell 命令或 box_exec 中的简短脚本编辑文件,不要使用本地文件工具。
  4. 预览 URL。 使用 box_preview 的 create 并传入 port。应用必须监听 0.0.0.0;绑定到 127.0.0.1 的服务器虽然能在 box 内响应 curl,但通过预览访问仍会返回 502。URL 格式为 https://<box-id>-<port>.preview.box.upstash.com。如果不希望任何拿到链接的人都能打开页面,请添加 basic_auth 或 bearer_token;凭据只会返回一次。回复中说明 URL 的有效时长:临时 box 会在 expires_at 时将其关闭。
  5. 截屏。 使用 box_browser 的 goto 打开 http://localhost:<port> 上的页面,然后调用 screenshot。不传 path 时,PNG 会作为图片返回,供你查看;传入 path 时,图片会写入 box,且只返回 {saved, bytes}。工作过程中查看截图,保存重要截图;对于长页面,传入 full_page: true。
  6. 发布截图。 GitHub 的附件接口会拒绝 box 的令牌,因此图片要通过 Blob 上传。使用 blob_bucket 的 list,如果没有合适的存储桶,就创建一个公开存储桶(私有存储桶只提供短期签名 URL)。传入 bucket_id 和 files: [{path: "<repo>/<branch>/after.png", content_type: "image/png", size: <bytes>}] 调用 blob_upload_url,并在使用前立即生成(URL 的有效时间最长为 10 分钟)。然后在 box_exec 中执行结果里的 curl_example,并逐字发送返回的标头(它们是签名的一部分)。字节会直接从 box 传到存储。
  7. 拉取请求。 使用 box_git 的 checkout 切换到一个分支,执行 commit,传入分支名称执行 push,然后使用 base、title 和 body 调用 create_pr;body 中要包含预览 URL,以及每张截图对应的 ![after](<public_url>)。create_pr 本身不会推送任何内容。回复中提供 PR URL、预览 URL 和截图 URL。
  8. 清理。 除非用户希望保留 box 或其预览,否则使用 box_manage 的 delete(或 pause)。临时 box 会自动过期。

扩展规模

  • 每项独立任务使用一个 box。创建时使用共享的 labels 条目,并行运行任务,最后使用 box_manage 的 list 并传入 label 来查找并删除这些 box。绝不要在同一个 box 中同时运行两项任务。
  • 如果客户端支持子 Agent,请为每个子 Agent 分配自己的 box 并行运行;共用一个 box 的 Agent 会覆盖彼此的文件和进程。
  • 如果每项任务都需要相同的耗时设置(克隆、安装依赖、构建缓存),请只执行一次,然后使用 box_snapshots 的 create 创建快照,再从该快照为每项任务 restore 一个新 box。对于空闲或已暂停的非临时 box,也可以使用 fork 执行相同操作。
  • size 可设为 small、medium 或 large;应根据任务选择,而不是一律选用更大的规格。
  • live_view URL 可让用户实时查看 box 中正在工作的浏览器标签页(只传出画面,不接收输入);长时间运行时可将其分享给用户。

在 box 中录制视频

录制功能目前还不是 MCP 工具,因此这是唯一需要使用 SDK 的流程。 使用 box_apikey create 创建密钥,将其保存在 Box 内的一个文件中, 然后通过 @upstash/box(box.browser.recordings,以及供 Playwright 使用的 box.browser.cdpUrl())操作 Box,并在完成后删除密钥。

录制内容。 Box 浏览器:固定分辨率下的所有标签页,并跟随前台标签页。 其他内容必须放进浏览器中。终端程序通过 ttyd 运行(从 GitHub releases 获取静态二进制文件;Debian 没有对应的软件包),并连接到固定大小的 tmux 会话;分小段使用 tmux send-keys -l 发送输入,因为 TUI 会折叠带括号的粘贴内容; 使用 tmux set -g status off,否则状态栏会出现在每一帧中。尽量留在同一个标签页中: 新打开的标签页不一定会被跟随。

在 Box 中运行 Agent 或 CLI。 手动启动的 CLI Agent 需要自己的模型密钥; Box 的托管密钥只能用于 Box 运行器启动的提示词。不要在聊天中粘贴密钥,而要将密钥传入 Box:从 Box 启动一个一次性表单(一个只接受一次 POST 的小型 HTTP 服务),通过 box_preview 公开该服务,将链接发给用户;表单会将值追加到文件中,然后退出。等待 localhost OAuth 回调的登录流程无法通过隧道转发(Box SSH 不允许 -L)。如果 CLI 允许设置重定向 URI(OpenCode:在 opencode.json 中设置 oauth.redirect_uri),则将其指向 Box 预览 URL:回调服务仍会在该 URI 的端口上绑定 127.0.0.1(https 使用 443,可由非特权用户使用),而预览只能访问 0.0.0.0,因此在授权期间将预览端口转发到该地址。否则,在 Box 中运行登录流程,让用户在自己的浏览器中批准,然后让用户将失败的 http://127.0.0.1:<port>/... URL 粘贴回来,并在 CLI 停止等待之前,在 Box 中通过 curl 访问该 URL。授权页面会选择账号,因此录制所依赖的资源必须存在于该账号中。对于无人值守的 Agent 运行,排除澄清问题的工作区指令有助于避免录制中途停滞。

限制。 录制时长最多为 600 s;如果 3 分钟内像素没有变化,录制会自动停止。一个 Box 只能有一个正在进行的录制;残留的录制会导致下一次 start 返回 409,因此要在崩溃处理程序中以及每次开始录制前停止录制。录下所有打算展示的内容,包括计划加速播放的等待过程;缺失的片段无法事后补回。

时间。 根据时间戳剪辑,而不是凭肉眼判断。记录脚本每项操作的墙上时钟时间;从结构化输出(会话导出、日志、API 响应)中获取录制程序自身的时间线,而不是从屏幕上读取,并将两者转换为视频时间。以结束时间为基准,而不是开始时间:录制会在 startedAt 约 2 s 后开始,因此第一帧的时间是 endedAt - <file duration>(ffprobe),而 startedAt 会使每个剪辑点都提前。终端中抓取的文本会在自动换行处断开。将大型 CLI 输出重定向到文件;管道可能会截断输出。

编辑(ffmpeg):

  • 加速漫长等待,而不是将其删掉;硬切会让人觉得画面卡顿。使用整数倍数(5、10、20、50x),片段时长随倍数调整,并在角落显示倍数:使用纯绿色圆角胶囊,搭配深色文字(box=1:boxcolor=0x00d48a),不要使用半透明徽章:无论背景是什么,都必须一眼就能看清。
  • 用屏幕文字说明正在发生的事:每个步骤配一条简短字幕,显示时间要足够长,便于阅读(约 0.7 s 或更长);步骤节奏较快时,减少字幕数量。
  • 无头录制没有指针和地址栏。发生输入时,绘制光标和点击标记;地址栏内容很重要时,绘制 URL。位置从 Playwright 边界框获取(先将元素滚动到视野内);如果是终端,则使用 ttyd 的 window.term:单元格大小为 .xterm-screen 矩形区域除以 cols 和 rows,行和列通过搜索 term.buffer.active 获取。
  • 让光标看起来像手动移动的。使用小巧、纤细、经过抗锯齿处理的箭头(在 1280x800 画面中约高 25 px),并添加柔和阴影。每次移动都要沿着轻微弧线(控制点向侧面偏移的二次贝塞尔曲线)平滑地加速和减速(smootherstep),在点击前稍作停顿,并在停留时添加轻微漂移。点击时显示短暂按压效果(精灵略微缩小,持续约 0.15 s),并添加一道纤细的波纹,在约 0.4 s 内扩散并淡出,而不是显示实心圆环。在每个片段边界处保持光标不动,避免其滑向下一片段的位置。
  • 将波纹渲染为 PNG 序列,并使用 tpad 为每次点击延迟一份副本。将滤镜图写入 -filter_complex_script;引号表达式中的逗号仍需写成 \,(下方示例未转义)。
[0:v]trim=T0:T1,setpts=(PTS-STARTPTS)/20,fps=30,
  drawtext=text='20x':fontcolor=0x062b1f:box=1:boxcolor=0x00d48a:boxborderw=10:x=w-tw-30:y=26,
  drawtext=text='<step>':enable='between(t,2.0,2.8)'[fast]
[ripple]format=rgba,tpad=start_duration=<click t>:color=0x00000000[r]
[v][r]overlay=x=<cx-36>:y=<cy-36>:eof_action=pass[v2]
[v2][cursor]overlay=eval=frame:enable='between(t,A,B)':
  x='st(0,clip((t-T0)/D,0,1));st(1,ld(0)^3*(ld(0)*(6*ld(0)-15)+10));
     (1-ld(1))^2*X0+2*(1-ld(1))*ld(1)*XC+ld(1)^2*X1':y='...'

使用 ffmpeg ... tile=3x3 联系表检查剪辑,通过 python3 -m http.server 提供并在 box_browser 中打开;不要在录制进行时检查(这是同一个浏览器)。使用 blob_upload_url 发布视频。

两次录制之间。 使用 box 工具录制的 Agent 会在创建任何内容前列出已有内容:如果上一次录制留下了 box,它就会跳过克隆并复用该 box。请先删除残留内容,或在提示词中注明“一个全新的 box”。录制 Agent 创建的 box 属于它授权访问的账户,不一定是你自己的会话可以访问的账户。

多次录制。 每次录制使用一个 box;如果客户端支持,则由子 Agent 并行驱动。切勿让多个 Agent 共用一个录制 box:tmux 服务、浏览器和录制槽位都按 box 隔离;多个 Agent 共用时,会在不知情的情况下终止彼此的会话并覆盖彼此的文件。

注意事项

  • 只读授权 → 创建、执行、截图到路径、Git 写入和上传 URL 均返回 403。关闭只读后重新授权。
  • 如果账号没有覆盖该仓库的 GitHub 安装,box_git create_pr 会失败;请让用户在 Upstash 控制台的 Box 设置中连接 GitHub。
  • 在 box_manage create 时,优先使用 box_git clone,而不是 clone_repo:对于临时 Box,该选项可能会被忽略;对于持久 Box,该操作会在后台运行,除了 box_logs 外没有完成信号。
  • Box 内的路径默认相对于 /workspace/home,除非使用绝对路径。ls /workspace 本身会被拒绝(目录由 root 所有,权限为 711)。
  • node 镜像没有 corepack,且 boxuser 无法运行 npm i -g,因此固定了 packageManager 的 pnpm 无法自行安装。请使用 npx -y pnpm@<version> 或 export npm_config_manage_package_manager_versions=false(使用预装的 pnpm);也可以使用 sudo npm i -g pnpm@<version>,sudo 无需密码。
  • blob_upload_url 的标头已签名。缺少或更改 content-type 或 cache-control → 存储服务返回 403(SignatureDoesNotMatch)。URL 过期 → 重新生成。
  • Bucket 名称在整个账号范围内唯一。请重复使用一个 Bucket,例如 agent-proof,并为不同仓库使用不同前缀,而不要每次运行都创建一个。
  • 如果创建 Box 时没有设置 browser: true,box_browser 会报错“browser is not enabled for this box”;之后无法再添加。
  • 公共 Blob 主机会将对象缓存一小时(由上传时的 cache-control 设置)。重新上传到同一路径仍会提供旧字节:请使用新名称发布替代文件,并在读取刚覆盖的内容时添加查询字符串。
  • box_exec 请求会在 60 s 后超时。使用 setsid ... & 将长时间运行的任务放到后台,在后续调用中轮询,并检查进程是否仍在运行。
  • 在 box_exec 中运行 pkill -f <pattern> 也会匹配调用它的 shell 命令行并终止该调用(退出码 143)。请改为运行 pkill -f 'patter[n]'。
  • 先运行 tmux kill-server,再立即运行 tmux new-session,可能会失败并提示“server exited unexpectedly”;请先等待旧服务器退出。
  • node 镜像没有 PIL 或 ImageMagick。请使用 sudo apt-get install 安装所需工具,或者用 Python 的 zlib 编写小型 PNG 文件。

评论

支持 Markdown