内容
# 钙通道
请参阅 [盐桥](https://github.com/mr-exitgames/salt-bridge) — Qubes 的姊妹项目。
> **⚠️ 实验性** — 该项目正在积极开发中,尚未经过正式审计。请勿将其用于安全敏感的系统。请自担风险。
**隔离Qubes虚拟机上的MCP服务器。**
钙通道允许你在专用的Qubes OS虚拟机中托管 [MCP](https://modelcontextprotocol.io/) 服务器,并从任何客户端虚拟机访问它们,只需使用qrexec和dom0策略。服务器虚拟机从不运行Claude,从不看到你的提示,从不相互接触。dom0策略精确控制哪些客户端可以访问哪些服务器 — 按服务器、按虚拟机。
```
┌─────────────────────────────────────────────────────────────────────┐
│ 工作原理 │
│ │
│ 客户端虚拟机 dom0 MCP虚拟机 │
│ ┌───────────┐ ┌────────────┐ ┌──────────────┐ │
│ │Claude代码│ │ qrexec │ │ 分发器 │ │
│ │ │────>│ 策略 │─────>│ (bash) │ │
│ │.mcp.json │ │ 检查 │ │ │ │ │
│ │指向 │ │ 允许/拒绝 │ │ MCP服务器 │ │
│ │qrexec- │ │ │ │ (标准输入) │ │
│ │客户端虚拟机 │<────│ │<─────│ (标准输出) │ │
│ └───────────┘ └────────────┘ └──────────────┘ │
│ ▲ ▲ │
│ │ JSON-RPC 超过 │ │
│ └────────── qrexec 标准输入/标准输出 ──────┘ │
│ │
│ 运行Claude 无代码 MCP服务器 │
│ + 管理 只有策略。 + 权限 │
│ MCP服务器。 + 机密 │
└─────────────────────────────────────────────────────────────────────┘
```
## 为什么
MCP服务器通常需要机密(API令牌、凭证)和广泛的工具访问权限。在与AI代理相同的虚拟机中运行它们意味着代理可以访问这些机密和机器上的其他所有工具。
钙通道通过分离角色来强制执行最小特权:
- **MCP服务器虚拟机** 持有机密并运行服务器。它们没有AI代理,没有Claude,没有网络访问客户端。
- **客户端虚拟机** 运行Claude代码(或任何MCP客户端)。它们通过qrexec连接到服务器 — 由dom0中介的进程间通信(IPC),而不是TCP/IP。
- **dom0策略** 是唯一的访问控制列表(ACL)。按服务器、按客户端的规则。除非明确授予,否则不允许任何操作。
MCP的标准输入/输出传输(JSON-RPC超过标准输入/标准输出)直接映射到qrexec的标准输入/标准输出管道。无需代理守护进程,无需协议转换 — 只需 `exec` 服务器并管道。
## 安全模型
- **MCP服务器被隔离** 在其自己的虚拟机中,拥有自己的机密。客户端虚拟机从未看到它们。
- **dom0 qrexec策略是ACL。** 按服务器、按客户端的规则。虚拟机只能访问策略明确允许的MCP服务器。
- **未打开网络路径。** 所有通信都是qrexec(由dom0中介的进程间通信),而不是TCP/IP。
- **每个连接都会启动一个新的MCP服务器实例。** 会话之间没有共享状态。
## 快速入门
### 1. 安装dom0服务
在dom0中(两步 - 直接管道会导致标准输入冲突):
```bash
qvm-run -p SOURCE_VM 'cat /path/to/calcium-channel/dom0-install.sh' > /tmp/cc-install.sh
bash /tmp/cc-install.sh SOURCE_VM [ADMIN_VM]
```
| 参数 | 描述 |
| --- | --- |
| `SOURCE_VM` | 包含钙通道存储库的虚拟机(文件从此处复制) |
| `ADMIN_VM` | 可以注册服务器和管理ACL的虚拟机(默认为`SOURCE_VM`)。仅当`SOURCE_VM`已经是用于钙通道管理的专用隔离qube时才省略此参数。**管理虚拟机应为隔离的qube** — 避免重用通用开发虚拟机。 |
### 2. 设置MCP服务器虚拟机
在dom0中运行(将安装程序 + 分发器与`tar`捆绑并将其管道传输到MCP虚拟机):
```bash
qvm-run --pass-io --no-filter-escape-chars SOURCE_VM \
'tar -cC /path/to/calcium-channel mcp-vm-install.sh mcp-vm/qubes-rpc/calciumchannel.Mcp' \
| qvm-run -p MCP_VM \
'd=$(mktemp -d) && tar -xC "$d" && bash "$d/mcp-vm-install.sh" && rm -rf "$d"'
```
或者,如果MCP虚拟机有存储库的副本,只需从那里运行 `bash mcp-vm-install.sh` 即可。
这只安装分发器和一个空注册表。
然后,通过编辑 `/rw/config/calcium-channel/registry.json` 在MCP虚拟机中添加服务器到注册表。每个条目将服务器名称映射到 `command` 和(可选)`args` 数组,以及可选的 `env_file`,其 `KEY=VALUE` 行在执行前被加载:
```json
{
"files": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env_file": "/rw/config/calcium-channel/env/github.env"
}
}
```
参见 [`mcp-vm/registry.json`](./mcp-vm/registry.json) 获取相同的示例。
### 3. 注册服务器和设置ACL
从管理虚拟机,向dom0告知哪些客户端可以访问哪些服务器:
```bash
echo '{"server":"files","mcp_vm":"mcp-vm","allow":["work-vm","dev-vm"]}' \
| qrexec-client-vm dom0 calciumchannel.McpRegister
```
或者使用管理MCP服务器(如果Claude代码在管理虚拟机中运行):
> 使用 `register_server` 工具,设置 `server="files"`、`mcp_vm="mcp-vm"`、`allow=["work-vm","dev-vm"]`。
### 4. 配置客户端虚拟机
在每个将连接Claude代码(或任何MCP客户端)的虚拟机中运行 `client-install.sh`:
```bash
./client-install.sh
```
这安装了一个轻量级的管理MCP服务器,并将正确的 `qrexec-client-vm` 条目写入每个检测到的客户端配置中:
- `~/.mcp.json` — 始终写入(Claude代码的项目约定)。
- `~/.claw/settings.json` — 如果存在 `~/.claw/`。
- `~/.gemini/settings.json` — 如果存在 `~/.gemini/`(gemini-cli)。
- `~/.qwen/settings.json` — 如果存在 `~/.qwen/`(qwen-code)。
其他设置文件中的密钥被保留;只有 `mcpServers` 被触及。传递显式路径(`./client-install.sh /path/to/config.json`)以写入单个文件。重启受影响的客户端以连接。
或者手动添加条目:
```json
{
"mcpServers": {
"files": {
"command": "qrexec-client-vm",
"args": ["mcp-vm", "calciumchannel.Mcp+files"]
}
}
}
```
## 架构
```
┌──────────────────────────────────────────────────────────────────────────┐
│ dom0(策略 + 服务) │
│ │
│ /etc/qubes/policy.d/30-calcium-channel.policy │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ calciumchannel.Mcp +files work-vm mcp-vm allow │ │
│ │ calciumchannel.Mcp +files @anyvm @anyvm deny │ │
│ │ calciumchannel.Mcp +github dev-vm mcp-vm allow │ │
│ │ calciumchannel.Mcp +github @anyvm @anyvm deny │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ 服务: │
│ McpList — 返回虚拟机可以访问的服务器列表 │
│ McpListAll — 转储完整的ACL矩阵(仅限管理员) │
│ McpRegister — 添加/更新每服务器策略规则(仅限管理员) │
│ McpRename — 设置显示别名(仅限管理员) │
│ McpUnregister — 删除规则或整个通道(仅限管理员) │
└──────────────────────────────────────────────────────────────────────────┘
│ │
│ qrexec │ qrexec
▼ ▼
┌────────────────────┐ ┌──────────────────────┐
│ 客户端虚拟机 │ │ MCP虚拟机 │
│ │ │ │
│ .mcp.json: │ qrexec + │ calciumchannel.Mcp │
│ "files" ──────────│── 标准输入/输出 ───>│ ├─ registry.json │
│ qrexec-client-vm│ │ │ "files" -> │
│ mcp-vm │<── 标准输入/输出 ────│ │ npx server-fs │
│ calciumchannel. │ │ └─ 执行命令 │
│ Mcp+files │ │ │
│ │ │ │
│ Claude代码 │ │ MCP服务器 + │
│ + 管理MCP服务器 │ │ 机密/权限 │
│ (可选) │ │ │
└────────────────────┘ └──────────────────────┘
```
### 组件
#### dom0
- **`calciumchannel.McpList`** — 发现服务。返回调用虚拟机可以访问的MCP服务器列表。每个虚拟机只看到其授权的服务器。
- **`calciumchannel.McpListAll`** — 管理员发现服务。返回每个注册服务器及其完整ACL矩阵(所有源虚拟机+操作)。仅可由管理员虚拟机调用。
- **`calciumchannel.McpRegister`** — 注册服务。添加每服务器策略规则。仅可由管理员虚拟机调用。
- **`calciumchannel.McpRename`** — 别名服务。设置或清除显示别名而无需触及ACL规则。仅可由管理员虚拟机调用。
- **`calciumchannel.McpUnregister`** — 删除服务。删除整个通道(所有规则+别名)或撤销单个源虚拟机的访问权限。仅可由管理员虚拟机调用。
- **策略文件** (`30-calcium-channel.policy`) — 具有 `+argument` 后缀的每服务器ACL规则,用于粒度控制。
- **元数据文件** (`30-calcium-channel-meta.json`) — 显示别名,存储在策略旁边。
#### MCP服务器虚拟机
- **`calciumchannel.Mcp`** — 分发器。读取 `QREXEC_SERVICE_ARGUMENT`,在注册表中查找服务器名称,源自其 `env_file`(如果有),并执行配置的命令。一个纯bash脚本 — 除了Python 3(用于JSON解析)之外,没有依赖项。
- **`registry.json`** — 将服务器名称映射到 `{command, args, env_file?}` 条目。位于 `/rw/config/calcium-channel/`(在AppVM重启后持续存在)。
#### 客户端虚拟机
- **`client-install.sh`** — 安装管理MCP服务器,查询 `McpList`,并同步每个检测到的客户端配置(`~/.mcp.json` 加上 `~/.claw/settings.json`、`~/.gemini/settings.json`、`~/.qwen/settings.json` 当这些目录存在时)。
- **`calcium-channel-mgmt.py`** — 管理MCP服务器(可选)。将钙通道管理公开为MCP工具,供代理工作流使用。
## 管理MCP服务器
`client-install.sh` 安装一个本地管理MCP服务器,该服务器将钙通道操作作为工具公开。这是一个可选操作 — 您可以通过上述shell命令管理所有内容。
| 工具 | 描述 | 授权 |
| --- | --- | --- |
| `list_servers` | 列出此虚拟机可以访问的MCP服务器 | 任何虚拟机 |
| `list_all_servers` | 转储每个注册服务器及其完整ACL矩阵 | 仅限管理员虚拟机(由dom0强制执行) |
| `register_server` | 注册服务器并设置ACL | 仅限管理员虚拟机(由dom0强制执行) |
| `rename_server` | 设置或清除显示别名 | 仅限管理员虚拟机(由dom0强制执行) |
| `unregister_server` | 删除整个通道,或撤销一个源虚拟机的访问权限 | 仅限管理员虚拟机(由dom0强制执行) |
| `refresh_mcps` | 重新同步每个检测到的客户端配置(或传递路径) | 任何虚拟机 |
dom0策略强制执行 `McpRegister`/`McpRename` 访问权限,因此 `register_server` 和 `rename_server` 对于非管理员虚拟机简单地失败。相同的管理服务器在客户端虚拟机(只读)和管理员虚拟机(完全管理)中工作相同。
**别名**:您可以为任何服务器设置显示别名(例如,`rename_server("signal", "metatron")`)。别名成为 `.mcp.json` 中的键和Claude代码中的工具命名空间前缀。调用 `refresh_mcps` 然后重启Claude代码。
## 管理CLI(`cc-admin`)
`cc-admin` 是围绕dom0 qrexec服务的标准库Python包装器,用于在没有AI代理的情况下进行手动管理。从管理员虚拟机运行它 — 相同的dom0策略控制管理MCP服务器的策略也控制此CLI。
伴侣脚本 [`cc-admin-dom0`](./cc-admin-dom0) 提供了相同的子命令,但直接调用已安装的qrexec处理程序(无需qrexec往返)。在dom0本身管理规则时使用它;在管理员虚拟机上使用 `cc-admin`。
| 子命令 | 描述 |
| --- | --- |
| `list [--json]` | 虚拟机可以访问的服务器。 |
| `list-all [--json]` | 完整的ACL矩阵。仅限管理员。 |
| `register SERVER MCP_VM VM [VM ...] [--alias ALIAS]` | 用给定的虚拟机替换 `SERVER` 的ACL。 |
| `grant SERVER SOURCE_VM` | 将一个虚拟机添加到 `SERVER` 的现有允许列表中。 |
| `revoke SERVER SOURCE_VM` | 删除一个允许规则。 |
| `unregister SERVER` | 删除 `SERVER` 的所有规则(和别名)。 |
| `rename SERVER [ALIAS]` | 设置显示别名。省略 `ALIAS` 以清除它。 |
### 工作示例
假设 `vault-vm` 是一个MCP服务器虚拟机,暴露了两个MCP服务(`notes` 和 `calendar`),并且您希望授予 `work-vm` 访问这两个服务的权限,然后将 `research-vm` 添加到仅 `notes`。
**1. 在 `vault-vm` 上** — 在 `/rw/config/calcium-channel/registry.json` 中编写注册表(一次性):
```json
{
"notes": {
"command": "npx",
"args": ["-y", "some-notes-mcp"]
},
"calendar": {
"command": "npx",
"args": ["-y", "some-calendar-mcp"]
}
}
```
每个顶级键都是服务名称。`command` + `args` 是分发器在客户端连接时将执行的二进制文件和argv。添加 `"env_file": "/path/to/file.env"` 以在执行前加载机密。
**2. 从管理员虚拟机** — 注册ACL。位置参数是 `SERVER MCP_VM CLIENT_VM [CLIENT_VM ...]`:服务名称(必须与MCP虚拟机上的注册表键匹配),托管它的虚拟机,以及一个或多个客户端虚拟机(其中运行Claude代码或其他MCP客户端)以授予访问权限:
```bash
# 服务器 MCP虚拟机 客户端虚拟机
./cc-admin register notes vault-vm work-vm
./cc-admin register calendar vault-vm work-vm research-vm
```
传递多个客户端虚拟机以授予它们所有访问权限(如下面的 `calendar`)。
**3. 检验:**
```bash
./cc-admin list-all
# notes -> vault-vm
# allow work-vm -> vault-vm
# deny @anyvm -> @anyvm
# calendar -> vault-vm
# allow work-vm -> vault-vm
# allow research-vm -> vault-vm
# deny @anyvm -> @anyvm
```
**4. 将另一个客户端添加到 `notes`** — `grant` 保留现有的允许列表(和别名):
```bash
./cc-admin grant notes research-vm
```
**5. 设置别名,然后撤销或删除:**
```bash
./cc-admin rename notes scratchpad # 别名成为 .mcp.json 中的键
./cc-admin revoke notes research-vm # 删除 research-vm 的访问权限
./cc-admin unregister calendar # 删除整个通道
```
**6. 在每个客户端虚拟机上** — 同步 `.mcp.json` 并重启MCP客户端:
```bash
./client-install.sh
```
## 文件结构
```
calcium-channel/
├── dom0-install.sh # dom0 安装程序(两步)
├── dom0-setup/
│ ├── policy.d/
│ │ └── 30-calcium-channel.policy # ACL 策略模板
│ └── qubes-rpc/
│ ├── calciumchannel.McpList # 发现服务
│ ├── calciumchannel.McpListAll # 管理员发现(完整的ACL矩阵)
│ ├── calciumchannel.McpRegister # 注册服务(仅限管理员)
│ ├── calciumchannel.McpRename # 别名服务(仅限管理员)
│ └── calciumchannel.McpUnregister # 删除服务(仅限管理员)
├── mcp-vm-install.sh # MCP虚拟机安装程序(仅限分发器)
├── mcp-vm/
│ ├── qubes-rpc/
│ │ └── calciumchannel.Mcp # MCP服务器分发器
│ └── registry.json # 示例注册表
├── calcium-channel-mgmt.py # 管理MCP服务器(源代码)
├── cc-admin # 管理CLI(在管理员虚拟机上运行)
├── cc-admin-dom0 # 管理CLI(在dom0上直接运行)
└── client-install.sh # 客户端设置:管理服务器 + .mcp.json同步
```
## 更新
在进行更改后:
- **dom0服务或策略** — 重新运行两步的dom0安装程序
- **MCP虚拟机分发器** — 在目标虚拟机上重新运行 `mcp-vm-install.sh`
- **客户端配置** — 在客户端虚拟机上重新运行 `client-install.sh`,然后重启Claude代码
## 致谢
由Claude与[@mr-exitgames](https://github.com/mr-exitgames)合作构建。
## 许可
MIT
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器