remote-ssh-mcp について
remote-ssh-mcpは、SSH経由の複数段階の作業を行うAIエージェント向けに、永続的なリモートBashセッションをMCPツールとして提供します。作業ディレクトリと環境を保持し、ローカルのOpenSSH設定を使って接続します。
主な機能
- 01作業ディレクトリと環境を保持するセッション
- 02ホストエイリアスの検出と接続
- 03長時間コマンドのポーリング
- 04コマンド中断とセッション管理
- 05出力の切り詰めと監査ログ
活用シーン
- 01リモートホストでの複数段階のデバッグ
- 02ビルド、デプロイ、ダウンロードの実行
- 03コマンド出力の確認と停止セッションの復旧
MCP 対応
stdio経由で、SSHホストの検出、セッションの開始、コマンド実行、出力確認、中断、終了のツールをMCPクライアントに提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
7掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| reload | boolean | いいえ |
詳細
Remote SSH MCP
AI エージェント向けの永続的でステートフルなリモート Bash セッション
Model Context Protocol 経由
概要 · 機能 · 仕組み · ツール · クイックスタート · 設定 · セキュリティ · 簡体字中国語
Remote SSH MCP が選ばれる理由
多くのエージェントは、次のようにリモートマシンに接続します。
bash → ssh host "cmd" → disconnect → repeat
呼び出しのたびに、同じコストが発生します。
| 問題 | 発生すること |
|---|---|
| 🔁 トークンの浪費 | バナー、MOTD、ログイン時のノイズ、pwd / whoami による確認がコンテキストを埋め尽くします |
| 🧊 状態の消失 | cwd、export、venv の有効化、シェルの副作用が失われます |
| 🔌 不安定さ | 新規接続ではタイムアウト、ホストキーの確認、ProxyJump、認証の不安定さが発生します |
| 🌀 エラーの悪循環 | モデルがより長い確認コマンドで補おうとするため、トークンがさらに増えます |
Remote SSH MCP は、長時間維持されるリモート Bash を、MCP の第一級ツールにします。1 つのセッション ID によって、作業ディレクトリ、環境変数、シェルの副作用が維持されます。環境をクリーンな状態にしたい場合は、新しいセッションを開いてください。
Bash の単発の ssh と比べて、なぜこちらを選ぶのか?
エージェントのワークフロー(デプロイ、デバッグ、ビルド、ログの確認など、複数ステップにわたるリモート作業)で具体的に得られるメリット:
| 項目 | 単発の ssh host "…" | Remote SSH MCP |
|---|---|---|
| 💰 トークン | 各ステップで接続時のノイズや状態確認のコストが再び発生します。モデルが cd や pwd を何度も実行することもよくあります | ssh_open 時に 一度だけ コストがかかり、その後の ssh_run が返すのは主に コマンドの出力 です。構造化されたツールと head/tail の上限設定により、ツールの結果による肥大化を抑えられます。複数ステップのセッションでは、接続のたびに再接続する方式と比べて、リモートツールのコンテキストを 約 50~80%削減 できることがよくあります(実際の削減量は MOTD のサイズやモデルの出力の多さによって異なります)。 |
| ✅ 成功率 | N ステップではハンドシェイクも約 N 回発生し、失敗する機会も N 回あります(タイムアウト、踏み台、エージェント、ホストキーなど) | セッションごとのハンドシェイクは 一度だけ で、その後のコマンドは接続中のシェルで実行されます。長時間実行される処理では、ツール呼び出しを中断してやり直す代わりに、running と ssh_peek を使用します。再接続が減るため、タスクの途中で誤って「SSH failed」となるループが 大幅に減ります。 |
| 🧳 移植性 | リモート側には追加のものは必要ありません。ただし、エージェントを実行する各マシンで、同じ脆弱な ssh … パターンを再実装する必要があります | Claude/Cursor/Grok などを実行するマシンに 一度インストールするだけ です。リモートホストへのインストールは不要です(Node、MCP デーモン、エージェントはいずれも不要)。必要なのは通常のシェルアカウントと、SSH ですでに必要なツール(bash、base64、stty など)だけです。キーと踏み台ホストの設定は、ローカル の ~/.ssh/config にそのまま残ります。 |
| 🧠 モデルの使いやすさ | モデルが ssh の文字列やエスケープ処理、復旧方法を考案します | 安定したツールを使用できます:open → run → peek → close。ハンドルはセッション ID だけです。 |
| 🔐 信頼境界 | キーを過剰に公開したり、帯域内でパスワードを要求したりしがちです | OpenSSH クライアントのみを使用します。ツールがパスワードや秘密鍵の情報を受け取ることはありません |
移植性を一言で言うと: MCP を 開発用マシン/AI ホストに配置すれば、SSH 設定に登録済みのすべてのサーバーに接続できます。リモートのサーバー群へのパッケージインストールは一切不要です。
┌─────────────────────────┐ SSH (OpenSSH) ┌──────────────────┐
│ Your laptop / CI agent │ ───────────────────────────► │ prod / staging │
│ Claude · Cursor · Grok │ ~/.ssh/config · agent │ no MCP install │
│ + remote-ssh-mcp │ │ plain Bash OK │
└─────────────────────────┘ └──────────────────┘
トークン使用量の概算(複数ステップにわたるリモートデバッグの例):
One-shot path (per step × 8):
ssh wrapper + banner/MOTD + pwd/whoami + re-cd + command output
→ noise dominates; context fills with reconnect junk
Session path:
ssh_open → once (handshake + READY)
ssh_run × 8 → mostly the real stdout/stderr (truncated head+tail)
→ context stays on the work product, not the transport
SSH を再実装するものではありません。システムの OpenSSH クライアントが引き続き処理を担うため、~/.ssh/config、known hosts、SSH エージェント、ProxyJump の経路、ハードウェアキーは、これまでどおり正確に機能します。
ssh_hosts() → discover allowed Host aliases
ssh_open(host) → session id
ssh_run(id, command) → same cwd + env as last time
ssh_peek / ssh_interrupt → observe or recover long / stuck work
ssh_close(id) → release the shell and connection
機能
🧠 永続的なリモートセッション
- 1 つの 安定したセッション ID が、1 つの長時間稼働するリモート Bash に対応します
ssh_runの呼び出し間でcwdと環境が維持されます- 必要に応じて 新しいセッションを開き、状態をリセットできます
- 同じホストまたは異なるホストを対象に、複数のセッションを実行できます(
maxSessionsまで)
🔧 OpenSSH とのネイティブ連携
- 本物の
sshバイナリを起動します。独自の暗号スタックは使用しません ~/.ssh/config、Include、エージェントのソケット、ProxyJump に対応しますBatchMode=yesとStrictHostKeyChecking=yesを強制します- モデルからパスワード、秘密鍵のテキスト、任意の SSH オプション引数を受け付けることはありません
📡 長時間実行されるコマンドに対応
ssh_runは最大wait_sec(デフォルトは 10s)だけ待機し、その後、リモートコマンドの実行を継続したままstatus: "running"を返します- ビジーループではなく、
ssh_peek(wait_sec=...)によるロングポーリングで状態を確認します - 任意のハード
timeout_secを設定すると Ctrl-C を送信します。デフォルトでは自動的に終了させません - ツール呼び出しを無期限にブロックしてはならない
docker pull、ビルド、ダウンロード、デプロイに最適です
🛡️ 安全性とコントロールプレーン
ssh_configと任意の設定/環境変数の上書きから作成される、完全一致のホストエイリアス許可リスト*、?、!を含むパターンは無視されます- フェイルクローズの割り込み:Ctrl-C の後、シェルの復旧を確認できない場合はセッションを閉じます
- 明らかに破壊的なパターンをいくつか対象とする、組み込みの 拒否リスト(完全なポリシーエンジンではありません)
- アイドル状態のセッション削除、セッション数の上限、コマンドをハッシュ化した JSONL 監査ログ(
0600)
📦 モデル向けにクリーンなツール結果
stdout/stderrストリームを分離- 有効な UTF-8 の境界を考慮した先頭・末尾のバイト単位の切り詰め
- モデルに出力が渡る前にANSI / PTY のノイズを除去(色、CSI、ブラケット付きペーストマーカー、制御文字のみの空行)
- 静かなオープンフレーム:
TERM=dumb、NO_COLOR、ブラケット付きペーストを無効化 — 出力元での余計な情報を削減 - スリムな JSON ペイロード:空の
stderr、falseの切り詰めフラグ、リクエストのエコーフィールドを省略し、contentとstructuredContentの両方を含む場合も低コストに ssh_hostsは安全なメタデータのみを返します:alias、hostname、user、port、proxy_jumpIdentityFile、証明書、エージェントソケット、ProxyCommandは決して漏えいしません
🔌 MCP ネイティブ
- Claude Desktop、Cursor、その他の MCP ホスト向けの stdio トランスポート
- レガシーと現行の両方の MCP ハンドシェイクに対応
- 親プロセスまたは stdio の終了時に、追跡対象の SSH 接続をすべて閉じます
動作の仕組み
flowchart LR
A[AI Agent] -->|MCP tools| B[Remote SSH MCP]
B -->|spawn| C[OpenSSH client]
C -->|SSH + PTY| D[Remote Bash]
D --> E[(cwd / env / side effects)]
subgraph Local machine
B
C
F[~/.ssh/config<br/>agent / keys]
C -.-> F
end
subgraph Remote host
D
E
end
一般的なエージェントのフロー
1. ssh_hosts() # pick an alias from the allowlist
2. ssh_open(host="prod") # get session id "s_…"
3. ssh_run(id, "cd app && …") # state sticks to this id
4. ssh_run(id, "npm test") # still in app/, env preserved
5. ssh_peek(id, wait_sec=20) # long-poll a slow job
6. ssh_close(id) # clean up when done
MCP ツール
| ツール | 機能 |
|---|---|
🗂️ ssh_hosts | 許可された Host エイリアスを一覧表示します(安全なメタデータのみ)。~/.ssh/config の編集後に reload=true を渡します |
🔓 ssh_open | 許可された Host エイリアス用のクリーンな永続シェルを開きます → セッション id を返します |
▶️ ssh_run | 既存のセッションで非対話型コマンドを実行します |
👀 ssh_peek | 最新の N 行の出力とステータスを返します。実行中にロングポーリングする場合は、任意で wait_sec を指定します |
⛔ ssh_interrupt | Ctrl-C を送信し、シェルの復旧が確認されるまで待機します |
📋 ssh_list | セッション、cwd、状態、アイドル状態のカウントダウン、容量を一覧表示します |
🔒 ssh_close | リモートの一時状態を破棄し、接続を閉じます |
ツールのパラメーター(要点)
| ツール | 主なパラメーター |
|---|---|
ssh_open | host(必須の Host エイリアス)、任意の name ラベル |
ssh_run | id、command、任意の wait_sec、任意の timeout_sec |
ssh_peek | id、任意の lines(デフォルトは 50、最大 1000)、任意の wait_sec |
ssh_interrupt / ssh_close | id |
ssh_hosts | 任意の reload ブール値 |
クイックスタート
要件
| 要件 | 備考 |
|---|---|
| Node.js | 20 以降 |
| OpenSSH クライアント | PATH 上にシステムの ssh があること(または sshPath を設定) |
| リモートホスト | Bash + base64、stty、mkdir、cat、rm |
| SSH の設定 | ~/.ssh/config に Host エイリアスがあり、ホスト鍵がすでに信頼されていること |
⚠️ ホスト鍵の初回確認と認証は、通常のターミナルで完了させる必要があります。MCP サーバーにパスワードや信頼確認のプロンプトが表示されることはありません。
インストール
git clone https://github.com/the-nine-nation/remote-ssh-mcp.git
cd remote-ssh-mcp
npm install
npm run build
npm test
サーバーを起動します:
node /absolute/path/to/remote-ssh-mcp/dist/index.js
または npm からインストールします(公開後):
npx @zyluo/remote-ssh-mcp
# or
npm install -g @zyluo/remote-ssh-mcp
remote-ssh-mcp
または、このリポジトリからローカルパッケージをインストールした後、remote-ssh-mcp 実行ファイルを使用します。
MCP ホストの設定
ほとんどの stdio ホストは、次のような形式を受け入れます(外側のキーは製品によって異なる場合があります):
{
"mcpServers": {
"remote-ssh": {
"command": "node",
"args": [
"/absolute/path/to/remote-ssh-mcp/dist/index.js"
],
"env": {
"SSH_MCP_ALLOWED_HOSTS": "prod,staging"
}
}
}
}
Cursor · Claude Desktop · Claude Code · その他の MCP 対応ホスト:command / args をビルド済みの dist/index.js に設定し、SSH_MCP_ALLOWED_HOSTS を設定します(または ~/.ssh/config からの自動検出を利用します)。
SSH_MCP_ALLOWED_HOSTS は許可リストにエイリアスを追加します。デフォルトでは、サーバーは ~/.ssh/config とその Include ファイルから正確な Host エントリーも検出します。ツールの入力として指定できるのは安全なエイリアスのみで、user@host、ポート、追加の SSH オプションは指定できません。
~/.ssh/config の編集後は、サーバーを再起動する代わりに ssh_hosts(reload=true) を呼び出します。
認証情報の境界
認証はローカルの OpenSSH クライアント内で処理されます:
- ツールでパスワードや秘密鍵のデータを受け付けることはありません
ssh_hostsが鍵のパス、証明書、エージェントソケット、ProxyCommandを返すことはありません- エージェントは Host エイリアスを指定して
ssh_openを呼び出す必要があります。また、ディスク上の~/.ssh秘密鍵を読み取ってはなりません
設定
任意の設定ファイル(デフォルトのパス):
~/.config/remote-ssh-mcp/config.json
{
"allowedHosts": ["prod", "staging"],
"sshConfigPath": "~/.ssh/config",
"sshPath": "ssh",
"maxTimeoutSec": 1800,
"defaultWaitSec": 10,
"maxWaitSec": 30,
"openTimeoutSec": 20,
"idleTimeoutSec": 1800,
"interruptGraceSec": 5,
"maxSessions": 8,
"outputMaxBytes": 32768,
"outputHeadBytes": 4096,
"auditLogPath": "~/.local/state/remote-ssh-mcp/audit.jsonl"
}
環境変数
| 変数 | 用途 |
|---|---|
SSH_MCP_CONFIG | 設定ファイルのパス |
SSH_MCP_ALLOWED_HOSTS | 追加の Host エイリアス(カンマ区切り) |
SSH_MCP_SSH_CONFIG | SSH 設定ファイルのパス |
SSH_MCP_SSH_PATH | OpenSSH 実行ファイル |
SSH_MCP_MAX_TIMEOUT_SEC | 明示的に指定できるコマンドタイムアウトの最大値 |
SSH_MCP_DEFAULT_WAIT_SEC | ssh_run が running を返すまで待機する時間 |
SSH_MCP_MAX_WAIT_SEC | ssh_run / ssh_peek の wait_sec の最大値 |
SSH_MCP_OPEN_TIMEOUT_SEC | 接続/ハンドシェイクのタイムアウト |
SSH_MCP_IDLE_TIMEOUT_SEC | アイドル状態のセッションの有効期間 |
SSH_MCP_INTERRUPT_GRACE_SEC | Ctrl-C 後のマーカー復旧猶予時間 |
SSH_MCP_MAX_SESSIONS | ライブセッションの最大数 |
SSH_MCP_OUTPUT_MAX_BYTES | ストリームごとに保持する出力の上限 |
SSH_MCP_OUTPUT_HEAD_BYTES | 切り詰め時に保持する先頭部分のバイト数 |
SSH_MCP_AUDIT_LOG | JSONL 監査ログのパス |
環境変数はファイルの設定より優先されます。監査ログはモード 0600 で作成され、セッション、ホスト、結果、所要時間、コマンドの長さ、コマンド名、SHA-256 を記録します。引数文字列全体は記録しません(シークレットの漏えいを抑えるためです)。
実行セマンティクス
エージェント(およびユーザー)が把握しておくべき詳細なルール:
| トピック | 動作 |
|---|---|
| 並行実行 | 1 つのセッションで同時に実行できるフォアグラウンドコマンドは 1 つです。追加の ssh_run は busy を返します |
wait_sec | MCP 呼び出しの待機時間のみを制限します。時間切れになると、status: "running" が返され、リモートでの処理は続行されます |
| 再試行しない | running の後、同じ長時間コマンドを再実行しないでください。ssh_peek で状態を確認してください |
| ハードタイムアウト | 明示的に指定した timeout_sec のみが、Ctrl-C を送信する期限を設定します |
ssh_peek | デフォルトでは直近 50 行(最大 1000 行)を返します。バイト数の上限も適用され、オプションでロングポーリングの wait_sec を指定できます |
| stdin | ユーザーコマンドには /dev/null が渡されます。vim、top、対話型インストーラーは使用できません |
| 割り込みからの復旧 | Ctrl-C の後、プロトコルマーカーの復旧猶予時間が設けられます。復旧に失敗すると、セッションは閉じられます(フェイルクローズ) |
| 出力 | stdout / stderr はそれぞれ先頭と末尾を保持します。常に有効な UTF-8 の境界で切り詰められます |
| 拒否リスト | リスクの高いパターンをいくつかブロックするだけで、完全なポリシーエンジンではありません |
| 信頼モデル | ローカルの信頼された開発者向けツールです。マルチテナントのリモート実行サービスではありません |
| ホストの終了 | MCP ホスト/stdio が終了すると、すべての SSH 接続が閉じられます。nohup / setsid のジョブはその後も動作する場合があります |
例: timeout_sec を指定せずに、wait_sec: 10 で docker pull を開始します。running が返された場合、元の pull は引き続き実行中です。別の pull を開始しないでください。idle になるまで、割り込みを行うまで、または並行作業用に別のセッションを開くまで、正の値の wait_sec を指定して ssh_peek を呼び出してください。
開発
npm run typecheck
npm test
npm run build
npm audit --omit=dev
テストスイートでは、MCP stdio の検出と呼び出し、永続的な cwd / 環境状態、ストリームの分離、任意のチャンク境界でのフレーミング、タイムアウト時のフェイルクローズ動作、シェルの終了、許可リストの検出、出力の切り詰め、安全拒否リストを網羅しています。
設計メモとワイヤプロトコル:远程SSH-MCP设计.md。
セキュリティ
セキュリティの脆弱性を、公開 GitHub イシューで報告しないでください。非公開のアドバイザリーワークフローが設定されるまでは、メンテナーのGitHub プロフィールに記載されているメールアドレスから連絡してください。
MCP トランスポートが正常でも、リモートコマンドによって取り消し不能な副作用が生じる可能性があります。最小権限のアカウントを使用し、許可リストを必要最小限に保ち、ホストの権限を慎重に確認してください。
プロジェクトのステータス
| 項目 | ステータス |
|---|---|
| バージョン | 0.2.2 |
| ライセンス | MIT |
| 言語 | TypeScript (Node ≥ 20) |
| プロトコル | stdio 経由の MCP |
| ホストへのトランスポート | システムの OpenSSH |
変更履歴
未リリース — 接続と進捗のフィードバック
- カスタムの
sshConfigPath/SSH_MCP_SSH_CONFIGは、ホストの検出だけでなく、OpenSSH の-Fを介した実際の接続も制御するようになりました。デフォルトの~/.ssh/configでは OpenSSH 本来の動作が維持されます。カスタムファイルでは-Fの仕様に従い、システム全体の設定はスキップされます。 - ホストの検出では、
Host=prod、HostName = example.com、Include=...の構文も受け付けるようになりました。 ssh_openの失敗時には、元のエラーに加えて、ホストの信頼性、認証、DNS、ネットワーク、タイムアウト、ローカルのセットアップに関するreasonと、対処に役立つhintが含まれます。- 短い進捗出力は、末尾がプロトコルマーカーの途中である可能性がある場合を除き、すぐに配信されます。
- 完了した
ssh_peekの応答にはcommand_statusとduration_msが含まれるようになり、シェルの状態(idle)とコマンドの結果が区別されます。セッションが終了したときに待機中だったpeekでは、取得可能な出力に加えて、タイムアウトや中断の詳細も保持されます。削除済みのセッションへの後続の呼び出しでは、引き続きsession_goneが返されます。
0.2.2 — リモート出力を静かにし、トークンを削減
PTY を介した対話型 bash では、JSON エスケープ時に「バイナリ」のように見えるエスケープシーケンス(\u001b[?2004h、カラー CSI、カーソルコード)が頻繁に挿入されていました。このノイズは、ssh_peek / ssh_run のたびにコンテキストを消費していました。
| 変更 | 内容 |
|---|---|
| 出力のサニタイズ | ANSI/OSC/CSI を除去し、CR による上書き(進捗バー)に対応し、制御文字のみの空行を削除してから、lines ウィンドウを適用します |
| セッション開始時の静音化 | TERM=dumb / NO_COLOR / CLICOLOR=0 をエクスポートし、ブラケット付きペーストを無効にして、開始時に \033[?2004l を一度だけ送信します |
| 軽量化したツールのペイロード | 空の stderr、false のフラグ(truncated、interrupted など)、エコーされた lines を除外します。無音を明示できるよう、空の stdout は保持します |
| テスト | サニタイズ、開始フレームの静音化、セッションの出力パス、軽量化した JSON のテスト範囲を追加します |
アップグレードするには、npm i -g @zyluo/[email protected] を実行するか、MCP 設定内のパッケージを更新してから、新しいサーバーバイナリが読み込まれるよう MCP プロセスを再起動してください。
0.2.1
- 開始フレームが PTY にエコーされる場合の READY マーカーの解析を修正
0.2.0
- npm / GitHub で初の一般公開リリース
スター履歴
このプロジェクトがトークンの節約や不安定な再接続の回避に役立った場合は、GitHub で ⭐ を付けると、ほかの人にも見つけてもらいやすくなります。
一度きりの ssh host "…" ではなく、本物のリモートシェルを必要とするエージェントのために作られています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。