Sign inSign up

muziyuyang/linux_handler_mcp

By muziyuyang

•Updated 22 days ago

Image
0

281

muziyuyang/linux_handler_mcp repository overview

⁠Linux Agent MCP 规格说明书 · 极简版 v2.0

⁠1. 产品概述

Docker 交付的 MCP Server + Web 管理端。Agent 通过 2 个 MCP 工具在局域网 Linux 主机上远程执行命令;管理员通过 Web 控制台管理主机、实时查看执行流、为敏感命令输入密码。

设计基调:面向个人局域网服务器运维,克制复杂度、不做迁移、安全适当放宽。

⁠2. 裁剪对照表(相对 v0.5 全量版)

编号v0.5 全量版v2.0 极简版理由
R-01高风险命令拦截 + confirm_command 一次性令牌移除,命令全部直接执行个人局域网无需双层审批
R-02linux.host_info 结构化系统采集(4 组解析器)移除,用 df -h / free -m 等普通命令替代类 Unix 命令不兼容风险高
R-03query_command / query_audits 审计查询工具移除,执行记录由 Web 执行流承载Agent 无二次查询需求
R-04linux.list_hosts 主机列表工具移除,主机清单并入 help_info 动态生成减少工具数量
R-05SSH host_key 指纹策略 + 缓存管理接口移除,统一 AutoAddPolicy安全放宽
R-06凭据 Fernet 加密 + 密钥轮换(previous key)保留加密,移除轮换(单密钥)轮换无场景
R-07审计分页查询页 + 输出分段下载Web 执行流:SSE 实时推最近 30 条监控无需分页
R-08Web 登录密码与 MCP API Key 分离统一为一个 API_KEY(Web 用户名 admin)单管理员无需双凭据
R-09sudo 三模式标记(预置密码/跳过/弹窗)统一 Web 弹窗实时输入;root 用户免弹窗直执行体验参照 linux-handler-python-mcp

⁠3. 功能需求(as-built)

编号功能实现要点
F-01主机管理Web 端增删改查、测试连接、启停;密码/私钥(含口令)两种认证;删除有历史记录时需二次确认
F-02linux.execute_commandhostId / command(≤8000) / operator / timeoutMs(1000~120000,越界钳制);同步返回 stdout/stderr/exitCode/状态/耗时
F-03linux.help_info无入参,返回 Markdown 六块:概述 / 参数表 / 动态主机清单 / 状态码 / 敏感输入机制 / 示例
F-04实时命令页(/console)SSE 推送最近 30 条(首帧 records 快照 + 增量 audit 事件,Last-Event-ID 重连),长输出 details 折叠
F-05主机管理页(/console/hosts)与执行流拆分的独立页面;两页顶部导航切换(2026-09-05 变更,见决策 D-4)
F-06敏感输入正则识别 sudo(自动改写 sudo -S)/ 无值 mysql -p / docker login,且主机用户非 root → 挂起为 WAITING_SECRET_INPUT 并生成挑战;MCP 立即返回 WAITING(含 challengeId 与有效期),不阻塞连接;Web 弹窗提交 /api/challenges/{id} 后经 SSH stdin 注入继续执行;密码错误可重试(默认最多 3 次),最终结果经 Web 控制台查看(2026-09-06 真机验证 as-built)
F-07登录/登出单管理员(admin / API_KEY);会话 Cookie + CSRF 头;登出后接口 401
F-08统一鉴权API_KEY 既是 Web 登录密码,又是 MCP X-API-Key / Bearer
F-09存储SQLite 单文件 WAL,建表即用不做迁移(schema 冗余列保留不写);执行记录 FIFO 保留 500 条
F-10高风险命令人工审批(v2.1 新增,D-6)内置 7 条高置信度规则(递归删除根/家/当前目录、格式化、dd 写块设备、关机重启、重定向覆盖块设备、fork 炸弹、drop/truncate 数据库对象、下载脚本直接执行);命中 → 挂起 WAITING_APPROVAL 并生成审批单(approval_challenges 表,TTL 默认 300s),MCP 立即返回 approvalId;Web 详情面板内嵌「批准/拒绝」,批准后按需转入密码挑战或直接执行,拒绝终态 REJECTED;审批单一次性消费;Agent 等待期间勿重试
F-11配置备份/还原(主机管理页,方案 A)主机管理页 /console/hosts 提供「备份配置」「还原配置」按钮:GET /api/hosts/backup 导出 hosts 表全列 JSON(含凭据密文原样、密钥单向指纹);POST /api/hosts/restore(UploadFile)按主机 ID 合并 upsert,保留其他主机与历史;还原时校验密钥指纹,不匹配弹告警但继续;不做还原前自动快照

⁠4. 命令状态机

PENDING ──→ RUNNING ──→ SUCCESS | FAILED | TIMEOUT
                │
                └─→ WAITING_SECRET_INPUT ──(Web 提交)──→ RUNNING
                         │
                         └─(120s 未提交)──→ FAILED(SECRET_INPUT_EXPIRED)
PENDING ──→ WAITING_APPROVAL ──(Web 批准)──→ RUNNING | WAITING_SECRET_INPUT
                    │               └─(Web 拒绝)──→ REJECTED
                    └─(300s 未审批)──→ APPROVAL_EXPIRED
  • 挑战提交为一次性:过期/已消费的 challengeId 提交返回错误,密码不落库、不回显、不出现在任何执行记录。

⁠5. 接口清单(as-built)

MCP 工具(2 个):linux.execute_command、linux.help_info(Streamable HTTP /mcp,X-API-Key 或 Bearer 鉴权)。

Web 页面:/login、/console(实时命令)、/console/hosts(主机管理);未登录访问控制台 303 → /login。

Web API:/api/hosts(GET/POST)、/api/hosts/{id}(PATCH/DELETE)、/api/hosts/{id}/test、/api/hosts/{id}/toggle、/api/hosts/backup(GET,下载 JSON)、/api/hosts/restore(POST,UploadFile)、/api/commands/recent、/api/console/stream(SSE)、/api/challenges/{id}(POST)、/api/approvals/{id}(POST,action=approve/reject)、/login、/logout、/health。

⁠6. 非功能约定

  • 输出单值上限 65,536 字符(超出截断并标记 truncated)
  • 敏感输入挑战有效期 120s(CHALLENGE_EXPIRE_SECONDS),过期惰性翻转;密码错误可重试,最多 3 次
  • 高风险审批有效期 300s(APPROVAL_EXPIRE_SECONDS),审批单一次性消费,拒绝/过期均为终态
  • 执行记录保留 500 条 FIFO;SSE 监控窗口 30 条
  • DB 只初始化不迁移:schema 变更须删库重建(数据宽松原则)
  • 打包约束:pyproject.toml package-data 必须含 web/*.html,改页面后须跑一次 wheel 构建核验

⁠7. 验收标准(与 .scratch/smoke_v2.py 32 项对齐)

编号验收点
AC-01/health 200 且 database ok
AC-02tools/list 恰好 2 个工具;AC-02b help_info 含主机清单
AC-03/04登录成功返回 CSRF;错误密码 401;登出后接口 401
AC-05未登录访问 /console 与 /console/hosts 均 303 → /login
AC-06/07主机新增/重复 409/列表无凭据/PATCH 改名不清凭证
AC-08普通命令 SUCCESS,记录含 stdout/stderr/exitCode
AC-09sudo(非 root)进入 WAITING_SECRET_INPUT;AC-09b Web 提交后流转完成
AC-10密码不出现在任何执行记录字段
AC-11TIMEOUT / 非法 hostId / 主机停用拒绝
AC-12明文凭据命令拒绝(不进入执行流程)
AC-13记录列表含命令与输出字段;AC-13b SSE 首帧 records 快照
AC-14空/纯空白命令在 schema 层与 service 层分别拒绝
AC-15登出成功
AC-16页面拆分:/console 不含主机表格,/console/hosts 不含执行流表格,两页均有顶部导航
AC-17高风险命令进入 WAITING_APPROVAL(含命中规则标注);非法 action 400/422;拒绝 → REJECTED 终态;批准 → 进入执行;审批单一次性消费;sudo+高风险先审批后转密码挑战(先审批后密码,D-6)

⁠8. 决策记录

  • D-1(决策 1)= 选项 A:完全移除高风险拦截与确认令牌。
  • D-2(决策 2)= 选项 A:移除 host_info 工具。
  • D-3(决策 3)= 选项 B:敏感输入采用 Web 弹窗实时输入,不预置 sudo 密码(体验基准:linux-handler-python-mcp)。
  • D-3+:应用户要求新增 linux.help_info 工具,承载参数说明与动态主机清单。
  • D-4(2026-09-05 16:40):控制台拆分为「主机管理」与「实时命令」双页面,顶部导航切换,功能不变;/console 保留为实时命令页。
  • D-5(2026-09-05 17:00):修复 _sudo_stdin_command 复合命令缺陷——原实现只改写行首第一个 sudo,sudo -k; sudo whoami 中第二个裸 sudo 改写后无法获得 stdin 密码通道。现改为行首及 ;/&/|/换行分隔后的每个 sudo 段均改写 sudo -S(已含 -S 的段跳过);risk.py 的 SUDO_PATTERN 同步支持换行分隔以保持识别/改写一致。已知边界:单条命令内多个都需要密码的 sudo 段,第二个起仍会因 stdin 密码已被消费而失败(stdin 单次注入机制限制),建议拆分执行。
  • D-6(2026-09-06 20:39):高风险命令人工审批回归(v2.1)。以 Web 人工审批方式替代 D-1 移除的 v1 BLOCKED/confirm 令牌机制(不复引入 confirm MCP 工具,工具数保持 2 个);新建 approval_challenges 表(应用户确认,项目无历史数据包袱);审批先于密码挑战(复合命令先审批、批准后再输密码);审批价值定位为防 Agent 误判/幻觉命令,静态规则库按"宁少拦不误拦"原则持续迭代。

⁠9. 原待确认项落地结果

编号原待确认问题落地
Q-01MCP 对敏感命令是否同步等待否(as-built 修正):立即返回 WAITING_SECRET_INPUT + challengeId,不阻塞 MCP 连接;挑战 120s 有效、密码错误最多重试 3 次,结果经 Web 控制台查看
Q-02裸 sudo 是否自动改写 -S是(首处 sudo 自动补 -S)
Q-03历史保留条数500 条 FIFO
Q-04输出单值上限65,536 字符

⁠10. 变更记录

日期版本说明
2026-09-05v2.0(原稿,已丢失)3 轮需求收敛后成稿
2026-09-05v2.1(重建版)依据决策记录与 as-built 代码重建;补充 D-4 双页面拆分与 AC-16;SSE/敏感输入/help_info 等条目与实现逐项核对
2026-09-05v2.1D-5:修复复合命令中后续裸 sudo 未改写 -S 的缺陷;识别正则同步支持换行
docker run -d \
  --name "${CONTAINER_NAME}" \
  --restart unless-stopped \
  --user "$(id -u):$(id -g)" \
  -p "${HOST_PORT}:${CONTAINER_PORT}" \
  -v "${DATA_VOLUME_HOST}:/app/data" \
  -e HOST="${HOST}" \
  -e PORT="${PORT}" \
  -e LOG_LEVEL="INFO" \
  -e LOG_JSON="true" \
  -e API_KEY="${API_KEY}" \
  -e CREDENTIAL_ENCRYPTION_KEY="oK7EKqEJkcOQ-uC71Yz2ioLw65LP_JV-l0v_SPhPydA=" \
  -e DATABASE_PATH="./data/linux_agent.db" \
  -e HOST_CONCURRENCY_LIMIT="3" \
  -e SESSION_IDLE_TIMEOUT_SECONDS="1800" \
  -e SESSION_COOKIE_SECURE="false" \
  -e CHALLENGE_EXPIRE_SECONDS="180" \
  -e APPROVAL_EXPIRE_SECONDS="300" \
  -e MCP_ALLOWED_HOSTS="192.168.100.120:*" \
  -e DEBUG="false" \
  "linux_handler_mcp"

call me: [email protected]⁠

Tag summary

Content type

Image

Digest

sha256:1480390cb…

Size

62.7 MB

Last updated

22 days ago

docker pull muziyuyang/linux_handler_mcp:v2.2.0