内容
# SSHand
一个开放的MCP服务器,为**任何AI代理**提供SSH访问远程Linux/Unix机器的能力 — Shell命令、文件读写和SFTP传输。
与**Claude.ai**、**Claude Desktop**、**ChatGPT**、**Cursor**、**VS Code Copilot**、**OpenAI Agents SDK**等兼容,并支持任何其他[MCP兼容客户端](https://modelcontextprotocol.io/clients)。
---
## 快速开始
```bash
# 1. 安装
pip install sshand
# 2. 首次运行设置:添加主机,测试,打印客户端配置
sshand setup
# 3. 随时管理主机(添加/测试/删除 + 重新打印配置)
sshand manage
```
这两个命令都会打开同一个干净的交互式终端UI — 使用**方向键**移动,使用**Enter**选择。`setup`运行引导式首次运行流程;`manage`是持续的主机管理器。
---
## 设置指南
`sshand setup`会引导您完成三个步骤:
**1. 添加主机。** 您需要提供:
- **别名** — 一个简短的昵称,如`webserver`或`db-prod`。
- **主机名/IP**、**端口**(默认为`22`)和**用户名**。
- **身份验证方法:**
- **SSH密钥文件**(推荐)— 私钥的路径,以及可选的密码短语。
- **密码** — 方便用于开发/测试,避免在面向互联网的主机上使用。
- **SSH代理** — 委托给正在运行的`ssh-agent`;不存储凭证。在Windows上,精灵还会检查OpenSSH Authentication Agent服务是否正在运行,并提供启动它。
主机保存在`hosts.yaml`(或`SSH_MCP_HOSTS_FILE`中的路径)。现有主机不会在没有确认的情况下被覆盖。
**2. 测试连接。** SSHand立即连接并运行一个无操作命令,以便您立即发现是否有问题(错误的密钥路径、错误的端口、无法访问的主机),而不是在对话中途发现。无论如何,主机都会被保存 — 如果测试失败,请修复问题并再次运行`sshand setup`。
**3. 打印客户端配置。** 选择一个客户端(或**所有客户端**),SSHand打印一个可以直接粘贴的配置片段,其中已经填充了正确的绝对路径:
> Claude Desktop · Cursor · VS Code (GitHub Copilot Chat) · OpenAI (Agents SDK / ChatGPT Desktop) · Hermes Agent · OpenClaw (via MCPorter) · Other (HTTP)
完整的客户端特定说明在下面的[连接到您的AI客户端](#连接到您的AI客户端)中。
> 随时重新运行`sshand setup`以添加另一个主机或重新打印一个片段 — 它不会影响现有的主机。
---
## 管理您的主机
`sshand manage`打开交互式主机管理器 — 一个实时表,显示您配置的主机以及一个菜单:
- **列出主机** — 刷新表格。
- **添加主机** — 与设置相同的流程,之后可以选择进行连接测试。
- **测试主机** — 连接并报告成功或失败。
- **删除主机** — 删除一个条目(需要确认)。
- **客户端配置片段** — 重新打印任何客户端的可以直接粘贴的配置,前面会列出代理可以访问的主机。
每次操作后,屏幕会实时刷新,显示您上一次操作的结果。按**q** / 选择**退出**以退出。
---
## 安装选项
### 选项A — pip(推荐大多数用户)
```bash
pip install sshand # 从PyPI
pip install -e . # 从源代码,可编辑安装
```
### 选项B — uvx(零安装,无venv需求)
[uv](https://docs.astral.sh/uv/)是现代Python包管理器。安装后,您可以运行SSHand,无需任何手动安装步骤:
```bash
uvx sshand # 直接运行服务器
uvx sshand setup # 运行设置向导
```
这是推荐给非技术用户的最干净的选项。
### 选项C — 普通Python(无安装)
```bash
git clone https://github.com/muradmalik23/sshand
cd sshand
pip install -r requirements.txt
python server.py # 启动服务器
python manage.py setup # 运行设置向导
python manage.py # 交互式主机管理器
```
---
## 连接到您的AI客户端
### Claude.ai 和 ChatGPT(网页 + 桌面)
对于Claude.ai网页和ChatGPT,SSHand作为一个**HTTP服务器**运行,您可以通过每个应用的原生集成UI连接它。
**→ 查看 [INTEGRATIONS.md](INTEGRATIONS.md) 了解完整的逐步指南**,包括如何使用ngrok或Cloudflare Tunnel公开暴露服务器,以及如何将其添加到Claude.ai集成和ChatGPT桌面。
---
### Claude Desktop
将以下内容添加到您的`claude_desktop_config.json`:
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"ssh": {
"command": "uvx",
"args": ["sshand"]
}
}
}
```
或使用普通Python:
```json
{
"mcpServers": {
"ssh": {
"command": "python",
"args": ["/absolute/path/to/sshand/server.py"]
}
}
}
```
不需要环境变量 — 主机自动存储在`~/.sshand/hosts.yaml`中。参见下面的[主机库存](#主机库存),如果您想使用不同的位置。
重启Claude Desktop后生效。
---
### Cursor
在您的项目中创建或更新`.cursor/mcp.json`(或全局Cursor MCP设置):
```json
{
"mcpServers": {
"ssh": {
"command": "uvx",
"args": ["sshand"]
}
}
}
```
不需要环境变量 — 主机自动存储在`~/.sshand/hosts.yaml`中。
---
### VS Code (GitHub Copilot Chat)
将以下内容添加到`.vscode/mcp.json`或工作区的`settings.json`:
```json
{
"mcp": {
"servers": {
"ssh": {
"type": "stdio",
"command": "uvx",
"args": ["sshand"]
}
}
}
}
```
不需要环境变量 — 主机自动存储在`~/.sshand/hosts.yaml`中。
---
### OpenAI Agents SDK
```bash
# 终端 1 — 保持此运行
sshand --transport http --port 8000
```
```python
from agents import Agent
from agents.mcp import MCPServerStreamableHttp
ssh_server = MCPServerStreamableHttp(url="http://localhost:8000/mcp")
agent = Agent(name="ops-agent", mcp_servers=[ssh_server])
```
---
### Hermes Agent
[Hermes Agent](https://github.com/NousResearch/hermes-agent)(Nous Research)从`~/.hermes/config.yaml`读取MCP服务器配置,位于`mcp_servers`键下 — 与其他地方相同的`command`/`args`/`env`形状:
```yaml
mcp_servers:
ssh:
command: "uvx"
args: ["sshand"]
```
如果您从源代码安装SSHand而不是通过`uvx`,请将`command`指向`python`并添加`["/absolute/path/to/sshand/server.py"]`作为`args`,与上面的Claude Desktop片段相同。
无论哪种方式,都不需要环境变量 — 主机自动存储在`~/.sshand/hosts.yaml`中。
启动(或重新加载)Hermes以生效:
```bash
hermes chat # 新启动
/reload-mcp # 或,从正在运行的会话中
```
Hermes为每个工具添加前缀`mcp_<server_name>_`, 因此例如`ssh_run_command`显示为`mcp_ssh_ssh_run_command` — 您通常不需要前缀名称,Hermes会根据您的提示自动选择正确的工具。
---
### OpenClaw
OpenClaw不直接接受MCP服务器 — 它通过[MCPorter](https://github.com/openclaw/mcporter)调用它们,MCPorter是一个单独的CLI,用于OpenClaw调用以进行模式发现和工具调用。首先安装MCPorter:
```bash
npm install -g mcporter
```
然后使用它注册SSHand:
```bash
mcporter config add ssh --command uvx --args sshand
```
这会将一个条目写入`config/mcporter.json`(或`~/.mcporter/mcporter.json`用于全局安装),采用与其他地方相同的`mcpServers`形状:
```jsonc
{
"mcpServers": {
"ssh": {
"command": "uvx",
"args": ["sshand"]
}
}
}
```
不需要环境变量 — 主机自动存储在`~/.sshand/hosts.yaml`中。
确认MCPorter可以看到它并列出工具:
```bash
mcporter list ssh --schema
```
不需要进一步的OpenClaw端配置 — 只需要求它执行需要SSH的操作(例如 *"检查webserver上的磁盘使用情况"*),OpenClaw将自动调用`mcporter call ssh.ssh_run_command ...`。
---
### 任何其他MCP客户端(HTTP)
```bash
sshand --transport http --port 8000
```
MCP端点:`http://localhost:8000/mcp`
对于远程访问,请使用反向代理(nginx / Caddy)并启用TLS。永远不要直接在公共接口上暴露端口8000。
---
## 主机库存
主机存储在`~/.sshand/hosts.yaml`中,无论SSHand如何安装(`pip`、`uvx`或从源代码),都会自动创建 — 不需要环境变量或额外配置。您可以直接编辑文件或让您的代理调用`ssh_add_host`。
想使用不同的位置吗?设置`SSH_MCP_HOSTS_FILE`以覆盖它,例如`"env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/hosts.yaml" }`在上述任何MCP配置中。
在git克隆中运行并希望库存位于源代码旁边?将`SSH_MCP_HOSTS_FILE`指向存储库本地的副本:
```bash
cp hosts.yaml.example hosts.yaml
export SSH_MCP_HOSTS_FILE="$PWD/hosts.yaml"
```
### 身份验证类型
**密钥文件** — 最常见,最安全:
```yaml
auth:
type: key
key_path: ~/.ssh/id_rsa # ~ 自动展开
passphrase: null # 如果密钥已加密,则设置
```
**密码** — 方便用于开发/测试,避免在面向互联网的服务器上使用:
```yaml
auth:
type: password
password: s3cr3t
```
**SSH代理** — 不存储凭证,委托给正在运行的`ssh-agent`:
```yaml
auth:
type: agent
```
---
## 可用工具
| 工具 | 描述 | 只读? |
|------|-------------|------------|
| `ssh_list_hosts` | 列出所有配置的SSH目标 | ✅ |
| `ssh_add_host` | 注册新的SSH主机 | ❌ |
| `ssh_remove_host` | 从库存中删除主机 | ❌ |
| `ssh_test_connection` | 验证主机认证是否有效 | ✅ |
| `ssh_run_command` | 执行Shell命令 + 捕获输出 | ❌ |
| `ssh_read_file` | 读取远程文件的内容 | ✅ |
| `ssh_write_file` | 创建或覆盖远程文件 | ❌ |
| `ssh_list_directory` | 浏览远程目录 | ✅ |
| `ssh_upload_file` | 将本地文件推送到远程主机(SFTP) | ❌ |
| `ssh_download_file` | 将远程文件拉取到此机器(SFTP) | ✅ |
| `ssh_get_local_info` | 返回MCP服务器主机的OS和路径样式 | ✅ |
---
## 示例对话
> *"您有哪些服务器可以访问?*"
> → `ssh_list_hosts`
> *"检查webserver上的磁盘使用情况"*
> → `ssh_run_command(alias='webserver', command='df -h')`
> *"读取web盒上的nginx配置"*
> → `ssh_read_file(alias='webserver', remote_path='/etc/nginx/nginx.conf')`
> *"跟踪bastion上的最后100行syslog"*
> → `ssh_run_command(alias='bastion', command='tail -n 100 /var/log/syslog')`
> *"将此配置文件部署到devbox"*
> → `ssh_write_file(alias='devbox', remote_path='/etc/myapp/config.yaml', content='...')`
> *"从webserver下载今天的数据库备份"*
> → `ssh_download_file(alias='webserver', remote_path='/backups/db-today.sql.gz', local_path='/tmp/db-today.sql.gz')`
---
## CLI参考
```
sshand [子命令] [选项]
子命令:
setup 交互式首次运行向导(添加主机,测试,打印配置)
manage 交互式主机管理器(添加/测试/删除 + 配置片段)
选项:
--transport {stdio,http} 传输(默认:stdio)
--port INT HTTP端口(默认:8000)
--host STR HTTP绑定地址(默认:127.0.0.1)
示例:
sshand # 启动stdio服务器
sshand setup # 首次运行向导
sshand manage # 交互式主机管理器
sshand --transport http # 启动HTTP服务器,端口:8000
```
---
## 安全说明
- 默认情况下,您的库存位于存储库外部的`~/.sshand/hosts.yaml`,因此它不会意外地进入版本控制。如果您将`SSH_MCP_HOSTS_FILE`指向存储库本地的`hosts.yaml`,请将其排除在.gitignore之外 — 它已包含在内。
- 对于任何面向互联网的主机,请优先使用基于密钥或代理的身份验证,而不是密码身份验证。
- HTTP传输默认绑定到`127.0.0.1`。
- 当公开暴露HTTP服务器(用于Claude.ai / ChatGPT网页)时,请使用TLS,并考虑通过反向代理添加身份验证。
- `ssh_run_command`标记为`destructiveHint: true` — 尊重注释的MCP客户端将在运行可能危险的命令之前提示。
---
## 项目结构
```
sshand/
├── server.py # FastMCP服务器 — 所有11种工具 + CLI入口点
├── ssh_client.py # 异步paramiko包装器(命令执行 + SFTP)
├── host_config.py # YAML主机库存管理器
├── manage.py # 交互式TUI — 设置向导 + 主机管理器(rich + questionary)
├── setup_wizard.py # 客户端配置片段构建器 + Windows代理助手(由manage.py使用)
├── platform_utils.py # Windows SSH代理助手
├── hosts.yaml.example # 安全模板 — 用于存储库本地SSH_MCP_HOSTS_FILE设置
├── hosts.yaml # 可选:仅当SSH_MCP_HOSTS_FILE指向此处(gitignored)
├── INTEGRATIONS.md # 指南:Claude.ai和ChatGPT原生扩展
├── pyproject.toml # 包元数据 + pip/uvx安装配置
├── requirements.txt # 普通pip安装备用
└── README.md
```