Let AI assistants operate your Linux servers — behind a human consent gate the model can't self-approve. について
Linux サーバー操作を安全に AI アシスタントに提供する MCP サーバー。読み取りは常に許可され、サーバー状態の変更には人間のみが持つ同意トークンが必須です。Claude Desktop、Cursor、Windsurf に対応。
主な機能
- 013 段階アクセスモード
- 02本番環境への書き込み保護
- 03帯域外同意トークン
- 04コマンド引数の Shell クォート
- 05サーバープロファイルスキャン
- 06監査ログ
活用シーン
- 01本番環境への安全なデプロイメント
- 02DevOps 自動化
- 03サーバー診断と監視
- 04ポリシー適用とバージョン管理
MCP 対応
MCP クライアントに Linux サーバーツールを公開し、読み取り専用アクセスは常に許可する一方、状態変更操作にはすべて人間の同意トークンが必須です。
詳細
devops-mcp
AI アシスタント(Claude Desktop、Cursor、Windsurf など)が Linux サーバーを実際に操作できるようにするモードベースの MCP(Model Context Protocol)サーバーです。ただし、鍵をすべて渡すわけではありません。
モデルは接続、スキャン、計画、デプロイができます。ただし、本番環境のようなサーバーの状態を変更するすべてのステップは、AI が自動承認できない承認ゲートを通過する必要があります。探索は設計上、読み取り専用です。
┌─────────────────┐ MCP / stdio ┌────────────────────┐
│ AI client │ ───────────────────────────► │ devops-mcp │
│ (Claude / │ │ │
│ Cursor / …) │ ◄─────────────────────────── │ ssh2 / docker / │
└─────────────────┘ │ child_process │
└────────┬───────────┘
│ SSH
▼
┌────────────────┐
│ Your VPS │
└────────────────┘
⚡ 初回セットアップ(一度読んで、一度実行してください)
正確に 4 つのステップがあります。ステップ 2 をスキップしないでください。
1. インストール
git clone <your-fork-url>.git devops-mcp
cd devops-mcp
npm install
npm run build
Node ≥ 18 が必要です。
2. 昇格トークンを生成して、失わない場所に保存してください
# Linux / macOS
openssl rand -hex 24
# Windows PowerShell
$bytes = New-Object byte[] 24; (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($bytes); [BitConverter]::ToString($bytes).Replace("-","").ToLower()
# Or, via Node
node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"
6ba329add30b19a5a347178f7e3705fdea0ac1aa66cb9274 のようなものが取得できます。
🔑 ステップ 3 の前にこのトークンを保存してください。
このトークンが、AI と本番環境への制御されていないアクセスの間の唯一の障壁です。モデルはこのトークンを見ることはありません。 AI が PROVISION/FULL モードへの昇格、破壊的なアクションの承認、サーバーのロール変更、または本番環境のようなサーバーへの書き込みを望むたびに、あなたは一度それを貼り付けます。
パスワードマネージャーに入力してください。失った場合:
- MCP クライアントの設定を手動で編集して新しいトークンを設定することができます。または
- 古いトークンがまだある場合、AI に
rotate_consent_tokenを呼び出すよう依頼することができます(両方を失った場合は循環参照になります)。リカバリフローはありません。これはゲートです。バックドアは用意していません。
3. devops-mcp を MCP クライアントの設定に追加する
Claude Desktop の場合、claude_desktop_config.json を編集してください:
- Windows:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
以下を追加(または既存の mcpServers にマージ)してください:
{
"mcpServers": {
"devops-mcp": {
"command": "node",
"args": ["/absolute/path/to/devops-mcp/dist/index.js"],
"env": {
"DEVOPS_MCP_ELEVATION_TOKEN": "<paste your token from step 2 here>",
"LOG_LEVEL": "info"
}
}
}
}
同じ構造は Cursor、Windsurf、および他の MCP クライアント — env ブロックはシークレットを渡すための標準的な MCP 方法です — で機能します。
4. MCP クライアントを完全に終了して再度開く
「ウィンドウを閉じる」ではなく、です。Windows では、システムトレイ → 終了を意味します。昇格トークンはスタートアップ時に読み込まれます。クライアントはそれを有効にするために再起動する必要があります。
完了です。次に AI と話すときに「… にサーバーを追加して」と言えば、ウォークスルーが表示されます。
なぜこれが存在するのか
汎用的な「任意のコマンドを実行」する MCP サーバーは本番環境のボックスでは危険です。ライブサーバーで完全なシェルを持つモデルは、間違ったサービスを再起動したり、使用中のポートにデプロイしたり、docker prune でデータベースボリュームを削除したり、誰もそうしないよう告げていないため自分自身を root に昇格させることができます — そしてそうします。
devops-mcp は読み取りと変更の間に厳密な線を引きます:
- 読み取りは常に許可されます(読み取り専用の SAFE 許可リスト内)。
- 本番環境のようなサーバーの変更には、ヒューマンのトークンが必要です — 帯域外で渡され、モデルからは見えません。
- 新しいプロジェクトのデプロイは、40 個のアドホックコマンドではなく、ポート競合チェックと見直し可能なスクリプトを通過します。
機能
アクセス制御
- 3階層モード:
SAFE(デフォルト、読み取り専用許可リスト)、PROVISION(システムインストール、デフォルト有効期限1時間)、FULL(root、デフォルト有効期限30分)。 - 帯域外同意トークン — エスカレーションと承認には、ユーザーのみが持つ文字列が必要です。モデルはこれを読むことができません。
- 本番環境書き込みゲート —
role: productionサーバー(またはスキャナーがproductionLikelyとしてフラグを付けたサーバー)では、SAFE 以外のコマンドにはconsentToken+acknowledgeProductionWrite: trueが必要です。カタストロフィックコマンド — バックアップなしでは復旧できないもの(非一時パスのrm、rm -rf /…、dd of=/dev/…、mkfs、SQL のDROP TABLE/DATABASE、docker rmi、docker volume rm、docker rm -v、docker system prune)— さらにbackupVerified: trueが必要です。通常の書き込みと復旧可能な操作(ファイルの編集、rm /tmp/scratch、イメージから再作成可能なコンテナのdocker rm)はbackupVerifiedを必要としません。拒否は正確に解決されたコマンドを返します。 - サーバーごとのポリシー —
allowedModes、blockedCommands、allowedPaths、requireApprovalはconfig/<server-id>/server.jsonに設定され、すべての SSH コマンドで適用されます。 - 必須の
role—add_serverは AI がロールを暗黙的にデフォルト値に設定することを許可しません。ユーザーに尋ねる必要があり、レスポンスには AI が読み返すroleConsequencesブロックが含まれます。 - トークンローテーション —
rotate_consent_tokenは新しいトークンを生成します(デフォルトはドライラン、apply: trueで MCP クライアント設定をアトミックに更新)。 - 認証情報ローテーション —
update_server_credentialsはパスワードをローテーションし、SSH キーを交換(keyPassphrase経由の暗号化キーを含む)するか、サーバーを再追加せずにホスト/ユーザー/ポートを移行します。ロール、制限、スキャンプロファイルは変わりません。そのサーバーへのアクティブセッションを最初にクローズし、テスト接続で新しい認証情報を検証し、本番環境では同意ゲートされます。 - AWS / EC2
.pem対応 —.pemファイル + ユーザー名 + IP でオンボードできます。参照のまま使用(externalKeyPath)または設定バンドルにコピー(keyFilePath);keyPassphraseはキーが暗号化されている場合のみ追加します。 - 複数同時接続、serverId でキー化 — MCP は サーバーごとに 1 つの SSH 接続を保持し、グローバルスロットではありません。Claude Desktop は全会話で単一の共有 MCP プロセスを実行します。グローバル接続では、2 つのチャットが 2 つのサーバーで作業している場合、互いに上書きします(「セッション 1 がサーバー A、セッション 2 がサーバー B に接続、A のコマンドが B に向かう」)。キー化接続なら両方が共存できます。
run_commandはserverIdを取ります。正確に 1 つのサーバーが接続されている場合はオプション、2 つ以上の場合は必須 — あいまいな呼び出しは推測ではなく拒否されます。すべてのrun_commandレスポンスはtarget.serverIdとactiveConnectionsを返します。 - ターゲットドリフト対策 —
run_command、set_mode、get_current_modeレスポンスはすべて接続されたサーバーの ID を含むため、会話が誤ったボックスで暗黙的に操作されることはありません。disconnect_serverはオプションのserverId(または"all")を取ります。 - ライブセッション対応オンボード —
add_serverは現在接続されているサーバーをレスポンスで表示し、AI に新規追加サーバーへの自動切り替えをユーザーに尋ねずに行わないよう指示します。
検出とプランニング
- サーバー検出スキャン — OS、ハードウェア、リッスンしているポート、インストールされたスタック(docker / nginx / apache / node / pm2)、実行中のコンテナ、解析された nginx サイト、systemd サービスの読み取り専用プローブ。出力は
ServerProfileとして永続化されます。 - 再接続時のプロファイル差分 —
diff_server_profileは再スキャンして、保存されたスナップショット以降の変更を報告します。 - ポート競合への対応 —
check_port_conflictはリッスンしているプロセスとデプロイ前の空きポート提案を返します。 - 実行ではなくプラン化 —
plan_deploymentはユーザーが確認する冪等な bash スクリプトを返します。MCP はこれを実行しません。
セキュリティ強化
- すべてのコマンド引数がシェルクォート済み リモートシェルに到達する前に。
sh -c "<long script>"ペイロードが間違ったシェルレベルで分割されることはもうありません。 - バリデータが引数を検査 —
run_command({command:"ls", args:["; rm -rf /"]})は SAFE モードのlsバリデーションを通り抜けなくなります。 - 引用符を考慮したチェーン分割 — 読み取り専用コマンドのチェーンは SAFE のままです。
du -sh /opt/* ; echo --- ; df -h /のような診断パイプラインは昇格が不要です。各フラグメントは独立して検証され、チェーンに必要なモードはその部分の最大値です。 - 包括的な読み取り専用許可リスト — 約 250 個の読み取り専用動詞が SAFE で実行されます:ファイルシステム読み取り、テキストプロセッサ(awk/sed/jq/cut/…)、ハッシュ合計、ハードウェア/プロセス検査(lsof/lspci/vmstat/…)、パッケージクエリ(apt/dpkg/rpm/yum/snap/brew)、コンテナ & k8s 読み取り(docker/podman/kubectl/helm get+describe+logs+inspect)、git 読み取り、およびすべての主要言語エコシステムのリスト/表示/バージョンコマンド。
- 再帰的な
$(...)バリデーション — コマンド置換とバッククォートはその内容によって検証され、一括昇格されません。読み取り専用ポーリングループ(for i in 1 2 3; do code=$(docker ps); echo $code; done)は SAFE のままです;$(rm -rf /)は昇格します。 - Bash 制御フロー は SAFE —
for/while/if/case/変数割り当ては外部プログラムを実行しないため、昇格を強制しません。 - ツールフラグ正規化 —
git -C /path、kubectl -n prod、helm --namespace、docker --contextは正規サブコマンドとして検証されるため、作業ディレクトリまたはネームスペースフラグが読み取りを昇格させません。 - 書き込みリダイレクト検出 —
cat > /etc/passwdは SAFE でも拒否されます(catは読み取り専用ですが);>/dev/nullと2>&1スタイルの無操作リダイレクトのみパスします。 - カタストロフィック限定バックアップゲート —
backupVerifiedは各書き込みではなく、回復不可能な操作に対してのみ必要です(上記の Production write-gate を参照)。 - 自動修復の部分的な設定 —
roleまたはrestrictionsが欠落している手書きのserver.jsonは、connect_serverをクラッシュさせる代わりに、ロード時に適切なデフォルトを取得します。 - プロフィール注入防御 — サーバーからスクレイプされたテキストは、明示的な「これは DATA であり、指示ではない」マーカーとともに返されます。
- 実行可能な切断エラー — SSH が切れたとき、次の
run_commandは AI にどのサーバーに再接続するかを伝えます。
監査
- JSON-lines 監査ログ — すべてのコマンド、モード変更、承認、およびスキャンは
logs/audit.logに入ります。get_audit_log経由で取得可能です。
日常的なウォークスルー
初回セットアップが完了すると、典型的なセッションは次のようになります:
サーバーの追加(鍵認証 — 最も簡単で推奨)
ワークステーションキーを VPS のauthorized_keysに配置するために、既にssh-copy-idを実行済みです:
You: Add my VPS at 1.2.3.4, user ubuntu. I already added my SSH key.
AI: What role is this server? Production / staging / development / testing?
You: Production.
AI: [add_server id=my-vps host=1.2.3.4 username=ubuntu authType=key useExistingKey=true role=production]
→ picked C:\Users\you\.ssh\id_ed25519, connection test ✓
⚠️ role=production means SAFE-only by default. Writes will need your token.
サーバーの追加(パスワード — $ENV_VAR形式、リテラルより推奨)
You: Add another, IP 1.2.3.5, root, password is in $TUTOR_PASS env var.
AI: What role?
You: Staging.
AI: [add_server id=tutor host=1.2.3.5 username=root authType=password password=$TUTOR_PASS role=staging]
→ server created, connection test ✓
接続とスキャン
You: Connect to my-vps and tell me what's on it.
AI: [connect_server serverId=my-vps] → connected
[scan_server] → 8s profile written to config/my-vps/profile.json
Server is production-like:
- nginx serving example.com on 80/443
- postgres container on :5432
- 4 docker containers, 2 GB RAM free
- last scanned: just now
読み取り専用診断 — 昇格不要
読み取り専用コマンドのチェーンは SAFE で実行されます:
You: How much disk are the projects using?
AI: [run_command "du -sh /opt/* 2>/dev/null ; echo --- ; df -h /" executor=ssh]
→ ran in SAFE mode (read-only chain, no elevation required)
新しいプロジェクトのデプロイ
You: Deploy https://github.com/me/newapp on this box, port 8000.
AI: [check_port_conflict port=8000] → in use by "node" (the example.com app)
Port 8000 is taken. Suggested free port: 8001. Use 8001 or stop the existing app?
You: Use 8001.
AI: [plan_deployment port=8001 runtime=node ...] → returns a 26-line bash script
Here's the script. Please review.
You: Looks good. Run it.
AI: [run_command ...] → refused: production write-gate.
To run this I need your elevation token and confirmation that a backup exists.
You: Token is <paste>. Yes, snapshot taken this morning.
AI: [run_command consentToken=<…> acknowledgeProductionWrite=true backupVerified=true]
→ ✓ deployed
認証情報のローテーション(VPS パスワードが変更された、または SSH キーをスワップした)
You: I rotated my-vps's root password. New one is in $MY_VPS_PASS_NEW.
AI: my-vps is role=production — for the rotation I need your elevation token.
You: Token is <paste>.
AI: [update_server_credentials serverId=my-vps authType=password
password=$MY_VPS_PASS_NEW consentToken=<…>]
→ closed active SSH session (was connected), new creds tested ✓
Reconnect with connect_server when ready.
You: Connect.
AI: [connect_server serverId=my-vps] → ✓
役割、制限、ブロック済みコマンドリスト、およびスキャンプロフィールは保持されます。変更されるのは認証フィールドのみです。
サーバーの役割を後で更新
You: Actually my-vps is staging now, not production.
AI: This is a production-touching change, please confirm with the token.
You: Token is <paste>.
AI: [update_server serverId=my-vps role=staging applyRoleDefaults=true consentToken=<…>]
→ role changed; allowedModes now [SAFE, PROVISION].
トークンのローテーション(古いトークンがチャットなどに流出した場合)
You: Generate a new elevation token and update Claude Desktop's config.
AI: For verification, paste the current token.
You: <paste current>
AI: [rotate_consent_token consentToken=<current> apply=true]
→ 🔑 NEW TOKEN: <new> ← SAVE THIS NOW, in a password manager.
Claude Desktop must be fully restarted for the new token to take effect.
Until then, the OLD token still works on this running session.
アクセスモード
| モード | デフォルト有効期限 | 許可される操作 |
|---|---|---|
SAFE | 有効期限なし | 読み取り専用許可リスト: ls, cat, df, ss, docker ps, nginx -T など。すべて SAFE のコマンドチェーンも動作します。 |
PROVISION | 1 時間 | apt/yum, docker run/build/stop, systemctl start/stop, nginx, ufw, ファイル操作 |
FULL | 30 分 | fdisk, dd, shutdown, rm -rf / を含むあらゆる操作 |
昇格には以下が必要です:
acknowledgeRisk: true(AI が設定します)consentToken: "<your token>"(あなただけが持っています)
ダウングレードはいつでも許可され、即座に適用されます。セッションは自動的に SAFE に戻ります。
ツールリファレンス (32 ツール)
サーバーライフサイクル
| ツール | モード | 機能 |
|---|---|---|
add_server | SAFE | ワンショットオンボーディング。5 つの認証パス: password (リテラルまたは $ENV_VAR), keyFilePath (キーをコンフィグにコピー), privateKey (インラインで貼り付け), externalKeyPath (既存キーをポイント、コピーしない), useExistingKey (自動選択 ~/.ssh/id_*)。role が必須です。接続を自動テストします。roleConsequences を返します。 |
update_server | SAFE | role、allowedModes、blockedCommands、allowedPaths、requireApproval、名前、説明を変更します。本番環境への変更には consentToken が必要です。認証フィールドはここでは変更できません — update_server_credentials を参照してください。 |
update_server_credentials | SAFE | パスワードをローテーション、SSH キーを入れ替え、ホスト/ユーザー/ポートをマイグレーションします。このサーバーへのアクティブな SSH セッションがある場合は先に閉じます。デフォルトで新しい認証情報をテストします。Role/制限/profile.json は保持されます。本番環境サーバーには consentToken が必要です。 |
setup_server_config | SAFE | 低レベル: init / add / status。add_server が使用するのと同じプリミティブです。 |
list_servers | SAFE | 設定されたすべてのサーバーをリストします |
test_connection | SAFE | 設定されたサーバーへの SSH 接続を試みます (コマンドは実行されません) |
connect_server | SAFE | 後続のコマンド用の動作中の SSH セッションを開きます |
disconnect_server | SAFE | SSH セッションを閉じます |
ディスカバリー (すべて読み取り専用)
| ツール | モード | 機能 |
|---|---|---|
scan_server | SAFE | OS / ハードウェア / ポート / スタック / ワークロードをプローブします。config/<id>/profile.json に保持します。ターゲットへの書き込みはありません。 |
get_server_profile | SAFE | 再スキャンせずに保存されたプロファイルを読み取ります |
diff_server_profile | SAFE | 再スキャンして変更内容をレポートします。accept: true の場合を除き、保存されたプロファイルを上書きしません。 |
check_port_conflict | SAFE | ポート X は使用中ですか? リスナーと無料ポート提案を返します |
list_containers | SAFE | 接続されたサーバー上の Docker コンテナをリストします |
list_playbooks | SAFE | 利用可能なプロビジョニングプレイブックをリストします |
実行とデプロイ
| ツール | モード | 機能 |
|---|---|---|
run_command | 様々 | コマンドを実行します(ローカル / ssh / docker)。引数はシェルクォート処理され、チェーンは分割され各フラグメントが検証されます。本番環境書き込みゲートが適用されます。 |
plan_deployment | SAFE | べき等な bash スクリプトを生成します(クローン + ビルド + pm2/docker)。acknowledgeConflict: true を指定しない限り、ポート競合時は拒否します。実行なし。 |
run_playbook | PROVISION | 事前定義されたプロビジョニングプレイブックを実行します |
install_docker | PROVISION | Docker + Compose をインストールします |
install_nginx | PROVISION | Nginx をインストールします |
configure_nginx | PROVISION | Nginx リバースプロキシ設定を生成して再読み込みします。ヒアドキュメントを使用してシェルクォート処理のバグを回避します。 |
deploy_app | 様々 | 低レベルデプロイプリミティブ(git クローン + ビルド + 開始)。すべての内挿値はシェルクォート処理されます。 |
container_action | SAFE / PROVISION | start / stop / restart / logs / inspect |
transfer_files | SAFE(ダウンロード)/ 様々(アップロード) | SFTP でファイル、フォルダ(再帰的)、またはアーカイブをアップロード/ダウンロードします。extract: true はアップロードされた .zip/.tar.gz/.tgz/.tar/.tar.bz2/.tar.xz/.gz をサーバー上で解凍します。verifyChecksum: true は単一ファイルに対してエンドツーエンド sha256 を実行します。本番環境のようなサーバーへのアップロードは書き込みゲートに達します。 |
モード、同意、監査
| ツール | 機能 |
|---|---|
get_current_mode | 現在のモード + パーミッション + 残り時間 |
set_mode | モードを変更します。昇格には acknowledgeRisk + consentToken が必要です |
approve_action | 保留中の高リスクアクションを承認します。consentToken が必要です |
list_pending_approvals | キューに登録された承認リクエストをリストします |
rotate_consent_token | 新しい昇格トークンを生成します。apply: true を指定すると MCP クライアント設定をアトミックに書き換えます。現在のトークンが必要です。クライアントを再起動する前に、レスポンス内の警告を読んでください。 |
generate_ssh_key | 自動有効期限付きのセッション SSH キーペアを生成します |
revoke_ssh_key | セッション SSH キーを失効させます |
get_audit_log | logs/audit.log をテール / フィルタリングします(JSON Lines をパース、since と action でフィルタリング) |
health_check | ライブネス + バージョン + 現在のモード |
認証オプション(add_server)
authType と設定するキー/パスワードフィールドで選択される 5 つの認証方法があります。
| オプション | スキーマフィールド | 使用時期 |
|---|---|---|
| パスワード | authType:"password" + password(リテラル または $ENV_VAR) | キー認証がセットアップされていない場合。パスワードが設定ファイルにディスク上に残らないよう、$ENV_VAR を推奨します。 |
| キーファイルをコピー | authType:"key" + keyFilePath | サーバー設定の隣に保存したい PEM ファイルがある場合(ポータブルバンドル) |
| キーをインラインで貼り付け | authType:"key" + privateKey | キーテキストだけがある場合 |
| 既存キーを指す | authType:"key" + externalKeyPath | ~/.ssh/whatever が既にある場合。コピーするのではなく、参照するだけです。~ は展開されます。 |
| キーを自動検出 | authType:"key" + useExistingKey: true | デフォルトの ~/.ssh/id_* が既にサーバーの authorized_keys にある場合。最も簡単です。 |
ハンドラーは呼び出しごとに 正確に 1 つ のキーソースを検証します。例えば useExistingKey と keyFilePath を組み合わせると、明確なエラーが返されます。
任意のキーパス(keyFilePath / externalKeyPath)は、暗号化された秘密鍵用に、オプションで keyPassphrase(リテラルまたは $ENV_VAR)を受け入れます。
AWS EC2(.pem ファイルの場合)
.pem ファイル、ユーザー名(ubuntu、ec2-user、admin など)、パブリック IP/DNS を取得します。2 つの方法があります:
// Reference the .pem where it sits (recommended — nothing copied)
{
"id": "my-ec2", "host": "ec2-1-2-3-4.compute.amazonaws.com",
"username": "ec2-user", "authType": "key",
"externalKeyPath": "C:\\Users\\you\\Downloads\\my-key.pem",
"role": "production"
}
// Or copy the .pem into the server's config folder (portable bundle)
{
"id": "my-ec2", "host": "1.2.3.4", "username": "ubuntu",
"authType": "key",
"keyFilePath": "C:\\Users\\you\\Downloads\\my-key.pem",
"role": "staging"
}
ほとんどの AWS キーはパスフレーズがありません。その場合は keyPassphrase を省略してください。暗号化されている場合は、"keyPassphrase": "$MY_PEM_PASS" を追加し、その環境変数を設定します。
最新の sshd とパスワード認証:ssh2 は PAM を使用する sshd セットアップ(Ubuntu 22.04+、Debian 12、Amazon Linux 2023、RHEL 9)に対して
tryKeyboard: trueが必要です。devops-mcp はこれを自動的に設定します。サーバーがPasswordAuthentication noを設定していてkeyboard-interactiveのみを許可している場合でも、パスワードは機能します。
ディスク上のサーバー設定
各サーバーは独自のフォルダに存在します:
config/
├── my-vps/
│ ├── server.json # config (host, user, auth, role, restrictions)
│ ├── key.pem # optional SSH private key (only if you used keyFilePath / privateKey)
│ └── profile.json # written by scan_server
└── _example/
└── server.json # template
server.json の例:
{
"name": "Production Web",
"host": "1.2.3.4",
"port": 22,
"username": "ubuntu",
"authType": "key",
"keyFile": "production.pem",
"role": "production",
"restrictions": {
"allowedModes": ["SAFE"],
"blockedCommands": ["rm -rf", "shutdown", "reboot", "dd"],
"requireApproval": true
},
"description": "Main production web server"
}
externalKeyPath ワークフロー(キーが ~/.ssh/ に留まる場合)の場合:
{
"name": "My VPS",
"host": "1.2.3.4",
"port": 22,
"username": "ubuntu",
"authType": "key",
"externalKeyPath": "C:\\Users\\you\\.ssh\\id_ed25519",
"role": "production"
}
パスワード認証の場合(常に $ENV_VAR を優先):
{
"authType": "password",
"password": "$MY_VPS_PASS"
}
$NAME は接続時に process.env.NAME に解決されます。リテラルパスワードをコミットしないでください。
server.json に role がない場合、または restrictions: {} がある場合、MCP はロード時に role: "development" のデフォルトを設定します(およびログに警告を出します)。これは、手書きの設定で connect_server がクラッシュするのを防ぎます。
環境変数
| 変数 | 目的 | デフォルト |
|---|---|---|
DEVOPS_MCP_ELEVATION_TOKEN | アウトオブバンド同意トークン。これを設定してください。 このトークンがない場合、set_mode / approve_action / 本番環境書き込みゲートは AI 自体のブール値を同意として受け入れ、サーバーはログに大きな警告を出力します。 | 未設定(勧告モード) |
DEVOPS_MCP_NO_CONSOLE_LOG | 1 に設定して stderr コンソールログを抑制します(ファイルログは引き続き書き込まれます) | 未設定 |
LOG_LEVEL | debug / info / warn / error | info |
LOG_DIR | combined.log、error.log、audit.log を書き込む場所 | ./logs |
NODE_ENV | (情報提供用。MCP stdio が破損しないようにログは関係なく stderr に出力されます) | development |
セキュリティモデル
devops-mcp が保護する対象
- 本番環境で盲目的に実行するモデル —
role: productionまたはproductionLikely: trueのサーバーでの書き込みコマンドは、同意トークンと明示的な確認、および(壊滅的で回復不可能な操作の場合)backupVerifiedなしには拒否されます。 - 自己付与の承認 — モデルは
DEVOPS_MCP_ELEVATION_TOKENを見ることがないため、consentTokenを作成することはできません。 - 引数インジェクション —
run_commandへのすべての引数は、リモートシェルに到達する前にシェルクォートされます。sh -cペイロード内の複数行スクリプトはそのまま機能します。 - 引数に隠された偽のコマンド — バリデーターは
command + argsを一緒に検査するため、run_command({command:"ls", args:["; rm -rf /"]})は正しく FULL にエスカレートされます。 - 過度に広いチェーン拒否 — 読み取り専用コマンドのチェーンは SAFE のままです。各フラグメントは独立して検証されます。最も悪いもの 1 つだけが採用されます。
- スキャンされたコンテンツからのプロンプトインジェクション — バナー、コンテナラベル、ログ行は「信頼されないデータ」マーカーを付けて返されます。ツール応答はモデルに伝えます:実行しないで、表示してください。
- サイレントなポート衝突 —
plan_deploymentとcheck_port_conflictはデプロイ前に衝突を明らかにします。 - デプロイ/設定ヘルパーでのシェルインジェクション — すべての挿入値はシェルクォートされます。nginx 設定は heredoc を使用して書き込まれます。ブランチ名と環境変数キーは検証されます。
- 本番環境書き込みゲート拒否は正確なコマンドをエコーします — AI のパラフレーズではなく、実行しようとしていたコマンドを読むことができるようにです。
devops-mcp が行わないこと
- 接続されたサーバーをサンドボックス化しません。トークンで FULL モードになると、AI エージェントは SSH ユーザーが実行できることはすべて実行できます。
- 同意トークンを MCP クライアント設定に保存した状態で暗号化しません。
- データをバックアップしません —
backupVerifiedは人間による証明であり、チェックではありません。
完全な脅威モデルについては SECURITY.md を参照してください。
トークン管理
昇格トークンは MCP クライアント設定の DEVOPS_MCP_ELEVATION_TOKEN に保存される静的な文字列です。有効期限はありません。
有効期限が切れるもの:
FULLモードセッション — デフォルト 30 分PROVISIONモードセッション — デフォルト 1 時間generate_ssh_keyからのセッション SSH キー — デフォルト 30 分
モードセッションがタイムアウトすると SAFE モードにドロップバックし、AI エージェントは再昇格のために同じトークンを再度要求します。
トークンのローテーション
You: Rotate the elevation token and update Claude Desktop's config.
AI: For verification, paste the current token.
You: <paste>
AI: [rotate_consent_token consentToken=<current> apply=true]
→ new token: <new>
→ 🔑 SAVE THIS NOW. Without it you're locked out of every write operation.
→ Fully quit and reopen Claude Desktop to activate it.
MCP はクライアント設定に新しいトークンをアトミックに書き込みます(DEVOPS_MCP_ELEVATION_TOKEN キーのみ — ファイル内のその他すべての内容は保持されます)。実行中の MCP プロセスはクライアントを再起動するまで古いトークンを使用し続けます。
ローテーションと再起動の間に古いトークンと新しいトークンの両方を失った場合、クライアント設定を手動で編集して新しいトークンを設定してください — これがリカバリーフローです。
プロジェクトレイアウト
src/
├── index.ts # MCP entry point (stdio)
├── types/ # TypeScript types
├── core/
│ ├── logger.ts # JSON-lines structured logger + audit logger
│ ├── mode-manager.ts # SAFE / PROVISION / FULL state machine
│ ├── command-validator.ts # Allowlist + quote-aware chain splitter + wrapper-token scan
│ ├── server-config-manager.ts # config/<id>/server.json + profile.json + auto-heal
│ ├── server-scanner.ts # SAFE-mode discovery (read-only by design)
│ ├── ssh-key-manager.ts # Session SSH keys with auto-expiry
│ └── approval-manager.ts # Approval queue
├── executors/ # Local / SSH / Docker — all shell-quote args
├── playbooks/ # Provisioning playbooks (Docker, Nginx, …)
└── tools/
├── tool-schemas.ts # Zod schemas + MCP tool definitions
└── tool-handlers.ts # The actual handlers
開発
npm run dev # watch mode (tsx)
npm run build # tsc → dist/
npm test # vitest
npm run test:run # vitest run (CI mode)
npm run lint # eslint src/**/*.ts
貢献
PR を歓迎します。CONTRIBUTING.md を参照してください。
接続されたサーバーに書き込む新しいツールを追加する場合、モード検証と本番書き込みゲートが適用されるように BaseExecutor.execute() を通じて実行されることを確認してください。ハンドラーから直接シェルを実行しないでください。値をシェルコマンドに補間する場合は、エグゼキューター内の shellQuote ヘルパーを使用してください — このコードベースの過去のバグはすべてクォートのバグです。
ライセンス
MIT — LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。