克莱布罗克
clibroker 是一个策略驱动的代理程序,用于将本地CLI工具包装在安全的HTTP API和MCP服务器后面。
它有两个表面:
- 包装并执行批准的CLI命令的服务器
- 与该服务器通信、获取令牌范围的配置并转发执行请求的客户端
它专为希望LLM或其他客户端使用CLI工具的情况而设计,但仅限于严格定义的allowlist。
它的作用
- 作为代理服务器运行
clibroker - 向直接客户发货
clibroker-client - 暴露单个REST端点:
POST /execute - 公开令牌范围的客户端发现终结点:
GET /client-config - 公开从允许的策略规则派生的MCP工具
- 通过经过身份验证的文件共享公开按工具配置的主机目录
- 强制默认拒绝策略评估
- 执行前验证标志和位置参数
- 按令牌应用RBAC
- 在不调用shell的情况下执行子流程
- 隔离子流程环境,除非配置了显式环境变量
- 限制输出并强制超时
- 发出结构化JSON审核日志
安全模型
- 无shell:命令执行时使用
asyncio.create_subprocess_exec() - 默认情况下拒绝:如果没有匹配的允许规则,则拒绝请求
- 拒绝优先级:拒绝规则覆盖允许,包括子命令路径
- RBAC:每个承载令牌只允许调用特定的规则ID
- MCP隔离:每个令牌都有自己的MCP服务器视图,只有授权的工具可见
- 秘密安全MCP URL:MCP/SSE端点使用
SHA-256(token)[:16]用蛞蝓代替原始代币 - 文件共享:主机路径保持在服务器端,URL需要承载身份验证,每个路径都包含在配置的共享根目录下
需求
- python
>=3.11
安装
更喜欢 uv 用于Python环境和包安装。
对于系统范围的CLI安装,首选 uv tool.
系统范围CLI安装
来自公共GitHub存储库:
仅服务器命令:
uv tool install 'git+https://github.com/alanzchen/clibroker'服务器+客户端命令:
uv tool install 'clibroker[client] @ git+https://github.com/alanzchen/clibroker'这将已发布的CLI应用程序安装到隔离的工具环境中,并公开:
clibrokerclibroker-client
本地项目安装
对于本地开发、可编辑安装或从签出工作,请使用 uv venv + uv pip.
仅限服务器:
uv venv .venv
uv pip install --python .venv/bin/python -e .服务器+客户端支持:
uv venv .venv
uv pip install --python .venv/bin/python -e .[client]发展:
uv venv .venv
uv pip install --python .venv/bin/python -e .[dev]已安装的命令:
clibroker:启动代理服务器clibroker-client:连接到代理服务器
配置
服务器和客户端使用单独的YAML配置。
服务器配置
从...开始 config.example.yaml:
cp config.example.yaml config.yaml主要部分:
server.bind:要侦听的主机和端口server.auth.tokens:承载令牌及其允许的规则IDtools..executable:包装CLI的绝对路径tools..default_args:始终位于命令的前面tools..env:显式子流程环境变量tools..file_sharing:暴露用于身份验证文件访问的主机目录tools..rules:允许/拒绝策略规则
令牌配置示例:
server:
auth:
tokens:
- name: reader
value: "env:CLIBROKER_TOKEN_READER"
allow_rules:
- list_messages令牌值可以是文字字符串或 env:VAR_NAME 参考文献
文件共享配置示例:
tools:
himalaya:
working_dir: /srv/clibroker/himalaya
file_sharing:
expose_working_dir: true
max_file_bytes: 1048576
shares:
- name: attachments
path: /srv/clibroker/attachments
access: read_write文件共享行为:
- 绝对的
working_dir值作为名为的只读共享公开working_dir默认情况下 - 明确的股份支持
access: read或access: read_write - 当令牌至少有一个工具的允许规则时,它可以访问该工具的文件共享
- 主机路径永远不会通过暴露
/client-config、MCP工具结果或文件URL - 文件路径必须位于共享根目录下;绝对路径,
..,反斜杠、NUL字节和符号链接转义被拒绝
客户配置
从...开始 client.example.yaml:
cp client.example.yaml client.yaml例子:
default_backend: local
backends:
local:
type: http
base_url: http://127.0.0.1:8080
token: env:CLIBROKER_TOKEN_READER
timeout_s: 30.0
verify_tls: true
review:
type: http
base_url: http://127.0.0.1:8081
token: env:CLIBROKER_TOKEN_REVIEW
timeout_s: 30.0
verify_tls: true当前后端类型:
http:直接HTTPS/HTTP连接到代理服务器
客户端令牌也支持 env:VAR_NAME 参考文献
跑步
服务器
.venv/bin/clibroker --config config.yaml重新加载的开发模式:
.venv/bin/clibroker --config config.yaml --reload客户
列出配置令牌可见的工具:
.venv/bin/clibroker-client --config client.yaml tools客户端还支持按以下顺序进行配置发现:
--configCLIBROKER_CLIENT_CONFIG~/.openclaw/clibroker-client.yaml${XDG_CONFIG_HOME:-~/.config}/clibroker/client.yaml
因此,如果你的配置已经在这些默认位置之一,你可以简单地运行:
.venv/bin/clibroker-client tools使用以下命令选择非默认服务器后端 --backend:
.venv/bin/clibroker-client --backend review tools如果你不通过 --backend,客户端的行为如下:
- 如果只配置了一个后端,则使用该后端
- 如果配置了多个后端并且工具名称恰好存在于一个后端中,
execute自动选择该后端 - 如果多个后端中存在相同的工具名称,
execute失败,告诉使用重新运行--backend
通过多个配置的后端, tools --json 返回一个聚合视图,其中包括 tool_index 显示哪些后端暴露了每个工具以及工具名称是否冲突。
将执行请求转发到服务器:
.venv/bin/clibroker-client --config client.yaml execute himalaya -- message read 42显示已编辑机密的选定本地后端配置:
.venv/bin/clibroker-client --config client.yaml config show列出所有已配置的后端:
.venv/bin/clibroker-client config listHTTP API
健康检查
curl http://127.0.0.1:8080/health答复:
{"status":"ok","version":"0.1.0"}执行命令
curl -X POST http://127.0.0.1:8080/execute \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"tool": "himalaya",
"argv": ["message", "read", "42"]
}'请求正文:
{
"tool": "himalaya",
"argv": ["message", "move", "42", "Archive"]
}响应形状:
{
"ok": true,
"exit_code": 0,
"stdout": {},
"stderr": "",
"duration_ms": 12.34,
"matched_rule": "move_message",
"timed_out": false
}笔记:
argv必须至少包含一个元素stdout尽可能解析为JSON;否则,它将作为字符串返回- 策略拒绝和验证失败返回
200随着ok: false - 身份验证失败返回
401或403
文件共享
配置的共享在经过身份验证的情况下可用 /files 网址:
curl http://127.0.0.1:8080/files/himalaya/attachments/report.pdf \
-H 'Authorization: Bearer YOUR_TOKEN' \
-o report.pdf目录请求返回JSON列表:
curl http://127.0.0.1:8080/files/himalaya/attachments \
-H 'Authorization: Bearer YOUR_TOKEN'文件共享备注:
- `GET /files///
` 需要标准承载标头
- 文件作为下载返回;目录返回JSON条目
- 目录列表包括
truncated和max_entries达到列表上限时的字段 - 生成的文件URL是相对的,不包含机密
- 读写共享可通过MCP文件工具写入,而不是通过HTTP API写入
客户端发现
代理客户端从服务器获取令牌范围的发现文档。
curl http://127.0.0.1:8080/client-config \
-H 'Authorization: Bearer YOUR_TOKEN'示例响应:
{
"version": "0.1.0",
"client_name": "reader",
"execute_url": "/execute",
"token_info_url": "/token-info",
"mcp_url": "/mcp/0123456789abcdef/",
"sse_url": "/sse/0123456789abcdef/",
"tools": [
{
"name": "himalaya",
"rules": [
{
"id": "list_messages",
"command": ["message", "list"],
"flags": ["--account", "--folder", "--page"],
"standalone_flags": ["--unread"],
"positionals": []
}
],
"file_shares": [
{
"name": "working_dir",
"access": "read",
"url": "/files/himalaya/working_dir"
},
{
"name": "attachments",
"access": "read_write",
"url": "/files/himalaya/attachments"
}
]
}
]
}此响应是令牌范围的:
- 只返回经过身份验证的令牌的允许规则
- 仅返回由经过身份验证的令牌授权的工具的文件共享
- 拒绝规则被省略
- 未返回原始服务器配置和机密
主控程序
clibroker 公开了可流式传输的HTTP MCP和SSE MCP传输。
终点:
POST /mcp//GET /sse//
哪里:
slug = SHA-256(token)[:16]
要发现你的蛞蝓:
curl http://127.0.0.1:8080/token-info \
-H 'Authorization: Bearer YOUR_TOKEN'示例响应:
{
"name": "reader",
"slug": "0123456789abcdef",
"mcp_url": "/mcp/0123456789abcdef/",
"sse_url": "/sse/0123456789abcdef/",
"allow_rules": ["list_messages", "read_message"]
}MCP行为:
- 每个令牌只看到其允许的规则ID的工具
- 拒绝规则未出现在MCP中
tools/list - MCP工具调用在执行之前仍然通过策略引擎
- 文件共享显示为
__files_*授权工具的MCP工具 - 读写共享支持MCP创建、写入、移动和删除操作
客户端CLI
这 clibroker-client 命令不执行本地子进程。它使用配置的后端与服务器通信,并让服务器保持安全边界。
当前命令:
tools:获取并打印令牌范围的发现文档execute --:向服务器转发执行请求config show:显示已编辑机密的选定本地客户端后端配置
示例:
.venv/bin/clibroker-client --config client.yaml tools --json
.venv/bin/clibroker-client --config client.yaml execute himalaya -- message list --account work
.venv/bin/clibroker-client --config client.yaml config show政策规则
每条规则包括:
id:唯一规则IDcommand:命令路径,例如['message', 'read']effect:allow或denyflags.allowed:允许需要值的标志flags.standalone:允许不取值的布尔标志inject_args:固定了始终为规则插入的服务器端参数positionals:位置参数验证器
允许规则示例:
- id: read_message
command: ["message", "read"]
effect: allow
inject_args: ["--preview"]
flags:
allowed: ["--account", "--folder"]
positionals:
- name: id
pattern: "^[0-9]+$"可变尾规则示例:
- id: search_messages
command: ["envelope", "list"]
effect: allow
flags:
allowed: ["--account", "--folder", "--page", "--page-size"]
positionals:
- name: query
pattern: "^[A-Za-z0-9_@.+:-]+$"
variadic: true拒绝规则示例:
- id: deny_delete
command: ["message", "delete"]
effect: deny重要验证规则:
command必须至少包含一个元素- 未知标志被拒绝
--flag=value被支持--标志着选项的结束flags.allowed条目必须使用一个值参数flags.standalone条目不得使用值flags.allowed和flags.standalone必须不相交- 只能标记最终位置
variadic: true - 可变位置分别验证尾部的每个标记
- 拒绝规则级联到子命令路径
笔记:
inject_args由服务器控制,在中不作为客户端提供的参数公开/client-config或MCP工具模式- 执行顺序为
executable + default_args + command + inject_args + validated user args
测试
运行所有测试:
.venv/bin/python -m pytest tests -v当前套件涵盖了REST、MCP、文件共享、策略评估、子流程强化和安全修复。
项目布局
src/clibroker/
app.py FastAPI app factory
auth.py Bearer auth and RBAC
client/ Client package and CLI
config.py YAML/Pydantic config models
file_sharing.py Safe per-tool host directory sharing
mcp_server.py MCP server and tool registration
middleware.py Request timeout middleware
models.py REST request/response models
policy.py Command matching and argv validation
routes.py /execute route
runner.py Hardened subprocess execution
audit.py Structured JSON audit logging已知限制
- 还没有利率限制
- 应用程序停止时还没有优雅的子进程关闭
- 正则表达式模式直接来自配置,因此模式质量很重要
- 客户端当前仅支持直接HTTP后端
- 客户端CLI没有专用的文件命令;使用MCP文件工具或经过身份验证
/files/...网址
