内容
# OWUI-Codebox-MCP
> 通过MCP为OpenWebUI提供可 disposable 的代码沙盒。每个语言一个工具,容器隔离,无状态。
## 🚀 设置
需要 **Docker**(守护进程运行中)或 **Podman**。
```bash
uv sync
cp .env.example .env
```
在 `.env` 中设置重要值:
- `JWT_SECRET` → OpenWebUI的 `WEBUI_SECRET_KEY`
- `JWT_ALGORITHM` → OpenWebUI JWT的签名算法;默认为 `HS256`,除非你在OpenWebUI侧更改了它
- `OWUI_BASE_URL` → 从本服务器可访问的OpenWebUI URL,例如 `http://localhost:3000`
- `OWUI_VERIFY_TLS` → 仅在自签名或纯HTTP实验室设置中设置为 `false`
- `CONTAINER_BACKEND` → `docker` 或 `podman`
特定于语言的设置(沙盒镜像、包索引等)针对每种语言在 [语言](#-语言) 下涵盖。
## ▶️ 运行
```bash
uv run python main.py
```
服务器监听 `0.0.0.0:8000`。将OpenWebUI的MCP/tools配置指向 `http://<host>:8000/mcp`。请求必须携带由 `JWT_SECRET` 签名的JWT,并包含OpenWebUI用户的 `id` 声称。
## 🐳 Docker(可选)
服务器在容器中运行良好,但需要访问容器运行时来启动沙盒。最简单的方法是Docker-out-of-Docker — 挂载主机套接字:
```bash
docker build -t owui-codebox-mcp .
docker run -d --restart unless-stopped \
-p 8000:8000 \
-v /var/run/docker.sock:/var/run/docker.sock \
--env-file .env \
owui-codebox-mcp
```
从您的 `.env` 读取配置,通过 `--env-file`;要公开不同的端口,请更改映射,例如 `-p 9000:8000`。预构建的镜像在 `main` 分支和版本标签上推送到 **ghcr.io**。
## 🧩 语言
每种语言都遵循相同的模式,因此新的语言(Go、Rust等)可以以相同的方式接入:
| 组件 | 约定 | Python示例 |
| --- | --- | --- |
| MCP工具 | `tools/<lang>.py` | `tools/python.py` |
| 沙盒镜像 | `.env`中的 `SANDBOX_IMAGE_<LANG>` | `SANDBOX_IMAGE_PYTHON` |
| 预构建镜像(可选) | `sandbox.<lang>.Dockerfile` | `sandbox.python.Dockerfile` |
所有语言的执行语义相同:每个调用都获得一个全新的、加固的容器,该容器在调用完成后立即被删除(参见 [沙盒和限制](#-沙盒和限制))。
目前支持: **Python**。
### 🐍 Python
**工具**
- `run_python` 在全新的沙盒中执行完整的Python脚本。它可以安装请求的包、读取附加的OpenWebUI文件(每个文件都放在选定的沙盒路径下),并上传生成的输出文件。
- `list_python_packages` 列出已配置的沙盒镜像中已存在的包,以便模型避免重新安装已有的包。
**沙盒镜像**
默认使用官方 `python:3.13-trixie` 镜像 — 在第一次运行之前拉取它:
```bash
docker pull python:3.13-trixie
```
对于更快的沙盒,`sandbox.python.Dockerfile` 使用常见的代码解释器包(numpy、pandas、matplotlib、scikit-learn、openpyxl、pymupdf、weasyprint、opencv等)和HTML→PDF的字体进行扩展:
```bash
docker build -f sandbox.python.Dockerfile -t owui-codebox-sandbox .
```
然后在 `.env` 中设置:
```env
SANDBOX_IMAGE_PYTHON=owui-codebox-sandbox
```
**私有包索引**
在构建预构建镜像时,将pip的设置作为构建参数传递 — 它们被烘焙到镜像中作为环境变量,在运行时也适用于安装:
```bash
docker build -f sandbox.python.Dockerfile \
--build-arg PIP_INDEX_URL=https://nexus.example.com/repository/pypi/simple \
--build-arg PIP_TRUSTED_HOST=nexus.example.com \
-t owui-codebox-sandbox .
```
## 🔒 沙盒和限制
- 容器是隔离边界。每个沙盒默认运行加固:所有Linux功能都被删除(仅保留 `DAC_OVERRIDE`,这是llm-sandbox需要的),`no-new-privileges`,`pids` 限制(fork-bomb防护),无交换(因此 `SANDBOX_MAX_MEMORY` 是硬上限)和CPU上限(`SANDBOX_MAX_CPUS`,例如 `1` = 一个核心)。根据需要进一步加强(锁定沙盒镜像、gVisor等)。
- **已知漏洞 — 网络**:沙盒具有完全的出站网络访问(它需要用于包安装),因此执行的代码可以访问互联网和您的局域网 — 包括OpenWebUI本身。如果在您的环境中这很重要,请使用专用Docker网络或防火墙规则限制出站流量。
- **已知漏洞 — 磁盘**:没有每个沙盒的磁盘配额。Docker的 `storage_opt size` 需要overlay2在xfs上使用 `pquota`;在其他底层文件系统(ext4、btrfs)上,运行可以在 `/var/lib/docker` 下填充磁盘,直到超时将容器关闭。请监控可用空间,或将Docker的数据根移动到xfs以获得真正的配额。
- 每个调用都会支付容器启动(以及第一次镜像拉取)的费用。
- `SANDBOX_EXEC_TIMEOUT`(秒)限制单个调用;超时后容器将被关闭,调用将返回错误。
- `SANDBOX_MAX_FILE_SIZE`(字节)限制OpenWebUI和沙盒之间传输的每个输入和输出文件;较大的文件将被错误拒绝。
- `MAX_CONCURRENT_SANDBOXES` 限制整个服务器的并发沙盒容器,`MAX_CONCURRENT_SANDBOXES_PER_USER` 限制每个OpenWebUI用户的并发沙盒容器;超过上限的调用将被容量错误拒绝。
- 请求按用户进行速率限制(令牌桶:`RATE_LIMIT_RPS` 持续,`RATE_LIMIT_BURST` 突发),以JWT的 `id` 声称作为键 — 主要用于抑制重试风暴在容量时。