
SSH Host Storage & Remote Exec
io.github.xlbbb-cn由 GitHub 帳號 xlbbb-cn 發布v0.1.3更新於 Oct 27, 2026
Stdio MCP server for SSH host storage and remote command execution with a connection-pool monitor.
發布方自己的服務:Tigris MCP Server
概覽
本機 stdio MCP 伺服器,保存以加密憑證儲存的 SSH 主機,讓助理執行遠端命令、互動式應答與多步驟劇本。
- 可以做什麼
- 列出已儲存的主機,僅回傳顯示名稱與 uid 識別碼
- 建立、更新與刪除主機記錄,密碼或私鑰憑證加密儲存
- 在主機上執行單一非互動命令,並設有強制逾時
- 執行需要回應提示(如 sudo)的命令,以及含 expect/answer 的多步驟劇本
- 以去識別化表格或 JSON 檢視即時連線池,含每台主機的命令計數
- 查看 CLI 的安裝與疑難排解說明
- 適用情境
- 適合讓助理在聊天用戶端中透過 SSH 操作遠端 Linux 或 Windows 機器:執行命令、重啟服務,或在本機已登錄的主機上執行可重複的多步驟流程。
- 執行需求
- 以本機 Node.js 程序執行,透過 npx 或全域安裝啟動,不需遠端端點。須先建立主機記錄,包含位址、連接埠、使用者名稱及密碼或私鑰。選用環境變數:MCP_SSH_CONFIG_DIR、MCP_SSH_MASTER_KEY、MCP_SSH_POOL_IDLE_MS、MCP_SSH_POOL_MAX_HOSTS。需要能連線至目標主機的網路。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 SSH Host Storage & Remote Exec,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
mcp-ssh-server
A standalone stdio MCP server that turns SSH host management and remote command execution into MCP tools. It also ships an interactive / batch CLI (
remote-ssh-cli) for managing SSH hosts on the local machine.简体中文文档见 README.zh-CN.md。
This is a Node.js re-implementation of the SSH-host half of a FastAPI project
(app/services/llm_tools.py + app/utils/ssh_helper.py + app/models/host.py) —
without the backend, without the database, without a network service. Any MCP
client (Claude Desktop, Continue, a custom agent, …) can start it with npx
and talk to it over JSON-RPC.
Highlights
- Fully standalone — its own encrypted JSON store (
~/.mcp-ssh-server/hosts.json); no FastAPI backend, no database. - No native dependencies — Node's built-in
cryptofor AES-256-GCM, pure-JSssh2for SSH; runs on Windows / macOS / Linux. - Standards-compliant stdio MCP — speaks the Model Context Protocol stdio transport and can be launched with
npx. - Credentials never leave the server — host tool responses never contain a password or a private key; the SSH tools decrypt them internally to open a connection and never echo them back.
- Connection pooling — one live SSH session per host, reused across commands and playbook steps.
- Pool monitoring —
pool_statusrenders the live pool as a desensitized table: uid, name, connection state, executed / failed commands and the last command (secrets and IP addresses masked). - CLI companion —
remote-ssh-climanages the very same store (interactive TUI, batch commands, CSV bulk import) and can monitor the connection pool live (one frame per second,qquits).
MCP tools
Nine tools are published:
The host identifier contract
host_listis the entry point: every host comes back as exactly two fields —sys_name(the name) anduid(the unique identifier).- Every other tool takes that same value under the name
host_id. Pass it back unchanged; never assemble or guess one. - When an id does not resolve, the tool answers with an actionable error:
Host '<id>' not found. host_id must be the exact 'uid' value returned by host_list — call host_list to obtain the valid identifiers.Callhost_listagain and retry with the value it returns. host_getis deliberately not published to MCP clients: the model only ever seessys_name+uid, never one host's address, user name or credential. The CLI keeps its owngetsubcommand for human operators.
Arguments at a glance
ip_address is unique across the store — creating a duplicate fails.
Command results come back as a plain text block:
Quick start
The build output lands in dist/ and provides two binaries:
Install
The package is published to two registries under the same name,
@xlbbb-cn/mcp_ssh_exec_cmd:
GitHub Packages requires authentication for installs as well — even for public packages — so give npm a token first:
The same thing can be written into ~/.npmrc:
Global install (CLI)
From a local checkout:
Or straight from a registry:
Afterwards remote-ssh-cli is on your PATH:
create / update take a JSON file, e.g.:
CSV bulk import
remote-ssh-cli import hosts.csv turns every row of the file into one host.
The first line must be a header row containing at least an ip_address column:
- Column names are case-insensitive and accept aliases (
ip,host,name,port,user,password, …). - Quoted commas, embedded newlines and
""escapes are parsed per RFC 4180, so private key material is never mangled. - A bad row never aborts the batch: every row ends up reported as created / skipped (duplicate IP) / failed (invalid data). The command prints a summary and exits with code
1when at least one row failed. --dry-runonly validates and reports — nothing is written.- The CSV template (header + example row) is printed in the
remote-ssh-clibanner, andremote-ssh-cli importwithout a file argument prints the same thing.
Windows note: if you hit
JScript runtime error (800A03EA), make sure npm is >= 10.8.0 or run the command from cmd.exe instead of PowerShell — the.ps1wrapper npm generates may not invokenodeexplicitly on older npm versions. Both entry points ship a#!/usr/bin/env nodeshebang.
Monitor the connection pool
remote-ssh-cli monitor opens a live view of the SSH connection pool. The
screen is redrawn once per second and the view is left with the q
key (Ctrl+C works as well):
- The monitor keeps the pool warm: every host is probed through the very
same
ConnectionPoolthe SSH tools use, so the connections it shows are real, reusable sessions. - The CLI runs its own pool — the MCP server is a separate process, so its connections cannot be inspected from the terminal.
- The default probe command is
echo(it exists in a POSIX shell and incmd.exe); every probe runs once per interval, so keep--intervalreasonable on large host lists. - Without a terminal (a pipe, a CI job) the monitor prints a single frame instead of looping — there would be no key to stop it.
The same view is available from the interactive TUI (7) Monitor connection pool).
Register it with an MCP client
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or
%APPDATA%\Claude\claude_desktop_config.json (Windows):
On GitHub Packages, add the registry to the same snippet:
The file: form points npx straight at your local checkout — handy while
developing, and it needs no registry at all:
Configuration
Everything is configured through environment variables:
SSH connection pool
- Every host keeps one SSH connection; consecutive commands and the steps of a playbook reuse it instead of reconnecting.
- The pool is keyed on the host id plus a fingerprint of the credentials. Changing the address, port, user name, auth method, password or key invalidates the cached connection right away;
host_updateandhost_deletedrop it explicitly. - Idle connections are closed after
MCP_SSH_POOL_IDLE_MS. A connection the peer dropped in the meantime is transparently re-established on the next use (one retry). - All pooled connections are closed when the process exits (i.e. when the MCP client disconnects).
remote-ssh-cli monitorshows the pool live (see Monitor the connection pool); it honours the same two environment variables.
Monitoring the pool from MCP
pool_status renders the state of the MCP server's own pool as a table —
one row per host that has a pooled connection or command traffic:
- The table is desensitized: credentials are masked (
mysql -pS3cret→mysql -p***), IP addresses are replaced (10.0.0.5→***), and no address, port, user name or credential of a host is ever shown. format: "json"returns the same information as a JSON document,include_history: trueadds the most recent commands per host,include_idle_hosts: truealso lists hosts without traffic, andhost_idnarrows the view to a single host.- The counters live in the server process: they describe the commands this MCP server ran and are reset when it restarts. The CLI monitor is a separate process and shows its own pool.
Timeout semantics
timeout_seconds is a hard cap: when it expires the command is terminated
and the result reports success=false, exit_code=null plus a note in
stderr. For ssh_run_playbook the value is the budget for the whole
playbook — every step only gets the time that is left.
Playbook format
ssh_run_playbook accepts a multi-line body. Two formats are supported.
Structured — directives start with # @:
Legacy — one command per line, optionally followed by expect: / answer: pairs:
Ordinary # comments are ignored. A playbook stops at the first non-zero exit
code and returns the transcript of every step that ran.
Storage & security
hosts.json— all host records as plain JSON. The metadata fields are stored in clear text;ssh_password,ssh_private_keyandssh_private_key_passphrasehold base64 ciphertext.master.key— the 32-byte master key (mode0o600on POSIX).- Writes go through a
.tmpfile plus a rename, so a crash never leaves a half-written file behind.
Secrets are encrypted with AES-256-GCM using a key derived from the master
key with PBKDF2-SHA-256 (200k iterations, 16-byte random salt). The layout
is [16-byte salt][12-byte IV][16-byte tag][ciphertext]; salt and IV are
fresh for every encryption, so the same plaintext never produces the same
ciphertext twice.
Keep the whole directory out of version control:
Project layout
Development
npm run build is the verification step — there is no separate lint or format
configuration. The tests execute dist/, so build before testing.
Smoke tests
npm test runs four plain Node scripts; none of them needs a real SSH server:
test/smoke.mjs— encrypt/decrypt round-trip, the full HostStore CRUD path (encrypt on write, read back, list, update, delete) and playbook parsing for both formats.test/features_smoke.mjs— CSV parsing and host-row mapping, bulk import (including--dry-runand duplicate-IP skipping), connection-pool reuse / credential-change invalidation / idle eviction, playbook parsing edge cases, the redaction of commands and errors, and thepool_statustable.test/monitor_smoke.mjs— the connection-pool monitor: frame rendering, the one-frame-per-interval loop, theqshortcut, the SSH probe (against a fake client) and the pool snapshot.test/mcp_smoke.mjs— spawns the MCP server as a child process, performs the JSON-RPC handshake and asserts that all 9 tools are registered, thathost_listexposes onlysys_name+uid, thathost_getis not advertised, thatpool_statusreturns a desensitized table, and that no password ever appears in a response.
Run a single file with node test/<file>.mjs. Every test isolates its state in
a temporary MCP_SSH_CONFIG_DIR, so your real hosts.json is never touched.
Releasing
Releases are published to npmjs.org, GitHub Packages and the
official MCP Registry (registry.modelcontextprotocol.io) by a GitHub
Actions workflow (.github/workflows/publish.yml). The two package jobs
build, run the smoke tests and publish with npm provenance attached to the
tarball; the third job then publishes server.json to the MCP Registry,
which is what directories mirroring the registry (Glama, PulseMCP, …)
list the server from.
The MCP Registry job runs after the npmjs.org job because the registry
verifies npm ownership by reading the mcpName marker out of the published
package: mcpName in package.json must always equal server.json's
name (asserted by test/features_smoke.mjs), and CI re-syncs the version
in server.json from package.json before publishing.
Without either the NPM_TOKEN secret or a configured trusted publisher the
npmjs.org job fails with an actionable error message.
The fallback token can be created from the CLI (it needs your 2FA code once):
--bypass-2fa is what keeps npm from asking for a one-time password on every
publish; without it the registry answers with EOTP.
Once trusted publishing works, the NPM_TOKEN secret can be deleted and the
package's Publishing access can be set to "Require two-factor
authentication and disallow tokens".
The workflow can also be started by hand from the Actions tab
(workflow_dispatch); tick dry_run to verify the tarball without publishing.
The published packages show up under https://github.com/xlbbb-cn/mcp_ssh_exec_cmd/packages and https://www.npmjs.com/package/@xlbbb-cn/mcp_ssh_exec_cmd.
Publishing to npmjs.org requires an npm account that owns the
@xlbbb-cnscope (an npm user or organization namedxlbbb-cn).
Relation to the FastAPI backend
Sharing one storage backend is deliberately avoided: as soon as a database or an API is involved, this server can no longer run standalone — and pointing both the MCP server and the backend at the same JSON file would create consistency problems.
To migrate hosts from the FastAPI backend, write a one-off script: list
/api/v1/hosts(requireshost:secure:read) and feed the same field shape into this server'shost_create.
Known limitations
- The host data lives in a single JSON file that is rewritten in full on every change — fine for hundreds of hosts, not for thousands.
- There is no concurrent-write protection: do not run two instances against the same
MCP_SSH_CONFIG_DIRat the same time. - There is no audit log or operation trail. If you need one, capture the SSH output in the calling agent's transcript.
- The MCP surface intentionally exposes no per-host metadata, so a model cannot look up a host's address or user name — it has to go through
host_list/host_create.
來源:README.md,提交 69688ea
工具
0版本歷史
1- v0.1.3最新Oct 23, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分
其他 Storage 整合
Tigris MCP Server
dev.storage官方發布者
遠端 MCP 端點,將 AI 助理連接到 Tigris,用來管理雲端物件儲存中的儲存桶與物件。
Kinnovis Self-Storage
ai.b77官方發布者
讓助理在對話中管理 Kinnovis 自助倉儲資費。
File Storage
ai.b77官方發布者
遠端 MCP 伺服器,讓助理在對話中上傳檔案並取回公開的 CDN 連結。

Bulk File Downloader — URL Lists to Storage, Links & SHA-256
由 GitHub 帳號 kriton-dev 發布
Bulk File Downloader — URL Lists to Storage, Links & SHA-256 的託管 MCP 服務;需要憑證;Streamable HTTP。

Gie Storage
由 GitHub 帳號 pipeworx-io 發布
GIE Storage MCP — 來自Gas的歐洲天然氣儲氣庫和LNG接收站透明度資料…AI 翻譯