内容
<!--
SPDX-FileCopyrightText: 2026 Peter Lemenkov <lemenkov@gmail.com>
SPDX-License-Identifier: Apache-2.0
-->
# MCP 沙盒
用于隔离的科学脚本执行的 MCP 服务器。在可丢弃的容器中运行 R、Python、GMT、GRASS GIS、LaTeX、Octave、Julia 等 — 完全无状态,无主机文件系统访问。
## 工具
| 工具 | 描述 |
| --------------- | ---------------------------------------- |
| `run_script` | 在隔离的沙盒容器中执行脚本 |
| `list_runtimes` | 列出可用的科学运行时 |
## 支持的运行时
| 运行时 | 工具 |
| --------- | ----------------------------------------------------------------------- |
| `r` | R + ggplot2, dplyr, tidyr, jsonlite |
| `python` | Python 3 + numpy, matplotlib, scipy, pandas, sympy, scikit-learn, obspy |
| `gmt` | 通用绘图工具 |
| `grass` | GRASS GIS — 无头;每次运行都获得一个临时位置 |
| `latex` | pdflatex (texlive) |
| `octave` | GNU Octave |
| `julia` | Julia |
| `gnuplot` | Gnuplot |
| `bash` | Bash 脚本 |
## 设计
- 每次运行都启动一个新的容器 — **完全无状态,不重复使用**
- 容器在执行后删除 (`--rm`)
- 启用网络访问
- 内存限制:2GB,CPU 限制:2 个核心
- 输入文件注入到 `/sandbox/input/` (base64)
- 输出文件从 `/sandbox/output/` 收集 (base64)
## 安装
沙盒以 **无根方式,作为专用的 `sandbox` 用户** 运行容器。镜像和运行服务必须位于该用户的 podman 存储中。这是唯一重要的事情 — 请参阅故障排除。
### 1. 创建服务用户
```
useradd -r -m -d /var/lib/mcp-sandbox -s /bin/bash sandbox
echo "sandbox:100000:65536" >> /etc/subuid
echo "sandbox:100000:65536" >> /etc/subgid
# 无根 podman 需要在启动时存在运行时目录(/run/user/<uid>):
loginctl enable-linger sandbox
```
### 2. 构建镜像 — *作为 `sandbox` 用户*
构建到 `sandbox` 用户的无根存储中。**不是** 您的登录用户,**不是** root 用户 — 服务器只读取 `sandbox` 的存储:
```
sudo -u sandbox -H podman build -t mcp-sandbox:latest -f Containerfile .
```
已经在其他地方构建了镜像?不要重新构建 — 跨存储边界传输:
```
podman save mcp-sandbox:latest | sudo -u sandbox -H podman load
```
### 3. 安装服务器
```
python3 -m venv venv
venv/bin/pip install -e .
```
## 作为服务运行
以 `sandbox` 用户身份运行服务器,以便其读取该用户的镜像存储。最小单元(调整检出路径和入口点到您的安装):
```
# /etc/systemd/system/mcp-sandbox.service
[Unit]
Description=mcp-sandbox MCP 服务器
After=network.target
[Service]
User=sandbox
ExecStart=/var/lib/mcp-sandbox/mcp-sandbox/venv/bin/mcp-sandbox
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
## 配置
```
HOST=127.0.0.1
PORT=8815
SANDBOX_IMAGE=mcp-sandbox:latest
DEFAULT_TIMEOUT=60
MAX_TIMEOUT=300
```
## 故障排除
**重建了镜像,但服务器仍在运行旧镜像?**
您很可能构建到了错误的 podman 存储中。容器以 `sandbox` 用户身份无根运行,该用户在其自己的存储下读取 `/var/lib/mcp-sandbox/.local/share/containers`。作为您的登录用户或 root 用户构建的镜像位于服务器从未读取的不同存储中 — 因此构建“成功”但没有任何更改。
确认服务实际看到的内容,并重建/加载到该存储中:
```
sudo -u sandbox -H podman images mcp-sandbox
sudo -u sandbox -H podman build -t mcp-sandbox:latest -f Containerfile .
# 或:podman save mcp-sandbox:latest | sudo -u sandbox -H podman load
```
之后不需要重启 MCP — 每次运行都是一个全新的 `--rm` 容器,该容器在启动时从 `sandbox` 存储中解析 `mcp-sandbox:latest`。只有在更改服务器代码或 `RUNTIMES` 时才重启服务。
## 许可证
Apache-2.0