使用说明
SSH-MCP
为任何AI代理提供安全、持久的SSH访问您的基础设施。
问题
AI代理是无状态的。每次工具调用都是一次新的执行——没有工作目录,没有连接重用,没有会话内存。当代理需要调试生产服务器时,它不能 cd 进入一个目录,运行一个命令,读取输出,然后在同一上下文中运行另一个命令。传统方法为每个命令启动一个新的SSH连接,失去所有状态。
解决方案
SSH-MCP位于人工智能代理和远程基础设施之间,作为 持久SSH会话管理器 这说明 模型上下文协议它通过工作目录跟踪保持长期的SSH连接,因此代理与远程服务器的交互方式与人类在终端中的交互方式相同。
┌──────────────┐ ┌──────────────────────────────────┐
│ │ MCP Protocol │ SSH-MCP Server │
│ AI Agent │◄──────────────────────► │ │
│ │ stdio / HTTP+SSE │ ┌────────────────────────────┐ │
│ Claude │ │ │ Session Pool │ │
│ Cursor │ │ │ │ │
│ Any MCP │ │ │ Session A ─► SSH Manager │──┼──► Server 1
│ Client │ │ │ Session B ─► SSH Manager │──┼──► Server 2
│ │ │ │ Session C ─► SSH Manager │──┼──► Bastion ─► Server 3
└──────────────┘ │ └────────────────────────────┘ │
└──────────────────────────────────┘
每个会话都有自己的隔离SSH连接管理器。跨工具调用的连接持续存在。工作目录在命令之间进行跟踪。文件通过SFTP流式传输。一个二进制文件,零运行时依赖关系。
快速开始
Docker(推荐)
docker run -v ssh-keys:/data -p 8000:8000 firstfinger/ssh-mcp:latest
来源
go build -o ssh-mcp ./cmd/server
./ssh-mcp
macOS启动代理(开发)
看 scripts/macos/README.md 用于持久后台服务设置。
然后将MCP客户端指向配置的端点(默认 http://127.0.0.1:8000/mcp).
配置
| 标志 | 环境 | 默认值 | 描述 |
|---|---|---|---|
-mode |
SSH_MCP_MODE |
http |
运输: stdio 或 http |
-port |
PORT |
8000 |
HTTP侦听端口 |
-global |
SSH_MCP_GLOBAL |
false |
在所有会话中共享一个SSH管理器 |
SSH密钥 在第一次连接时自动生成Ed25519:
- 发展:
./data/id_ed25519 - 生产(Docker):
/data/id_ed25519(装入卷)
运作原理
会话隔离
每个MCP客户端都有一个隔离的SSH连接池。根据部署情况,有三种模式:
┌─ Session Pool ────────────────────────────────────────────────┐
│ │
│ Per-session (default) │
│ Each MCP session gets a UUIDv7 ID and its own SSH manager │
│ │
│ Header-based (X-Session-Key) │
│ Sticky routing for load balancers — sessions survive │
│ MCP reconnects as long as the header stays the same │
│ │
│ Global (-global flag) │
│ Single shared manager — for single-user / local use │
│ │
└───────────────────────────────────────────────────────────────┘
基于标头的会话在5分钟不活动后过期。MCP会话结束时,每个会话池都会被销毁。
连接生命周期
connect(host, user) Creates SSH client, tracks as "primary"
connect(host2, user, alias) Creates second client with alias
run(command) Executes on primary, tracks CWD
run(command, target=alias) Executes on aliased connection
read/write/edit(path) SFTP operations on target
disconnect() Closes all connections in session
工作目录持续存在 run 电话-- cd /tmp && pwd 紧随其后 ls 将列出 /tmp这是与无状态执行的关键区别。
跳转主机隧道
Agent ──► SSH-MCP ──► Bastion ──► Internal Server
(via)
connect(bastion, admin, alias="jump")
connect(internal-host, admin, via="jump")
第二个连接隧道穿过第一个。代理不需要知道网络拓扑。
工具
按领域组织的43个工具。五人 核心工具 (connect, disconnect, run, read, write)是基础——其他一切都是一个更高级的包装器,它构造shell命令并调用相同的SSH执行路径。
核心
| 工具 | 它做什么 |
|---|---|
connect |
打开SSH连接(密码、密钥或自动生成的密钥) |
disconnect |
关闭一个或所有连接 |
run |
使用CWD跟踪和可配置超时执行命令 |
identity |
获取服务器的公钥 authorized_keys |
info |
远程操作系统、内核、主机名 |
文件
| 工具 | 它做什么 |
|---|---|
read |
通过SFTP读取文件(上限10MB) |
write |
通过SFTP写入文件——写入前验证语法 |
edit |
类似Sed的操作:替换、正则表达式、插入、追加、删除 |
validate |
服务器端语法检查(JSON、YAML、TOML、XML、INI、Dockerfile、ENV) |
list_dir |
包含元数据的目录列表 |
sync |
在两个远程主机之间流式传输文件 |
验证在MCP服务器上的Go中运行——否 jq, python3,或 xmllint 远程主机上需要。
系统监控
usage ps logs journal_read dmesg_read diagnose_system list_services
码头工人
docker_ps docker_logs docker_op docker_ip docker_find_by_ip docker_networks docker_cp_from docker_cp_to
数据库
db_query db_schema list_db_containers
网络与搜索
net_stat search_files search_text package_manage
VoIP/SIP/RTP
voip_discover_containers voip_sip_capture voip_call_flow voip_registrations voip_call_stats voip_extract_sdp voip_packet_check voip_network_capture voip_rtp_capture voip_network_diagnostics
例子
连接并运行命令:
{"tool": "connect", "arguments": {"host": "10.0.0.1", "username": "admin"}}
{"tool": "run", "arguments": {"command": "hostname && uptime"}}
{"tool": "read", "arguments": {"path": "/etc/hostname"}}
跳转主机:
{"tool": "connect", "arguments": {"host": "bastion.example.com", "username": "admin", "alias": "bastion"}}
{"tool": "connect", "arguments": {"host": "10.0.0.50", "username": "admin", "via": "bastion"}}
编辑配置文件:
{"tool": "edit", "arguments": {"path": "/etc/nginx/nginx.conf", "old_text": "worker_connections 512", "new_text": "worker_connections 1024"}}
主机之间的同步:
{"tool": "connect", "arguments": {"host": "server-a", "username": "admin", "alias": "A"}}
{"tool": "connect", "arguments": {"host": "server-b", "username": "admin", "alias": "B"}}
{"tool": "sync", "arguments": {"source_node": "A", "source_path": "/data/dump.sql", "dest_node": "B", "dest_path": "/data/dump.sql"}}
建筑
cmd/server/main.go Entry point, HTTP/stdio transport, session hooks
internal/ssh/
├── pool.go Session pool — isolation, cleanup, header routing
├── manager.go Per-session connection manager — connect, execute, SFTP
├── client.go SSH client — CWD tracking, output caps, reconnection
└── keys.go Ed25519 key generation and loading
internal/tools/
├── core.go connect, disconnect, run, identity, info
├── files.go read, write, edit, validate, list_dir, sync
├── monitoring.go usage, ps, logs, journal, dmesg, diagnose, services
├── docker.go Container management tools
├── network.go net_stat, search, packages
├── voip.go SIP/RTP capture and analysis
└── utils.go Shell quoting, sed escaping, input sanitization
设计决策
- 符合POSIX标准的命令 --所有shell命令都可以在Linux、macOS和BSD上运行。GNU特定标志(
sed -i,ps --sort,/proc/*)用便携式替代品代替。 - 壳牌到处报价 --所有用户输入都通过
shellQuote()在到达外壳之前。Sed操作对模式、文字和替换使用单独的转义函数。 - 无路径限制 --文件访问遵循SSH用户的操作系统权限。没有破坏现实世界DevOps工作流程的人工沙盒。
- 服务器端验证 --文件语法在MCP服务器上的Go中进行验证,而不是通过远程主机上的工具进行验证。
- 输出上限 --stdout的上限为10MB,stderr为1MB,文件读取为10MB。防止失控命令导致内存耗尽。
- 使用回退重新连接 --丢失的SSH连接会在5秒的冷却后自动重新连接,以避免损坏主机。
部署
生产检查表
- TLS:在反向代理后运行或使用HTTPS终止
- 网络:限制访问专用网络或VPN
- 验证:验证
X-Session-Key使用授权密钥 - 卷:在以下位置装载持久存储
/data用于SSH密钥
端点
POST/GET http://host:port/mcp
Header: X-Session-Key: <your-session-key>
负载均衡
在上使用一致哈希 X-Session-Key 用于跨多个实例的粘性路由。
许可证
麻省理工学院
