Skip to main content
Glama

SSH MCP 服务器(安全版)

npm 版本 CI/CD 许可证:MIT

这是 zibdie/SSH-MCP-Server 的一个安全分支,具备命令白名单/黑名单过滤、网络设备支持和批量连接管理功能,可通过 MCP(模型上下文协议)实现安全的远程服务器管理。

主要特性

  • 一次性执行ssh_run 在单次工具调用中完成连接、执行命令和断开连接——无需传递 connectionId

  • 命令白名单/黑名单:控制可执行的命令

  • 危险模式检测:阻止 fork 炸弹、命令注入和破坏性模式

  • 网络设备支持:Cisco、Juniper、MikroTik、FortiGate、Palo Alto、Sophos,支持持久化 shell 会话和自动分页抑制

  • 跳转 Shell 支持:SSH 连接到主机后进入嵌套 CLI(telnet 到主机、FreeSWITCH fs_cli 等)——命令在嵌套 shell 内执行,并提供有序的跳转命令回退列表

  • 批量连接管理:从 CSV/JSON 文件加载数十个连接

  • 环境变量凭据:密码通过 connectionId 自动从环境变量解析——聊天中不出现任何机密信息

  • 多连接执行:可同时在所有或选定的连接上运行命令

  • 连接健康监控:keepalive 跟踪、死连接检测、自动清理

  • 可配置安全策略:通过配置文件或环境变量设置

  • 审计日志:记录所有被阻止的命令尝试

Related MCP server: SSH MCP Server

安装

快速设置(推荐)

# Add to Claude CLI
claude mcp add ssh-mcp-secured npx '@marian-craciunescu/ssh-mcp-server-secured@latest'

手动安装

npm install -g @marian-craciunescu/ssh-mcp-server-secured
{
  "mcpServers": {
    "ssh-mcp-secured": {
      "command": "ssh-mcp-server-secured"
    }
  }
}

使用方法

1. 单个连接

使用 ssh_connect 连接到主机。您只需提供主机、用户名和 connectionId——密码会自动从环境变量中解析:

Connect to host 172.168.0.2 with user admin connectionId=router1

LLM 调用 ssh_connect 时使用:

{
  "host": "172.168.0.2",
  "username": "admin",
  "deviceType": "cisco",
  "connectionId": "router1"
}

工具调用中不包含密码。 服务器会自动从环境变量中查找 ROUTER1_PASSWORD

凭据解析约定

connectionId 会转换为环境变量前缀:转换为大写,非字母数字字符替换为 _

connectionId

密码的环境变量

启用密码的环境变量

router1

ROUTER1_PASSWORD

ROUTER1_ENABLE_PASSWORD

my-connection

MY_CONNECTION_PASSWORD

MY_CONNECTION_ENABLE_PASSWORD

dc1.switch.3

DC1_SWITCH_3_PASSWORD

DC1_SWITCH_3_ENABLE_PASSWORD

可选地,如果未提供用户名,也会解析 <PREFIX>_USERNAME

在 MCP 配置中设置凭据:

{
  "mcpServers": {
    "ssh-mcp-secured": {
      "command": "ssh-mcp-server-secured",
      "env": {
        "SSH_FILTER_MODE": "blacklist",
        "ROUTER1_PASSWORD": "admin123",
        "ROUTER1_ENABLE_PASSWORD": "enable123",
        "SERVER1_PASSWORD": "rootpass",
        "SERVER1_USERNAME": "root"
      }
    }
  }
}

凭据存放在 MCP 配置中(或通过 CI/CD、vault 等注入),绝不会出现在聊天或工具调用中。如果在工具调用中显式提供了密码,则优先于环境变量。

旧设备的 SSH 选项

当连接到需要非默认算法的旧设备时(相当于 ssh -o),请使用 sshOptions 参数:

用自然语言描述:

以用户身份连接到 10.0.0.1 端口 2222,connectionId 为 old-switch,使用 KexAlgorithms +diffie-hellman-group-exchange-sha1 和 HostKeyAlgorithms +ssh-rsa

{
  "host": "10.0.0.1",
  "port": 2222,
  "username": "admin",
  "connectionId": "old-switch",
  "sshOptions": {
    "KexAlgorithms": "+diffie-hellman-group-exchange-sha1",
    "HostKeyAlgorithms": "+ssh-rsa"
  }
}

这相当于:

ssh -p 2222 admin@10.0.0.1 -o KexAlgorithms=+diffie-hellman-group-exchange-sha1 -o HostKeyAlgorithms=+ssh-rsa

在值前加 + 表示追加到 ssh2 默认值。不加 + 时,该值将完全替换默认值。

选项

SSH2 等效项

使用场景

KexAlgorithms

algorithms.kex

旧式密钥交换(例如 diffie-hellman-group1-sha1

HostKeyAlgorithms

algorithms.serverHostKey

旧式主机密钥(例如 ssh-rsassh-dss

Ciphers

algorithms.cipher

旧式加密算法(例如 aes128-cbc

MACs

algorithms.hmac

旧式 MAC(例如 hmac-sha1

sshOptions 支持在 ssh_connectssh_connect_with_jump_command 以及通过 ssh_load_connections 加载的 JSON 文件中使用。

键盘交互认证会自动启用(tryKeyboard: true)。拒绝标准密码认证并要求 keyboard-interactive 的旧设备无需额外配置即可正常工作。

2. 从文件批量连接

使用 ssh_load_connections 从 CSV 或 JSON 文件加载多个连接。密码使用相同的 connectionId 约定从环境变量解析:

CSV 格式connections.csv):

host,username,port,deviceType,connectionId
172.168.0.2,admin,22,cisco,router1
10.1.2.15,noc,22,cisco,router2
192.168.1.1,root,22,linux,server1

文件中不包含密码。服务器会从环境变量中解析 ROUTER1_PASSWORDROUTER2_PASSWORDSERVER1_PASSWORD

注意:CSV 无法承载对象,因此旧设备的 SSH 选项必须通过单独的环境变量或 JSON 文件设置。

JSON 格式connections.json):

[
  {
    "host": "172.168.0.2",
    "username": "admin",
    "deviceType": "cisco",
    "connectionId": "router1"
  },
  {
    "host": "10.1.2.15",
    "username": "noc",
    "deviceType": "cisco",
    "connectionId": "router2",
    "sshOptions": {
      "KexAlgorithms": "+diffie-hellman-group-exchange-sha1",
      "HostKeyAlgorithms": "+ssh-rsa"
    }
  }
]

配置文件: 定义可复用的连接配置文件,用于连接具有相似设置的同类设备(例如所有 Cisco 交换机)。 配置文件可以包含旧设备的默认 SSH 选项,这样您就不必在每个连接中重复设置。

解析优先级: 显式参数 > 配置文件环境变量 > connectionId 环境变量

export PROFILE_CISCO_USER=admin
export PROFILE_CISCO_PASSWORD=secret123
export PROFILE_CISCO_DEVICE_TYPE=cisco
export PROFILE_CISCO_PORT=2222
export PROFILE_CISCO_SSH_OPTIONS='{"KexAlgorithms":"+diffie-hellman-group-exchange-sha1","HostKeyAlgorithms":"+ssh-rsa"}'

以下是加载 CSV/JSON 连接时配置文件环境变量如何解析的示例。PROFILE_CISCO_SSH_OPTIONS 的值会解析为 JSON,并应用于所有 deviceTypecisco 的连接。

环境变量示例

字段

PROFILE_CISCO_USER

username

admin

PROFILE_CISCO_PASSWORD

password

secret123

PROFILE_CISCO_DEVICE_TYPE

deviceType

cisco

PROFILE_CISCO_SSH_OPTIONS

sshOptions(解析为 JSON)

{"KexAlgorithms":"+diffie-hellman-group-exchange-sha1","HostKeyAlgorithms":"+ssh-rsa"}

PROFILE_CISCO_JUMP_COMMAND

jumpCommand

telnet lh

PROFILE_CISCO_PRESET

preset

topex

PROFILE_CISCO_PORT

port

2222

PROFILE_CISCO_WHITELIST

按配置文件划分的命令白名单(逗号分隔或 JSON 数组)

show ospf neigh,show version

PROFILE_CISCO_BLACKLIST

按配置文件划分的命令黑名单(逗号分隔或 JSON 数组)

show running config,conf t

PROFILE_CISCO_DISABLE_PAGER

按配置文件划分的分页开关(true/false

false

ssh_connect host=10.0.0.1 profile=CISCO connectionId=SWITCH1"

按配置文件划分的命令过滤

除了全局的 SSH_WHITELIST / SSH_BLACKLIST 之外,每个配置文件还可以通过 PROFILE_<NAME>_WHITELISTPROFILE_<NAME>_BLACKLIST 携带自己的命令过滤器。这些过滤器在执行时叠加在全局过滤器之上,适用于使用该配置文件打开的任何连接:

  • 配置文件黑名单始终阻止——即使全局过滤器允许的命令也会被阻止(例如阻止 show running config)。

  • 配置文件白名单重新允许特定命令,并且当存在时具有权威性:未列出的任何内容都会被阻止(例如允许 show ospf neigh,而黑名单仍然阻止其余命令)。

  • 在直接冲突时,黑名单优先

export PROFILE_ROUTERS_BLACKLIST="show running config,conf t,configure terminal"
export PROFILE_ROUTERS_WHITELIST="show ospf neigh,show version,show ip interface brief"
ssh_connect host=10.0.0.1 profile=ROUTERS connectionId=router1
# show ospf neigh        → allowed (profile whitelist)
# show running config    → blocked (profile blacklist)

PROFILE_<NAME>_DISABLE_PAGER=false 会关闭使用该配置文件的连接的分页抑制功能,覆盖全局的 SSH_DISABLE_PAGER 默认值。

用法:

Load connections from /path/to/connections.csv and connect to all

注意: 如果您愿意,仍然可以直接在 CSV/JSON 中提供密码——环境变量解析仅在密码字段缺失或为空时生效。

3. 网络设备类型

服务器支持不同的设备类型,并采用相应的连接处理方式:

设备类型

行为

使用场景

linux

标准 SSH exec 模式(默认)

Linux/Unix 服务器

cisco

持久化 shell,支持启用模式

Cisco IOS/IOS-XE 路由器和交换机

cisco_xe

持久化 shell(terminal length 0

Cisco IOS-XE

cisco_xr

持久化 shell(terminal length 0

Cisco IOS-XR

cisco_asa

持久化 shell(terminal length 0

Cisco ASA 防火墙

cisco_nexus

持久化 shell(terminal length 0

Cisco Nexus(NX-OS)

juniper

持久化 shell(set cli screen-length 0

Juniper JunOS 设备

mikrotik

持久化 shell

MikroTik RouterOS

fortinet

持久化 shell(config system console / set output standard

FortiGate / FortiOS 防火墙

paloalto

持久化 shell(set cli pager off

Palo Alto PAN-OS 防火墙

sophos

持久化 shell(运行时自动处理分页)

Sophos XG/XGS(SFOS)防火墙

network

通用持久化 shell

其他网络设备

jump_shell

持久化 shell + 嵌套 CLI

ssh_connect_with_jump_command 内部使用

网络设备使用分配了 PTY 的持久化 shell 会话,而不是标准的 exec(),因为许多网络操作系统会在每次 exec 命令后关闭 SSH 通道。

4. 一次性命令(ssh_run

ssh_connect + ssh_execute + ssh_disconnect 需要三次工具调用,而且中间两次要求模型逐字复制生成的 connectionId。ssh_run 将其合并为一次调用:

{
  "host": "10.1.2.15",
  "profile": "ROUTERS",
  "command": "show version"
}

连接、运行命令并关闭连接。返回命令输出——无需跟踪 connectionId。

失败时连接保持打开,以便您可以重试其他命令。结果是一个结构化对象(同时以 JSON 文本和 structuredContent 形式返回):

{
  "status": "error",
  "connectionId": "10_1_2_15_2026_08_12_sessionid_a1b2c3",
  "command": "show bogus",
  "error": "Command exited with code 2",
  "exitCode": 2,
  "output": "% Invalid input detected",
  "retry": "The SSH connection is still open. Call ssh_execute with this connectionId to run a different command, then ssh_disconnect when finished."
}

使用该 connectionId 重试 ssh_execute,然后执行 ssh_disconnect。被遗弃的连接由 SSH_IDLE_TIMEOUT(默认 120 秒)回收。

配置文件、白名单/黑名单、主机过滤、审计日志、分页器处理以及大输出卸载的行为均与 ssh_connect + ssh_execute 完全一致。被过滤器阻止的命令会在任何 SSH 会话建立之前被拒绝。

成功定义为:命令已执行且其退出码为 0 或不存在。持久化 shell 路径上的网络设备不报告退出码,因此除非执行本身失败,否则这些命令视为成功。在 Linux 上,非零退出码计为失败并保持连接打开。

带跳转的嵌套 CLI(ssh_run_with_jump

与单次调用流程相同,但首先进入嵌套 CLI。jumpCommands 是一个按顺序尝试的列表,直到其中一个到达嵌套提示符:

{
  "host": "10.0.0.1",
  "username": "admin",
  "preset": "topex",
  "jumpCommands": ["telnet lh", "telnet 127.0.0.1"],
  "command": "view portsoncard *"
}

如果 telnet lh 未能到达提示符,则尝试 telnet 127.0.0.1。每次尝试都是一个新的连接,因此失败尝试产生的半开 telnet 不会破坏下一次尝试。如果所有候选都失败,错误信息会列出每个候选的返回结果。

所有候选共享同一个 jumpPromptPattern(直接提供或通过 preset 提供)。当候选需要不同的提示符模式时,请改用 ssh_connect_with_jump_command。当省略 jumpCommands 时,PROFILE_<NAME>_JUMP_COMMAND 提供单个候选。

5. 在多个连接上执行

使用 ssh_execute_on_multiple 在特定连接上运行命令:

{
  "command": "show version",
  "connectionIds": ["router1", "router2", "switch1"]
}

或者在所有连接上运行:

{
  "command": "show ip interface brief",
  "connectionIds": ["*"]
}

6. 跳转 Shell(通过 SSH 嵌套 CLI)

当您需要先 SSH 登录主机,然后在执行命令之前进入嵌套交互式 shell 时,请使用 ssh_connect_with_jump_command。这适用于以下场景:

  • 从 SSH 跳转主机 Telnet 到 Topex VoIP 网关

  • 在远程服务器上使用 FreeSWITCH fs_cli

  • 任何需要在 SSH 之后进行交互式会话的 CLI

工作原理:

SSH → open shell → send jump command (e.g. "telnet lh") → wait for nested prompt (e.g. "topexsw>") → ready

connectionId 上的所有后续 ssh_execute 命令都在嵌套 shell 内运行。

Topex 网关示例(使用预设):

{
  "host": "10.0.0.1",
  "username": "admin",
  "connectionId": "topex1",
  "preset": "topex",
  "jumpCommand": "telnet lh"
}

topex 预设自动填充 jumpPromptPattern: "topexsw>\\s*$"jumpExitCommand: "quit"。您只需提供 jumpCommand

然后在 Topex CLI 内执行命令:

{
  "command": "view portsoncard *",
  "connectionId": "topex1"
}

FreeSWITCH 示例(预设填充所有内容):

{
  "host": "10.0.0.5",
  "username": "root",
  "connectionId": "fs1",
  "preset": "freeswitch"
}

freeswitch 预设自动填充 jumpCommand: "fs_cli"jumpPromptPattern: "freeswitch@...>"jumpExitCommand: "/exit"。然后:

{
  "command": "sofia status",
  "connectionId": "fs1"
}

完全自定义(无预设):

{
  "host": "10.0.0.1",
  "username": "admin",
  "connectionId": "custom1",
  "jumpCommand": "telnet 192.168.1.100",
  "jumpPromptPattern": ">\\s*$",
  "jumpExitCommand": "quit",
  "jumpReadyTimeout": 8000
}

内置预设:

预设

jumpCommand

提示符模式

退出命令

freeswitch

fs_cli

freeswitch@...>

/exit

topex

(用户提供)

topexsw>

quit

预设可以被覆盖——任何显式提供的参数优先。

Shell 恢复: 如果 shell 断开,ssh_execute 会自动重新打开 shell 并重新进入跳转 shell。

断开连接: ssh_disconnect 会在关闭 SSH 连接之前优雅地向嵌套 CLI 发送退出命令。

7. 日志记录

通过环境变量设置日志级别:

变量

默认值

SSH_LOG_LEVEL

DEBUG、INFO、WARN、ERROR

INFO

SSH_LOG_FILE

日志文件路径

(无)

日志格式:

[2026-01-22T20:26:02.044Z] [INFO ] ✓ SSH connection established to 172.168.0.2:22
[2026-01-22T20:26:02.046Z] [DEBUG] ♥ Keepalive #1 sent to 172.168.0.2 | {"uptime":"10s"}
[2026-01-22T20:26:12.047Z] [WARN ] ⚠ CONNECTION CLOSED BY REMOTE HOST: router1

配置

环境变量

变量

默认值

描述

SSH_FILTER_MODE

whitelistblacklistdisabled

blacklist

命令过滤模式

SSH_ALLOW_SUDO

truefalse

true

允许 sudo 命令

SSH_LOG_BLOCKED

truefalse

true

将被阻止的命令记录到 stderr

SSH_MCP_CONFIG

文件路径

-

配置文件 JSON 路径

SSH_WHITELIST

逗号分隔或 JSON

-

覆盖白名单命令

SSH_BLACKLIST

逗号分隔或 JSON

-

覆盖黑名单命令

SSH_DANGEROUS_PATTERNS

JSON 数组

-

覆盖危险正则模式

SSH_LOG_LEVEL

DEBUGINFOWARNERROR

INFO

日志级别

SSH_LOG_FILE

路径

-

日志文件

SSH_HOST_FILTER_MODE

whitelist、blacklist、disabled

disabled

主机过滤模式

SSH_HOST_WHITELIST

逗号分隔的 IP

-

允许的主机 IP 白名单

SSH_HOST_BLACKLIST

逗号分隔的 IP

-

禁止的主机 IP 黑名单

SSH_IDLE_TIMEOUT

120

空闲连接超时

SSH_FAILED_CONNECTIONS_LOG

文件路径

./ssh-failed-connections.json

记录失败连接尝试的 JSON 文件

SSH_AUDIT_ENABLED

truefalse

true

将每次命令会话审计(命令 + 完整输出)写入 JSONL

SSH_AUDIT_DIR

路径

./audit

每日 audit_YYYY-MM-DD.jsonl 文件的目录

SSH_ENABLE_LARGE_OUTPUT

truefalse

false

将过大的命令输出卸载到上传端点,并返回 URI 而非内联文本

SSH_MAX_OUTPUT_LENGTH

整数(字符)

10000

超过此大小的输出将被卸载

SSH_FILE_UPLOAD_ENDPOINT

URL

-

大输出 POST 目标。接收 {content, filename},必须返回 {file_id, artifact_uri}

SSH_DISABLE_PAGER

truefalse

true

在 shell 和 exec 中抑制交互式分页器(less/---(more)---

SSH_DISABLE_PAGER_CMD_<DEVICETYPE>

字符串

按设备类型默认

覆盖特定设备类型(如 SSH_DISABLE_PAGER_CMD_CISCO)的禁用分页器命令

SSH_PAGER_REGEX

正则字符串

内置

覆盖用于检测分页器提示符的模式

SSH_PAGER_ADVANCE_KEY

字符串

" "(空格)

发送以翻到下一页分页器内容的按键

SSH_MAX_PAGER_PAGES

整数

1000

每条命令自动翻页的安全上限

任何遵循 <CONNECTIONID>_PASSWORD 约定的额外环境变量都会自动用于凭据解析(参见 凭据解析约定)。

MCP 配置示例

主机白名单/黑名单:

黑名单模式及自定义被阻止命令:

{
  "ssh_mcp": {
    "command": "ssh-mcp-server-secured",
    "args": [],
    "env": {
      "SSH_FILTER_MODE": "blacklist",
      "SSH_ALLOW_SUDO": "true",
      "SSH_LOG_BLOCKED": "true",
      "SSH_BLACKLIST": "rm,rmdir,mkfs,fdisk,shutdown,reboot,halt,poweroff,passwd,useradd,userdel,iptables,crontab,conf t,configure terminal"
    }
  }
}

白名单模式(严格——仅允许特定命令):

{
  "ssh_mcp": {
    "command": "ssh-mcp-server-secured",
    "args": [],
    "env": {
      "SSH_FILTER_MODE": "whitelist",
      "SSH_ALLOW_SUDO": "false",
      "SSH_LOG_BLOCKED": "true",
      "SSH_WHITELIST": "ls,cat,grep,tail,head,df,du,free,uptime,ps,systemctl,journalctl,docker,kubectl,ping,curl,dig,ss,netstat,show,display"
    }
  }
}

带凭据环境变量的网络操作:

{
  "ssh_mcp": {
    "command": "ssh-mcp-server-secured",
    "args": [],
    "env": {
      "SSH_FILTER_MODE": "blacklist",
      "SSH_ALLOW_SUDO": "true",
      "SSH_LOG_LEVEL": "DEBUG",
      "SSH_BLACKLIST": "conf t,configure terminal,rm,shutdown,reboot",
      "ROUTER1_PASSWORD": "admin123",
      "ROUTER1_ENABLE_PASSWORD": "enable123",
      "ROUTER2_PASSWORD": "pass123",
      "SERVER1_PASSWORD": "pass1234"
    }
  }
}

现在在聊天中您只需说 connect to 172.168.0.2 as admin connectionId=router1——无需暴露密码。

通过 npx(无需全局安装):

{
  "ssh_mcp": {
    "command": "npx",
    "args": ["@marian-craciunescu/ssh-mcp-server-secured"],
    "env": {
      "SSH_FILTER_MODE": "blacklist",
      "SSH_ALLOW_SUDO": "true"
    }
  }
}

配置文件

创建 config.jsonssh-mcp-config.json

{
  "commandFilter": {
    "mode": "whitelist",
    "allowSudo": false,
    "logBlocked": true,
    "whitelist": [
      "ls", "cat", "grep", "df", "ps", "systemctl", "docker", "show", "ping"
    ],
    "blacklist": [
      "rm", "shutdown", "reboot", "passwd", "conf t", "configure terminal"
    ],
    "dangerousPatterns": [
      ";\\s*rm\\s+-rf",
      "curl.*\\|\\s*bash"
    ]
  }
}

过滤模式

黑名单模式(默认)

黑名单中的命令被阻止。其他所有命令均被允许。支持多词条目,如 configure terminalconf t

✓ ls -la
✓ docker ps
✓ show ip interface brief
✗ rm -rf /tmp/files       → Blocked: 'rm' is in blacklist
✗ configure terminal      → Blocked: 'configure terminal' is in blacklist
✗ shutdown now            → Blocked: 'shutdown' is in blacklist

白名单模式

仅允许白名单中的命令。其他所有命令均被阻止。

✓ ls -la                  → Allowed: 'ls' is whitelisted
✓ show version            → Allowed: 'show' is whitelisted
✗ vim /etc/hosts          → Blocked: 'vim' not in whitelist
✗ make install            → Blocked: 'make' not in whitelist

混合模式

两个列表同时生效,过滤器采用默认拒绝策略:命令必须匹配白名单条目才能运行。发生冲突时,最长的匹配条目胜出,无论它来自哪个列表。这就是为什么您可以允许一个宽泛的前缀、从中剔除危险的子集、然后再允许一个更窄的例外。

匹配基于前缀:当命令等于条目,或以条目开头后跟空格、制表符或换行符时,即视为匹配。比较时会将内容转为小写并去除首尾空白。

SSH_FILTER_MODE=mixed
SSH_WHITELIST=show, show running-config interface, show running-config | include, ping -c , ls -lha, terminal length 0
SSH_BLACKLIST=show running-config, conf t, configure terminal, reload, rm, shutdown, ping

最终决策:

✓ show version                            → 'show' (4) beats nothing
✓ show interfaces terse                   → 'show' (4) beats nothing
✗ show running-config                     → 'show running-config' (19) beats 'show' (4)
✓ show running-config interface Gi0/1     → 'show running-config interface' (29) beats 'show running-config' (19)
✓ show running-config | include hostname  → 'show running-config | include' (29) beats 'show running-config' (19)
✓ ping -c 4 8.8.8.8                       → 'ping -c' (7) beats 'ping' (4)
✗ ping 8.8.8.8                            → only 'ping' (4) matches, and it is blacklisted
✓ terminal length 0                       → whitelisted, so the server can disable its own pager
✓ ls -lha                                 → exact whitelist entry
✗ ls -la                                  → matches NEITHER list → blocked by deny-by-default
✗ reload                                  → blacklisted, no whitelist match
✗ rm -rf /tmp/x                           → 'rm' (2) blacklisted, no whitelist match

有两点需要了解:

  • ls -lha 被允许,但 ls -la 不被允许。 白名单条目是字面前缀,而非模式。在混合模式下,任何您未显式允许的内容都会被阻止,因此请列出您打算运行的确切命令形式。

  • 完全相同时白名单胜出。 如果同一个字符串同时出现在两个列表中,该命令被允许。

请将您的禁用分页器命令(terminal length 0set cli screen-length 0)包含在白名单中。服务器在打开 shell 时会自行发出这些命令,而混合模式否则会阻止它们。

与黑名单和白名单模式不同,混合模式不会检查管道或命令链的各个分段——它只匹配完整的命令字符串。混合模式下的分段级保护来自危险模式列表,该列表首先运行且无法被覆盖:

✗ show version | rm -rf /   → Blocked: dangerous pattern /\|\s*rm/i

禁用模式

不进行命令过滤(请谨慎使用)。

命令验证顺序

  1. 检查过滤是否已禁用

  2. 检查 sudo 权限

  3. 检查危险模式(正则表达式)——始终优先,任何白名单都无法覆盖

  4. mixed 模式下:对完整命令进行白名单和黑名单的最长匹配;若两者均不匹配则默认拒绝。在此结束。

  5. 对完整命令进行黑名单检查(支持多词)

  6. 从管道/命令链中提取基础命令

  7. 对每个基础命令进行黑名单/白名单检查

  8. 在全局结果之上应用按配置文件(按连接)的白名单/黑名单

使用 ssh_get_command_filter 查看当前生效的规则,并查询特定命令是否会被允许或阻止。

稳定的连接 ID

如果你没有向 ssh_connect 传递 connectionId(或传递 default),服务器会生成一个稳定的、结构化的 ID,并在连接响应中返回它

<IP>_YYYY_MM_DD_sessionid_<6 random chars>

示例:10_0_0_1_2026_06_08_sessionid_a1b9f3

IP 中的点被替换为 _,因此该 ID 可以安全地用作环境变量前缀(用于 <PREFIX>_PASSWORD 解析)和文件名。请捕获返回的 connectionId,并在后续的 ssh_execute / ssh_disconnect 调用中复用。

会话审计(命令 + 输出)

每条已执行命令及其输出都会作为一行 JSONL 写入按日生成的文件中,与服务器诊断日志(SSH_LOG_FILE)分开:

<SSH_AUDIT_DIR>/audit_YYYY-MM-DD.jsonl

每条记录:

{"timestamp":"2026-06-08T11:07:12.569Z","connectionId":"10_0_0_1_2026_06_08_sessionid_a1b9f3","host":"10.0.0.1","command":"show version","exitCode":0,"output":"..."}

使用 SSH_AUDIT_ENABLED=false 禁用。

大输出卸载

当命令输出超过 SSH_MAX_OUTPUT_LENGTHSSH_ENABLE_LARGE_OUTPUT=true 时,完整输出会被 POST 到 SSH_FILE_UPLOAD_ENDPOINT,调用方会收到一个包含返回的 artifact_urifile_id 以及一小段预览的简短摘要——这样庞大的 show tech-support 输出就不会淹没模型上下文。端点接收 { "content": "...", "filename": "..." },必须返回 { "file_id": "...", "artifact_uri": "..." }。如果端点未设置或上传失败,输出将以内联方式返回作为回退。

分页器处理

交互式分页器(Linux less、Cisco/Juniper ---(more)---)否则会阻塞命令直到超时。服务器通过两种方式处理:

  • 预防——在打开 shell 时发送适合设备的禁用分页器命令(Cisco 使用 terminal length 0,Juniper 使用 set cli screen-length 0),在 Linux exec 时设置 SYSTEMD_PAGER=PAGER=catGIT_PAGER=cat

  • 检测——如果分页器提示符仍然出现,则自动前进(发送空格,上限由 SSH_MAX_PAGER_PAGES 控制)用于网络 shell,或发送 q 退出交互式 Linux 分页器,然后从输出中剥离提示符痕迹。

使用 SSH_DISABLE_PAGER=false 全局切换,使用 PROFILE_<NAME>_DISABLE_PAGER=false 按配置文件切换,使用 SSH_DISABLE_PAGER_CMD_<DEVICETYPE> 按设备类型覆盖命令,使用 SSH_PAGER_REGEX / SSH_PAGER_ADVANCE_KEY 覆盖检测。

危险模式

以下模式始终被阻止,无论过滤模式如何:

模式

示例

风险

Fork 炸弹

:(){ :|:& };:

系统崩溃

管道 rm

find . | rm

数据丢失

链式 rm

ls && rm -rf /

数据丢失

设备重定向

> /dev/sda

磁盘损坏

系统配置覆盖

> /etc/passwd

系统受损

远程代码执行

curl | bash

任意代码执行

递归 chmod 777

chmod -R 777 /

安全受损

可用工具

一次性(推荐)

工具

描述

ssh_run

连接、运行一条命令并在成功后关闭连接——一次调用,无需跟踪 connectionId。失败时连接保持打开,并返回其 connectionId,以便你可以使用 ssh_execute 重试不同的命令。必需:hostcommand

ssh_run_with_jump

ssh_run 相同,但先进入嵌套 CLI。将 jumpCommands 作为列表传入,并按顺序尝试,直到其中一个到达嵌套提示符。必需:hostcommand

连接管理

工具

描述

ssh_connect

打开持久连接并返回 connectionId。密码自动从 <CONNECTIONID>_PASSWORD 环境变量解析;支持 sshOptions 用于旧算法协商。

ssh_connect_with_jump_command

SSH 进入主机,然后通过单个跳转命令进入嵌套 CLI(telnet、fs_cli 等)。支持预设。当每个候选需要自己的提示符模式时使用此工具。

ssh_load_connections

从 CSV/JSON 文件加载连接(凭据按 connectionId 从环境变量解析)。

ssh_disconnect

断开一个连接。

ssh_disconnect_all

断开所有连接。

执行

工具

描述

ssh_execute

在现有连接上运行命令。必需:commandconnectionId

ssh_execute_on_multiple

在选定的连接上运行命令(["*"][] = 全部)。按顺序运行。

状态与内省

工具

描述

ssh_get_command_filter

显示适用于连接的命令过滤器(白名单/黑名单,全局 + 按配置文件,含优先级规则)和主机过滤器(允许/阻止的主机);可选地检查特定命令是否会被允许。

ssh_list_connections

列出活动连接及其状态。

ssh_check_connections

对所有连接进行健康检查(死套接字检测、shell 状态)。

ssh_failed_connections

列出最近的失败连接尝试(来自 failed-connections JSONL 日志)。

文件传输(SFTP)

工具

描述

ssh_upload_file

通过 SFTP 上传文件。

ssh_download_file

通过 SFTP 下载文件。

ssh_list_files

通过 SFTP 列出远程目录。

示例工作流

单条命令(一次调用)

→ ssh_run {
    host: "172.168.0.2",
    profile: "ROUTERS",
    command: "show version"
  }
  (connects, runs, closes; returns the output)

嵌套 CLI 中的单条命令(一次调用)

→ ssh_run_with_jump {
    host: "10.0.0.1",
    username: "admin",
    preset: "topex",
    jumpCommands: ["telnet lh", "telnet 127.0.0.1"],
    command: "view portsoncard *"
  }

失败后重试

1. → ssh_run { host: "172.168.0.2", profile: "ROUTERS", command: "show bogus" }
   ← { status: "error", connectionId: "172_168_0_2_..._sessionid_a1b2c3", exitCode: 2, ... }
     (connection left open)

2. → ssh_execute {
       command: "show interfaces terse",
       connectionId: "172_168_0_2_..._sessionid_a1b2c3"
     }

3. → ssh_disconnect { connectionId: "172_168_0_2_..._sessionid_a1b2c3" }

批量操作(持久连接)

1. Load connections from CSV (passwords auto-resolved from env vars)
   → ssh_load_connections { filePath: "devices.csv", connectAll: true }
   (ROUTER1_PASSWORD, ROUTER2_PASSWORD resolved automatically)

2. Execute show commands on all devices
   → ssh_execute_on_multiple {
       command: "show ip interface brief",
       connectionIds: ["*"]
     }

3. Execute a command on one specific router
   → ssh_execute {
       command: "show running-config | include hostname",
       connectionId: "router1"
     }

4. Check connection health
   → ssh_check_connections {}

5. Inspect why a command was blocked
   → ssh_get_command_filter {
       connectionId: "router1",
       command: "configure terminal"
     }

6. Disconnect all
   → ssh_disconnect_all {}

架构说明

Shell 缓冲区管理

每条命令执行前都会清除缓冲区。稳定性检测使用缓冲区在 3 × 500ms 内保持不变 = 命令完成。密码提示符在缓冲区最后 200 个字符中检测。

保活系统

SSH2 每 10 秒发送一次保活(keepaliveInterval: 10000)。3 次保活失败后,连接自动关闭(keepaliveCountMax: 3)。自定义间隔记录保活计数用于调试。

连接健康监控

服务器检测死连接(套接字已销毁)、跟踪网络设备的 shell 状态、自动清理死连接,并在网络设备的 shell 已关闭时尝试重新打开 shell。

跳转 Shell

当调用 ssh_connect_with_jump_command 时,服务器:(1) 打开 SSH 连接,(2) 打开 PTY shell,(3) 发送跳转命令(例如 telnet lh),(4) 每 300ms 轮询 shell 缓冲区以匹配预期的提示符正则表达式,(5) 将连接标记为 jump_shell 并设置 jumpShellActive: true。断开连接时,在关闭 SSH 会话前发送嵌套 CLI 退出命令。在 shell 恢复时,自动重新发送跳转命令。

环境变量凭据解析

创建连接时(通过 ssh_connectssh_load_connections),如果未提供密码,服务器会自动从环境变量中查找 <PREFIX>_PASSWORD,其中 <PREFIX> 是 connectionId 的大写形式,非字母数字字符替换为 _。相同的约定适用于 _ENABLE_PASSWORD_USERNAME。显式提供的值始终优先。

与原版的比较

功能

zibdie/SSH-MCP-Server

本分支

基础 SSH/SFTP

命令白名单

命令黑名单

多词黑名单条目

危险模式检测

审计日志

命令验证工具

配置文件支持

网络设备类型(Cisco、Juniper、MikroTik)

Cisco enable 模式

跳转 shell(通过 SSH 的嵌套 CLI)

从 CSV/JSON 批量连接

多连接执行

环境变量凭据

连接健康监控

Keepalive 跟踪

host/hostname 兼容性

开发

# Clone
git clone https://github.com/marian-craciunescu/ssh-mcp-server-secured.git
cd ssh-mcp-server-secured

# Install dependencies
npm install

# Run in development mode
npm run dev

# Test with MCP Inspector
npx @modelcontextprotocol/inspector node index.js

安全考虑

  • 默认采用黑名单模式 — 在保持灵活性的同时提供保护

  • 始终检查危险模式 — 即使在禁用模式下也会检查

  • 默认启用审计日志 — 跟踪被阻止的尝试

  • 可限制 sudo — 在高安全环境中设置 SSH_ALLOW_SUDO=false

  • 凭据隔离 — 密码通过 connectionId 从环境变量解析,绝不会在聊天中键入或在工具调用中可见

许可证

MIT — 参见 LICENSE 文件

致谢

支持

A
license - permissive license
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
2wRelease cycle
18Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    A
    quality
    F
    maintenance
    A server based on the MCP framework that provides remote server management capabilities through SSH, supporting features like connection pooling, file transfers, and remote command execution.
    7
  • A
    license
    A
    quality
    C
    maintenance
    A secure remote server management tool based on MCP protocol, supporting SSH connections, command execution, and SFTP file transfers.
    20
    41
    6
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    An MCP server for SSH/SCP operations with passwordless authentication, enabling remote command execution, file transfer, and session management.
    19
    23
    MIT

View all related MCP servers

Related MCP Connectors

  • An MCP server for deep research or task groups

  • MCP Server for JFrog, providing tools for development and artifact management.

  • An authenticated remote MCP server for user-owned devices and one-shot capability invocation.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/marian-craciunescu/ssh-mcp-server-secured'

If you have feedback or need assistance with the MCP directory API, please join our Discord server