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. 04SSH接続のプール管理
  5. 05情報を伏せたプール監視
  6. 06対話型・バッチCLI

活用シーン

  1. 01MCP経由の運用対象ホスト管理
  2. 02MCPクライアントからのリモート実行
  3. 03複数段階のSSH手順の自動化
  4. 04ホストの一括登録と接続状態の確認

MCP 対応

SSHホスト管理、リモートコマンド実行、プレイブック、プール状態をstdio型MCPツールとして公開します。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

SSH ホスト管理とリモートコマンド実行を MCP ツールとして提供する、スタンドアロンのstdio MCP サーバーです。 ローカルマシン上の SSH ホストを管理するための、対話型/バッチ型 CLI(remote-ssh-cli)も同梱しています。

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

FastAPI プロジェクト(app/services/llm_tools.py + app/utils/ssh_helper.py + app/models/host.py)の SSH ホスト部分を Node.js で再実装したものです。バックエンドもデータベースもネットワークサービスも必要ありません。任意の MCP クライアント(Claude Desktop、Continue、カスタムエージェントなど)は、npx で起動し、JSON-RPC 経由で通信できます。

主な特長

  • 完全にスタンドアロン — 独自の暗号化 JSON ストア(~/.mcp-ssh-server/hosts.json)を使用します。FastAPI バックエンドやデータベースは不要です。
  • ネイティブ依存関係なし — AES-256-GCM には Node 組み込みの crypto、SSH には純粋な JavaScript 製の ssh2 を使用します。Windows/macOS/Linux で動作します。
  • 標準準拠の stdio MCP — Model Context Protocol の stdio トランスポートに対応し、npx で起動できます。
  • 認証情報がサーバーの外部に出ることはありません — ホストツールのレスポンスにパスワードや秘密鍵が含まれることはありません。SSH ツールは内部でそれらを復号して接続を確立し、レスポンスに含めることはありません。
  • 接続プーリング — ホストごとに 1 つの SSH セッションを維持し、コマンドやプレイブックの各ステップで再利用します。
  • プールの監視 — pool_status は、稼働中のプールを機密情報をマスキングした表として表示します。uid、名前、接続状態、実行済み/失敗したコマンド、最後のコマンドが含まれます(シークレットと IP アドレスはマスキングされます)。
  • CLI コンパニオン — remote-ssh-cli で同じストアを管理できます(対話型 TUI、バッチコマンド、CSV 一括インポート)。接続プールをリアルタイムで監視することもできます(1 秒ごとに更新。q で終了)。

MCP ツール

9 つのツールを公開しています。

ツール説明
cli_helpremote-ssh-cli のインストール/使用方法/トラブルシューティングに関する説明です。topic で対象を絞り込めます
host_list登録済みホストを一覧表示します — sys_name と uid のみ(アドレス、ユーザー名、認証情報は含まれません)。uid は、ほかのすべてのツールが必要とする host_id です
host_createホストを追加します(パスワード/秘密鍵/パスフレーズは保存時に暗号化されます)
host_updateホストのフィールドを更新します(省略した認証情報フィールドは現在の値を維持します)
host_deleteホストを削除します
ssh_run_commandホストで対話なしの単一コマンドを実行します
ssh_run_interactiveexpect/answer のペアを使ってプロンプトに応答しながらコマンドを実行します(sudo など)
ssh_run_playbook複数ステップのプレイブックを実行します(構造化された # @… ディレクティブ、または従来形式の expect:/answer: 行)
pool_status稼働中の接続プールを監視します — ホストごとに、機密情報をマスキングした行を 1 つ表示します(uid、名前、状態、実行済み/失敗したコマンド、最後のコマンド)
ホスト識別子の仕様
  • host_list が最初の入口です。各ホストは sys_name(名前)と uid(一意の識別子)の、ちょうど 2 つのフィールドで返されます。
  • ほかのすべてのツールでは、同じ値を 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 のみで、ホストのアドレス、ユーザー名、認証情報が見えることはありません。CLI には、人間のオペレーター向けの 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(複数行のプレイブック本文)、timeout_seconds
pool_statushost_id?(ホストを1台のみ指定)、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/ に配置され、2つのバイナリが提供されます。

バイナリエントリーポイント用途
remote-ssh-serverdist/index.jsstdio MCP サーバー(MCP クライアントによって起動されます)
remote-ssh-clidist/cli.js対話型/バッチ型のホスト管理 CLI
インストール

パッケージは、同じ名前で2つのレジストリに公開されています。 @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.comread:packages 権限を持つクラシック形式の個人用アクセストークン

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
グローバルインストール(CLI)

ローカルのチェックアウトからインストールする場合:

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 は、ファイルの各行を 1 台のホストに変換します。 1 行目はヘッダー行で、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 行以上失敗した場合は終了コード 1 で終了します。
  • --dry-run は検証と報告のみを行い、何も書き込みません。
  • CSV テンプレート(ヘッダー+サンプル行)は remote-ssh-cli のバナーに表示されます。また、ファイル引数なしで remote-ssh-cli import を実行すると、同じ内容が表示されます。

Windows に関する注意: JScript runtime error (800A03EA) が発生した場合は、npm が 10.8.0 以上であることを確認するか、PowerShell ではなく cmd.exe からコマンドを実行してください。古いバージョンの npm が生成する .ps1 ラッパーでは、node が明示的に呼び出されないことがあります。どちらのエントリーポイントにも #!/usr/bin/env node のシバンが含まれています。

接続プールを監視する

remote-ssh-cli monitor は SSH 接続プールのライブビューを開きます。画面は 1 秒ごとに再描画され、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 シェルと cmd.exe のどちらにもあります)。各プローブは間隔ごとに 1 回実行されるため、ホスト数が多い場合は --interval を適切な値に設定してください。
  • ターミナル以外(パイプ、CI ジョブなど)では、モニターはループせずに 1 フレームだけ出力します。停止するためのキーがないためです。
オプション説明デフォルト
--interval <ms>再描画間隔1000
--timeout <s>ホストごとのプローブタイムアウト(1~600 秒)5
--probe-cmd <cmd>ホストのプローブに使用するコマンドecho
--host <host_id>このホストのみを監視します(複数回指定可能)すべてのホスト
--all無効なホストも一覧に表示します(プローブは実行されません)オフ
--once1 フレームだけ出力して終了しますオフ

同じビューは対話型 TUI(7) 接続プールを監視)からも利用できます。

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_KEY16 進文字列(16 進数 64 文字)で指定する 32 バイトのキーです。必ずバックアップしてください。この値を変更するか、別のマシンに移行すると、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 接続を 1 つ維持します。連続するコマンドやプレイブックの各ステップでは、再接続せずにその接続を再利用します。
  • プールのキーは、ホスト ID と認証情報のフィンガープリントです。アドレス、ポート、ユーザー名、認証方式、パスワード、またはキーを変更すると、キャッシュされた接続は直ちに無効になります。host_update と host_delete は接続を明示的に破棄します。
  • アイドル状態の接続は MCP_SSH_POOL_IDLE_MS の経過後に閉じられます。その間にピアが切断した接続は、次回の使用時に透過的に再確立されます(再試行は 1 回です)。
  • プロセスの終了時(つまり、MCP クライアントの切断時)に、プール内のすべての接続が閉じられます。
  • remote-ssh-cli monitor でプールの状態をリアルタイムに確認できます(接続プールの監視を参照)。同じ 2 つの環境変数が適用されます。
MCP からのプールの監視

pool_status は MCP サーバー自体のプールの状態をテーブルで表示します。プール接続またはコマンドの実行履歴があるホストごとに 1 行表示されます。

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 を指定すると、表示対象を 1 つのホストに絞り込めます。
  • カウンターはサーバープロセス内で管理されます。この MCP サーバーが実行したコマンドを記録し、再起動するとリセットされます。CLI モニターは別プロセスであり、独自のプールを表示します。
タイムアウトの動作

timeout_seconds は 厳密な上限時間です。時間切れになるとコマンドは終了され、結果は success=false、exit_code=null となり、stderr に注記が含まれます。ssh_run_playbook では、この値はプレイブック 全体に対する時間枠です。各ステップには残り時間だけが割り当てられます。

プレイブックの形式

ssh_run_playbook は複数行の本文を受け付けます。2つの形式に対応しています。

構造化形式 — ディレクティブは # @ で始まります。

# @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: ペアに応答します)

レガシー形式 — 1行につき1つのコマンドを記述し、必要に応じて expect: / answer: ペアを続けます。

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

通常の # コメントは無視されます。最初に終了コードが 0 以外になった時点でプレイブックは停止し、実行されたすべての手順の記録を返します。

ストレージとセキュリティ

  • hosts.json — すべてのホストレコードをプレーンな JSON 形式で保存します。メタデータフィールドは平文で保存されます。ssh_password、ssh_private_key、ssh_private_key_passphrase には Base64 形式の暗号文が格納されます。
  • master.key — 32 バイトのマスターキー(POSIX ではモード 0o600)。
  • 書き込みは .tmp ファイルを経由してからリネームするため、クラッシュしても書き込み途中のファイルが残ることはありません。

シークレットは、マスターキーから PBKDF2-SHA-256(200k 回の反復処理、16 バイトのランダムソルト)で導出したキーを使い、AES-256-GCM で暗号化されます。形式は [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 や format の設定はありません。テストは dist/ を実行するため、テストの前にビルドしてください。

スモークテスト

npm test は4つの通常の Node スクリプトを実行します。どのスクリプトも実際の SSH サーバーを必要としません。

  • test/smoke.mjs — 暗号化と復号の往復、HostStore の CRUD 全体(書き込み時の暗号化、読み戻し、一覧表示、更新、削除)、および両形式のプレイブック解析。
  • test/features_smoke.mjs — CSV の解析とホスト行のマッピング、一括インポート(--dry-run と重複 IP のスキップを含む)、接続プールの再利用/認証情報の変更時の無効化/アイドル接続の削除、プレイブック解析のエッジケース、コマンドとエラーのマスキング、および pool_status テーブル。
  • test/monitor_smoke.mjs — 接続プールのモニター:フレームの描画、インターバルごとに1フレームを描画するループ、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)に公開されます。2 つのパッケージジョブでビルドとスモークテストを実行し、tarball に npm provenance を付与して公開します。その後、3 つ目のジョブで server.json を MCP Registry に公開します。レジストリをミラーリングするディレクトリ(Glama、PulseMCP など)では、この情報をもとにサーバーが掲載されます。

MCP Registry のジョブは、npmjs.org のジョブの後に実行されます。レジストリは、公開済みパッケージから mcpName マーカーを読み取って npm の所有権を検証するためです。package.json の mcpName は常に server.json の name と一致している必要があり(test/features_smoke.mjs で検証されます)、CI は公開前に package.json から server.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
レジストリ認証情報入手先
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 のジョブは対処方法を示すエラーメッセージとともに失敗します。

フォールバックトークンは CLI から作成できます(2FA コードを一度入力する必要があります)。

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

--bypass-2fa を指定すると、公開のたびに npm からワンタイムパスワードを求められなくなります。指定しない場合、レジストリは EOTP を返します。

信頼された公開が機能するようになったら、NPM_TOKEN シークレットを削除し、パッケージの Publishing access を 「Require two-factor authentication and disallow tokens」 に設定できます。

ワークフローは Actions タブから手動で開始することもできます(workflow_dispatch)。公開せずに tarball を検証するには、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 に対して、2 つのインスタンスを同時に実行しないでください。
  • 監査ログや操作履歴はありません。必要な場合は、呼び出し元のエージェントのトランスクリプトに SSH の出力を記録してください。
  • MCP のインターフェースでは、ホストごとのメタデータを意図的に公開していません。そのため、モデルはホストのアドレスやユーザー名を参照できず、host_list / host_create を経由する必要があります。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。