Skip to main content
Glama

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

项目目录结构

ssh-mcp/ ├── .env # 环境变量配置 ├── Dockerfile # Docker 镜像构建文件 ├── README.md # 项目说明文档 ├── docker-compose.yml # Docker Compose 配置 ├── package.json # Node.js 项目配置 ├── package-lock.json # 依赖版本锁定文件 ├── tsconfig.json # TypeScript 配置 ├── dist/ # 编译输出目录 ├── node_modules/ # Node.js 依赖包 ├── public/ # 公共静态资源目录 │ └── index.html └── src/ # 源代码目录 ├── index.ts # 入口文件:MCP Server 主逻辑 └── webshell-gateway/ # 内联 WebShell Gateway 模块 ├── index.ts # Gateway 主逻辑(HTTP/WS 服务) └── db.ts # 数据库操作(SSH 目标与会话管理)

目录说明:

文件/目录

说明

package.json

NPM 项目配置,包含依赖和脚本命令

tsconfig.json

TypeScript 编译配置

Dockerfile

用于构建 Docker 镜像

docker-compose.yml

用于编排 Docker 容器

.env

环境变量配置文件

src/

TypeScript 源代码目录

public/

静态资源目录(WebShell 终端页面)

dist/

编译后的输出目录

快速开始

方式一:Docker Compose(推荐,用于生产与测试环境)

在 ssh-mcp 目录执行:

docker compose up -d --build

该命令会启动两个容器:

  • 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)

docker build -t ssh-mcp:latest . docker run -d \ -p 3001:3001 \ -e PORT=3001 \ -e SSH_WEBSHELL_API_URL=http://localhost:9100 \ -e MOCK_WEBSHELL_PORT=9100 \ -e WEBSHELL_DB_HOST=<你的 MySQL 主机地址> \ -e WEBSHELL_DB_PORT=3306 \ -e WEBSHELL_DB_USER=webshell \ -e WEBSHELL_DB_PASSWORD=webshell_pass \ -e WEBSHELL_DB_DATABASE=webshell \ --name ssh-mcp \ ssh-mcp:latest

方式三:本地运行

npm install npm run build npm start

配置说明

服务端口

  • PORT:MCP HTTP 服务端口,默认 3001

WebShell 网关连接

  • SSH_WEBSHELL_API_URL:WebShell 网关地址,默认建议为 http://localhost:9100

  • SSH_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:数据库主机,默认 mysql

  • WEBSHELL_DB_PORT:数据库端口,默认 3306

  • WEBSHELL_DB_USER:数据库用户名,默认 webshell

  • WEBSHELL_DB_PASSWORD:数据库密码,默认 webshell_pass

  • WEBSHELL_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

同时用于 /session/:id 链接中的 ID

targetId

varchar(191)

关联的 SSH 目标 ID

对应 targets.id

targetName

varchar(255)

目标名称冗余

便于审计查询

host

varchar(255)

连接时使用的主机名或 IP

冗余存储,避免后续目标变更影响审计

port

int

连接时使用的端口

冗余存储

username

varchar(255)

连接时使用的账户名

冗余存储

startTime

datetime

会话开始时间

创建会话链接时写入

endTime

datetime (nullable)

会话结束时间

WebSocket 关闭或异常时更新

status

enum('connected','disconnected','error')

会话最终状态

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)

认证提供方标识

当前默认值为 local

created_at

datetime

创建时间

索引:

  • 主键:PRIMARY KEY (id)

  • idx_username (username)

说明:当前内联 Gateway 尚未暴露基于 users 表的对外登录接口,该表为未来用户体系预留。

auth_sessions 表(预留认证会话)

字段名

类型

说明

备注

token

varchar(191)

会话 Token(主键)

用于标识登录态或访问会话

username

varchar(191)

关联的用户名

对应 users.username

provider

varchar(32)

认证提供方标识

当前默认值为 local

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 实例(示例):

docker run -d \ --name webshell-mysql \ -e MYSQL_ROOT_PASSWORD=webshell_root \ -e MYSQL_DATABASE=webshell \ -e MYSQL_USER=webshell \ -e MYSQL_PASSWORD=webshell_pass \ -p 3306:3306 \ mysql:8.0

2. 配置 ssh-mcp 环境变量

在 ssh-mcp 目录下创建或编辑 .env(或通过 Docker 环境变量注入):

PORT=3001 # MCP 通过 HTTP 调用内联 Gateway SSH_WEBSHELL_API_URL=http://localhost:9100 SSH_WEBSHELL_HTTP_TIMEOUT_MS=15000 # 内联 Gateway 监听端口与对外访问地址 MOCK_WEBSHELL_PORT=9100 WEBSHELL_PUBLIC_BASE_URL=http://localhost:9100 # MySQL 连接 WEBSHELL_DB_HOST=127.0.0.1 WEBSHELL_DB_PORT=3306 WEBSHELL_DB_USER=webshell WEBSHELL_DB_PASSWORD=webshell_pass WEBSHELL_DB_DATABASE=webshell

3. 启动服务并访问

cd ssh-mcp npm install npm run build npm start
  • MCP 控制台 UI:访问 http://localhost:3001

  • 内联 WebShell Gateway 会话页:通过 MCP 工具返回的一次性会话链接,例如 http://localhost:9100/session/<uuid>

在 Docker Compose 场景下,默认映射为宿主机的 http://localhost:3001http://localhost:9100,如修改端口请同步更新 WEBSHELL_PUBLIC_BASE_URL。

会话与失效策略

WebShell SSH 会话(/session/:id)

  • 会话生成:

    • MCP 工具调用内联 Gateway 的 /api/session 接口创建会话。

    • 内联 Gateway 为每次请求生成随机 UUID 作为 sessionId

    • 会话信息写入两处:

      • 进程内内存 Map:键为 sessionId,值包含 targetIdreasoncreatedAt 等。

      • 数据库 sessions 表:写入一条会话历史记录(startTime、status、reason 等)。

  • 会话访问:

    • 浏览器访问 /session/<sessionId> 时:

      • 如果内存 Map 中存在对应条目,则渲染 WebShell 终端页面并建立 WebSocket /ws?sessionId=...

      • 如果不存在,则返回 404 文本:会话不存在或已过期

  • 会话结束:

    • WebSocket 正常关闭时:

      • 内联 Gateway 调用 updateSessionEndTime,将 sessions 表中的 endTime 更新为当前时间,status 置为 disconnected

    • 连接远程主机出错时:

      • 会话记录的 status 置为 errorendTime 同样更新为当前时间。

  • 失效策略(当前版本):

    • sessionId 仅保存在内存 Map 中,不会被持久化用于恢复实时 SSH 通道。

    • 服务重启后内存 Map 清空,所有历史链接都会返回“会话不存在或已过期”。

    • 当前未对 sessionId 设置基于时间的自动 TTL 清理,在服务不重启的情况下同一链接可被多次访问。

    • 建议上层调用方将会话链接视为短期凭证,不长期缓存或下发到不可信环境。

认证会话(auth_sessions)

  • auth_sessions 表用于保存认证会话 Token(预留能力):

    • token:会话 Token 主键。

    • username / provider:标识对应用户与认证来源。

    • expires_at:过期时间。

  • 失效判断:

    • 在读取会话时,如果 expires_at <= 当前时间,会被视为已过期并立刻从表中删除。

    • 提供批量清理能力,用于定期清理历史过期会话。

  • 当前版本尚未对外暴露基于该表的登录接口,后续如启用认证体系,可基于此表实现登录态管理。

工具输出格式

list_ssh_targets

输出为纯 JSON:

{"targets":[{"index":1,"id":"prod-a","name":"prod","host":"8.140.200.0","port":22,"username":"root"}]}

失败时输出:

{"error":"获取目标列表失败: ...","targets":[]}

create_ssh_web_terminal

输出文本中包含一次性会话链接。

open_ssh_terminal

输出文本中包含一次性会话链接,并包含匹配到的目标信息。

扩展方式

在 src/index.ts 中新增 MCP 工具,建议遵循以下步骤:

  1. 通过 mcpServer.registerTool 定义工具名称、描述与 inputSchema

  2. 在工具实现中调用 WebShell 网关 API 或其它后端服务

  3. 返回结构化 JSON 或稳定格式的文本输出

  4. 执行 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:会话起止时间,可用于统计使用时长和活跃度。

  • statusconnected / 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

  • 常见原因:

    • 数据库连接失败(账号密码不正确或网络不可达)

    • 环境变量缺失或配置错误

    • 宿主机资源不足导致进程被杀死

-
security - not tested
A
license - permissive license
-
quality - not tested

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/Have-myn/ssh-mcp'

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