内容
# Linux MCP 服务器
一个轻量级、可一次性使用的 Ubuntu 24.04 容器,用作 Linux MCP(模型上下文协议)服务器的**测试目标**。它在几秒钟内启动,携带了一组小型且众所周知的命令行工具,旨在频繁地在开发和 CI 中创建和销毁 - 它**不是**生产运行时。
## 目录
- [概述](#概述)
- [已安装内容](#已安装内容)
- [先决条件](#先决条件)
- [存储库布局](#存储库布局)
- [构建镜像](#构建镜像)
- [启动容器](#启动容器)
- [进入容器](#进入容器)
- [停止容器](#停止容器)
- [重启容器](#重启容器)
- [挂载卷](#挂载卷)
- [内置示例 MCP 服务器](#内置示例-mcp服务器)
- [更新已安装的软件包](#更新已安装的软件包)
- [可选 Docker CLI](#可选docker-CLI)
- [故障排除](#故障排除)
- [清理 Docker 资源](#清理docker资源)
- [验证检查清单](#验证检查清单)
- [设计说明](#设计说明)
## 概述
MCP 客户端/服务器需要自动化 Linux 系统,因此需要一个现实但安全的目标。此镜像提供了一个最小的 Ubuntu 基础、一个非 root 用户 `dev`、一个挂载的 `/workspace`,以及足够的 shell/network/dev 工具来执行典型的 MCP 工具调用(运行命令、读取/写入文件、检查进程、使用 git 等),而无需拖入完整的桌面或服务器堆栈。
容器的唯一任务是**保持活动** (`sleep infinity`),以便 MCP 客户端可以随时使用 `docker exec` 附加。
一个小的示例 MCP 服务器被内置到镜像中(参见 [内置示例 MCP 服务器](#内置示例-mcp服务器)),因此在容器启动时,有一个真实的东西可以连接,而无需任何手动设置。
## 已安装内容
| 类别 | 软件包 |
|---|---|
| Shell & 核心工具 | `bash`, `coreutils`, `findutils`, `grep`, `sed`, `gawk`, `procps`, `psmisc`, `util-linux`, `file`, `which`, `less`, `nano`, `vim-tiny` |
| 网络 | `curl`, `wget`, `iproute2`, `iputils-ping`, `dnsutils`, `net-tools`, `openssh-client` |
| 开发 | `git`, `python3`, `python3-pip`, `python3-venv`, `make`, `build-essential` |
| 系统实用程序 | `jq`, `tree`, `lsof`, `zip`, `unzip`, `tar`, `gzip`, `bzip2`, `xz-utils` |
| TLS 支持 | `ca-certificates`(需要 `curl`/`wget`/`git` 通过 HTTPS - 因而添加了此项) |
故意**不**安装:systemd、snap、桌面软件包、Web 服务器、数据库、PHP、Node.js、Java 或 Docker 引擎。Docker *CLI* 作为可选构建参数提供 - 请参见 [可选 Docker CLI](#可选docker-CLI)。
除了 apt 软件包外,镜像还内置了一个 Python 依赖项 - [`mcp[cli]`](https://pypi.org/project/mcp/) - 安装到其自己的虚拟环境中,位于 `/opt/mcp-server/venv`,用于捆绑的示例服务器。有关更多信息,请参见 [内置示例 MCP 服务器](#内置示例-mcp服务器)。
## 先决条件
- Docker 引擎 24+(或 Docker Desktop)
- Docker Compose v2(`docker compose`,与最近的 Docker 安装捆绑)
- `make`(可选,仅在您使用提供的 `Makefile` 时需要)
## 存储库布局
```
.
├── Dockerfile # 镜像定义
├── docker-compose.yml # Compose 服务定义
├── .dockerignore # 从构建上下文中排除的文件
├── .gitignore
├── Makefile # 常用命令的快捷方式
├── README.md
├── mcp-server/ # 示例 MCP 服务器,在构建时内置到镜像中
│ ├── server.py
│ └── requirements.txt
└── workspace/ # 绑定到容器中的 /workspace
```
## 构建镜像
```bash
docker compose build
```
或,不使用 Compose:
```bash
docker build -t linux-mcp-test:latest .
```
要固定或更改 Ubuntu 基础版本:
```bash
docker compose build --build-arg UBUNTU_VERSION=24.04
```
## 启动容器
```bash
docker compose up -d
```
这会在后台启动容器,名为 `linux-mcp-test`,分配了一个 TTY,stdin 保持打开,自动重启(`unless-stopped`)如果它崩溃或主机重启 - 直到您显式停止它。
检查它是否正在运行:
```bash
docker ps --filter name=linux-mcp-test
docker logs linux-mcp-test
```
## 进入容器
```bash
docker exec -it linux-mcp-test bash
```
您将以非 root 用户 `dev` 的身份登录到 `/workspace`。这也是 MCP 服务器用于对容器运行命令的入口点。
## 停止容器
```bash
docker compose down
```
这会停止并删除容器(镜像和主机上的 `./workspace` 内容保持不变)。要停止但不删除它:
```bash
docker stop linux-mcp-test
```
## 重启容器
```bash
docker compose restart
```
或,通过 Makefile:
```bash
make restart
```
## 挂载卷
主机上的 `./workspace` 绑定到容器中的 `/workspace`,由 `dev` 用户(UID/GID 1000)拥有。任何放置在任一位置的内容都在两个位置可见 - 使用它来传递文件到容器中或将工件拉回。因为它是一个绑定挂载,其内容在 `docker compose down` / `up` 周期中持续存在;它们只会在您自己删除主机上的 `workspace/` 文件夹时丢失。
## 内置示例 MCP 服务器
镜像中内置了一个小的示例 MCP 服务器,位于 `./mcp-server/`(参见 [mcp-server/README.md](mcp-server/README.md) 以了解它公开的内容),因此在 `docker compose up` 后立即有一个真实的东西可以测试 - 无需额外的手动复制或 `pip install` 步骤。
在构建时,`server.py` 和 `requirements.txt` 被复制到 `/opt/mcp-server/` 并安装到它们自己的虚拟环境中(与系统 Python 分开,并绕过 Ubuntu 24.04 对全局 `pip install` 的 PEP 668 限制)。位于 `/usr/local/bin/mcp-linux-example` 的一行包装器运行它,并且 `WORKSPACE_ROOT` 自动设置为 `/workspace`,因此服务器的文件/命令工具在上述绑定挂载的目录上操作。
**使用 MCP Inspector 试用:**
```bash
npx -y @modelcontextprotocol/inspector \
docker exec -i linux-mcp-test mcp-linux-example
```
**将 MCP 客户端(例如 Claude Desktop)指向它:**
```json
{
"mcpServers": {
"linux-mcp-test": {
"command": "docker",
"args": ["exec", "-i", "linux-mcp-test", "mcp-linux-example"]
}
}
}
```
客户端配置中不需要 `env` 块 - 容器内已经设置了 `WORKSPACE_ROOT`。
**要更改服务器本身:** 编辑 `mcp-server/server.py`(或其 `requirements.txt`),然后重建:
```bash
docker compose build
docker compose up -d
```
运行容器始终反映最后构建时内置的内容,而不是主机上文件的实时视图。
## 更新已安装的软件包
镜像故意不在构建时运行 `apt-get upgrade`,以保持构建的可确定性。要获取新的软件包版本:
```bash
docker compose build --no-cache
docker compose up -d
```
要添加或删除软件包,请编辑 `Dockerfile` 中的软件包列表,然后像上面一样重建。
要临时修补正在运行的容器(不持久 - 仅用于一次性调试):
```bash
docker exec -it linux-mcp-test bash -lc "sudo -n true 2>/dev/null; apt-get update"
```
注意:`dev` 用户设计上没有 sudo 访问权限(参见 [设计说明](#设计说明)),因此持久的软件包更改属于 `Dockerfile`,而不是在实时容器中。
## 可选 Docker CLI
可以为容器需要与主机或 sibling Docker 守护进程通信的场景(例如,通过挂载的 `/var/run/docker.sock`)包含 Docker *客户端* 二进制文件:
```bash
docker compose build --build-arg INSTALL_DOCKER_CLI=true
```
默认情况下关闭,以保持标准镜像尽可能小。
## 故障排除
**容器在 `docker compose up -d` 后立即退出**
检查日志:`docker logs linux-mcp-test`。由于容器的命令只是 `sleep infinity`,因此立即退出几乎总是意味着镜像未能正确构建 - 使用 `docker compose build --no-cache` 重建并观察错误。
**`docker exec` 表示容器未运行**
使用 `docker ps -a --filter name=linux-mcp-test` 确认状态。如果它处于 `Exited` 状态,请使用 `docker compose up -d`(或 `docker start linux-mcp-test`)启动它,然后再执行 `exec`。
**写入 `/workspace` 被拒绝**
容器的 `dev` 用户是 UID/GID 1000。如果您的主机用户具有不同的 UID,则主机上创建的文件可能无法从容器内部写入,反之亦然。或者,使用 UID 1000 运行主机命令,或在主机上使用 `sudo chown -R 1000:1000 ./workspace` 调整所有权。
**构建因 `groupadd: GID '1000' already exists` 而失败**
这意味着您正在使用旧的缓存层或修改的 Dockerfile,跳过了清理步骤。当前的 `ubuntu:24.04` 基础镜像附带一个预先创建的 `ubuntu` 用户/组,UID/GID 均为 1000(24.04 中引入;22.04 及更早版本没有)。Dockerfile 删除了该已发货帐户 - 如果您仍然遇到此问题,请运行 `docker compose build --no-cache` 以排除过时的缓存,并确认 `userdel`/`groupdel` 保护步骤没有意外删除。
**`ModuleNotFoundError: No module named 'mcp'`**
您正在使用系统 Python 而不是其专用虚拟环境运行服务器。使用包装器(`mcp-linux-example`)或虚拟环境解释器直接(`/opt/mcp-server/venv/bin/python3 /opt/mcp-server/server.py`)- 普通 `python3 /opt/mcp-server/server.py` 将看不到虚拟环境的软件包。
**`apt-get` 在构建过程中因 DNS/网络错误而失败**
这是主机网络问题,而不是镜像问题 - 确认 Docker 守护进程具有出站互联网访问权限(`docker run --rm ubuntu:24.04 getent hosts archive.ubuntu.com`)。
**需要为 `apt-get` 传递代理以在构建过程中使用**
使用标准的 Docker 构建参数,例如 `docker compose build --build-arg http_proxy=... --build-arg https_proxy=...`(如果您定期依赖此功能,则需要将匹配的 `ARG`/`ENV` 行添加到 `Dockerfile` 中)。
## 清理 Docker 资源
删除此项目的容器和镜像:
```bash
docker compose down --rmi local
```
删除容器、本地镜像和任何匿名卷/孤儿:
```bash
make clean
# 等效于:
docker compose down -v --rmi local --remove-orphans
```
更广泛的 Docker 维护(影响主机上的所有停止的容器、悬空镜像和未使用的网络 - 请谨慎使用):
```bash
docker system prune
```
## 验证检查清单
构建后,以下所有操作都应成功:
```bash
docker compose build # 镜像构建
docker compose up -d # 容器启动
docker ps --filter name=linux-mcp-test # 容器保持运行
docker exec -it linux-mcp-test whoami # -> dev
docker exec -it linux-mcp-test bash -lc 'touch /workspace/ok && ls /workspace'
docker exec -it linux-mcp-test python3 --version
docker exec -it linux-mcp-test git --version
docker exec -it linux-mcp-test curl -sI https://example.com
docker exec -it linux-mcp-test ping -c1 1.1.1.1
docker exec -it linux-mcp-test which mcp-linux-example
docker exec -it linux-mcp-test /opt/mcp-server/venv/bin/python3 -c "import mcp; print('mcp SDK OK')"
docker images linux-mcp-test --format '{{.Size}}' # 镜像大小检查
```
对于实际的协议级检查(不仅仅是“进程可以启动”),请使用 [内置示例 MCP 服务器](#内置示例-mcp服务器) 中的 MCP Inspector 命令 - 它执行真正的 MCP 握手并允许您交互式地调用每个工具。
## 设计说明
- **单个 apt 层。** 所有软件包安装都在一个 `RUN` 中进行,`rm -rf /var/lib/apt/lists/*` 和 `apt-get clean` 在同一层中,以便缓存和元数据永远不会在最终镜像中持续存在。
- **`--no-install-recommends`** everywhere,以避免引入不必要的依赖项(文档、额外字体等),这些依赖项会增加大小而不增加测试价值。
- **无密码 sudo。** 任务只需要一个工作的非 root 用户;添加 sudo(无论是否无密码)只会扩大容器的有效权限,而不增加相应的需求。如果您的 MCP 测试特别需要特权升级场景,请有意添加 `sudo` 和作用域内的 `/etc/sudoers.d/dev` 条目,而不是授予空白的 root 访问权限。
(此处“一次性”意味着 *容器* 可以廉价地重新创建,而不是其用户应该以 `root` 身份运行。)
- **`dev` 的固定 UID/GID 1000**,以便绑定挂载的文件与典型的单个用户主机帐户对齐,而无需额外的 `chown` 步骤。这适用于单个开发人员设置;对于共享/团队使用,请考虑通过构建参数将 UID/GID 参数化。
- **`sleep infinity` 作为 PID 1,exec 形式。** 没有 shell 包装器,以便进程直接干净地响应 `docker stop`。
- **示例 MCP 服务器位于 `/opt` 下的其自己的虚拟环境中,而不是系统 Python。** 这避免了与 Ubuntu 24.04 的 PEP 668 守护进程对 `pip install` 到系统解释器的冲突,并将其依赖项 (`mcp[cli]`) 与容器生命周期中可能安装的其他内容分开。`/usr/local/bin/mcp-linux-example` 包装器隐藏了此详细信息,以防有人配置 MCP 客户端。
- **确定性构建。** Ubuntu 版本通过构建参数固定(默认为 `24.04`),并且在构建时不会运行 `apt-get upgrade` - 今天和下个月从同一提交重建会安装来自同一基础镜像标签的相同软件包版本。