Skip to main content
Glama

ssh-mcp

A centralized MCP gateway that gives AI agents controlled access to SSH infrastructure over Streamable HTTP.

ssh-mcp runs as a single HTTP service. Multiple AI clients — agents, CI pipelines, dashboards — connect to one gateway. SSH credentials stay on the gateway. Authorization policies, audit logging, and rate limiting are applied centrally before any SSH command executes.

License: MIT Docker MCP Security M8ven Live Monitored


目次


Related MCP server: MCP SSH Orchestrator

アーキテクチャ

ローカル stdio MCP(一般的なパターン)

AI client
   │
   ▼
local MCP process ──► SSH target

各エージェントは独自のプロセスで実行されます。SSH 認証情報はすべてのマシンに置かれ、集中管理はありません。

ssh-mcp(集中型 HTTP ゲートウェイ)

AI clients ───────┐
CI agents ────────┼──► ssh-mcp ──► SSH targets
Dashboards ───────┘      │
                         ├─ API-key authentication
                         ├─ per-client authorization
                         ├─ rate limiting
                         ├─ audit logging
                         └─ connection pooling

単一のデプロイがすべてのクライアントにサービスを提供します。認証情報、ポリシー、ログは一か所に集約されます。


ssh-mcp を選ぶ理由

  • 集中型 HTTP ゲートウェイ — 単一のデプロイがすべての AI エージェント、CI パイプライン、ダッシュボードに Streamable HTTP でサービスを提供します

  • クライアント単位の認可 — API キーごとに異なるコマンドセットを異なるサーバーに対して許可します

  • 多層コマンドポリシー — ブロックパターン、危険シェル検出、ターゲットごとの許可リストが連携して機能します

  • 集中型 SSH アクセス — SSH 認証情報はゲートウェイ上に置かれ、各エージェントのマシンには置かれません

  • 監査証跡 — すべてのコマンド、すべてのクライアント、すべての結果をリクエストトレーシング付きの構造化 JSONL ログとして記録します

  • 運用上の回復力 — コネクションプーリング、サーキットブレーカー、指数バックオフ付きリトライ

  • 可観測性 — 監視用の Prometheus メトリクスとヘルスエンドポイント


マルチエージェントのアクセス制御

エージェントごとに必要な権限は異なります。ssh-mcp はこれをゲートウェイで強制します。

monitoring agent  →  API key A  →  read-only commands  →  all servers
deployment agent  →  API key B  →  deploy commands      →  web servers only
database agent    →  API key C  →  db commands           →  database server only
                  ┌─ monitoring agent (read-only, all servers)
                  ├─ deployment agent (deploy commands, web only)
MCP clients ──────┼─ database agent (db commands, db server only)
                  └─ ...
                         │
                         ▼
                      ssh-mcp
                         │
                  centralized policies
                         │
              ┌──────────┼──────────┐
              ▼          ▼          ▼
             web         db      monitoring
           servers    servers     servers

この構成を示す最小限の設定例:

{
  "version": 1,
  "ssh_targets": {
    "web-1": { "host": "10.0.1.10", "username": "deploy" },
    "db-1":  { "host": "10.0.1.20", "username": "dbadmin" }
  },
  "allowed_commands": {
    "default": {
      "web-1": { "allow": ["uptime", "df -h", "free -m"] }
    },
    "api_keys": {
      "deploy-key": {
        "web-1": { "allow": ["systemctl restart app", "deploy *"] }
      },
      "db-key": {
        "db-1": { "allow": ["systemctl restart postgres", "pg_dump *"] }
      }
    }
  }
}

課題

ほとんどの MCP SSH サーバーはローカルの stdio プロセスとして実行されます。クライアントごとにプロセスが分かれ、共有状態、集中認可、監査証跡がありません。複数の AI エージェント、CI パイプライン、ダッシュボードが SSH アクセスを必要とする場合、それぞれが独自の SSH キーを管理し、独自の MCP プロセスを実行します。これにより次の問題が発生します:

  • 集中アクセス制御がない — 各クライアントが実行内容を自分で決めてしまう

  • 監査証跡がない — コマンドは運用チームから見えない

  • SSH キーの乱立 — キーがエージェントを実行するすべてのマシンに散在する

  • レート制限がない — 暴走したエージェントがターゲットを圧倒する可能性がある

  • コネクションプーリングがない — 各クライアントが独立して SSH セッションを開閉する

ssh-mcp は、単一の MCP サーバーを HTTP ゲートウェイとしてデプロイすることでこの問題を解決します。すべてのクライアントがゲートウェイに接続し、ゲートウェイが SSH ターゲットに接続します。認可、認証、レート制限、コネクションプーリング、監査ログは一か所で行われます。


ユースケース

マルチエージェントサーバー管理

アクセスレベルが異なる AI エージェントのチームを運用します。デプロイエージェントは Web サーバー上で systemctl restart nginx を実行でき、監視エージェントはどこでも journalctl を実行でき、データベースエージェントは DB サーバー上で psql のみ実行できます。各エージェントは独自の API キーで認証され、各キーには独自の権限セットがあります。

CI/CD パイプライン統合

すべてのランナーで SSH キーを管理する代わりに、CI パイプラインを ssh-mcp に向けます。パイプラインごとに単一の API キー、CI サブネット用のネットワークベースのルール、コマンド許可リストにより、デプロイスクリプトは意図したコマンドだけを実行します。それ以上は実行されません。

ログと設定の一元的な取得

ssh_download_file を使用すると、MCP クライアントから離れることなく、リモートサーバーからログ、設定ファイル、データベースダンプを取得できます。8 層のパス検証とサンドボックスルート設定により、ファイル転送は安全な境界内に留まります。

サーバーヘルスダッシュボード

uptimefreedfps をフリート全体で照会する MCP ベースのダッシュボードを構築します。コネクションプールが SSH セッションを再利用し、サーキットブレーカーが障害のあるターゲットを隔離し、/metrics の Prometheus メトリクスが既存の監視スタックに供給されます。

コンプライアンスと監査

すべてのコマンドは構造化 JSONL で記録されます。誰が、どのサーバーで、どの IP から、何を実行したか、許可されたかどうか、所要時間。matched_via フィールドは、どの認可レイヤーが判断を下したかを正確に追跡します。設定変更は変更前後の状態とともに別途記録されます。


セキュリティモデル

ssh-mcp はすべてのレイヤーで多層防御を適用します。完全なセキュリティモデルは docs/SECURITY.md に記載されています。

セキュリティ境界: ssh-mcp は SSH の前に認可、認証、監査レイヤーを追加します。基盤となる SSH アカウントの権限を置き換えるものではありません。コマンドが許可された場合、SSH ユーザーはそのアカウントが持つ権限でコマンドを実行します。ゲートウェイ自体は TLS とネットワークアクセス制御で保護する必要があります。ログにはコマンド出力が含まれる可能性があるため、それに応じて取り扱ってください。

コマンド認可チェーン

コマンドは順序付けられた多層チェーンで評価されます。いずれかのレイヤーが拒否した場合、リクエストはそこで停止します。

レイヤー

チェック内容

1. ターゲット検証

サーバー名が既知か?

2. block_patterns

コマンドがブロック済みの正規表現に一致するか?

3. 危険パターン

$()、バッククォート、または改行が含まれるか?

4. リダイレクトガード

シェルリダイレクトが /dev//proc//sys/ を対象にしているか?

5. セグメント化

リダイレクトを除去し &&, `

, ;, |\, 各セグメントが完全なチェーンを実行します

6. default ルール

全クライアントの許可/拒否ルール

7. api_keys ルール

キーごとの許可/拒否ルール

8. networks ルール

CIDR ごとの許可/拒否ルール

9. 拒否

暗黙のフォールバック

認証

API キーは X-API-Key または Authorization: Bearer ヘッダーで送信されます。キーは PBKDF2-HMAC-SHA256(100,000 回の反復、ランダムな 16 バイトのソルト)でハッシュ化され、定数時間比較で検証されます。生のキーが保存されることはありません。

入力サニタイズ

コマンド、ターゲット名、ログ文字列は処理前にサニタイズされます。ヌルバイトの除去、制御文字の削除、NFKC 正規化、そして block_patterns に対する ReDoS 保護 が適用されます。

パストラバーサル防止

SFTP 転送は、ヌルバイトチェック、制御文字の除去、ドットセグメントの正規化、シンボリックリンクの解決、サンドボックスルートの強制を含む 8 層のパス検証を通過します。

レート制限

クライアント IP ごとのスライディングウィンドウレートリミッター(60 リクエスト / 60 秒、/health は免除)。違反は Retry-After 付きの HTTP 429 を返します。

レート制限は settings.rate_limit で設定できます:

"settings": {
  "rate_limit": {
    "enabled": true,                        // set false to disable entirely
    "max_requests_per_minute": 60,          // max requests per client IP in the window
    "window_seconds": 60.0,                 // sliding-window duration
    "cleanup_interval_seconds": 300.0       // expired-entry GC interval
  }
}

注: レートリミッターはコンテナ起動時に初期設定から一度だけ構築され、設定のホットリロードでは再構築されません。レート制限を無効にするには、起動時に存在する設定(例: マウントされたボリューム内の config/ssh-mcp-config.json)で settings.rate_limit.enabledfalse に設定する必要があります。これは、単一の IP から多数のリクエストを発行する高トラフィッククライアントやテストスイートに便利です。


クイックスタート

前提条件

  • Docker と Docker Compose

  • 接続先サーバー用の SSH キーペア(またはターゲットごとのパスワード)

1. ディレクトリを準備する

mkdir -p config logs
ssh-keygen -t ed25519 -f ssh_key -N ""
cp default-config.json config/ssh-mcp-config.json

2. SSH ターゲットを追加する

config/ssh-mcp-config.json を開き、ターゲットを 1 つ追加します:

{
  "version": 1,
  "ssh_targets": {
    "web-server": {
      "host": "192.168.1.10",
      "port": 22,
      "username": "deploy",
      "private_key": "/app/ssh_key"
    }
  },
  "block_patterns": [ "\\brm\\s+-rf\\b", "\\bdd\\s+if=" ],
  "allowed_commands": {
    "default": [
      { "targets": ["*"], "commands": ["hostname", "uptime", "free", "df", "ps", "ls", "cat"] }
    ]
  },
  "settings": {}
}

3. サーバーを起動する

docker compose up -d --build

4. 起動を確認する

curl http://localhost:9080/health
# {"status": "ok", "connection_pool": {...}}

5. MCP クライアントを接続する

Streamable HTTP をサポートする MCP クライアントは接続できます。API キーヘッダーを付けて http://localhost:9080/mcp を指定します。詳細は MCP クライアント構成 を参照してください。

6. サーバーを一覧表示してコマンドを実行する

curl -X POST http://localhost:9080/mcp \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "ssh_list_servers",
      "arguments": {}
    }
  }'

curl -X POST http://localhost:9080/mcp \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "ssh_execute_command",
      "arguments": {"server_name": "web-server", "command": "uptime"}
    }
  }'

MCP クライアント構成

Streamable HTTP トランスポートをサポートする MCP クライアントは接続できます。設定形式はクライアントによって異なります。以下の URL とヘッダーを使用してください。

設定

トランスポート

Streamable HTTP

URL

https://ssh-mcp.example.com/mcp

認証

X-API-Key ヘッダーまたは Authorization: Bearer

汎用 Streamable HTTP 構成

{
  "mcpServers": {
    "ssh": {
      "url": "http://localhost:9080/mcp",
      "headers": {
        "Authorization": "Bearer <your-api-key>"
      }
    }
  }
}

Python クライアント

import requests

MCP_URL = "https://ssh-mcp.example.com/mcp"
API_KEY = "your-api-key"


def call_tool(name: str, arguments: dict) -> dict:
    response = requests.post(
        MCP_URL,
        headers={
            "Content-Type": "application/json",
            "X-API-Key": API_KEY,
        },
        json={
            "jsonrpc": "2.0",
            "id": 1,
            "method": "tools/call",
            "params": {"name": name, "arguments": arguments},
        },
    )
    response.raise_for_status()
    return response.json()


print(call_tool("ssh_list_servers", {}))
print(call_tool("ssh_execute_command", {
    "server_name": "web-server",
    "command": "uptime",
}))

生の JSON-RPC

ツール呼び出しを JSON-RPC の tools/call リクエストとして /mcp に送信します:

curl -X POST http://localhost:9080/mcp \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "ssh_execute_command",
      "arguments": {"server_name": "web-server", "command": "uptime"}
    }
  }'

ツール

すべてのツール呼び出しは JSON-RPC の tools/call リクエストとして /mcp に送信されます。すべてのツールは文字列(JSON またはプレーンテキスト)を返します。

Tool

Parameters

Description

ssh_list_servers

(なし)

設定済みのSSHターゲット(ホスト、ポート、ユーザー名 — シークレットは含まない)を一覧表示します

ssh_list_allowed_commands

server_name (str)

現在のクライアントがターゲット上で実行できるコマンドを一覧表示します(default + api_key + networkルールの和集合)

ssh_execute_command

server_name (str)、command (str)、timeout (int、デフォルト 30)、sudo (bool、デフォルト false)

SSH経由でコマンドを実行します。stdoutを返します(stderrは[STDERR]として、終了コードは[EXIT: n]として付加されます)

ssh_download_file

server_name (str)、remote_path (str)

SFTP経由でファイルをダウンロードします。認可はcat <path>と同等です

ssh_upload_file

server_name (str)、remote_path (str)、content (str)、permissions (str、デフォルト "0644")

SFTP経由でファイルをアップロードします。認可はtee <path>と同等です

ssh_check_connection

server_name (str)、timeout (int、デフォルト 10)

ターゲットのcheckcommandを実行してSSH接続を確認します。成功フラグ、出力、終了コードを返します

# List available servers
call_tool("ssh_list_servers", {})
# {"web-server": {"host": "192.168.1.10", "port": 22, "username": "deploy"}}

# List what this client can run on web-server
call_tool("ssh_list_allowed_commands", {"server_name": "web-server"})
# ["cat", "df", "du", "free", "grep", "head", "hostname", ...]

# Execute a command
call_tool("ssh_execute_command", {
    "server_name": "web-server",
    "command": "uptime",
})
# " 07:12:33 up 10 days,  2:15,  1 user,  load average: 0.08, 0.03, 0.01"

# Download a file
call_tool("ssh_download_file", {
    "server_name": "web-server",
    "remote_path": "/etc/hostname",
})
# "web-server\n"

# Upload a file
call_tool("ssh_upload_file", {
    "server_name": "web-server",
    "remote_path": "/tmp/backup.sql",
    "content": "CREATE TABLE ...;\n",
    "permissions": "0640",
})
# "OK: Uploaded 19 bytes to /tmp/backup.sql"

# Check SSH connectivity
call_tool("ssh_check_connection", {"server_name": "web-server"})
# {"success": true, "output": "ping", "error": null, "exit_code": 0, "checkcommand": "echo ping"}

# Check with custom timeout
call_tool("ssh_check_connection", {"server_name": "web-server", "timeout": 5})

sudoに関する注意: sudo_passwordパラメータはありません。sudoがパスワードを要求する場合、設定内のターゲットのpasswordフィールドから取得されます。sudoフラグはsudo -S -p ''(設定からのパスワード)またはsudo -n(パスワードなし)でラップします。

エラーレスポンス

失敗時、ツールは以下を返します:

{
  "error": true,
  "error_type": "AuthorizationError",
  "message": "Command rejected: target 'foo' not found",
  "retryable": false,
  "request_id": "abc-123"
}

一般的なerror_typeの値: AuthorizationErrorPathValidationErrorFileTransferErrorSSHAuthenticationErrorSSHTimeoutErrorMCPSSHErrorretryableフラグはSSHTimeoutErrorの場合にtrueになります。レート制限違反は代わりにHTTP 429を返します。


設定

設定ファイルの場所

サーバーは<config_dir>/ssh-mcp-config.jsonを読み取ります。config_dir--configCLIフラグまたはMCP_SSH_CONFIG_PATH環境変数で設定します(デフォルト: /config)。ファイルが存在しない場合、サーバーはバンドルされたdefault-config.jsonを書き込みます。

トップレベルの構造

{
  "version": 1,
  "ssh_targets": { ... },
  "block_patterns": [ ... ],
  "allowed_commands": {
    "default": [ ... ],
    "api_keys": [ ... ],
    "networks": [ ... ]
  },
  "settings": { ... }
}

設定はロード時にconfig.schema.json(JSON Schema Draft 2020-12)に対して検証されます。不明なキーはハードエラーを引き起こします。

ssh_targets

サーバー識別子をキーとするオブジェクト。各ターゲットにはhostportusernameと、private_keyまたはpasswordの少なくとも一方が必要です。

"ssh_targets": {
  "web-server": {
    "host": "192.168.1.10",
    "port": 22,
    "username": "deploy",
    "private_key": "/app/ssh_key",
    "checkcommand": "echo ping"
  }
}

フィールド

必須

デフォルト

説明

host

はい

ホスト名またはIPアドレス

port

いいえ

22

SSHポート

username

はい

SSHユーザー名

private_key

*

サーバーのファイルシステム上のSSH秘密鍵ファイルへのパス

password

*

SSHパスワード(secrets.jsonまたは環境変数でも設定可能)

checkcommand

いいえ

"echo ping"

ssh_check_connectionが接続確認のために実行するコマンド

* private_keyまたはpasswordの少なくとも一方が必要です。

private_keyはサーバーのファイルシステム上のパスです(Dockerではコンテナにマウントされます)。インラインキーではありません。

block_patterns

正規表現パターンのリスト。パターンに一致するコマンドは、他の許可リスト層にかかわらず拒否されます。パターンはロード時に破滅的バックトラッキング構造がないか検査され(ReDoS保護)、実行時にはタイムアウトガード付きでコンパイルされます。

allowed_commands

3つのサブオブジェクトが、各クライアントが実行できるコマンドを制御します:

  • default — すべてのクライアント向けのルール(より具体的なレイヤーが先に決定しない限り)

  • api_keys — キーごとのルール。key_hashで照合されます

  • networks — CIDRごとのルール。クライアントの送信元IPで照合されます

各ルールにはtargetsリスト(サーバーIDまたは全対象の"*")とcommandsリスト(基本コマンド名または任意のコマンドの"*")があります。

"allowed_commands": {
  "default": [
    { "targets": ["*"], "commands": ["hostname", "uptime", "free", "df", "ps"] }
  ],
  "api_keys": [
    {
      "name": "ci-bot",
      "key_hash": "pbkdf2:sha256:100000$<salt>$<hash>",
      "rules": [
        { "targets": ["web-server"], "commands": ["systemctl", "journalctl"] }
      ]
    }
  ],
  "networks": [
    {
      "name": "home-lan",
      "range": "192.168.1.0/24",
      "rules": [
        { "targets": ["*"], "commands": ["*"] }
      ]
    }
  ]
}

settings

設定

デフォルト

説明

max_output_length

50000

クライアントに返されるコマンド出力の最大バイト数(整数またはサイズ文字列)

command_timeout_max

120

コマンドタイムアウトの上限(秒)

retry_max_attempts

3

一時的なSSH障害時の再試行回数

retry_backoff_base_seconds

1.0

指数バックオフの基準値(秒)

circuit_breaker_failure_threshold

5

ターゲットごとにサーキットブレーカーが開くまでの失敗回数

circuit_breaker_timeout_seconds

60.0

開いたサーキットの回復タイムアウト(秒)

log_level

"INFO"

ログレベル: DEBUG、INFO、WARNING、ERROR

max_log_output

4096

ログエントリに保存される出力の最大文字数

compress_rotated

true

ローテーションされたログファイルをGzip圧縮する

pool_max_connections_per_target

5

ターゲットごとのプールされるSSH接続の最大数

pool_idle_timeout_seconds

300.0

アイドル接続のタイムアウト(秒)

pool_cleanup_interval_seconds

60.0

プールのクリーンアップ間隔(秒)

max_concurrent_ssh_connections

20

全ターゲットにわたるグローバル上限。超過時はHTTP 503を返します

watcher_debounce_seconds

2.0

設定リロード間の最小間隔。0で無効

trusted_proxies

[]

信頼するリバースプロキシのIP(IPv4/IPv6)

SFTP設定(settings.sftp

設定

デフォルト

説明

sftp.sandbox_root

"/"

SFTPパス検証のルートディレクトリ

sftp.max_path_length

4096

SFTPパスの最大許容長(バイト)。0で無効

シークレット

SSHターゲットのパスワードとAPIキーのハッシュは、メイン設定から分離して<config_dir>/secrets.jsonまたはMCP_SSH_SECRET_*環境変数に格納できます。優先順位:

environment variables  >  secrets.json  >  ssh-mcp-config.json

シークレットソース

効果

secrets.json

ターゲットごとのpasswordとキーごとのkey_hashの上書き(名前で照合)

MCP_SSH_SECRET_PASSWORD_<TARGET_ID>

ssh_targets[<TARGET_ID>].passwordを上書き

MCP_SSH_SECRET_API_KEY_<KEY_NAME>

api_keysエントリ<KEY_NAME>key_hashを上書き

<TARGET_ID><KEY_NAME>は大文字化され、-_に変換されます。APIキーの値はハッシュ文字列である必要があり、生のキーではありません。

環境変数とCLIフラグ

環境変数

CLIフラグ

デフォルト

レガシーフォールバック

MCP_SSH_CONFIG_PATH

--config

/config

CONFIG_DIR

MCP_SSH_SSH_KEY

--ssh-key

ssh_key

SSH_KEY_PATH

MCP_SSH_LOG_DIR

--log-dir

/logs

LOG_DIR

MAX_OUTPUT_LENGTH

--max-output

50000

CONFIG_API_ENABLED

false

CONFIG_API_TOKEN

(API有効時に必須)

--fix-permissions

False

--print-default-config

CLIフラグは環境変数より優先されます。settingsの任意のキーは、実行時にMCP_SSH_SETTING_<KEY>(大文字化、-_)で上書きできます。

ホットリロード

サーバーは設定ファイルの変更をポーリングします(15秒間隔、2秒デバウンス)。変更が検出されると、再読み込み、検証を行い、新しい設定をアトミックに入れ替えます。設定変更コールバック(認可ルールの再構築、接続プールの更新)は、入れ替えが成功した後に実行されます。利用可能な場合はウォッチドッグベースのファイル監視が使用されます。


可観測性

ヘルスチェック

GET /health{"status": "ok"}と接続プールの統計情報を返します。コンテナのHEALTHCHECKはこのエンドポイントを使用します。

Prometheusメトリクス

GET /metricsは専用レジストリにメトリクスを公開します。すべてmcpssh_プレフィックスが付きます:

メトリクス

タイプ

ラベル

mcpssh_requests_total

Counter

toolstatus(success/error/denied)

mcpssh_ssh_connections_total

Counter

target

mcpssh_ssh_connection_duration_seconds

Histogram

target

mcpssh_auth_denials_total

Counter

reason

mcpssh_command_duration_seconds

Histogram

target

mcpssh_pool_active_connections

Gauge

target

mcpssh_pool_idle_connections

Gauge

target

mcpssh_pool_created_total

Counter

target

構造化ロギング

mcp-sshサーバーは、設定ファイルのsettings.logging.log_targetsで構成されるプラグイン可能なログターゲットをサポートしています。各ターゲットは、すべてのログエントリを受け取る独立したドライバーです。

デフォルトの動作

デフォルトでは、ログエントリは人間が読めるテキスト形式でstdoutに書き込まれます。これは、コンテナログがランタイムによって取得されるDocker環境に適しています。

ログターゲットの種類

Target

Config value

Format

Description

Stdout

"stdout"

Text

標準出力に書き込みます。デフォルトのターゲット。

JSON File

"jsonfile"

JSONL

1行に1つのJSONオブジェクトをファイルに書き込みます。

Text File

"file"

Text

人間が読みやすいテキストをファイルに書き込みます。

設定

{
  "settings": {
    "log_level": "INFO",
    "logging": {
      "log_targets": [
        { "target": "stdout" },
        { "target": "jsonfile", "filepath": "logs/ssh-mcp.log" }
      ],
      "max_log_output": 4096,
      "compress_rotated": true
    }
  }
}

ログレベル

  • 設定ファイル: settings.log_level を設定してデフォルトレベルを制御します。

  • 環境変数: MCP_SSH_LOG_LEVEL を設定すると、設定ファイルのデフォルトを上書きします(例: MCP_SSH_LOG_LEVEL=DEBUG)。

  • ターゲットごと: 各ログターゲットは独自の log_level を持ち、デフォルトを上書きできます。

レガシー設定

settings.logging が存在しない場合、サーバーはログディレクトリ(デフォルトでは /logs)内の単一の JSONL ファイルターゲットにフォールバックします。これにより、既存の設定との後方互換性が維持されます。

テキストフォーマット

標準出力およびテキストファイルターゲットは次の形式を使用します:

2025-01-15 10:30:00 INFO ssh_execute_command: Command executed on server1

JSONフォーマット

JSONファイルターゲットは1行に1つのJSONオブジェクトを書き込みます:

{"timestamp": "2025-01-15T10:30:00+00:00", "event": "ssh_execute_command", "level": "INFO", "message": "Command executed on server1", "request_id": "abc-123", "log_level": "INFO", "log_format_version": 1}

ファイルローテーション

ファイルベースのターゲットは max_file_size_mb(デフォルト: 10 MiB)を超えるとローテーションされ、backup_count 個のバックアップ(デフォルト: 5)が保持されます。ローテーションされたファイルは、compress_rotatedtrue の場合に gzip 圧縮されます。

設定変更イベント

Event

Meaning

config.load

起動時に初期設定が読み込まれた

config.reload

設定がディスクから再読み込みされた(successchanged_keystargets_addedtargets_removed を含む)

config.migrated

スキーママイグレーションが適用された(from_versionto_version

config.default_created

同梱のデフォルト設定がコピーされた

config.fallback

メモリ内デフォルトにフォールバックした

config.callback_error

設定変更コールバックが例外を発生させた


設定APIとWebダッシュボード

統合コンテナには、オプションの 設定APIとWebダッシュボード が含まれています。これは、SSHポリシー、ターゲット、コマンドルール、バックアップのための完全な管理プレーンです。設定ファイルの編集は不要です。この機能はデフォルトで無効になっています。

機能概要

  • Webダッシュボード — 5つのページ(SSH Targets、Block Patterns、Command Rules、Settings、Backups)を備えたレスポンシブなシングルページアプリケーションです。APIトークンでログインし、ブラウザからすべてを管理できます。

  • REST API — すべての設定セクションに対する完全なCRUDに加え、設定検証、APIキーのハッシュ化、バックアップ管理、インラインSSH接続テストを提供します。

  • APIキーハッシュ化ユーティリティ — プレーンテキストのAPIキーを、設定にそのまま使えるPBKDF2文字列にハッシュ化します。ハッシュ形式を推測する必要はもうありません。

  • バックアップとリストア — 書き込みのたびに設定を自動バックアップします。ダッシュボードまたはAPIからバックアップの一覧表示、リストア、削除が可能です。

  • アトミックでスレッドセーフな書き込み — すべての設定書き込みは検証され、スレッドロックで直列化され、ディスクにアトミックに書き込まれます。

  • Swagger UI & ReDoc/api/docs/api/redoc に自動生成された対話型APIドキュメントを提供します。

設定APIを有効にする

compose.yaml または .env ファイルで以下の環境変数を設定します:

Variable

Default

Description

CONFIG_API_ENABLED

false

Configuration API を有効にするには true に設定します

CONFIG_API_TOKEN

(有効時は必須)

APIリクエストを認証するためのBearerトークン

services:
  mcp-ssh:
    environment:
      CONFIG_API_ENABLED: "true"
      CONFIG_API_TOKEN: "your-secret-token-here"

APIエンドポイント

すべてのエンドポイントは、MCPサーバーと同じStarlette ASGIアプリケーションの /api にマウントされます。

ヘルスとユーティリティ

Method

Path

Description

GET

/api/health

設定APIのヘルスチェック(認証不要)

POST

/api/hash-key

プレーンテキストのAPIキーをPBKDF2-HMAC-SHA256文字列にハッシュ化します

GET

/api/config/schema

設定JSONスキーマを返します(認証不要)

POST

/api/config/validate

ディスクに書き込まずに設定dictを検証します

設定

Method

Path

Description

GET

/api/config

完全な設定を取得します(シークレットは秘匿されます)

PUT

/api/config

完全な設定を置き換えます

GET

/api/config/{section}

単一の設定セクションを取得します(settingsssh_targetsallowed_commandsblock_patterns

PUT

/api/config/{section}

単一の設定セクションを置き換えます

SSHターゲット

Method

Path

Description

GET

/api/config/ssh_targets/{name}

特定のSSHターゲットを取得します(シークレットは除去されます)

PUT

/api/config/ssh_targets/{name}

SSHターゲットを作成または置き換えます

DELETE

/api/config/ssh_targets/{name}

SSHターゲットを削除します

POST

/api/config/ssh_targets/{name}/check

ターゲットの checkcommand を使用してSSH接続をテストします

コマンドルール

Method

Path

Description

GET

/api/config/allowed_commands

許可コマンドルールを一覧表示します(GET /api/config/{section} 経由)

PUT

/api/config/allowed_commands

許可コマンドルールを置き換えます(PUT /api/config/{section} 経由)

ブロックパターン

Method

Path

Description

GET

/api/config/block_patterns

ブロックパターンを一覧表示します(GET /api/config/{section} 経由)

PUT

/api/config/block_patterns

すべてのブロックパターンを置き換えます

POST

/api/config/block_patterns

ブロックパターンを追加します

PUT

/api/config/block_patterns/{index}

インデックスを指定して単一のブロックパターンを置き換えます

DELETE

/api/config/block_patterns/{index}

インデックスを指定して単一のブロックパターンを削除します

バックアップ

Method

Path

Description

GET

/api/backups

設定バックアップを一覧表示します(新しい順)

POST

/api/backups/{name}/restore

バックアップから設定をリストアします

DELETE

/api/backups/{name}

バックアップファイルを削除します

認証

/api/health/api/config/schema を除くすべてのAPIリクエストでは、Authorization ヘッダーに Bearer トークンが必要です:

curl -H "Authorization: Bearer your-secret-token-here" http://localhost:9080/api/config

Webダッシュボード

有効にすると、http://localhost:9080/ui/レスポンシブなシングルページアプリケーション を利用できます。これは Tailwind CSS で構築された完全な管理UIです。ページリロードなし、すべての操作に対するトースト通知、編集用のモーダルダイアログを備えています。

Page

Capabilities

SSH Targets

ターゲットの表示、追加、編集、削除; checkcommand によるインライン接続テスト; ホスト/ポート/ユーザー名のテーブル表示

Block Patterns

個々のパターンの追加、編集(インデックス指定)、削除; パターン一覧の表示

Command Rules

デフォルト、APIキー、ネットワークルールの編集; ターゲットとコマンド一覧を備えた完全なルールエディタ

Settings

すべてのサーバー設定を編集: SFTPサンドボックス、レート制限、ロギング、接続プーリング、サーキットブレーカーなど

Backups

設定バックアップの一覧表示、リストア、削除; 各バックアップのタイムスタンプとサイズ

追加機能:

  • トークンベースのログイン — セッション管理付き(sessionStorage に保存)

  • 設定検証 — 変更は書き込み前に検証されます

  • APIキーのハッシュ化 — ダッシュボードから直接プレーンテキストのキーをハッシュ化します

  • レスポンシブデザイン — デスクトップとモバイルで動作します

  • トースト通知 — すべての操作に対する成功/エラーのフィードバック

Swagger / ReDoc

対話型APIドキュメントは FastAPI によって自動生成されます:

  • Swagger UI: http://localhost:9080/api/docs

  • ReDoc: http://localhost:9080/api/redoc


デプロイ

Docker Compose

compose.yaml は、MCPサーバーと、オプションとして設定API & Webダッシュボードの両方をホストする単一の mcp-ssh サービスを定義します。設定APIは CONFIG_API_ENABLED 環境変数(デフォルト: false)で有効になります。

mcp-ssh — MCP SSH ゲートウェイ + 設定API

Host path

Container path

Mode

./config

/config

rw

./logs

/logs

rw

./ssh_key

/app/ssh_key

ro

./ssh_key.pub

/app/ssh_key.pub

ro

ホストのポート 9080 で公開されます(コンテナのポート 8080 にマッピング)。ランタイムイメージは python:3.13-alpine で、ダイジェストがハッシュ固定されています。非rootユーザー mcpssh がプロセスを実行します。CycloneDX SBOM はビルド時に sbom ステージで生成されます。

設定API & Webダッシュボード(オプション)

.env ファイルまたは環境で CONFIG_API_ENABLED=true と設定すると、設定APIが有効になります:

# Generate an auth token
openssl rand -hex 32
CONFIG_API_ENABLED=true
CONFIG_API_TOKEN=<your-token>

有効にすると、設定APIはMCPゲートウェイと同じHTTPサーバーの /api にマウントされます。以下を提供します:

  • REST APIhttp://localhost:9080/api/... に、SSHターゲット、ブロックパターン、コマンドルール、バックアップ、設定の完全なCRUDを提供します

  • Webダッシュボード(GUI)http://localhost:9080/ui/ に、ビジュアルなポリシー管理のためのシングルページアプリケーションを提供します(SSHターゲット、ブロックパターン、コマンドルール、設定、バックアップ)

  • APIドキュメントhttp://localhost:9080/api/docs(Swagger UI)と http://localhost:9080/api/redoc(ReDoc)

Makefile

コマンド

説明

make build

Dockerイメージをビルドする(ghcr.io/gelse/ssh-mcp:latest

make up

docker compose up -d

make down

docker compose down

make test

単体テストを実行する

make config-test

config-apiの単体テストを実行する

make integrationtest

テストイメージをビルドし、統合テストを実行する

make clean-test

テスト成果物とコンテナを削除する

GHCRからのプル

Dockerイメージは自動的にビルドされ、GitHub Container Registryに公開されます:

docker pull ghcr.io/gelse/ssh-mcp:latest

制限事項と脅威モデル

ssh-mcpができないこと

  • シェルではない。 対話型ターミナルセッションは利用できません。すべての実行はワンショットのコマンド呼び出しです。

  • ファイルマネージャーではない。 SFTPは、パス検証とサンドボックス強制を備えた単一ファイルのアップロード/ダウンロードに限定されます。ディレクトリ一覧表示や再帰的操作はできません。

  • ネットワークファイアウォールではない。 レート制限はIP単位で、デフォルト値は固定されています。暴走するクライアントからは保護しますが、執拗な攻撃者からは保護しません。

脅威モデル

脅威

対策

チェインによるコマンドインジェクション(cmd1 && cmd2

コマンド分割 — 各セグメントが完全な認可チェーンを実行します

シェルリダイレクションによる機密パスへの書き込み(> /etc/passwd

リダイレクト先ガードが /dev//proc//sys/ へのリダイレクトを拒否します

SFTPでのパストラバーサル

8層のパス検証:nullバイトチェック、制御文字の除去、ドットセグメントの正規化、シンボリックリンク解決、サンドボックスルートの強制

block_patterns によるReDoS

読み込み時の静的スクリーニング+実行時タイムアウトガード

APIキーのブルートフォース攻撃

定数時間検証を備えたPBKDF2-HMAC-SHA256、IP単位のレート制限

ログインジェクション

ログ記録前に、ユーザー制御のすべてのフィールドに対して改行サニタイズを実施

設定内のシークレット

secrets.json の分離、MCP_SSH_SECRET_* 環境変数、0600 ファイル権限

対象外

  • TLS終端(リバースプロキシで処理)

  • APIキーを超えたユーザー認証(アプリケーション層でのOAuth、mTLSはなし)

  • SSHセッションマルチプレクシング(tmux/screenパススルーなし)

  • 監査ログの改ざん防止(ログはローカルファイルです。不変性の確保には独自のログ転送を使用してください)


開発

プロジェクト構成

  • server.py — FastMCPアプリのファクトリ+CLIエントリポイント

  • lib/ — 単一責任のモジュール30個(認証、設定、SSHクライアント、ファイル転送、ロギングなど)

  • config-api/ — 設定API+Webダッシュボード(FastAPI、CONFIG_API_ENABLED=true のときに /api にマウント)

  • tests/ — 単体テストファイル36個+実際のDockerコンテナを使用した統合テスト

技術スタック

Python 3.13, FastMCP 3.4.x, paramiko 5.0, Starlette 1.4, FastAPI 0.115+, Pydantic 2.10+, httpx 0.28+, uvicorn 0.34+

テストの実行

# Unit tests (fast inner loop)
source .venv/bin/activate
python -m pytest tests/test_<module>.py -x

# Full unit test suite
make test

# Integration tests (requires Docker)
make integrationtest

新しいツールの追加

AGENTS.mdの実例では、新しい @mcp.tool() ハンドラをエンドツーエンドで追加する手順を説明しています:定数、型、再エクスポート、ハンドラ、テスト、コミット。

リンター/型チェックツールなし

このプロジェクトには ruffmypypyrightflake8 の設定はありません。フォーマットは .editorconfig のデフォルト(Pythonはスペース4つ、88文字行)に従います。


ロードマップ

  • ビジュアルなポリシー管理のための設定GUI


ライセンス

MIT License — 詳細は LICENSE を参照してください。

A
license - permissive license
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
<1hResponse time
Release cycle
1Releases (12mo)
Commit activity

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables secure remote access operations through SSH, SFTP, rsync, VPN, and tunneling with enterprise-grade policy enforcement and audit logging. Provides AI assistants with secure, policy-driven access to remote systems while maintaining comprehensive audit trails and zero-trust security.
    1
    Apache 2.0
  • A
    license
    B
    quality
    A
    maintenance
    Provides policy-driven, auditable SSH access to server fleets for AI assistants with zero-trust security controls, command whitelisting, and comprehensive audit logging to safely manage infrastructure.
    13
    27
    Apache 2.0
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to securely execute remote SSH commands, perform file transfers, and monitor system status through a standardized interface. It features robust security controls including command whitelisting, blacklisting, and credential isolation to prevent unauthorized operations.
    10
    22
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to securely execute SSH commands on remote servers with connection pooling, session isolation, and a web audit panel.
    3
    MIT

View all related MCP servers

Related MCP Connectors

  • Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Agent payments, API key vaulting, and governed mandates. Agents spend within user-defined limits.

View all MCP Connectors

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

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