Integrates with MySQL to store and manage SSH target configurations, session history, and audit logs, enabling the server to retrieve and provide structured connection data to clients.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SSH MCP Serverlist my available servers and open a web terminal for the production host"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
SSH MCP 服务
SSH MCP 是一个 MCP Server,用于把 WebShell 网关能力封装成 MCP 工具并通过 HTTP 提供给客户端(如 LangChain 原生 tools)。它会调用 WebShell 网关的 API 来获取目标列表与创建一次性 WebShell 会话链接。
功能概览
提供 MCP HTTP 端点:/mcp 与 /stream
工具能力:list_ssh_targets、create_ssh_web_terminal、open_ssh_terminal
通过 HTTP API 连接内联 WebShell 网关
架构与主要逻辑
进程模型:单 Node.js 进程同时承载 MCP Server 与内联 WebShell Gateway
数据存储:MySQL 保存 SSH 目标与会话历史记录
典型调用链:
list_ssh_targets:从 MySQL 读取目标表并返回结构化 JSON
create_ssh_web_terminal:在数据库中生成一次性会话记录,返回一次性 WebShell 会话链接
open_ssh_terminal:根据用户输入匹配 SSH 目标,复用 create_ssh_web_terminal 逻辑返回会话链接
网络与端口(Docker Compose 部署):
mysql 服务:提供 3306 端口,ssh-mcp 容器内通过主机名 mysql 访问
ssh-mcp 服务:对外暴露 3001(MCP 控制台 + HTTP 端点)和 9100(WebShell 会话页)
容器内部 MCP 通过
http://localhost:9100调用内联 WebShell Gateway
项目目录结构
目录说明:
文件/目录 | 说明 |
| NPM 项目配置,包含依赖和脚本命令 |
| TypeScript 编译配置 |
| 用于构建 Docker 镜像 |
| 用于编排 Docker 容器 |
| 环境变量配置文件 |
| TypeScript 源代码目录 |
| 静态资源目录(WebShell 终端页面) |
| 编译后的输出目录 |
快速开始
方式一:Docker Compose(推荐,用于生产与测试环境)
在 ssh-mcp 目录执行:
该命令会启动两个容器:
mysql:WebShell 网关使用的 MySQL 数据库
ssh-mcp:包含 MCP Server 与内联 WebShell Gateway
默认行为与端口:
ssh-mcp 对外暴露 3001(MCP 控制台 + /mcp、/stream 等 HTTP 端点)
ssh-mcp 对外暴露 9100(WebShell 会话页,对应一次性会话链接)
容器内部 MCP 通过
SSH_WEBSHELL_API_URL=http://localhost:9100调用内联 Gateway容器内部访问数据库使用主机名
mysql与端口3306
如需调整端口或数据库账号,请编辑 docker-compose.yml 或通过环境变量覆盖。
方式二:Docker build/run(单容器,依赖外部 MySQL)
方式三:本地运行
配置说明
服务端口
PORT:MCP HTTP 服务端口,默认 3001
WebShell 网关连接
SSH_WEBSHELL_API_URL:WebShell 网关地址,默认建议为
http://localhost:9100SSH_WEBSHELL_HTTP_TIMEOUT_MS:请求超时,默认 15000
SSH_WEBSHELL_API_TOKEN:调用 WebShell 网关受保护接口时使用的固定 API Token(内联 Gateway 当前不会强制校验,仅用于兼容旧配置)
内联 WebShell Gateway(已合并进 ssh-mcp)
从当前版本起,WebShell Gateway 的核心能力已经内联到 ssh-mcp 中,由同一进程启动并监听独立端口。
MOCK_WEBSHELL_PORT:内联 WebShell Gateway HTTP/WS 端口,默认 9100
WEBSHELL_PUBLIC_BASE_URL:会话链接对外暴露的基础地址,默认
http://localhost:9100
数据库连接(用于存储 SSH 目标与会话历史)
内联 Gateway 使用 MySQL 存储 SSH 目标和会话历史记录,对应原 WebShell Gateway 的数据结构:
WEBSHELL_DB_HOST:数据库主机,默认
mysqlWEBSHELL_DB_PORT:数据库端口,默认
3306WEBSHELL_DB_USER:数据库用户名,默认
webshellWEBSHELL_DB_PASSWORD:数据库密码,默认
webshell_passWEBSHELL_DB_DATABASE:数据库名称,默认
webshell
数据库表结构
targets 表(SSH 目标)
字段名 | 类型 | 说明 | 备注 |
id | varchar(191) | 目标唯一 ID | MCP 工具与 UI 侧使用此 ID 标识 |
host | varchar(255) | SSH 主机地址或 IP | |
port | int | SSH 端口 | 默认为 22 |
username | varchar(255) | 登录用户名 | |
password | text (nullable) | 登录密码 | 可为空,生产建议优先用密钥认证 |
privateKey | text (nullable) | 私钥内容(PEM) | 可为空 |
name | varchar(255) | 目标展示名称(别名) | 可为空 |
索引:
主键:
PRIMARY KEY (id)
sessions 表(SSH 会话历史 / 审计日志)
字段名 | 类型 | 说明 | 备注 |
id | varchar(191) | 会话 ID | 同时用于 |
targetId | varchar(191) | 关联的 SSH 目标 ID | 对应 |
targetName | varchar(255) | 目标名称冗余 | 便于审计查询 |
host | varchar(255) | 连接时使用的主机名或 IP | 冗余存储,避免后续目标变更影响审计 |
port | int | 连接时使用的端口 | 冗余存储 |
username | varchar(255) | 连接时使用的账户名 | 冗余存储 |
startTime | datetime | 会话开始时间 | 创建会话链接时写入 |
endTime | datetime (nullable) | 会话结束时间 | WebSocket 关闭或异常时更新 |
status | enum('connected','disconnected','error') | 会话最终状态 |
|
reason | text (nullable) | 创建会话时的原因说明 | 由上游调用方传入,用于审计 |
索引:
idx_targetId (targetId)idx_startTime (startTime)
users 表(预留用户信息)
字段名 | 类型 | 说明 | 备注 |
id | varchar(191) | 用户唯一 ID | |
username | varchar(191) | 用户名 | 唯一索引 |
password_hash | varchar(255) | 密码哈希 | 存储加密后的口令 |
provider | varchar(32) | 认证提供方标识 | 当前默认值为 |
created_at | datetime | 创建时间 |
索引:
主键:
PRIMARY KEY (id)idx_username (username)
说明:当前内联 Gateway 尚未暴露基于 users 表的对外登录接口,该表为未来用户体系预留。
auth_sessions 表(预留认证会话)
字段名 | 类型 | 说明 | 备注 |
token | varchar(191) | 会话 Token(主键) | 用于标识登录态或访问会话 |
username | varchar(191) | 关联的用户名 | 对应 |
provider | varchar(32) | 认证提供方标识 | 当前默认值为 |
created_at | datetime | 会话创建时间 | |
expires_at | datetime | 会话过期时间 | 用于失效判断和定期清理 |
索引:
主键:
PRIMARY KEY (token)idx_username (username)idx_expires_at (expires_at)
说明:auth_sessions 表用于记录认证会话 Token,
expires_at字段用于决定会话是否过期。当前代码中已提供按过期时间自动清理的能力,实际登录流程可在未来接入。
生产环境配置建议
数据库账号与密码:
强烈建议在生产环境中为数据库创建独立账号,并替换默认密码
建议限制数据库账号仅具备所需最小权限(最小权限原则)
WebShell 会话访问地址:
将 WEBSHELL_PUBLIC_BASE_URL 设置为经过反向代理或网关暴露的 HTTPS 域名
对公网暴露时建议配合 WAF、IP 白名单等防护手段
API 调用安全:
如需在 MCP 侧做额外鉴权,可结合上层调用方实现 RBAC 或 Token 校验
SSH_WEBSHELL_API_TOKEN 可预留用于与外部 Gateway 集成时的签名/鉴权
资源与容量规划:
为 MySQL 分配独立存储卷(docker-compose.yml 已默认配置)
根据实际会话量评估连接数与超时配置,合理设置 SSH_WEBSHELL_HTTP_TIMEOUT_MS
MCP 端点
POST /mcp
POST /stream
内联 WebShell Gateway 使用方式
1. 准备 MySQL
可以使用 Docker 启动一个 MySQL 实例(示例):
2. 配置 ssh-mcp 环境变量
在 ssh-mcp 目录下创建或编辑 .env(或通过 Docker 环境变量注入):
3. 启动服务并访问
MCP 控制台 UI:访问
http://localhost:3001内联 WebShell Gateway 会话页:通过 MCP 工具返回的一次性会话链接,例如
http://localhost:9100/session/<uuid>
在 Docker Compose 场景下,默认映射为宿主机的 http://localhost:3001 与 http://localhost:9100,如修改端口请同步更新 WEBSHELL_PUBLIC_BASE_URL。
会话与失效策略
WebShell SSH 会话(/session/:id)
会话生成:
MCP 工具调用内联 Gateway 的
/api/session接口创建会话。内联 Gateway 为每次请求生成随机 UUID 作为
sessionId。会话信息写入两处:
进程内内存 Map:键为
sessionId,值包含targetId、reason、createdAt等。数据库
sessions表:写入一条会话历史记录(startTime、status、reason 等)。
会话访问:
浏览器访问
/session/<sessionId>时:如果内存 Map 中存在对应条目,则渲染 WebShell 终端页面并建立 WebSocket
/ws?sessionId=...。如果不存在,则返回 404 文本:
会话不存在或已过期。
会话结束:
WebSocket 正常关闭时:
内联 Gateway 调用
updateSessionEndTime,将sessions表中的endTime更新为当前时间,status置为disconnected。
连接远程主机出错时:
会话记录的
status置为error,endTime同样更新为当前时间。
失效策略(当前版本):
sessionId仅保存在内存 Map 中,不会被持久化用于恢复实时 SSH 通道。服务重启后内存 Map 清空,所有历史链接都会返回“会话不存在或已过期”。
当前未对
sessionId设置基于时间的自动 TTL 清理,在服务不重启的情况下同一链接可被多次访问。建议上层调用方将会话链接视为短期凭证,不长期缓存或下发到不可信环境。
认证会话(auth_sessions)
auth_sessions 表用于保存认证会话 Token(预留能力):
token:会话 Token 主键。username/provider:标识对应用户与认证来源。expires_at:过期时间。
失效判断:
在读取会话时,如果
expires_at <= 当前时间,会被视为已过期并立刻从表中删除。提供批量清理能力,用于定期清理历史过期会话。
当前版本尚未对外暴露基于该表的登录接口,后续如启用认证体系,可基于此表实现登录态管理。
工具输出格式
list_ssh_targets
输出为纯 JSON:
失败时输出:
create_ssh_web_terminal
输出文本中包含一次性会话链接。
open_ssh_terminal
输出文本中包含一次性会话链接,并包含匹配到的目标信息。
扩展方式
在 src/index.ts 中新增 MCP 工具,建议遵循以下步骤:
通过 mcpServer.registerTool 定义工具名称、描述与 inputSchema
在工具实现中调用 WebShell 网关 API 或其它后端服务
返回结构化 JSON 或稳定格式的文本输出
执行 npm run build 生成 dist
开发注意事项
Node.js 版本:
建议使用 Node.js 18+,以获得更好的性能与长期支持
本地开发:
使用
npm run dev以 TS 源码方式启动,默认监听PORT与内联 Gateway 端口修改 TypeScript 源码后无需手动编译,
tsx会实时加载
类型与质量检查:
提交代码前建议执行
npm run type-check确认类型检查无误若项目新增脚本或配置,请同步更新本文档相关章节
与数据库联调:
本地调试时推荐使用 Docker 启动 MySQL,并通过 WEBSHELL_DB_HOST 指向容器或本机
避免在生产数据库直接进行开发调试操作
日志与审计字段
会话审计(sessions 表)
sessions 表既承担会话历史记录,也可以作为基础的审计日志,核心字段含义如下:
id:会话唯一标识,等同于/session/:id中的路径参数。targetId/targetName:关联的 SSH 目标 ID 和冗余名称,便于按业务目标检索。host/port/username:会话建立时实际使用的连接参数,冗余存储,避免目标后续修改影响历史数据。startTime/endTime:会话起止时间,可用于统计使用时长和活跃度。status:connected/disconnected/error,代表会话最终状态。reason:上游调用方传入的业务原因描述,例如工单号、变更单号等,建议生产环境按规范填充便于审计。
在生产环境中,可以基于 sessions 表构建报表或对接审计系统,例如统计单用户、单目标或单时间区间内的会话次数与失败率。
UI 最近会话列表(/ui/recent-sessions)
MCP UI 通过 /ui/recent-sessions 接口返回内存中最近会话列表,其数据结构为:
id:最近会话记录的内部 ID,与数据库 sessions 表的id不同。targetId:目标 ID,对应targets.id。reason:创建会话时填写的原因。sessionUrl:内联 Gateway 返回的 WebShell 会话链接。createdAt:记录创建时间(毫秒时间戳)。
recentSessions 列表只保存在内存中,默认只保留最近 20 条记录,便于在 UI 侧快速查看最新发起的会话。
服务启动与错误日志(标准输出)
当前服务的日志主要通过标准输出/错误输出产生,典型包括:
MCP HTTP 服务启动日志:
SSH MCP HTTP server listening on http://localhost:<port>
内联 WebShell Gateway 启动日志:
SSH WebShell gateway listening on http://localhost:<MOCK_WEBSHELL_PORT>
HTTP Server 错误:
在监听端口出错时,会将错误信息写入标准错误输出并退出进程。
生产环境中通常通过 Docker 日志、systemd 日志或容器编排平台(如 Kubernetes)集中采集上述输出,如需要更细粒度的结构化日志,可以在现有基础上引入统一的日志框架并扩展记录字段。
常见问题
端口被占用
启动失败并提示端口占用时:
修改 PORT,或停止占用 3001 端口的进程后再启动
若 Docker 场景下 3001/9100 被占用,可在 docker-compose.yml 中调整宿主机端口映射
WebShell 网关不可达或会话链接打不开
检查 SSH_WEBSHELL_API_URL:
Docker Compose 默认在容器内使用
http://localhost:9100,无需修改若自行拆分 Gateway,请确保 URL 指向可访问的 HTTP 服务
检查会话访问地址:
确认 WEBSHELL_PUBLIC_BASE_URL 与对外访问地址一致
宿主机上确认 9100 端口已映射且未被防火墙拦截
无法连接 MySQL 或 list_ssh_targets 无返回数据
检查数据库连接配置:
确认 WEBSHELL_DB_HOST/PORT/USER/PASSWORD/DATABASE 与实际数据库一致
Docker Compose 场景下应保持 WEBSHELL_DB_HOST=mysql
检查数据库服务状态:
查看容器日志:
docker compose logs mysql确认数据库已初始化完成且能正常接受连接
检查数据是否存在:
登录数据库确认目标表中已写入 SSH 目标数据
容器反复重启
查看 ssh-mcp 容器日志:
docker compose logs ssh-mcp常见原因:
数据库连接失败(账号密码不正确或网络不可达)
环境变量缺失或配置错误
宿主机资源不足导致进程被杀死