SSH远程命令执行服务

一个通过SSH在远程Linux系统上安全执行诊断命令的模型上下文协议(MCP)服务器,支持结构化命令格式和白名单安全机制。

  • by Gmacem
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 Gmacem/mcp-ssh-ops

使用说明

MCP SSH操作

一种模型上下文协议(MCP)服务器,用于通过SSH在远程Linux系统上执行安全诊断命令。

特性

  • 结构化命令格式:命令被指定为结构化JSON——通过构造不可能进行shell注入
  • 基于允许列表的安全:只能执行预先批准的命令
  • 危险指挥保护:有潜在风险的命令需要明确的许可
  • 管道支持:将命令与管道连在一起
  • 灵活配置:通过YAML轻松自定义允许的命令

项目结构

mcp-ssh-ops/
├── src/mcp_ssh_ops/
│   ├── __init__.py         # Package initialization
│   ├── server.py           # MCP server implementation
│   ├── ssh_client.py       # SSH client wrapper
│   ├── commands.py         # Command validation logic
│   ├── host_memory.py      # Host descriptions from hosts.yaml
│   └── recap.py            # Optional command recap logging
├── commands.yaml           # Allowlist configuration
├── pyproject.toml          # Project configuration
└── README.md

设置

  1. 安装依赖项:
uv sync
  1. 运行服务器:
uv run mcp-ssh-ops

CLI参数

参数 描述 默认值
--hosts-config PATH 通往 hosts.yaml 带主机描述 无(主机内存为空)
--commands-config PATH 通往 commands.yaml 与排外主义者 commands.yaml 包裹旁边
--recap-dir PATH 保存命令执行摘要的目录 无(已禁用)

MCP客户端配置示例:

{
  "mcpServers": {
    "ssh-ops": {
      "command": "mcp-ssh-ops",
      "args": [
        "--hosts-config", "/etc/mcp/hosts.yaml",
        "--commands-config", "/etc/mcp/commands.yaml",
        "--recap-dir", "/var/log/mcp-recaps"
      ]
    }
  }
}

当 --recap-dir 设置后,每个命令执行都另存为 .log 文件下 recap-dir/YYYY-MM-DD/HHMMSS_ffffff.log.

用法

服务器公开了一个MCP工具: ssh_exec

参数

  • hostname:SSH服务器主机名或IP地址
  • pipeline:结构化命令管道(见以下格式)
  • username:SSH用户名(如果在~/.SSH/config中设置,则可选)
  • password:SSH密码(可选)
  • key_file:SSH私钥文件的路径(可选)
  • port:SSH端口(默认值:22)
  • allow_dangerous:启用危险命令(默认值:false)

管道格式

命令以结构化方式传递 pipeline 包含命令列表的对象。每个命令指定一个 program 及其 args 单独:

{
  "pipeline": {
    "commands": [
      {"program": "ps", "args": ["aux"]}
    ]
  }
}

多个命令通过管道连接:

{
  "pipeline": {
    "commands": [
      {"program": "ps", "args": ["aux"]},
      {"program": "grep", "args": ["python"]},
      {"program": "wc", "args": ["-l"]}
    ]
  }
}

这构造了: ps aux | grep python | wc -l 每一枚代币都通过 shlex.quote().

示例命令

安全命令 (始终允许):

// Process information
{"commands": [{"program": "ps", "args": ["aux"]}]}
{"commands": [{"program": "ps", "args": ["aux", "--sort=-%mem"]}, {"program": "head", "args": ["-20"]}]}

// Network diagnostics
{"commands": [{"program": "ss", "args": ["-tulpn"]}]}
{"commands": [{"program": "ip", "args": ["-br", "addr"]}]}

// Disk usage
{"commands": [{"program": "df", "args": ["-h"]}]}
{"commands": [{"program": "df", "args": ["-h"]}, {"program": "grep", "args": ["-v", "tmpfs"]}]}

// Memory information
{"commands": [{"program": "free", "args": ["-h"]}]}

// System information
{"commands": [{"program": "uptime"}]}
{"commands": [{"program": "uname", "args": ["-a"]}]}

// Logs
{"commands": [{"program": "journalctl", "args": ["-n", "50", "--no-pager"]}]}
{"commands": [{"program": "dmesg"}, {"program": "tail", "args": ["-50"]}]}

// Pipelines
{"commands": [{"program": "cat", "args": ["/proc/meminfo"]}, {"program": "grep", "args": ["MemTotal"]}]}
{"commands": [{"program": "ps", "args": ["aux"]}, {"program": "grep", "args": ["python"]}, {"program": "wc", "args": ["-l"]}]}

危险指令 (要求 allow_dangerous=true):

{"commands": [{"program": "kill", "args": ["-9", "1234"]}]}
{"commands": [{"program": "systemctl", "args": ["restart", "nginx"]}]}

配置

编辑 commands.yaml 自定义允许的命令。两者 safe_commands 和 dangerous_commands 是字典,其中每个键都是一个命令名。没有值的命令(或 null)没有争论限制。要限制参数,请添加 args 钥匙与 whitelist 和 blacklist:

safe_commands:
  ps:
  df:
  free:
  ip:
    args:
      blacklist: [add, del, set, flush]
  dmesg:
    args:
      blacklist: [-C, --clear, -c]

dangerous_commands:
  kill:
  systemctl:
  awk:
  sed:

settings:
  allow_pipes: true
  max_command_length: 1000
  default_timeout: 30

命令类别

  • 安全命令:只读诊断工具(ps、df、free等)
  • 危险指令:可以修改系统状态(kill、systemctl)或执行任意命令(awk、sed),需要 allow_dangerous=true
  • 不在allowlist:自动拒绝(rm、关机等)

按命令参数限制

每个命令都可以定义 whitelist 和 blacklist 在...之下 args:

  • 白名单:如果设置,则只允许这些确切的参数
  • 黑名单:如果设置,这些参数将被阻止(支持精确匹配, --flag=value,并组合短旗,如 -Cl 匹配 -C)

两者可以结合使用——首先检查白名单,然后检查黑名单。

黑名单匹配示例:

  • 精确匹配: -C 块 dmesg -C
  • 带值的长标志: --vacuum-size 块 journalctl --vacuum-size=100M
  • 组合短旗: -C 块 dmesg -Cl
  • 子命令: add, set 块 ip addr add, ip link set

安全

此服务器通过构造消除了shell注入:

  • 结构化输入:AI将程序名称和参数作为单独的JSON字段提供,从不提供原始shell字符串
  • 自动逃逸:每个令牌都通过 shlex.quote() 在到达外壳之前。最终命令中唯一的shell运算符是 | 服务器本身插入的字符
  • 程序名称验证:程序名称必须匹配 ^[a-zA-Z0-9_][a-zA-Z0-9_.+-]*$ --没有像这样的路径 /bin/bash,没有shell运算符
  • 允许名单执行:仅命令在 safe_commands 或 dangerous_commands 被允许
  • 每个命令参数白名单/黑名单:根据每个命令限制或阻止特定参数
  • 无测序操作员:仅管道(|)支持--否 &&, ||,或 ;AI可以进行多个工具调用以进行顺序操作