runpod-mcp
runpod-mcp — Learning-to-Swim replication 用のカスタム MCP サーバー
スタンドアロンに関する注記: このサーバーは
learning-to-swim-replicationプロジェクトから(完全な履歴付きで)抽出されたものです。../runbook/RUNBOOK.mdのような相対リンクはその親プロジェクトを参照しており、このリポジトリが親プロジェクトの中に置かれている場合(またはシンボリックリンクされてそこから解決される場合)にのみ解決されます。サーバー自体はスタンドアロンで動作します。
親プロジェクトの runbook/RUNBOOK.md をミラーリングしたタスク形状のツール(14個)であり、約50個の汎用APIミラー(generic API mirrors)ではありません。カスタム実装である理由は、RunPod APIにはポッド上でコマンドを実行する機能が一切ないためです。公式のMCPはコントロールプレーンのみをカバーしており、pod_setup.sh の実行、軸の健全性診断(sanity sweep)、トレーニングにはSSH + rsyncが必要です。それらを本サーバーでは、コスト保護のガードレール(cost guardrails)とともにコードとして実装しています。
アーキテクチャ
.mcp.json → run.sh (venv bootstrap) → server.py (FastMCP, stdio; thin)
└── runpod_mcp/
config.py Keychain key fetch + rpa_ scrubber
api.py REST v1 (pods/volumes/billing) + unauth GraphQL gpuTypes
guardrails.py one-pod-per-vehicle (unknown refused) · 4090-only · no spot · volume required · confirm gate
ssh.py hardened ssh/scp/rsync; known_hosts_runpod; 60s conn cache
jobs.py detached jobs: /workspace/jobs/<id>/{cmd.sh,pid,out.log,exit_code,meta.json}
training.py DR tables (RUNBOOK/yaml-cross-checked) + verbatim train cmd
supervise.py Mac-side background CLI: launch→poll→pull→sync→spend→stop (reuses tools.*)
watch.py Mac-side ADVISORY observation CLI: discover job→tail out.log→parse metrics→page on plateau/failure/stall (read-only; never stops pods)
remote/ job_wrapper.sh · idle_watchdog.sh · apply_bluerov2_patch.py
deadman.py Mac-side stop-pod fuse: arm --vehicle → sleep → stop with retries (per-vehicle pid/summaries)
supervise.sh → caffeinate -i wrapper around python -m runpod_mcp.supervise
watch.sh → caffeinate -i wrapper around python -m runpod_mcp.watch (live-pod behavior UNVERIFIED — fixture/mock-verified only; see CLAUDE.md §D)
deadman.sh → caffeinate -i wrapper around python -m runpod_mcp.deadman (arm/cancel REQUIRE --vehicle; bare status reports all vehicles)ステートレス & ビークル単位: 「ポッド」とは、選択したビークルの設定名に一致する
GET /podsが返すものです(hippocampus→lts-replication、bluerov2→lts-replication-bluerov2。すべてのツールのvehicleパラメータのデフォルトはhippocampusであり、stop_pod/terminate_podでは明示的な指定が必須です)。コンソールとMCPは常に一致します。ローカルに保持する状態は、ビークルごとの60秒間の (host, port) キャッシュのみです。リモート/job実行: SSHを1回呼び出して
setsid bash job_wrapper.sh <dir> <pod_id> <ceiling> <auto_stop>を起動します。状態はネットワークボリューム上にあるため、MCPの再起動、Macのスリープ、ポッド停止をまたいでも保持されます。timeout --kill-afterが壁面時計時間の上限を強制します(exit 124)。auto_stopの後続処理は exit_code が書き込まれた 後に 実行されるので、タイムアウトがこれを無効化することはできません。Pod ID はargv経由で注入されます(デタッチされた BatchMode シェルではコンテナ環境変数は信頼できないため)。runpodctl の認証情報を取り込むために/etc/rp_environmentをスクリプト実行し、auto_stop のアーミングでは runpodctl を同期的にプローブし、動作できない場合は大きなエラーを出します。プローブ(2026-08-09)は3方向の診断です。素のシェルでのチェックは何も判定しません(H1 対 H2 のどちらかを答え、素の PATH を捕捉します)。そのうえで/etc/rp_environmentを無条件に string し、source 後に得られた組み合わせが判定を持ちます —NO_RUNPODCTL(source してもバイナリが存在しない場合、exit 90)、NO_RUNPODCTL_AUTH_SOURCED(source 後でも認証が拒否される場合、exit 91)、PROBE_OK(source 後のみ成功。NO_RUNPODCTL_AUTH_BAREは継続する中間診断です)。アイドルウォッチドッグ: running への遷移ごとに再インストールされます — コンテナディスクのワイプが、実行時にインストールされたもの(
idle_watchdog.sh自身、apt の X11/GL ライブラリ、rsync)を削除するため、遷移のたびにインストールし続ける設計です。runpodctlはイメージに同梱されており、起動のたびに復帰します(ワイプはディスクをイメージから復元するものであって、空にするものではありません — 2026-08-09 に修正)。5分ごとに行われる判定:実行中のジョブ pid がなく、sshd セッションがなく、/workspace/.keepaliveが60分以上前に更新された場合 →runpodctl stop podを実行します。touch /workspace/.keepaliveが手動セッションのエスケープハッチです。インストールが成功するとarmed (stop path unverified)と報告されます — プローブは READ(get pod)を保証しますが、ウォッチドッグが求めるのは WRITE(stop pod)です。最初に実際に確認できるのは、/workspace/.idle_watchdog.logへの正常停止の記録です。ステータス(2026-08-09):記録されている起動すべてでインストールプローブが失敗しています(修正前は不透明な rc=91)。つまりウォッチドッグはまだ一度もアームに成功していません。問題の2は CLOSED ではなく DIAGNOSED として納品され、次の持ち込み時のセンチネルで解決します。idle_watchdog: FAILEDの場合は、どのジョブよりも前に Mac 側の停止確認(deadman)をアームしてください。ガードレールはコード: 宣言したビークルごとに1ポッド(アカウント内の他のポッド名は拒否)、RTX 4090 を1枚、SECURE、interruptible を強制的に false、ネットワークボリューム必須、
terminate_podには明示的なvehicleに加えてそのビークルのpod_nameに対応する完全一致の文字列(例:terminate lts-replication)が必要、forceがない限り1ポッドあたり同時実行ジョブは1つです。
インストール / 登録
サーバーをプロジェクトの .mcp.json(Claude Code)に、run.sh の絶対パスで登録してください — run.sh は初回起動時に自身の .venv をブートロットラップします:
{
"mcpServers": {
"runpod": {
"command": "bash",
"args": ["/path/to/runpod-mcp/run.sh"]
}
}
}セットアップ
APIキー(ディスクや git、argv には決して置かない — macOS Keychain のみ。サーバーは
security find-generic-passwordでそれを読み取り、あらゆるエラーとログからrpa_値を除去します):security add-generic-password -a kyle -s runpod-api-key -w '<KEY>'(ルックアップ時のアカウント名は現在
runpod_mcp/config.pyでkyleにハードコードされています — macOS アカウントが異なる場合は両方を合わせて調整してください。)SSHキー:
~/.ssh/id_ed25519(.pub)が存在する必要があります。.pubはポッド作成時にPUBLIC_KEY環境変数を介して注入されます(runpod/pytorchイメージが実際に尊重する変数です — 生の環境で検証済み。安全のためSSH_PUBLIC_KEYにも設定します)。直接root@publicIp:portMappings["22"]へ SSH します。RunPod のプロキシSSHは使いません(scp なし)。ホスト鍵は専用の~/.ssh/known_hosts_runpodに置かれ、ポッド起動のたびに切り詰められます(コンテナディスクのワイプがホスト鍵を再生成するため、古いエントリは偽の MITM 証明書エラーの原因にしかなりません)。他には何もありません —
run.shが初回起動時に.venv/を作成し、requirements.txt をインストールします(スタンプによるギャップ制御あり)。
テスト
runpod-mcp/.venv/bin/python -m pytest runpod-mcp/tests -q # offline (default)
RUNPOD_MCP_LIVE=1 runpod-mcp/.venv/bin/python -m pytest \
runpod-mcp/tests/test_live.py -q # live $0 read-onlyオフラインテストは httpx.MockTransport とダックタイピングのフェイクSSHを使用します — ネットワーク不要・キー不要。ライブテストは読み取り専用のGET と、run.sh を通したMCP stdio ハンドシェイク(14ツールすべてが登録されることを検証)です。DR テーブルは、BLUEROV2/config/bluerov2_heavy.yaml、RUNBOOK.md、APPLY.md を解析して相互チェックされます。パッチスクリプトは、固定された 7c5ebe7 リビジョンのコミット済みフィクスチャ抜粋に対して実行されます(さらに、実際のリファレンスクローンが存在する場合は、SHA で管理された読み取り専用の tmp コピーに対するテストも実行されます)。
test_supervise.py は、注入されたフェイクとフェイククロック(実際の待機なし)で supervise CLI のコアを駆動し、すべての安全ブランチをカバーします:正常完了、ジョブ失敗、max-wait での強制停止、ポッド未実行による拒否、起動拒否、一時的なポーリングエラー、キャプチャ失敗でも停止すること、 --no-stop、そしてすべてのケースで terminate_pod が呼び出されないことを検証します。
ルートリポジトリの pytest -q はこのフォルダを無視します(conftest.py の collect_ignore — いうのが、ルートのスリムな venv には mcp/httpx がないためです)。
監視付き実行(supervise.sh)
実行全体をつなぐ1つのコマンド — ポッドが実行中かを確認 → ドライランで 有限な 壁面時計時間の上限を導出 → launch(auto_stop=false) → job_status をポーリング → /workspace/jobs/<job_id>/ と sync_logs と spend_report を無条件で取得 → stop_pod → 永続的な JSON サマリー — を自動化するため、エージェントはこれを バックグラウンドタスクとして一度だけ 投入し、完了時に通知されます。runpod_mcp.tools.* を再利用し(ロジックの重複なし、すべてのガードレールを継承)、決して terminate_pod を呼び出しません。これはMac側のCLIであり、15番目のMCPツールではありません — 数分間ポーリングするだけのツールは stdio サーバーをブロックしてしまうためです。
# training run (background task)
supervise.sh --training curee --dr DR_0 --seed 1 \
[--interval 45] [--max-wait N] [--backstop 300] [--no-stop] \
[--sync-subdir rsl_rl/warpauv_direct] [--summary-path PATH]
# generic job — --sync-subdir REQUIRED (pass 'none' to skip the analysis sync;
# the job-dir pull always happens); --vehicle routes the pod (default
# hippocampus; --training mode derives it from the training vehicle instead)
supervise.sh --job-name eval --command "…" --workdir /workspace \
--sync-subdir <dir|none> [--max-runtime-sec N] [--vehicle bluerov2]コストの安全策:ポーリングループの終了条件は正確に2つです — 正常の完了 → stop_pod、または running のまま --max-wait(常に有限)が経過した場合 → 強制停止 + 非ゼロ終了コード + force_stopped サマリーフラグです。起動 拒否 は → 停止なし(修正して再試行)、exit 2 です。ビークルのログディレクトリ(logs/pod/ は hippocampus、logs/pod/bluerov2/ は bluerov2)にある supervise-<job_id>.json サマリーが、復旧のための契約です(後続のセッションがこのサマリーから停止状態を調整します)。生存性の注意点:caffeinate -i はアイドルスリープを防ぎますが、ノートの蓋を閉じることは防ぎません。run_in_background が WarmLifecycle の回収を生き残るかは未確認です — ジョブの timeout の上限が保証された最後の防御です。ポッド側のアイドルウォッチドックもこれを後方支援しますが、記録された起動ではまだ一度もアームされたことがなく(DIAGNOSED 相当であって CLOSED ではない — アイドルウォッチドックの項目を参照)、そのため ensure_pod が idle_wallback を示す場合は、Mac側の手動確認(デッドマン)をアームしてください。
キャンペーンチェーン(CUREE/chains/)
キャンペーンごとに1つの bash スクリプト(キャンペーンIDで命名、例:chain-011-CUREE_Adaptive-weights.sh)が用意されています。これは、そのキャンペーンのポッド側ジョブシーケンス — パッチ、ゲート、トレーニング、評価、同期 — を、順序付けられたSHA参照のリンクとして保持します。チェーンは supervise.sh 経由で起動されます(キャプチャと停止は supervise.sh が所有します)。手作業で直接実行されてはならず、キャンペーンが実行した内容を正確に記録した永続リダブルな記録です。
ドライラン
ensure_pod、run_pod_setup、run_job、launch_training、apply_bluerov_patches はすべて dry_run=true を受け付け、何も変更せず($0)に、実際にそのまま使われるであろうペイロード/編集/コマンドを返します。supervise はこのドライラン経路を使って、実際の起動前に有限の --max-wait を導出します。
NGC フォールバックイメージ(手動での切り替え — 必ず先に読むこと)
nvcr.io/nvidia/isaac-sim:4.5.0(RUNBOOK の Day-1 フォールバック)には sshd がありません — このサーバー全体の SSの構成が壊れます。切り替えには、docker-start コマンド(単なる一行変更ではなく)で sshd をインストールして起動することが必要です。image_name を pod_defaults.yaml でいつ変えるとしても、その前に必ず Kyle にフラグを上げてください。
既知のリスク(計画時に許容したもの)
pod_setup.shの IsaacSim 4.5.0 のダウンロード URL が404になる可能性があります —job_statusのログの末尾に現れます。修正は runbook 編集であり、MCP の変更ではありません。4090 の在庫は DC ごとに変動します;ネットワークボリュームは1つの DC に固定されます。
gpu_availability(data_center_id=...)とensure_podの GPU なしからの復旧手順でカバーします。最悪の場合、別の DC に2つ目のボリュームを作成します。
ライセンス
MIT — 詳細は LICENSE を参照。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Create and manage AI agents that collaborate and solve problems through natural language interacti…
Build, validate, and deploy multi-agent AI solutions from any AI environment.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/kyle-nelson-berkeley/runpod-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server