mcpField
S
SSH Host Storage & Remote Exec

SSH Host Storage & Remote Exec

本地服务
github.com云与基础设施16 天前更新

关于 SSH Host Storage & Remote Exec

这是一个用于保存 SSH 主机并执行远程命令的独立 stdio MCP 服务及配套 CLI。它在本地加密凭据、复用 SSH 会话,并提供连接池监控。

主要功能

  1. 01加密保存本地主机信息
  2. 02SSH 主机管理工具
  3. 03执行命令、交互命令和剧本
  4. 04复用 SSH 连接
  5. 05脱敏监控连接池
  6. 06交互式与批处理 CLI

适用场景

  1. 01管理 MCP 运维所用的主机
  2. 02通过 MCP 客户端执行远程命令
  3. 03自动运行多步骤 SSH 剧本
  4. 04批量导入主机并查看连接状态

MCP 相关

通过 stdio MCP 工具提供 SSH 主机管理、远程命令执行、剧本运行和连接池状态。MCP 客户端可在本地启动该服务。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"xlbbb-cn-mcp-ssh-exec-cmd": {
"command": "npx",
"args": [
"-y",
"@xlbbb-cn/mcp_ssh_exec_cmd"
],
"env": {
"MCP_SSH_CONFIG_DIR": "<MCP_SSH_CONFIG_DIR>",
"MCP_SSH_MASTER_KEY": "<MCP_SSH_MASTER_KEY>",
"MCP_SSH_POOL_IDLE_MS": "<MCP_SSH_POOL_IDLE_MS>",
"MCP_SSH_POOL_MAX_HOSTS": "<MCP_SSH_POOL_MAX_HOSTS>"
}
}
}
}
启动命令npx -y @xlbbb-cn/mcp_ssh_exec_cmd
需要配置的环境变量
MCP_SSH_CONFIG_DIRDirectory holding hosts.json and master.key (default: ~/.mcp-ssh-server).
MCP_SSH_MASTER_KEY密钥64-hex-character AES-256-GCM master key; auto-generated into <config dir>/master.key when unset.
MCP_SSH_POOL_IDLE_MSIdle SSH connections are closed after this many milliseconds (default: 60000, 0 disables pooling).
MCP_SSH_POOL_MAX_HOSTSMaximum number of pooled SSH connections (default: 32).

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@xlbbb-cn/mcp_ssh_exec_cmd0.1.3

工具

9

收录的工具列表 · 更新于 6 天前

参数类型必填说明
topicstring否可选的帮助主题筛选条件:'install'、'list'、'get'、'create'、'update'、'delete'、'import'、'monitor'、'tui';排查问题时可选 'windows'。省略则获取完整帮助文本。

详细介绍

mcp-ssh-server

一个独立的 stdio MCP 服务,可将 SSH 主机管理和远程命令执行转化为 MCP 工具。 此外,它还附带一个交互式/批处理命令行工具(remote-ssh-cli),用于管理本机上的 SSH 主机。

简体中文文档见 README.zh-CN.md。

这是一个 Node.js 实现,重写了 FastAPI 项目中 SSH 主机相关的部分 (app/services/llm_tools.py + app/utils/ssh_helper.py + app/models/host.py)—— 不依赖后端、数据库或网络服务。任何 MCP 客户端(Claude Desktop、Continue、自定义 Agent 等)都可以通过 npx 启动它,并通过 JSON-RPC 与其通信。

亮点

  • 完全独立——使用自己的加密 JSON 存储(~/.mcp-ssh-server/hosts.json);不需要 FastAPI 后端或数据库。
  • 无原生依赖——使用 Node 内置的 crypto 实现 AES-256-GCM,使用纯 JavaScript 的 ssh2 实现 SSH;可在 Windows/macOS/Linux 上运行。
  • 符合标准的 stdio MCP——使用 Model Context Protocol stdio 传输协议,可通过 npx 启动。
  • 凭据不会离开服务端——主机工具的响应不会包含密码或私钥;SSH 工具会在内部解密凭据以建立连接,绝不会将其回传。
  • 连接池——每台主机保留一个活动 SSH 会话,并在多条命令和剧本步骤之间复用。
  • 连接池监控——pool_status 会将活动连接池显示为脱敏表格:uid、名称、连接状态、已执行/失败的命令以及最后一条命令(机密信息和 IP 地址均已屏蔽)。
  • 配套命令行工具——remote-ssh-cli 管理同一个存储(交互式 TUI、批处理命令、CSV 批量导入),还可以实时监控连接池(每秒刷新一帧,按 q 退出)。

MCP 工具

共发布九个工具:

工具描述
cli_help提供 remote-ssh-cli 的安装、使用和故障排除说明;可使用 topic 指定主题
host_list列出已知主机——仅返回 sys_name 和 uid(不包含地址、用户名或凭据);uid 是其他工具所需的 host_id
host_create添加主机(密码/私钥/口令短语均会在静态存储时加密)
host_update更新主机字段(未提供的凭据字段保留当前值)
host_delete删除主机
ssh_run_command在主机上运行一条非交互式命令
ssh_run_interactive通过 expect/answer 对运行会响应提示的命令(sudo 等)
ssh_run_playbook运行多步骤剧本(结构化的 # @… 指令或旧版 expect:/answer: 行)
pool_status监控活动连接池——每台主机对应一行脱敏信息(uid、名称、状态、已执行/失败的命令、最后一条命令)
主机标识符约定
  • host_list 是入口:每台主机返回的字段恰好为两个——sys_name(名称)和 uid(唯一标识符)。
  • 其他所有工具都使用 host_id 这一名称接收同一个值。原样传回;绝不要自行拼接或猜测。
  • 如果找不到对应 ID,工具会返回可供采取操作的错误: Host '<id>' not found. host_id must be the exact 'uid' value returned by host_list — call host_list to obtain the valid identifiers. 请重新调用 host_list,并使用其返回的值重试。
  • host_get 不会发布给 MCP 客户端:模型始终只能看到 sys_name + uid,不会看到任何主机的地址、用户名或凭据。命令行工具为人工操作人员保留了自己的 get 子命令。
参数一览
工具参数
cli_helptopic? — 以下之一:install、list、get、create、update、delete、import、monitor、tui、windows
host_listenabled_only?(bool)
host_createip_address(必填)、system_name?、ssh_port?(1-65535,默认 22)、ssh_username?(默认 root)、ssh_auth_method?(password | pubkey)、ssh_password?、ssh_private_key?、ssh_private_key_passphrase?、is_enable?(默认 true)
host_updatehost_id(必填)以及上述任意字段 — 未提供的字段将保留当前值
host_deletehost_id
ssh_run_commandhost_id、command、timeout_seconds(1-600,必填)
ssh_run_interactivehost_id、command、expects?([{ expect, answer }])、timeout_seconds
ssh_run_playbookhost_id、content(多行 playbook 正文)、timeout_seconds
pool_statushost_id?(仅一个主机)、format?(table | json)、include_history?(bool)、include_idle_hosts?(bool)

ip_address 在存储中必须唯一 — 创建重复项会失败。

命令结果以纯文本块的形式返回:

[stdout]
hello
[stderr]
[exit_code=0 success=true duration_ms=42]

快速开始

git clone https://github.com/xlbbb-cn/mcp_ssh_exec_cmd.git
cd mcp_ssh_exec_cmd
npm install
npm run build

构建输出位于 dist/,并提供两个二进制文件:

二进制文件入口点用途
remote-ssh-serverdist/index.jsstdio MCP 服务(由 MCP 客户端启动)
remote-ssh-clidist/cli.js交互式 / 批量主机管理命令行工具
安装

该软件包以同一名称发布在两个注册表中: @xlbbb-cn/mcp_ssh_exec_cmd:

注册表安装命令身份验证
npmjs.org(推荐)npm install -g @xlbbb-cn/mcp_ssh_exec_cmd无 — 公共注册表无需令牌
GitHub Packagesnpm install -g @xlbbb-cn/mcp_ssh_exec_cmd --registry=https://npm.pkg.github.com具有 read:packages 权限的个人访问令牌(classic)

GitHub Packages 安装时也需要身份验证 — 即使是公共软件包也不例外, 因此请先为 npm 配置令牌:

npm login --scope=@xlbbb-cn --auth-type=legacy --registry=https://npm.pkg.github.com
# Username: <your GitHub username>
# Password: <your PAT>

也可以将相同内容写入 ~/.npmrc:

//npm.pkg.github.com/:_authToken=<PAT>
@xlbbb-cn:registry=https://npm.pkg.github.com
全局安装(命令行工具)

在本地检出目录中运行:

npm run build
npm install -g --allow-scripts=ssh2,cpu-features .

或者直接从注册表安装:

npm install -g @xlbbb-cn/mcp_ssh_exec_cmd                                      # npmjs.org
npm install -g @xlbbb-cn/mcp_ssh_exec_cmd --registry=https://npm.pkg.github.com  # GitHub Packages

之后,remote-ssh-cli 就会位于你的 PATH 中:

remote-ssh-cli                        # interactive TUI
remote-ssh-cli list                   # JSON list of every host
remote-ssh-cli get <host_id>
remote-ssh-cli create <json-file>
remote-ssh-cli update <host_id> <json-file>
remote-ssh-cli delete <host_id>
remote-ssh-cli import <csv-file> [--dry-run]
remote-ssh-cli monitor                # live connection-pool monitor (q quits)

create / update 接受 JSON 文件,例如:

{
  "ip_address": "192.168.1.100",
  "system_name": "web-01",
  "ssh_port": 22,
  "ssh_username": "root",
  "ssh_auth_method": "password",
  "ssh_password": "your-password"
}
CSV 批量导入

remote-ssh-cli import hosts.csv 会将文件中的每一行转换为一个主机。 第一行必须是表头行,并且至少包含 ip_address 列:

ip_address,system_name,ssh_port,ssh_username,ssh_auth_method,ssh_password
192.168.1.100,web-01,22,root,password,secret
192.168.1.101,db-01,2222,deploy,password,secret
列说明默认值
ip_address必填,主机地址,在表中唯一—
system_name显示名称空
ssh_portSSH 端口22
ssh_usernameSSH 用户名root
ssh_auth_methodpassword / pubkeypassword
ssh_password明文密码(写入磁盘前会加密)—
ssh_private_key明文私钥(写入磁盘前会加密)—
ssh_private_key_path密钥文件路径(可替代 ssh_private_key)—
ssh_private_key_passphrase保护密钥的密码短语(写入磁盘前会加密)—
is_enabletrue/false/1/0/yes/notrue
  • 列名不区分大小写,并接受别名(ip、host、name、port、user、password 等)。
  • 按照 RFC 4180 解析带引号的逗号、内嵌换行符和 "" 转义,因此私钥内容不会遭到破坏。
  • 错误行不会中止批量导入:每一行都会被报告为已创建/已跳过(IP 重复)/失败(数据无效)。命令会打印摘要;只要有一行失败,退出码就是 1。
  • --dry-run 只验证并报告,不会写入任何内容。
  • CSV 模板(表头 + 示例行)会显示在 remote-ssh-cli 横幅中;不带文件参数运行 remote-ssh-cli import 也会打印相同内容。

**Windows 注意事项:**如果遇到 JScript runtime error (800A03EA),请确保 npm 版本不低于 10.8.0,或者改用 cmd.exe 而非 PowerShell 运行命令——在较旧的 npm 版本中,npm 生成的 .ps1 包装脚本可能不会显式调用 node。两个入口都包含 #!/usr/bin/env node shebang。

监控连接池

remote-ssh-cli monitor 会打开 SSH 连接池的实时视图。屏幕每秒重绘一次,按 q 键即可退出(也可以按 Ctrl+C):

SSH connection pool monitor · 15:05:31 · tick 42 · refresh 1000ms · last tick 41ms
pool 2/32 connections · idle timeout 1m00s · probe timeout 5s · press q to quit

HOST          ADDRESS       USER   STATUS    LATENCY  LAST OK  POOL
------------  ------------  -----  --------  -------  -------  ----
web-01        192.168.1.100 root   up        12ms     15:05:30 1m05s
db-01         10.0.0.5:2222 deploy down      8ms      -        -

problems (1):
  db-01 (10.0.0.5:2222): connect ECONNREFUSED 10.0.0.5:2222
列含义
STATUSup(探测成功)、down(连接失败)或 disabled(主机已关闭——会列出,但不会探测)
LATENCY上次探测的端到端耗时
LAST OK上次探测成功的时间
POOL连接池中连接的存续时间——会话在未重新建立的情况下被复用的时长
  • 监控器会让连接池保持热状态:每台主机都会通过 SSH 工具使用的同一个 ConnectionPool 进行探测,因此显示的连接都是真实且可复用的会话。
  • CLI 运行自己的连接池——MCP 服务是独立进程,因此无法从终端检查它的连接。
  • 默认探测命令为 echo(POSIX shell 和 cmd.exe 中都存在);每次间隔都会运行一次探测,因此主机列表较大时,请合理设置 --interval。
  • 如果没有终端(例如管道或 CI 作业),监控器只会打印一帧,而不会循环——因为没有按键可以停止它。
选项说明默认值
--interval <ms>重绘间隔1000
--timeout <s>每台主机的探测超时时间(1-600 s)5
--probe-cmd <cmd>用于探测主机的命令echo
--host <host_id>只监控此主机(可重复指定)所有主机
--all同时列出已禁用的主机(不会探测)关闭
--once打印一帧后退出关闭

交互式 TUI 中也提供相同视图(7) Monitor connection pool)。

在 MCP 客户端中注册

~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows):

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": ["-y", "-p", "@xlbbb-cn/mcp_ssh_exec_cmd", "remote-ssh-server"]
    }
  }
}

使用 GitHub Packages 时,请在同一代码片段中添加注册表:

"args": [
  "--registry=https://npm.pkg.github.com",
  "-y",
  "-p",
  "@xlbbb-cn/mcp_ssh_exec_cmd",
  "remote-ssh-server"
]

file: 形式会让 npx 直接指向本地检出目录——开发时很方便,也无需任何注册表:

"args": ["-y", "-p", "file:./mcp_ssh_exec_cmd", "remote-ssh-server"]

配置

所有配置均通过环境变量完成:

变量说明默认值
MCP_SSH_MASTER_KEY以十六进制字符串表示的 32 字节密钥(64 个十六进制字符)。请备份此密钥:更改密钥或迁移到另一台机器,都会导致 hosts.json 中的所有凭据无法解密首次启动时生成并存储在 <config_dir>/master.key
MCP_SSH_CONFIG_DIR覆盖配置目录~/.mcp-ssh-server
MCP_SSH_POOL_IDLE_MS空闲连接在连接池中保留的时长(毫秒)。0 会完全禁用连接池,因此每条命令都会建立新连接60000
MCP_SSH_POOL_MAX_HOSTS连接池保持活动状态的主机数上限(超过上限时,会驱逐最近最少使用的空闲连接)32
SSH 连接池
  • 每台主机保留 一个 SSH 连接;连续执行的命令和操作手册中的各个步骤都会复用该连接,而不是重新连接。
  • 连接池的键由主机 ID 和凭据指纹组成。更改地址、端口、用户名、身份验证方法、密码或密钥会立即使缓存连接失效;host_update 和 host_delete 会显式关闭对应连接。
  • 空闲连接会在 MCP_SSH_POOL_IDLE_MS 指定的时长后关闭。如果对端在此期间断开连接,下次使用时会自动重新建立连接(重试一次)。
  • 进程退出时(即 MCP 客户端断开连接时),所有连接池中的连接都会关闭。
  • remote-ssh-cli monitor 可实时查看连接池(参见监控连接池);它遵循相同的两个环境变量。
从 MCP 监控连接池

pool_status 会将 MCP 服务自身 连接池的状态以表格形式呈现 — 每台有连接池连接或命令流量的主机占一行:

SSH connection pool · 1/32 connections · idle timeout 1m00s · 2 commands executed · 1 failed · updated 15:24:16
Commands and error messages are desensitized (secrets masked, IP addresses replaced).

UID                                   SYS_NAME  STATE   EXECUTED  FAILED  LAST CMD                 LAST RESULT  LAST ERROR                     LAST RUN  POOL AGE
------------------------------------  --------  ------  --------  ------  -----------------------  -----------  -----------------------------  --------  --------
9bcb7682-537b-4837-8b9e-6e37b4c61cdc  web-01    pooled  3         1       systemctl restart nginx  exit=1       connect to *** port 22 failed  12s ago   1m05s
列含义
UID主机 ID,与 host_list 返回的 uid 值相同
SYS_NAME主机名称
STATEpooled(连接存活且空闲)、busy(正在运行命令)、down(连接已断开)、idle(运行过命令,但当前没有打开连接)、new(从未使用)
EXECUTED / FAILED主机上运行的命令数,以及其中失败的命令数
LAST CMD / LAST RESULT上一条命令及其结果(ok、exit=1、timeout、error)
LAST ERROR上次失败时经过脱敏的错误消息
LAST RUN上次运行命令距今的时长
POOL AGE连接池中的连接被复用的时长
  • 表格已脱敏:凭据会被屏蔽(mysql -pS3cret → mysql -p***),IP 地址会被替换(10.0.0.5 → ***),并且绝不会显示主机的地址、端口、用户名或凭据。
  • format: "json" 会以 JSON 文档返回相同信息;include_history: true 会添加每台主机最近运行的命令;include_idle_hosts: true 还会列出没有流量的主机;host_id 可将视图缩小到单台主机。
  • 计数器保存在服务进程中:它们记录的是此 MCP 服务运行的命令,并会在服务重启时重置。CLI 监控器是独立进程,显示的是它自身连接池的状态。
超时语义

timeout_seconds 是一个硬性上限:达到上限时,命令会被终止, 结果会报告 success=false、exit_code=null,并在 stderr 中附带说明。对于 ssh_run_playbook,该值是整个操作手册的时间预算 — 每个步骤只能使用剩余时间。

Playbook 格式

ssh_run_playbook 接受多行内容。支持两种格式。

结构化 —— 指令以 # @ 开头:

# @section "Restart nginx"
# @desc "Reload the reverse proxy after the config change"
systemctl stop nginx
# @on "systemctl start nginx"
expect: [sudo] password for deploy:
answer: secret
# @note "the site is back up"
# @danger "this drops active connections"
指令含义
# @section "Title"将后续步骤归入一个章节
# @desc "…"当前章节的描述
# @note "…"附加到当前步骤的注释
# @danger "…"附加到当前步骤的危险警告
# @on "command"以交互方式运行此命令(为后续的 expect:/answer: 配对提供回答)

旧格式 —— 每行一个命令,可选地跟上 expect: / answer: 配对:

sudo systemctl restart nginx
expect: [sudo] password for deploy:
answer: secret

普通的 # 注释会被忽略。Playbook 会在首次遇到非零退出码时停止,并返回所有已执行步骤的记录。

存储与安全

  • hosts.json — 所有主机记录均以纯 JSON 格式存储。元数据字段以明文存储;ssh_password、ssh_private_key 和 ssh_private_key_passphrase 保存的是 base64 密文。
  • master.key — 32 字节的主密钥(POSIX 上的模式为 0o600)。
  • 写入操作会先写入 .tmp 文件,再通过重命名完成,因此即使发生崩溃,也不会留下只写了一部分的文件。

密钥使用 AES-256-GCM 加密,密钥由主密钥通过 PBKDF2-SHA-256 派生(200k 次迭代,16 字节随机盐)。数据布局为 [16-byte salt][12-byte IV][16-byte tag][ciphertext];每次加密都会生成新的盐和 IV,因此相同明文不会产生相同的密文。

请确保整个目录不纳入版本控制:

# mcp-ssh-server state
.mcp-ssh-server/

项目结构

src/
  index.ts        MCP entry point — stdio transport, tool registration, dispatch
  cli.ts          remote-ssh-cli — interactive TUI + batch subcommands
  monitor.ts      live connection-pool monitor (one frame per second, q quits)
  pool.ts         ConnectionPool — one live SSH connection per host + the command counters
  ssh.ts          ssh2 execution primitives + playbook parser/runner
  storage.ts      HostStore — hosts.json load/save with an atomic full-file rewrite
  csv.ts          RFC 4180 CSV reader + host-row mapping
  importer.ts     bulk-import orchestration
  crypto.ts       AES-256-GCM encryption of secrets at rest
  master_key.ts   master-key resolution (env var or key file)
  paths.ts        configuration-directory paths
  redact.ts       masks secrets and IP addresses in commands and error messages
  tools/
    _types.ts     shared MCP tool shape + the host-identifier wording
    hosts.ts      host_list / host_create / host_update / host_delete
    ssh_exec.ts   ssh_run_command / ssh_run_interactive / ssh_run_playbook
    pool_status.ts  pool_status — the desensitized pool table
    help.ts       cli_help
test/
  smoke.mjs         encryption round-trip, HostStore CRUD, playbook parsing
  features_smoke.mjs  CSV parsing/import, connection pool behaviour
  monitor_smoke.mjs   monitor frames, the refresh loop, the 'q' shortcut
  mcp_smoke.mjs     end-to-end JSON-RPC handshake against a spawned server

开发

npm run dev    # tsc --watch
npm run build  # tsc  (the only typecheck)
npm test       # all four smoke tests

npm run build 是验证步骤——没有单独的 lint 或格式配置。测试会执行 dist/,因此测试前请先构建。

冒烟测试

npm test 会运行四个纯 Node 脚本;它们都不需要真实的 SSH 服务:

  • test/smoke.mjs — 加密/解密往返测试、完整的 HostStore CRUD 流程(写入时加密、读回、列出、更新、删除),以及两种格式的 Playbook 解析。
  • test/features_smoke.mjs — CSV 解析和主机行映射、批量导入(包括 --dry-run 和跳过重复 IP)、连接池复用 / 凭据变更时失效 / 空闲时逐出、Playbook 解析边缘用例、命令和错误的脱敏,以及 pool_status 表格。
  • test/monitor_smoke.mjs — 连接池监视器:帧渲染、每个时间间隔循环一帧、q 快捷键、SSH 探测(针对模拟客户端)以及连接池快照。
  • test/mcp_smoke.mjs — 将 MCP 服务作为子进程启动,执行 JSON-RPC 握手,并断言所有 9 个工具均已注册、host_list 仅公开 sys_name + uid、host_get 未被公开、pool_status 返回脱敏表格,且响应中绝不会出现密码。

使用 node test/<file>.mjs 运行单个文件。每项测试都会将状态隔离到临时的 MCP_SSH_CONFIG_DIR 中,因此不会触及你的真实 hosts.json。

发布

发布流程通过 GitHub Actions 工作流(.github/workflows/publish.yml)将版本发布到 npmjs.org、GitHub Packages 和官方 MCP Registry(registry.modelcontextprotocol.io)。两个软件包任务会进行构建、运行冒烟测试,并发布带有 npm 来源证明的压缩包;随后第三个任务会将 server.json 发布到 MCP Registry,镜像该 Registry 的目录(Glama、PulseMCP 等)会从中列出此服务。

MCP Registry 任务会在 npmjs.org 任务之后运行,因为 Registry 会读取已发布软件包中的 mcpName 标记,以验证 npm 归属:package.json 中的 mcpName 必须始终与 server.json 的 name 相等(由 test/features_smoke.mjs 断言),并且 CI 会在发布前将 server.json 中的版本与 package.json 同步。

# 1. bump the version in package.json, commit
git commit -am "chore: release v0.1.1" && git push github master

# 2. tag it — the tag triggers the publish workflow
git tag v0.1.1
git push github v0.1.1
Registry凭据来源
GitHub PackagesGITHUB_TOKEN工作流内置,无需配置
npmjs.org可信发布(OIDC)在 npmjs.org 上一次性配置:Packages → @xlbbb-cn/mcp_ssh_exec_cmd → Settings → Trusted publisher → 用户 xlbbb-cn、仓库 mcp_ssh_exec_cmd、工作流文件名 publish.yml。无需密钥——工作流会将短期 GitHub OIDC 令牌交换为发布令牌。
npmjs.org(备用)NPM_TOKEN仓库密钥(Settings → Secrets and variables → Actions)。必须是具有 @xlbbb-cn 作用域的 Read and write 权限,并启用 Bypass 2FA 的细粒度 npm 令牌——普通用户令牌会导致 npm 返回 EOTP(需要一次性密码)。仅在配置可信发布之前需要。
MCP RegistryGitHub OIDC工作流内置,无需密钥:publish-mcp-registry 任务会在 npmjs.org 任务之后运行 mcp-publisher login github-oidc 和 mcp-publisher publish。mcp-publisher 二进制文件的版本固定在 publish.yml 中——请谨慎升级。

如果既没有 NPM_TOKEN 密钥,也没有配置可信发布,npmjs.org 任务会失败并显示可操作的错误消息。

可以通过命令行创建备用令牌(需要输入一次 2FA 代码):

npm token create --scopes=xlbbb-cn --packages-and-scopes-permission=read-write \
                 --bypass-2fa --otp=<your-2fa-code>

--bypass-2fa 可避免 npm 在每次发布时都要求输入一次性密码;如果没有此选项,Registry 会返回 EOTP。

可信发布生效后,可以删除 NPM_TOKEN 密钥,并将软件包的 Publishing access 设置为 “Require two-factor authentication and disallow tokens”。

也可以从 Actions 选项卡手动启动工作流(workflow_dispatch);勾选 dry_run 可在不发布的情况下验证压缩包。

已发布的软件包会显示在 https://github.com/xlbbb-cn/mcp_ssh_exec_cmd/packages 和 https://www.npmjs.com/package/@xlbbb-cn/mcp_ssh_exec_cmd。

发布到 npmjs.org 需要使用拥有 @xlbbb-cn 作用域的 npm 账户(名为 xlbbb-cn 的 npm 用户或组织)。

与 FastAPI 后端的关系

方面Python 后端此 MCP 服务
存储PostgreSQL / SQLite(app.models.host)本地 JSON 文件(~/.mcp-ssh-server/hosts.json)
加密Fernet(AES-128-CBC + HMAC)AES-256-GCM + PBKDF2
SSH 客户端paramikossh2
协议HTTP REST(/api/v1/hosts 等)MCP(通过 stdio 传输的 JSON-RPC)
身份验证 / 授权RBAC(host:* 权限代码)单用户本地进程,由文件系统权限保护

我们有意避免共用存储后端:一旦涉及数据库或 API,此服务就无法再独立运行;而让 MCP 服务和后端指向同一个 JSON 文件则会造成一致性问题。

要从 FastAPI 后端迁移主机,请编写一次性脚本:列出 /api/v1/hosts(需要 host:secure:read),并将相同的字段结构传入此服务的 host_create。

已知限制

  • 主机数据存储在单个 JSON 文件中,每次更改时都会完整重写——对于数百台主机来说没问题,但不适用于数千台。
  • 不提供并发写入保护:请勿同时运行两个实例并使用相同的 MCP_SSH_CONFIG_DIR。
  • 没有审计日志或操作记录。如有需要,请在调用方 Agent 的记录中保存 SSH 输出。
  • MCP 接口有意不公开每台主机的元数据,因此模型无法查询主机地址或用户名——必须通过 host_list / host_create 操作。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。