关于 Let AI assistants operate your Linux servers — behind a human consent gate the model can't self-approve.
一个 MCP 服务,让 AI 助手(Claude Desktop、Cursor、Windsurf)连接和操作 Linux 服务器,但所有改变生产服务器状态的操作都需要人工同意令牌批准。读操作始终允许,提供安全、可审计的 DevOps 自动化。
主要功能
- 01三级访问模式
- 02生产服务器写入保护
- 03出带外同意令牌
- 04命令参数 Shell 转义
- 05服务器配置文件扫描
- 06审计日志记录
适用场景
- 01生产服务器安全部署
- 02DevOps 自动化任务
- 03服务器诊断和监控
- 04版本控制和策略执行
MCP 相关
作为 MCP 服务暴露 Linux 服务器工具给客户端,要求所有改变性操作通过人工同意令牌验证,读操作默认允许。
详细介绍
devops-mcp
一个基于模式的 MCP(Model Context Protocol,模型上下文协议)服务,让 AI 助手(Claude Desktop、Cursor、Windsurf……)可以实际操作 Linux 服务器,但不会让它们获得完全控制权。
该模型可以连接、扫描、规划和部署——但每一步改变生产类服务器状态的操作都必须通过 AI 无法自行批准的同意关卡。发现功能在设计上是只读的。
┌─────────────────┐ MCP / stdio ┌────────────────────┐
│ AI client │ ───────────────────────────► │ devops-mcp │
│ (Claude / │ │ │
│ Cursor / …) │ ◄─────────────────────────── │ ssh2 / docker / │
└─────────────────┘ │ child_process │
└────────┬───────────┘
│ SSH
▼
┌────────────────┐
│ Your VPS │
└────────────────┘
⚡ 首次设置(读一次,做一次)
恰好四个步骤。不要跳过第 2 步。
1. 安装
git clone <your-fork-url>.git devops-mcp
cd devops-mcp
npm install
npm run build
需要 Node ≥ 18。
2. 生成你的提升令牌并将其保存在不会丢失的地方
# Linux / macOS
openssl rand -hex 24
# Windows PowerShell
$bytes = New-Object byte[] 24; (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($bytes); [BitConverter]::ToString($bytes).Replace("-","").ToLower()
# Or, via Node
node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"
你会得到类似 6ba329add30b19a5a347178f7e3705fdea0ac1aa66cb9274 的东西。
🔑 在第 3 步之前保存此令牌。
此令牌是阻止 AI 获得无限制生产访问权的唯一防线。该模型永远看不到它。 每当 AI 想要提升到 PROVISION/FULL 模式、批准破坏性操作、更改服务器角色或在生产类服务器上写入时,你只需粘贴一次。
将其保存在密码管理器中。如果你丢失了它:
- 你可以手动编辑 MCP 客户端的配置以设置新令牌,或者
- 如果你仍然拥有旧令牌,可以要求 AI 调用
rotate_consent_token(如果两个都丢失了就不行了)。没有恢复流程。这是关卡;我们没有提供后门。
3. 将 devops-mcp 添加到 MCP 客户端配置
对于 Claude Desktop,编辑 claude_desktop_config.json:
- Windows:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
添加(或合并到现有 mcpServers):
{
"mcpServers": {
"devops-mcp": {
"command": "node",
"args": ["/absolute/path/to/devops-mcp/dist/index.js"],
"env": {
"DEVOPS_MCP_ELEVATION_TOKEN": "<paste your token from step 2 here>",
"LOG_LEVEL": "info"
}
}
}
}
相同的结构适用于 Cursor、Windsurf 和任何其他 MCP 客户端——env 块是传递机密的标准 MCP 方式。
4. 完全退出并重新打开 MCP 客户端
不是"关闭窗口"。在 Windows 上,这意味着系统托盘 → 退出。提升令牌在启动时读取;客户端必须重新启动才能生效。
完成。下次你和 AI 交谈时,说"在……添加我的服务器",它会引导你完成。
存在的原因
通用的"运行任何命令"MCP 服务在生产服务器上很危险。一个拥有对实时服务器完全 shell 访问权限的模型可以——而且会——重启错误的服务、部署到正在使用的端口、docker prune 一个数据库卷,或因为没有人告诉它不能就提升自己到 root。
devops-mcp 在读取和更改之间划出了一条硬线:
- 读取总是被允许的(在只读的 SAFE 允许列表内)。
- 在生产类服务器上更改需要人类的令牌——带外传递,对模型不可见。
- 部署新项目通过端口冲突检查和可审查的脚本进行,而不是 40 个临时命令。
特性
访问控制
- 三层模式:
SAFE(默认,只读白名单)、PROVISION(系统安装,默认 1 小时过期)、FULL(root,默认 30 分钟过期)。 - 带外同意令牌 — 提升权限和批准需要仅用户持有的字符串。大模型根本无法读取它。
- 生产环境写入门控 — 在
role: production服务(或任何扫描器标记为productionLikely的服务)上,任何非 SAFE 命令都需要consentToken+acknowledgeProductionWrite: true。灾难性命令 — 不进行备份无法恢复的命令(rm非临时路径、rm -rf /…、dd of=/dev/…、mkfs、SQLDROP TABLE/DATABASE、docker rmi、docker volume rm、docker rm -v、docker system prune)— 另外还需要backupVerified: true。普通写入和可恢复操作(编辑文件、rm /tmp/scratch、简单docker rm可从镜像重新创建的容器)无需backupVerified。拒绝会回显确切解析的命令。 - 按服务策略 —
allowedModes、blockedCommands、allowedPaths、requireApproval位于config/<server-id>/server.json中,在每个 SSH 命令上强制执行。 - 必需的
role—add_server不会让 AI 无声地默认 role;它必须询问用户,响应包含 AI 回读给你的roleConsequences块。 - 令牌轮换 —
rotate_consent_token生成新令牌(默认为空运行;apply: true原子地更新你的 MCP 客户端配置)。 - 凭证轮换 —
update_server_credentials轮换密码、交换 SSH 密钥(包括通过keyPassphrase的加密密钥),或在不重新添加服务的情况下迁移 host/user/port。role、限制和扫描配置文件保持不变。首先关闭到该服务的任何活跃会话,使用测试连接验证新凭证,并在生产环境上需要同意门控。 - AWS / EC2
.pem已就绪 — 使用.pem文件 + 用户名 + IP 进行登录。就地引用它(externalKeyPath)或将其复制到配置包中(keyFilePath);仅当密钥已加密时才添加keyPassphrase。 - 多个并发连接,由 serverId 键控 — MCP 为每个服务持有一个 SSH 连接,而不是一个全局槽。Claude Desktop 在所有对话中运行单个共享 MCP 进程;使用全局连接,两个对话在两个服务上工作会相互覆盖("会话 1 在服务 A 上,会话 2 连接到 B,现在 A 的命令被发送到 B")。键控连接让两者共存。
run_command接受serverId:当恰好连接一个服务时可选,连接两个或更多个时必需 — 含糊调用被拒绝而不是猜测。每个run_command响应回显target.serverId和activeConnections。 - 防目标漂移 —
run_command、set_mode和get_current_mode响应都带有已连接的服务身份,因此对话永远不会无声地在错误的机器上结束。disconnect_server接受可选的serverId(或"all")。 - 会话感知的实时登录 —
add_server在其响应中显示当前连接的服务,并告知 AI 在不询问的情况下不要自动切换到新添加的服务。
发现与规划
- 服务器发现扫描 — 操作系统、硬件、监听端口、已安装堆栈(docker / nginx / apache / node / pm2)、运行容器、解析的 nginx 站点、systemd 服务的只读探测。输出持久化为
ServerProfile。 - 重新连接时的配置文件差异 —
diff_server_profile重新扫描并报告自保存快照以来的更改。 - 端口冲突意识 —
check_port_conflict在部署前返回监听进程 + 可用端口建议。 - 规划,不要执行 —
plan_deployment返回用户审查的幂等 bash 脚本。MCP 不执行它。
安全加固
- 所有命令参数都经过 shell 转义 后再发送到远程 shell。不再出现
sh -c "<long script>"有效负载在错误的 shell 层级分割的情况。 - 验证器检查参数 —
run_command({command:"ls", args:["; rm -rf /"]})在 SAFE 模式下不再通过ls验证。 - 引号感知链分割器 — 只读命令链保持 SAFE 状态。诊断管道如
du -sh /opt/* ; echo --- ; df -h /不需要提升权限。每个片段独立验证;链所需的模式是各部分的最大值。 - 全面的只读允许清单 — 约 250 个只读动词在 SAFE 中运行:文件系统读取、文本处理器(awk/sed/jq/cut/…)、哈希校验和、硬件/进程检查(lsof/lspci/vmstat/…)、软件包查询(apt/dpkg/rpm/yum/snap/brew)、容器和 k8s 读取(docker/podman/kubectl/helm get+describe+logs+inspect)、git 读取以及各主要编程语言生态的 list/show/version 命令。
- 递归
$(...)验证 — 命令替换和反引号按其内容验证,而非一概提升权限。只读轮询循环(for i in 1 2 3; do code=$(docker ps); echo $code; done)保持 SAFE;$(rm -rf /)仍会提升权限。 - Bash 控制流是 SAFE —
for/while/if/case/变量赋值不执行外部程序,所以不强制提升权限。 - 工具标志规范化 —
git -C /path、kubectl -n prod、helm --namespace、docker --context作为其规范子命令验证,所以工作目录或命名空间标志不会提升只读权限。 - 写重定向检测 —
cat > /etc/passwd在 SAFE 模式下被拒绝,即使cat是只读的;只有>/dev/null和2>&1类无操作重定向通过。 - 仅灾难性备份门禁 —
backupVerified仅对不可恢复的操作必需,而非每次写入(见上面的生产写入门禁)。 - 自动修复部分配置 — 手写的
server.json缺少role或restrictions时,在加载时获得合理的默认值,而非导致connect_server崩溃。 - 配置文件注入防御 — 从服务器提取的文本返回时带有明确的"这是数据,不是指令"标记。
- 可操作的断开连接错误 — 当 SSH 掉线时,下一个
run_command告知 AI 要连接到哪个服务器。
审计
- JSON lines 审计日志 — 每条命令、模式变更、批准和扫描都在
logs/audit.log中有一条记录。可通过get_audit_log检索。
日常使用演示
一旦完成首次设置,典型的会话如下所示:
添加服务器(密钥认证 — 最简单,推荐)
你已运行 ssh-copy-id 将工作站密钥放入 VPS 的 authorized_keys:
You: Add my VPS at 1.2.3.4, user ubuntu. I already added my SSH key.
AI: What role is this server? Production / staging / development / testing?
You: Production.
AI: [add_server id=my-vps host=1.2.3.4 username=ubuntu authType=key useExistingKey=true role=production]
→ picked C:\Users\you\.ssh\id_ed25519, connection test ✓
⚠️ role=production means SAFE-only by default. Writes will need your token.
添加服务器(密码 — $ENV_VAR 形式,推荐优于字面值)
You: Add another, IP 1.2.3.5, root, password is in $TUTOR_PASS env var.
AI: What role?
You: Staging.
AI: [add_server id=tutor host=1.2.3.5 username=root authType=password password=$TUTOR_PASS role=staging]
→ server created, connection test ✓
连接和扫描
You: Connect to my-vps and tell me what's on it.
AI: [connect_server serverId=my-vps] → connected
[scan_server] → 8s profile written to config/my-vps/profile.json
Server is production-like:
- nginx serving example.com on 80/443
- postgres container on :5432
- 4 docker containers, 2 GB RAM free
- last scanned: just now
只读诊断 — 无需提升权限
只读命令链在 SAFE 中运行:
You: How much disk are the projects using?
AI: [run_command "du -sh /opt/* 2>/dev/null ; echo --- ; df -h /" executor=ssh]
→ ran in SAFE mode (read-only chain, no elevation required)
部署新项目
You: Deploy https://github.com/me/newapp on this box, port 8000.
AI: [check_port_conflict port=8000] → in use by "node" (the example.com app)
Port 8000 is taken. Suggested free port: 8001. Use 8001 or stop the existing app?
You: Use 8001.
AI: [plan_deployment port=8001 runtime=node ...] → returns a 26-line bash script
Here's the script. Please review.
You: Looks good. Run it.
AI: [run_command ...] → refused: production write-gate.
To run this I need your elevation token and confirmation that a backup exists.
You: Token is <paste>. Yes, snapshot taken this morning.
AI: [run_command consentToken=<…> acknowledgeProductionWrite=true backupVerified=true]
→ ✓ deployed
轮换凭证(VPS 密码已更改,或你更换了 SSH 密钥)
You: I rotated my-vps's root password. New one is in $MY_VPS_PASS_NEW.
AI: my-vps is role=production — for the rotation I need your elevation token.
You: Token is <paste>.
AI: [update_server_credentials serverId=my-vps authType=password
password=$MY_VPS_PASS_NEW consentToken=<…>]
→ closed active SSH session (was connected), new creds tested ✓
Reconnect with connect_server when ready.
You: Connect.
AI: [connect_server serverId=my-vps] → ✓
角色、限制、被阻止命令列表和扫描配置文件被保留。仅认证字段改变。
稍后更新服务器角色
You: Actually my-vps is staging now, not production.
AI: This is a production-touching change, please confirm with the token.
You: Token is <paste>.
AI: [update_server serverId=my-vps role=staging applyRoleDefaults=true consentToken=<…>]
→ role changed; allowedModes now [SAFE, PROVISION].
轮换令牌(旧令牌已泄露,例如进入聊天)
You: Generate a new elevation token and update Claude Desktop's config.
AI: For verification, paste the current token.
You: <paste current>
AI: [rotate_consent_token consentToken=<current> apply=true]
→ 🔑 NEW TOKEN: <new> ← SAVE THIS NOW, in a password manager.
Claude Desktop must be fully restarted for the new token to take effect.
Until then, the OLD token still works on this running session.
访问模式
| 模式 | 默认过期时间 | 允许的操作 |
|---|---|---|
SAFE | 无过期 | 只读许可列表:ls、cat、df、ss、docker ps、nginx -T 等。所有 SAFE 命令的链式调用也可行。 |
PROVISION | 1 小时 | apt/yum、docker run/build/stop、systemctl start/stop、nginx、ufw、文件操作 |
FULL | 30 分钟 | 任何操作,包括 fdisk、dd、shutdown、rm -rf / |
提升权限需要:
acknowledgeRisk: true(由 AI 设置)consentToken: "<your token>"(仅你拥有)
降级始终被允许且即时生效。会话自动过期回到 SAFE。
工具参考(32 个工具)
服务器生命周期
| 工具 | 模式 | 功能 |
|---|---|---|
add_server | SAFE | 一次性入门。五种身份验证方式:password(字面值或 $ENV_VAR)、keyFilePath(将密钥复制到配置)、privateKey(粘贴内联)、externalKeyPath(指向现有密钥而不复制)、useExistingKey(自动选择 ~/.ssh/id_*)。需要 role。自动测试连接。返回 roleConsequences。 |
update_server | SAFE | 更改角色、allowedModes、blockedCommands、allowedPaths、requireApproval、名称或描述。修改生产环境需要 consentToken。身份验证字段在此处不可变——请参阅 update_server_credentials。 |
update_server_credentials | SAFE | 轮换密码、交换 SSH 密钥、迁移主机/用户/端口。首先关闭与此服务器的任何活动 SSH 会话。默认测试新凭据。保留角色/限制/profile.json。生产服务器需要 consentToken。 |
setup_server_config | SAFE | 更低级别:init / add / status。与原始 add_server 使用的相同。 |
list_servers | SAFE | 列出所有已配置的服务器 |
test_connection | SAFE | 尝试 SSH 连接到已配置的服务器(不运行命令) |
connect_server | SAFE | 打开工作 SSH 会话以供后续命令使用 |
disconnect_server | SAFE | 关闭 SSH 会话 |
发现(全部只读)
| 工具 | 模式 | 功能 |
|---|---|---|
scan_server | SAFE | 探测操作系统 / 硬件 / 端口 / 堆栈 / 工作负载。持久化保存到 config/<id>/profile.json。目标上无写入操作。 |
get_server_profile | SAFE | 读取已保存的配置文件而无需重新扫描 |
diff_server_profile | SAFE | 重新扫描并报告发生了什么更改。除非 accept: true,否则不覆盖已保存的配置文件 |
check_port_conflict | SAFE | 端口 X 是否被占用?返回监听器和空闲端口建议 |
list_containers | SAFE | 列出连接的服务器上的 Docker 容器 |
list_playbooks | SAFE | 列出可用的配置 playbook |
执行与部署
| 工具 | 模式 | 功能 |
|---|---|---|
run_command | varies | 执行命令(本地 / ssh / docker)。参数被 shell 引用;链式命令被分割,每个片段都被验证;应用生产环境写入门禁。 |
plan_deployment | SAFE | 生成一个幂等的 bash 脚本(克隆 + 构建 + pm2/docker)。除非设置 acknowledgeConflict: true,否则拒绝端口冲突。不执行。 |
run_playbook | PROVISION | 运行预定义的配置 playbook |
install_docker | PROVISION | 安装 Docker + Compose |
install_nginx | PROVISION | 安装 Nginx |
configure_nginx | PROVISION | 生成 nginx 反向代理配置并重载。使用 heredoc 避免 shell 引用错误。 |
deploy_app | varies | 更底层的部署原语(git 克隆 + 构建 + 启动)。所有插值值都被 shell 引用。 |
container_action | SAFE / PROVISION | start / stop / restart / logs / inspect |
transfer_files | SAFE(下载)/ varies(上传) | 通过 SFTP 上传/下载文件、文件夹(递归)或存档。extract: true 在服务器上解包上传的 .zip/.tar.gz/.tgz/.tar/.tar.bz2/.tar.xz/.gz;verifyChecksum: true 对单个文件执行端到端 sha256 校验。上传到生产环保的服务器会触发写入门禁。 |
模式、同意与审计
| 工具 | 功能 |
|---|---|
get_current_mode | 当前模式 + 权限 + 剩余时间 |
set_mode | 改变模式。提升权限需要 acknowledgeRisk + consentToken |
approve_action | 批准一个待处理的高风险操作。需要 consentToken |
list_pending_approvals | 列出队列中的批准请求 |
rotate_consent_token | 生成新的提升权限令牌。apply: true 原子性地重写 MCP 客户端配置。需要当前令牌。在重启客户端前请阅读响应警告。 |
generate_ssh_key | 生成有自动过期的会话 SSH 密钥对 |
revoke_ssh_key | 撤销会话 SSH 密钥 |
get_audit_log | 尾部/筛选 logs/audit.log(解析 JSON 行,按 since 和 action 筛选) |
health_check | 存活性 + 版本 + 当前模式 |
认证选项(add_server)
五种认证方式,通过 authType 和相应的密钥/密码字段选择:
| 选项 | Schema 字段 | 何时使用 |
|---|---|---|
| 密码 | authType:"password" + password(字面量或 $ENV_VAR) | 未配置密钥认证时。优先使用 $ENV_VAR 以防密码出现在配置文件中。 |
| 复制密钥文件 | authType:"key" + keyFilePath | 你有想与服务器配置一起存储的 PEM 文件(便携式包) |
| 粘贴内联密钥 | authType:"key" + privateKey | 你只有密钥文本 |
| 指向现有密钥 | authType:"key" + externalKeyPath | 你已有 ~/.ssh/whatever — 不复制,仅引用。~ 会被展开。 |
| 自动查找密钥 | authType:"key" + useExistingKey: true | 你的默认 ~/.ssh/id_* 已在服务器的 authorized_keys 中。最简便。 |
处理器验证恰好一个密钥来源。不允许同时组合 useExistingKey 和 keyFilePath 等,会返回清晰的错误。
任何密钥路径(keyFilePath / externalKeyPath)都可选接受 keyPassphrase(字面量或 $ENV_VAR)来处理加密的私钥。
AWS EC2(.pem 文件的情况)
你获得一个 .pem 文件、一个用户名(ubuntu、ec2-user、admin 等)和一个公网 IP/DNS。有两种方式:
// Reference the .pem where it sits (recommended — nothing copied)
{
"id": "my-ec2", "host": "ec2-1-2-3-4.compute.amazonaws.com",
"username": "ec2-user", "authType": "key",
"externalKeyPath": "C:\\Users\\you\\Downloads\\my-key.pem",
"role": "production"
}
// Or copy the .pem into the server's config folder (portable bundle)
{
"id": "my-ec2", "host": "1.2.3.4", "username": "ubuntu",
"authType": "key",
"keyFilePath": "C:\\Users\\you\\Downloads\\my-key.pem",
"role": "staging"
}
大多数 AWS 密钥没有密码短语 — 省略 keyPassphrase。如果你的密钥已加密,添加 "keyPassphrase": "$MY_PEM_PASS" 并设置该环境变量。
现代 sshd + 密码认证:ssh2 需要
tryKeyboard: true来适配使用 PAM 的 sshd 设置(Ubuntu 22.04+、Debian 12、Amazon Linux 2023、RHEL 9)。devops-mcp 会自动设置这个选项 — 即使服务器配置了PasswordAuthentication no并仅允许keyboard-interactive,密码认证仍然有效。
磁盘上的服务配置
每个服务都位于自己的文件夹中:
config/
├── my-vps/
│ ├── server.json # config (host, user, auth, role, restrictions)
│ ├── key.pem # optional SSH private key (only if you used keyFilePath / privateKey)
│ └── profile.json # written by scan_server
└── _example/
└── server.json # template
server.json 示例:
{
"name": "Production Web",
"host": "1.2.3.4",
"port": 22,
"username": "ubuntu",
"authType": "key",
"keyFile": "production.pem",
"role": "production",
"restrictions": {
"allowedModes": ["SAFE"],
"blockedCommands": ["rm -rf", "shutdown", "reboot", "dd"],
"requireApproval": true
},
"description": "Main production web server"
}
对于 externalKeyPath 工作流(密钥保留在 ~/.ssh/):
{
"name": "My VPS",
"host": "1.2.3.4",
"port": 22,
"username": "ubuntu",
"authType": "key",
"externalKeyPath": "C:\\Users\\you\\.ssh\\id_ed25519",
"role": "production"
}
对于密码认证(始终优先使用 $ENV_VAR):
{
"authType": "password",
"password": "$MY_VPS_PASS"
}
$NAME 在连接时解析为 process.env.NAME。不要提交字面密码。
如果 server.json 缺少 role 或具有 restrictions: {},MCP 会在加载时填入 role: "development" 的默认值(并在日志中发出警告)。这可以防止 connect_server 在手写配置上崩溃。
环境变量
| 变量 | 用途 | 默认值 |
|---|---|---|
DEVOPS_MCP_ELEVATION_TOKEN | 带外同意令牌。**设置此项。**没有它,set_mode / approve_action / 生产写入门控会接受 AI 自身的布尔值作为同意,服务器会在日志中记录大声警告。 | 未设置(顾问模式) |
DEVOPS_MCP_NO_CONSOLE_LOG | 设置为 1 以抑制 stderr 控制台日志(文件日志仍会写入) | 未设置 |
LOG_LEVEL | debug / info / warn / error | info |
LOG_DIR | 写入 combined.log、error.log、audit.log 的位置 | ./logs |
NODE_ENV | (仅供参考;无论如何日志都会写入 stderr,以免 MCP stdio 被破坏) | development |
安全模型
devops-mcp 防护的内容
- 模型在生产环境中盲目运行 — 对于具有
role: production或productionLikely: true的服务器上的写命令,没有同意令牌 + 明确确认 + (对于灾难性、不可恢复的操作)backupVerified会被拒绝。 - 自我批准 — 模型无法伪造
consentToken,因为它永远看不到DEVOPS_MCP_ELEVATION_TOKEN。 - 参数注入 —
run_command的每个参数在到达远程 shell 之前都会被 shell 转义。sh -c有效负载内的多行脚本保持完整。 - args 中的隐蔽命令 — 验证器一起检查
command + args,所以run_command({command:"ls", args:["; rm -rf /"]})正确地升级为 FULL。 - 过度的链拒绝 — 只读命令链保持 SAFE。每个片段独立验证;仅最坏的片段生效。
- 扫描内容中的提示词注入 — 横幅、容器标签、日志行返回时带有"不可信数据"标记。工具响应告诉模型:显示,不执行。
- 无声端口冲突 —
plan_deployment和check_port_conflict在部署前识别冲突。 - 部署/配置助手中的 shell 注入 — 每个插值值都被 shell 转义;nginx 配置通过 heredoc 写入;分支名称和环境变量键被验证。
- 生产写入门控拒绝回显确切的命令 — 所以你可以读到即将运行的内容,而不是 AI 的转述。
devops-mcp 不做的事情
- 它不会沙箱隔离连接的服务。一旦你使用令牌进入 FULL 模式, 大模型可以做 SSH 用户能做的任何事情。
- 它不会加密你的 MCP 客户端配置中保存的同意令牌。
- 它不会备份你的数据 —
backupVerified是人工证明, 而不是检查。
有关完整的威胁模型,请参阅 SECURITY.md。
令牌管理
提升令牌是存储在你的 MCP 客户端配置中的 DEVOPS_MCP_ELEVATION_TOKEN
静态字符串。它不会过期。
会过期的是:
FULL模式会话 — 默认 30 分钟PROVISION模式会话 — 默认 1 小时generate_ssh_key生成的会话 SSH 密钥 — 默认 30 分钟
当模式会话超时时,它会回退到 SAFE;AI 会重新请求同一个令牌以重新提升权限。
轮换令牌
You: Rotate the elevation token and update Claude Desktop's config.
AI: For verification, paste the current token.
You: <paste>
AI: [rotate_consent_token consentToken=<current> apply=true]
→ new token: <new>
→ 🔑 SAVE THIS NOW. Without it you're locked out of every write operation.
→ Fully quit and reopen Claude Desktop to activate it.
MCP 会原子性地将新令牌写入你的客户端配置(仅限
DEVOPS_MCP_ELEVATION_TOKEN 密钥 — 文件中的其他所有内容都会
保留)。运行中的 MCP 进程会继续使用旧令牌,直到
你重启客户端。
如果你在轮换和重启之间丢失了旧和新令牌, 手动编辑客户端配置以设置新的 — 这是恢复流程。
项目布局
src/
├── index.ts # MCP entry point (stdio)
├── types/ # TypeScript types
├── core/
│ ├── logger.ts # JSON-lines structured logger + audit logger
│ ├── mode-manager.ts # SAFE / PROVISION / FULL state machine
│ ├── command-validator.ts # Allowlist + quote-aware chain splitter + wrapper-token scan
│ ├── server-config-manager.ts # config/<id>/server.json + profile.json + auto-heal
│ ├── server-scanner.ts # SAFE-mode discovery (read-only by design)
│ ├── ssh-key-manager.ts # Session SSH keys with auto-expiry
│ └── approval-manager.ts # Approval queue
├── executors/ # Local / SSH / Docker — all shell-quote args
├── playbooks/ # Provisioning playbooks (Docker, Nginx, …)
└── tools/
├── tool-schemas.ts # Zod schemas + MCP tool definitions
└── tool-handlers.ts # The actual handlers
开发
npm run dev # watch mode (tsx)
npm run build # tsc → dist/
npm test # vitest
npm run test:run # vitest run (CI mode)
npm run lint # eslint src/**/*.ts
贡献
欢迎提交 PR。请参阅 CONTRIBUTING.md。
添加在连接的服务上写入的新工具时,请确保它
通过 BaseExecutor.execute() 运行,以便模式验证器和
生产写入门控应用。不要直接从处理程序调用 shell,
如果必须在 shell 命令中插值某个值,请使用
执行器中的 shellQuote 帮助器 — 此代码库中的历史 bug
都是引号 bug。
许可证
MIT — 见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。