Skip to main content
Glama
SC-ML-cmd
by SC-ML-cmd

SSH MCP

一个不依赖 Xshell 的 Python SSH MCP Server。它由 MCP Server 自己建立交互式 SSH PTY 会话,适合 CMSM/堡垒机菜单、进入 master、进入 pod 后复用当前 shell 状态的排障流程。

能力概览

  • open_session(profile, owner_label=None):按配置打开持久 SSH 会话,并返回对应的浏览器 viewer_url

  • list_sessions():查看当前 MCP Server 实例内的活动会话和运行时信息。

  • send_text(session_id, text, enter=True, wait_for="", timeout=30):向菜单或 shell 发送文本。

  • execute_command(session_id, command, wait_for_prompt=True, timeout=30):在当前 shell 状态下执行命令。

  • get_screen(session_id, lines=100):查看内存中最近的终端输出。

  • get_transcript(session_id, tail=200):读取 JSONL 审计记录。

  • interrupt(session_id):发送 Ctrl+C

  • search_logs(...):在当前远端 shell 中执行 find + grep 日志搜索。

Related MCP server: ssh-session-mcp

架构

Claude / Codex / MCP Client
  -> ssh-mcp FastMCP Server
  -> Paramiko SSH interactive shell channel
  -> remote CMSM / master / pod shell

ssh-mcp Server
  -> runtime/instances/<server_instance_id>/logs/ssh_mcp.log
  -> runtime/instances/<server_instance_id>/transcripts/<session_id>.jsonl
  -> local browser viewer

每个 MCP Server 进程都会生成独立的 server_instance_id。多个 LLM 窗口同时启动 MCP Server 时,默认写入不同的实例目录,避免日志和 transcript 混在一起。

安装

python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e .

开发测试可直接使用:

.\.venv\Scripts\python.exe -m unittest discover -s tests -v

SSH 配置

复制配置模板:

Copy-Item .\config\profiles.example.json .\config\profiles.json

示例:

{
  "profiles": {
    "dev": {
      "host": "10.0.0.10",
      "port": 22,
      "username": "your-user",
      "key_filename": "C:/Users/you/.ssh/id_rsa",
      "passphrase_env": "SSH_MCP_KEY_PASSPHRASE",
      "allow_agent": true,
      "look_for_keys": true,
      "auto_add_host_key": true,
      "term": "xterm-256color",
      "width": 120,
      "height": 40,
      "keepalive_interval": 30
    }
  }
}

keepalive_interval 使用 Paramiko transport keepalive,只做 SSH 探活,不会向远端 shell 注入命令。

运行

直接启动:

.\.venv\Scripts\python.exe -m ssh_mcp.server --viewer-host 127.0.0.1 --viewer-port auto

常用环境变量:

  • SSH_MCP_CONFIG:profile 配置路径,默认 config/profiles.json

  • SSH_MCP_RUNTIME_DIR:运行产物根目录,默认 runtime

  • SSH_MCP_CLIENT_LABEL:当前 MCP Server 来源标签,例如 claude-order-debugcodex-local

  • SSH_MCP_KEY_PASSPHRASE:私钥口令。

  • SSH_MCP_KEEPALIVE_INTERVAL:默认 SSH keepalive 秒数,可被 profile 覆盖。

兼容旧配置:

  • 显式设置 SSH_MCP_LOG_PATH 时,运行日志写到该路径。

  • 显式设置 SSH_MCP_TRANSCRIPTS_DIR 时,transcript 写到该目录。

Claude / Codex 接入

仓库提供 .mcp.json.codex/config.toml 示例。默认建议只设置:

  • SSH_MCP_CONFIG

  • SSH_MCP_RUNTIME_DIR

  • SSH_MCP_CLIENT_LABEL

  • SSH_MCP_KEY_PASSPHRASE

不要让多个 MCP Server 固定写同一个 logs/ssh_mcp.logtranscripts/,否则排查时很难区分不同 LLM 窗口。

启动 Claude Code 前可设置:

$env:SSH_MCP_KEY_PASSPHRASE = "<your-private-key-passphrase>"
$env:SSH_MCP_CLIENT_LABEL = "claude-payment-debug"
claude

open_session 时建议传入 owner_label

{"profile": "lab", "owner_label": "payment-log-check"}

SSH_MCP_CLIENT_LABEL 标记 MCP Server 来源,owner_label 标记具体 SSH session 的用途。

浏览器 Viewer

MCP Server 启动时会同时启动本地 viewer。默认从 8765 附近自动选择可用端口。

  • /:按 server_instance_id 分组展示 sessions。

  • /sessions/<session_id>:单个 session 的终端式页面。

  • /api/sessions:返回 session 列表和 server 元数据。

  • /api/sessions/<session_id>/events:长轮询读取 transcript 增量。

open_session 会返回准确的 viewer_url,不要手动猜 session URL。

也可以只启动历史 viewer:

.\.venv\Scripts\python.exe -m ssh_mcp.viewer --port 8765 --transcripts-dir transcripts

Runtime 目录

默认结构:

runtime/
  instances/
    <server_instance_id>/
      server_meta.json
      logs/
        ssh_mcp.log
      transcripts/
        <session_id>.jsonl

server_meta.json 记录:

  • server_instance_id

  • pid

  • cwd

  • started_at

  • client_label

  • viewer_base_url

  • log_path

  • transcripts_dir

  • config_path

旧的 transcripts/*.jsonl 仍可被 viewer 读取,并标记为 legacy

Transcript 与安全

每个 SSH session 都有独立 JSONL 文件。首行是 session_meta,包含 profile、host、username、owner_label、server_instance_id、client_label、viewer_url 等信息。

示例事件:

{"dir":"session_meta","session_id":"lab-...","owner_label":"payment-log-check","server_instance_id":"ssh-mcp-..."}
{"dir":"send","tool":"send_text","text":"2\n"}
{"dir":"recv","text":"Logged in to master...\n"}
{"dir":"session_health","health_status":"unhealthy","health_error":"SSH transport is inactive"}

重要:send_text(..., sensitive=true) 不会脱敏,text 仍按原文写入 transcript。请保护 runtime/logs/transcripts/ 的文件权限。

SSH 心跳与断线处理

当前策略是“只探活,不自动重连”:

  • 使用 Paramiko transport keepalive 保持 SSH 连接活跃。

  • 后台 health monitor 定期检查 transport/channel。

  • 断开后 session 会标记为 unhealthyclosed

  • 后续 send_text / execute_command 返回可读错误。

  • 不自动重放 CMSM -> master -> pod 路径,避免误以为恢复了原始 shell 状态。

本地 CMSM 测试环境

仓库内置 CMSM simulator:

lab/cmsm_simulator/

它模拟:

CMSM 菜单 -> master shell -> kubectl exec -> pod shell

部署和测试步骤见 lab/cmsm_simulator/README.md

常见问题

为什么 viewer 端口不是 8765?

如果端口被占用,viewer 会自动选择后续可用端口。以 open_session 返回的 viewer_url 为准。

多个 Claude/Codex 窗口如何区分?

设置不同的 SSH_MCP_CLIENT_LABEL,并在 open_session 传入 owner_label。运行日志、server_meta 和 transcript 都会记录这些字段。

MCP 重启后 SSH session 还在吗?

不在。当前实现使用 Paramiko interactive shell channel,MCP Server 进程退出后 SSH 连接也会关闭。历史 transcript 会保留在 runtime 目录。

什么时候考虑 tmux?

如果需要 MCP 重启后仍能 attach 原 SSH 会话,可以在后续版本评估 tmux 底座。但 Windows 原生部署会更复杂,本项目当前优先保持 Python/Paramiko 的轻量实现。

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (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.

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/SC-ML-cmd/ssh-mcp'

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