AIに動画を作らせる 開けた口は3つだけ

公開: 2026-09-26
AIエージェントMCP権限分離動画生成OpenClaw

Mac miniに常駐させたエージェントに、Windows機(RTX 5070 Ti)の動画生成を頼めるようにした。頼めるのは3つの操作だけで、動画の解像度もモデルもエージェントには選ばせない。

結果から書く。**MCP経由で軽量設定の動画が1本、約200秒で出た。**1.63秒、H.264、80KB。実機で確かめたのはWindows機の中(ループバック)までで、miniからLAN越しに届くかは、まだ確かめていない。

9月24日から25日にかけての作業で、コミットは #1733 になる。

生の口を、そのまま開けなかった

最初に考えたのは、動画生成アプリ(video-gen)のポートをLANへ出す案だ。やめた。

考えた脅威は、LANの他人ではない。エージェント自身だ。外部の文章に仕込まれた指示を、ローカルの小型モデルが真に受ける。LANが自分だけでも、この経路は残る。

並べた案と判断は次のとおり。

案判断
ComfyUIをLANへ公開する却下。認証が無く、任意のワークフローが通る
video-genのポートをLANへ公開する却下。上の転送と、任意パス・GUIの口がある
口を3本だけの中継にする却下。注文しかできず、工程を操作できない
video-genをopenclawのコンテナへ入れる却下。ComfyUIと同じPCのフォルダを読み書きしていて、別のマシンでは動かない
Windows側にMCPサーバーを置き、高レベルなツールだけ公開する採用

開けた口は3つ

openclawminiのコンテナvideo-gen/mcpWindows。LANに見える唯一の口video-gen3031ComfyUI8188LANへ出さないMCP + Bearerlocalget_statusgenerate_shotsget_jobツールはこの3つだけシェル(curl)署名付きURLだけ/files(動画の受け取り口)親トークンはゲートウェイ側だけ
LANに見えるのはWindows側のMCPサーバーだけ。動画を作る本体には、ここを通らないと届かない。

ツールはget_status(状態を見る)、generate_shots(注文する)、get_job(結果を見る)の3つ。注文の入力は、次のように絞った。

**解像度、長さ、ステップ数、モデル、負プロンプト、開始画像は受け取らない。**プリセットで固定してある。受け取らない項目を増やすほど、エージェントが間違った指示や仕込まれた指示に従っても、起きることが小さくなる。

ジョブは直列に処理する。待ちが3件を超えたら断り、空きメモリが閾値を下回っているときも断る。

受け取りで詰まった

動画は/filesから取る。最初は、ここにもBearerトークンを必須にしていた。すぐに気づいた。エージェントがcurlで動画を保存するには、**シェルにトークンが要る。**設計書の脅威モデルは、コンテナの中で動くものは環境変数を読める前提で書いてある。親トークンをシェルへ渡す形は、それと食い違う。

そこで、get_jobが「ジョブ・ショット・期限」に紐づく署名付きURLを返す形にした。有効期限は15分で、切れたらget_jobを呼び直す。シェルに見えるのはそのURLだけで、親トークンはMCPクライアント(ゲートウェイ)側にしか置かない。

1つの扉だけが開いた壁のロッカー。手前には、その扉の札と薄い砂時計が下がり、親鍵は奥のガラスケースの中にある

作りは署名付きURLで鍵を隠すにまとめた。今日、テストを動かして確かめたことだけ書く。

動いた設定は1つだけ

プリセットはSulphur2の量子化版(Q5)に固定した。ltx2は、非量子化のGemma(27GB)を読み込む段階でこのマシンのメモリが逼迫し、直接生成でも事前エンコード方式でも生成できなかった。ただし、「ltx2が不可」とは断定していない。過去に事前エンコード方式で動いた記録がある。

9月24日に、UIからSulphur2で768x512・153フレーム・20ステップが通った(エンコード約12秒、生成約376秒)。これをstandardとし、軽くした設定をlightにした。

lightstandard
解像度512x320768x512
フレーム数49(約1.6秒)153(約5.1秒)
実測約200秒(MCP経由、9/25)376秒(UI実行、9/24)

lightの約200秒は、ComfyUIを再起動した直後の初回で、サンプリング約156秒を含む。実行中の空きメモリは約15GBまで、仮想メモリの空きは約31GBまで下がった。停止のしきい値は8GBなので、余裕はあった。

ComfyUIが消えて、ログが白紙だった

ltx2を試していた9月24日、ComfyUIが数分で消えた。自作のメモリ監視(仮想メモリの空きが8GB未満で止める)が働いた可能性が高い。「可能性が高い」としか言えないのは、その監視のログが出なかったからだ。

BOMなしUTF-81行目に日本語のコメントがあるWindowsPowerShell 5.1がANSIとして読む1行目の日本語が次の行を巻き込む(ログ先の代入)ログが出ない止まった理由を後から辿れない対処: スクリプトをASCIIだけに書き直した2はMicrosoft Learnに記載がある。2から3への巻き込みは、決定ログの結論で、Windowsでの再現はしていない。
保護は働いたのに、働いた記録が残らなかった経路。

Microsoft Learnの文字コードのページに、こう書いてある。BOMなしのUTF-8のスクリプトは、Windows PowerShellが古い「ANSI」コードページとして読み違える。日本語のコメントを1行目に置いていたスクリプトが、これに当たった。決定ログの結論は、日本語コメントが次の行(ログの出力先を決める代入)を巻き込んだ、というものだ。スクリプトはASCIIだけに書き直した。

落ちたブレーカーのレバーと、その下に置かれた罫線だけの白紙の記録帳と鉛筆

大事なのは、保護が働いたことより、働いた記録が無かったことだ。先日書いたガードが素通りする書き方と同じ型で、止める側が壊れていても、止まらないだけで表には何も出ない。

検証で見つけた抜け

記事の裏取りのため、MCPの仕様(Streamable HTTP)を原文で読み直した。セキュリティの節は、サーバーに次を求めている。

作ったサーバーは、束縛(既定は127.0.0.1)と認証(Bearer)は満たしている。Originは、ソースを検索した限り見ていなかった。/mcpはBearer必須なので悪用の道は狭いが、仕様のMUSTは満たしていなかった。

その場で直した。Origin付きの要求は既定で403にし、許可する送信元だけ環境変数で足す。curlやMCPクライアントはOriginを付けないので、今までどおり通る。判定は認証より前に置いた。

直したあとに、修正を外して新しいテストが落ちることを確かめた。テストが素通りしていないかの確認だ。テストは53件が通り、修正を外すと、新しく足した結合テスト1件だけが落ちた。

今日の教訓

まだ確かめていないことも残る。miniのコンテナからWindows機のMCPへLAN越しに届くか、openclaw側のMCP登録、台本を書くモデルの選定(今は推定で選んだだけで、出来を比べていない)。次はここを実機で通す。

関連