文件功能: - 新增 file_read / file_write / file_stat 工具(文本/base64/图片,分块读取,原子替换写入,SHA-256) - 新增 file_link 工具与 GET/PUT /files 端点:HMAC 签名限时链接或 Bearer 认证, 支持 Range、HEAD、chunked、Expect: 100-continue,大文件不经过模型上下文 - 新增 --file-root / --max-upload;配置白名单但未限定目录时文件功能自动禁用 安全: - 白名单改为程序名精确匹配,shell 模式禁止元字符,shell_write 输入逐行受检;黑名单检查每一段 - HTTP 签发 Mcp-Session-Id,按会话隔离 shell 会话与取消,支持 DELETE 终止会话 - HTTP 客户端不能再用 notifications/exit 关停服务;token 常量时间比较 正确性: - 后台进程占用输出管道时 run_command 不再挂起(detached=true) - shell_read 改用绝对偏移,修复缓冲裁剪后错位;被信号杀死的会话能报告退出;阻塞读可取消 - 输出与分块读取不再切断 UTF-8 多字节字符 - shell_* 结果改为标准 content + structuredContent - POST + SSE 的 tools/call 在同一响应流中推送进度与结果 - /mcp 支持 Expect: 100-continue(curl 发送大请求时不再白等 1 秒) - CLI 参数优先于环境变量;SIGTERM 在 stdio 模式下也能清理退出;Windows 支持 Ctrl+C 清理与优雅退出 资源:并发工具调用 / HTTP 连接 / shell 会话数量上限,空闲会话自动回收 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bolt — 极速单文件 MCP 命令执行服务器
让 AI(Claude Code / Claude Desktop / Cursor 等 MCP 客户端)通过 MCP 协议连接后,在服务器上执行 shell 命令、读写和传输文件。
- 单文件:全部代码在
src/main.rs,仅依赖serde_json(Unix 下加libc);base64 / SHA-256 / HMAC 均为手写 - 零框架:手写 JSON-RPC 2.0 + MCP 协议 + Streamable HTTP 服务器,无 async runtime、无重量级依赖
- 双传输:
stdio(本地 AI 客户端默认)与Streamable HTTP(远程连接)
快速开始
cargo build --release # 产物: target/release/bolt (~1MB)
本地模式(stdio):由 MCP 客户端拉起本进程
# Claude Code
claude mcp add --transport stdio bolt -- /abs/path/to/bolt
# 或通用 MCP 客户端配置
# {"mcpServers": {"bolt": {"command": "/abs/path/to/bolt"}}}
远程模式(Streamable HTTP):AI 通过网络连接
bolt --http 127.0.0.1:8080 # 仅本机
bolt --http 0.0.0.0:8080 --token mysecret # 对外 + Bearer 认证
bolt --http 0.0.0.0:8080 --token mysecret --allow "git,docker,curl" --file-root /srv/data
# Claude Code 连接远程
claude mcp add --transport http bolt http://127.0.0.1:8080/mcp
工具
| 工具 | 说明 |
|---|---|
run_command |
执行 shell 命令:完整 shell 语法(管道/重定向/&&)、cwd、env、timeout_ms(超时自动杀进程树)、max_output_bytes(输出截断防膨胀)、shell=false 直接执行二进制;客户端可传 _meta.progressToken 接收进度通知,支持 notifications/cancelled 取消 |
shell_open |
开启持久化交互式 shell 会话(cd、环境变量等状态跨次保留),可指定 shell(sh/bash/zsh/fish)与 cwd;空闲 30 分钟自动回收 |
shell_write |
向会话写入输入(自动补换行) |
shell_read |
读取会话新输出,可阻塞等待(timeout_ms,0 = 等到会话退出),可被取消 |
shell_close |
关闭并杀掉会话进程树 |
file_read |
读取文件:UTF-8 文本按文本返回,图片按 image 返回,其余按 base64;offset + length 分块读取,不会切断多字节字符 |
file_write |
写入文件:overwrite(默认,临时文件 + rename 原子替换,保留原权限)/ create(已存在则失败)/ append;encoding=base64 写二进制;mkdirs 自动建目录;返回 SHA-256 |
file_stat |
文件信息(是否存在、类型、大小、修改时间、权限),可选计算 SHA-256 |
file_link |
仅 HTTP 模式:生成带 HMAC 签名、限时有效的 /files 直传链接,并给出可在客户端本机执行的 curl 命令 |
所有工具结果都同时提供 content 与 structuredContent(file_read 为两块 content:元数据 JSON + 文件内容)。
run_command 返回:exit_code / signal / timed_out / cancelled / detached / duration_ms / stdout / stderr / 截断标志等。命令退出后若仍有后台进程占用输出管道(如 python -m http.server &),等待 300ms 后返回 detached=true,后台进程继续运行。
文件传输
MCP 工具的参数和结果都要经过模型上下文,所以分两层:
- 小文件(配置、脚本、日志片段、截图):直接用
file_read/file_write,stdio 和 HTTP 都可用。 - 大文件(HTTP 模式):数据走
/files端点,不经过模型。-
AI 调用
file_link拿到签名链接,在客户端本机执行返回的curl命令即可:curl -fsSL -o ./backup.tar.gz 'http://host:8080/files?path=/srv/data/backup.tar.gz&exp=...&sig=...' # 下载 curl -fsS -T ./dataset.zip 'http://host:8080/files?path=/srv/data/dataset.zip&exp=...&sig=...&mode=overwrite&mkdirs=0' # 上传 -
也可以直接带 Bearer 令牌访问:
curl -H "Authorization: Bearer $T" -T f.bin "http://host:8080/files?path=/srv/data/f.bin&mkdirs=1"。 -
支持
Range断点续传(206)、HEAD、chunked 上传、Expect: 100-continue;上传同样是原子替换,失败不破坏原文件,响应里带 SHA-256。 -
签名覆盖方法、路径、写入模式和过期时间,链接只能用于签名时指定的那一个操作;签名密钥在进程启动时随机生成,重启后旧链接失效。
-
配置
CLI 参数(环境变量 BOLT_* 为回退):
| 参数 | 默认 | 说明 |
|---|---|---|
--http <addr> |
无(stdio) | 启用 Streamable HTTP 监听地址,如 127.0.0.1:8080(:8080 等价于 127.0.0.1:8080) |
--token <t> |
无 | HTTP 要求 Authorization: Bearer <t> |
--allow <a,b> |
空 | 命令白名单(按程序名精确匹配;非空时 shell 模式禁止元字符) |
--deny <a,b> |
空 | 命令黑名单(按程序名匹配命令中每一段,尽力而为) |
--timeout-ms <n> |
30000 | 命令默认超时(工具参数可覆盖,0 = 无限) |
--cwd <dir> |
当前 | 命令与相对文件路径的默认工作目录 |
--max-output <n> |
1M | 单流输出捕获上限(支持 K/M/G) |
--allow-origin <url> |
localhost/127.0.0.1 | 额外允许的 HTTP Origin(防 DNS rebinding) |
--file-root <d1,d2> |
不限 | 文件工具与 /files 只能访问这些目录;配置了 --allow 时必须设置,否则文件功能禁用 |
--max-upload <n> |
2G | PUT /files 单次上传上限(支持 K/M/G) |
export BOLT_TOKEN=xxx BOLT_ALLOW="git,docker" BOLT_TIMEOUT_MS=60000 BOLT_FILE_ROOT=/srv/data
bolt --http 127.0.0.1:8080
协议实现(2025-06-18 规范)
initialize(协议版本协商,支持 2024-11-05 / 2025-03-26 / 2025-06-18)、ping、tools/list、tools/call、shutdownnotifications/initialized、notifications/cancelled、notifications/exit(仅 stdio 生效)、notifications/progress(进度上报)- 工具执行错误以
isError: true返回;协议错误返回标准 JSON-RPC 错误码(-32601/-32602/-32700 等) - Streamable HTTP:
initialize时签发Mcp-Session-Id;携带该头的请求按会话隔离 shell 会话与取消,未知/过期 ID 返回 404,DELETE /mcp终止会话并清理其资源;不带该头的客户端共用一个匿名作用域(兼容无状态客户端)- POST:通知 → 202;请求 → JSON 或 SSE。
Accept含text/event-stream的tools/call会在同一个 SSE 响应里先推进度通知、最后推结果 - GET:长连接 SSE 流(接收本会话的服务器通知 + 10s 心跳)
- 支持 chunked 请求体、CORS、Origin 校验、Bearer 认证
性能与资源
- 复用缓冲区,输出计数用原子操作,进度推送不占主循环;stdio 每个工具调用一个工作线程,HTTP 每个连接一个线程
- 子进程独占进程组(
setpgid),超时/取消按进程组SIGKILL,连带杀掉整棵进程树,无僵尸 - 上限:并发工具调用 128、HTTP 连接 512、shell 会话 64(空闲 30 分钟回收)、MCP 会话 1024(空闲 24 小时回收)
- 实测(本机,含 Python 客户端逐字节 I/O 开销):
- ping 往返吞吐 ≈ 14,700 msg/s
- 并发
echo命令平均 4.7 ms/次(进程 spawn + 捕获输出)
- 构建配置:
lto = "fat"、codegen-units = 1、strip = true
测试
cargo test --release # 单元测试(策略/编码与摘要/HTTP 解析/文件读写与目录限制/会话缓冲/执行引擎等)
cargo test --release test_files # 只跑某一个
端到端测试脚本在 docs/(需要 Unix 主机;二进制路径默认 target/release/bolt,可用 BOLT_BIN 指定):
python3 docs/bolt_stdio_test.py # stdio 端到端
python3 docs/bolt_http_test.py # HTTP 端到端(含 Mcp-Session-Id、/files、签名链接)
安全说明
- 默认只接受本机连接(
127.0.0.1),对外公开需显式0.0.0.0+--token(未设置时启动日志会警告) - 该服务器等于远程 root shell 入口,务必配置认证后再暴露公网
- 白名单(
--allow):按程序名精确匹配,shell 模式下禁止; & | $ \< > ( ) { }和换行,防止git status; rm -rf ~这类串联绕过;shell_write写入的每一行同样受检。注意白名单内的程序如果自身能执行任意命令(sh、env、docker、find -exec、git -c ...`),白名单就约束不了它 - 黑名单(
--deny):检查命令每一段的程序名(去掉路径、引号、转义和前置的VAR=x),但仍可能被包装命令绕过,只适合防误操作 - 文件功能等同于任意写文件(可写
authorized_keys、crontab),所以配置白名单时必须用--file-root限定目录,否则文件功能自动禁用;路径会解析符号链接并拒绝..逃逸 - 不同 MCP 会话之间的 shell 会话与取消相互隔离;HTTP 客户端无法通过
notifications/exit关停服务 - Unix 下命令在独立进程组运行,取消/超时会连带杀掉子进程;收到 SIGINT/SIGTERM(Windows 为 Ctrl+C)时先清理全部子进程再退出
平台
- Linux / macOS(完整功能:进程组杀、信号处理)
- Windows(基础功能:
cmd /C、taskkill /T杀进程树、Ctrl+C 清理退出)
在其他设备上部署(最快方式)
一键脚本支持 Linux(systemd)和 macOS(launchd),自动识别 amd64 / arm64;Apple Silicon 即使在 Rosetta 终端中也优先选择 arm64。安装需要 root 权限。
默认下载 v0.1.0 的 bolt-<平台>-<架构> 附件,例如 bolt-linux-amd64、bolt-darwin-arm64。对应附件需要事先发布到 Gitea Release;可通过 BOLT_VERSION 指定版本,或通过 BOLT_DL_URL / --binary 指定其他来源。
# 1. 下载并执行安装脚本(私有仓库下载附件需先 export 下载令牌)
export BOLT_DL_TOKEN=你的Gitea令牌
curl -fsSL -H "Authorization: token $BOLT_DL_TOKEN" https://git.draws.qzz.io/jocay/bolt/raw/branch/main/deploy/install.sh -o install.sh
sudo BOLT_DL_TOKEN="$BOLT_DL_TOKEN" sh install.sh --http 127.0.0.1:8080
# 2. 完成(脚本自动:下载二进制 → 装到 /usr/local/bin → 写 /etc/bolt.env 与
# systemd 单元 → 开机自启 → 启动服务)。看状态:
systemctl status bolt
macOS arm64(Apple Silicon)
在 Mac 上运行上面的安装命令,脚本会下载 bolt-darwin-arm64,安装到 /usr/local/bin/bolt,并创建以 root 运行的 launchd 系统服务 io.jocay.bolt。
v0.1.0 Release 提供 bolt-darwin-arm64 附件。也可以将该二进制下载或拷到 Mac 后安装:
sudo sh deploy/install.sh --binary ./bolt-darwin-arm64 --http 127.0.0.1:8080 --token 你的令牌
配置保存在 /Library/Application Support/bolt/io.jocay.bolt.plist,包含监听地址、认证令牌、命令规则和超时。启用开机自启时,脚本还会复制配置到 /Library/LaunchDaemons/io.jocay.bolt.plist。两份配置均仅 root 可读写;更改参数建议重新运行安装脚本,以保持一致。
--no-enable 只保留手动启动配置,取消本服务的开机配置,仍可立即启动;--no-start 本次不加载服务,已运行的本服务也会卸载,下次开机是否启动由 --no-enable 决定。两个参数可一起使用。
# 查看服务 / 重启已加载的服务 / 停止并卸载
sudo launchctl print system/io.jocay.bolt
sudo launchctl kickstart -k system/io.jocay.bolt
sudo launchctl bootout system/io.jocay.bolt
# 停止后或使用 --no-start 安装后,手动加载并启动
sudo launchctl bootstrap system '/Library/Application Support/bolt/io.jocay.bolt.plist'
# 查看日志
sudo tail -f /var/log/bolt/stdout.log /var/log/bolt/stderr.log
macOS 服务的工作目录为 /var/root,PATH 包含 /opt/homebrew/bin 和 /opt/homebrew/sbin,不会加载个人 shell 配置。认证下载使用 BOLT_DL_TOKEN,HTTP 服务认证使用 --token,两者独立。
该附件交叉编译为 aarch64-apple-darwin,最低目标系统为 macOS 11.0,未进行 Mac 实机运行验证。SHA-256:
39274c7d1f965ae924ee51d4e9e4d8a260a84d083971cd50dc6ce645245cc4b8 bolt-darwin-arm64
常用安装参数(全部可选):
| 参数 | 含义 |
|---|---|
--http <addr> |
监听地址,默认 127.0.0.1:8080;对外用 0.0.0.0:8080 |
--token <t> |
Bearer 认证令牌(公网必填) |
--allow <a,b> / --deny <a,b> |
命令白/黑名单 |
--timeout-ms <n> |
默认命令超时 |
--file-root <d1,d2> |
文件功能允许访问的目录(配置 --allow 时必填,否则文件功能禁用) |
--max-upload <n> |
PUT /files 单次上传上限(默认 2G) |
--binary <路径或URL> |
跳过下载,用本地已拷贝的二进制(如 scp 过去的) |
--no-start / --no-enable |
只安装不启动 / 不设开机自启 |
注意:仓库是私有时,Release 附件下载需要认证 —— export BOLT_DL_TOKEN=你的令牌 后再跑脚本;若目标设备与开发机同网,直接 scp root@开发机:/usr/local/bin/bolt ./bolt 后用 --binary ./bolt 最省事。也可以把仓库设公开,附件即可匿名下载。
systemd 服务部署(手动)
仓库内 deploy/ 提供现成的部署文件:
sudo install -m 0755 target/release/bolt /usr/local/bin/bolt
sudo cp deploy/bolt.service /etc/systemd/system/
sudo cp deploy/bolt.env.example /etc/bolt.env # 按需修改(监听地址在 service 文件 ExecStart)
sudo systemctl daemon-reload
sudo systemctl enable --now bolt # 开机自启 + 立即启动
常用管理命令:
systemctl status bolt # 查看状态
systemctl restart bolt # 重启(改完配置后)
systemctl stop bolt # 停止
systemctl disable bolt # 取消开机自启
journalctl -u bolt -f # 实时查看日志
特性:崩溃自动重启(Restart=on-failure,2 秒间隔)、优雅停机(SIGTERM 时杀掉所有子进程树)、日志进 journald、LimitNOFILE=65536。默认监听 127.0.0.1:8080,对外暴露前务必在 /etc/bolt.env 设置 BOLT_TOKEN。