Web Claude に画像生成器をつなぐ — リモート MCP コネクタと画像転送の問題


Web Claude は画像を読む。写真を分析し、レイアウトを解析し、生成のための参照画像も受け取る。しかし画像を作ることはできない。テキストプロンプトを渡して画像を求めても、そのためのツールが存在しないため拒否する。我々のチームはこれを、Claude MCP コネクタを自前で構築することで解決した。

[toc]

🔍 ギャップ — Web Claude には画像生成ツールがない

Claude MCP(Model Context Protocol)は、AI クライアントが外部ツールサーバーと通信するための標準だ。ローカル MCP サーバーをすでに持っていれば、Claude Code と Desktop はそれをそのまま利用できる。Web Claude は事情が異なる。

我々のチームは画像生成 MCP サーバーを運用していた。これは三つのプロバイダ — Gemini、xAI Grok、GPT-Image — を単一のインターフェースの背後にまとめたものだ。テキストからの画像生成、指示ベースの編集、参照ベースの生成、四コマ漫画の生成。これらすべてが Claude Code と Desktop で問題なく動作していた。

当然の発想は、Web Claude を同じサーバーに向けることだった。その当然の発想は機能しない。理由は単純かつ根本的だ。

📡 なぜローカル stdio サーバーは Web クライアントに届かないのか

stdio MCP サーバーは、同一マシン上の標準入力と標準出力を介して通信する。Web クライアントは自分のマシン上では動いていない。カスタムコネクタを追加すると、Web クライアントは Anthropic のクラウドから、公開インターネットを経由してサーバーに到達する。ローカルプロセスはそこからは見えない。コネクタをどう設定しても、ローカル stdio サーバーが到達可能になることはない。

MCP Streamable HTTP Transport

リモートクライアント向けに spec 2025-03-26 で導入された。単一の HTTPS エンドポイントが POST と GET の両方をサポートし、オプションで SSE ストリーミングを提供する。これは spec 2024-11-05 の古い HTTP+SSE 方式を置き換えるものだ。MCP spec は、公開されるサーバーは HTTPS で提供されることを明示的に要求している。

結論は明確だった。Web クライアントにツールを接続するには、公開された HTTPS エンドポイントが必要だ。サーバーをゼロから新規に構築するか、既存のツールの上に HTTP を載せるかのどちらかである。

我々は既存の stdio サーバーには手を触れなかった。同じツール関数をインポートする別の HTTP ランチャーを書いた。サーバー定義は一つ、トランスポートは二つ。画像生成のロジックは一行も変わっていない。stdio クライアントは元のパスを使い続け、Web クライアントは同じツールに HTTP 経由で到達する。

🛠️ 本当の課題 — 画像をクライアントへ返す

二つ目のトランスポートを追加することは難しい部分ではなかった。本当の課題は、生成した画像をクライアントへ返すことだった。

ローカルクライアントは単純だ。サーバーがファイルをディスクに保存してパスを返し、クライアントがそのファイルを開く。Web クライアントは自分のディスクにアクセスできない。画像そのものがツール結果の内部を移動しなければならない。

試み 1 — フル解像度 PNG → base64 インライン → 失敗

最も自明なアプローチ。生成した画像を base64 にエンコードし、ツール結果に直接返す。これは失敗した。フル解像度の PNG は数メガバイトある。base64 はおよそ 33% のオーバーヘッドを加える。Claude のツール結果の上限は 25,000 トークン、画像は 5MB が上限だ。数メガバイトの base64 は、ペイロードエラーとしてクライアントのサンドボックスに拒否される。画像の代わりに、エラーメッセージが返ってくる。

試み 2 — サムネイル縮小 → 収まるが使えない

サイズの問題を解くため、画像を縮小した。数百ピクセルのプレビューはサンドボックスを通過する。しかしそれは「モデルがプロンプトを理解したか」を確認する程度にしか役立たない。キャラクターの一貫性や色の正確さ、実際に使う上で判断すべきものには使えない。実用に耐える品質ではなかった。

解決策 — 三つの形式を同時に返す

最終的な構造はハイブリッドだ。各ツール結果が、画像を三つの形式で同時に運ぶ。各クライアントは自分が使えるものを取る。

形式 内容 用途
インライン中解像度 JPEG 長辺最大 1280px、中程度の品質。数百キロバイト程度。 Web クライアントの即時プレビュー。サンドボックスを通過する。会話内に直接レンダリングされる。
短命の署名付き URL フル解像度の原本。有効期限 1 時間、推測不能なトークン。 実際の利用 — ダウンロード、さらなる編集。列挙不能な構造。
ローカルファイルパス ディスク上のパス、そのまま。 stdio クライアントの後方互換性。既存のワークフローを維持する。

中解像度 JPEG は見るためのもの、署名付き URL は使うためのものだ。両方を持つことで、どのクライアントも自分に必要なものを取れる。これはコンテキストコストと品質のトレードオフに対する意図的な設計上の応答だ。数百キロバイトの base64 が即座に判読可能なプレビューを与え、必要なときにはフルのファイルがワンクリックで手に入る。

同じ問題は、参照画像の入力では逆向きに現れる。ローカルクライアントはファイルパスを渡せるが、Web クライアントはサーバーのファイルシステムを指し示すことができない。そこでサーバーは、入力を base64、URL、パスのいずれでも受け取り、先頭のマジックバイトから形式を自動判別するようにした。参照ベースの生成は、どちらのクライアントからも同じように動作する。

🔐 認証 — なぜ静的 Bearer トークンは失敗したか

HTTP サーバーの最初のバージョンは、静的な Bearer トークンを使っていた。シークレットを設定し、ヘッダーで送る、それだけだ。考えうる最も単純なもので、ローカルのテストでは機能した。

それは実際のクライアントとの接触に耐えられなかった。Claude のカスタムコネクタのフローは OAuth ハンドシェイクを前提としている。クライアントがサーバーの認証メタデータを発見し、自分自身を動的に登録し(Dynamic Client Registration、RFC 7591)、ユーザーを標準的なログインフローへ導く。静的なトークンを貼り付けるフィールドは UI に存在しない。

⚠️ MCP spec 2025-11-25 以降:公開される MCP サーバーは OAuth 2.1 + PKCE(S256) の使用が要求される。静的 Bearer トークンは spec を満たさず、主要な AI クライアントは OAuth ハンドシェイクを要求する。Dynamic Client Registration(RFC 7591)は事実上必須だ。

最終的な構成は OAuth プロバイダ + 許可リストだ。OAuth が認証を担い、アカウントレベルのフィルタで承認済みのアカウントだけがツールを呼べるようにする。我々は FastMCP フレームワークを使った。これは OAuth のメタデータエンドポイント、DCR、トークン検証を標準で処理してくれる。ここで得た最も実践的な教訓は、構築が最も簡単な認証が、必ずしもクライアントが実装する認証ではないということだ。

🔒 公開オリジン上のファイル配信のセキュリティ

サーバーが公開 HTTPS オリジン上でファイルをホストした瞬間、ローカル stdio サーバーには無縁だった一群の問題を引き継ぐ。何かを公開する前に、二つのことを直す必要があった。

Content-type の強制

保存されたものをそのまま返すファイル配信エンドポイントは、HTML や SVG を配信させられると、保存型 XSS のベクターになる。対策は、実際の先頭バイトを調べ、本物のラスタ形式 — PNG、JPEG、WEBP、GIF — だけを配信することだ。認識できない形式は拒否する。レスポンスには X-Content-Type-Options: nosniff も付け、ブラウザがコンテンツタイプを推測したり何かを実行したりしないようにする。

フェイルクローズなアップロードパス

初期のバージョンは、アップロード用シークレットが未設定のときにアップロードを許可していた。それはまさに逆だ。シークレットが設定されていないということは、エンドポイントが無効であることを意味すべきだ。フェイルクローズ。設定不備の状態は、開いた門ではなく、施錠された門であるべきだ。

公開オリジンのファイル配信 — セキュリティチェックリスト

  • マジックバイトで content-type を強制する(PNG/JPEG/WEBP/GIF のみ)
  • レスポンスに X-Content-Type-Options: nosniff を設定する
  • アップロードパスはフェイルクローズ — シークレット欠如 = エンドポイント無効
  • 短い有効期限 + 推測不能なトークンの署名付き URL
  • パストラバーサルの防止(ストレージディレクトリ外へのアクセスを遮断)

どちらの対策も巧妙ではない。両方とも後から見れば自明であり、画像を表示させることに集中していると見落としやすい。公開サーバーはローカルプロセスとは異なる脅威面を持つ。早くそう扱うほど、後で改修すべきものは少なくなる。

📊 結果 — どのデバイスからでも Web Claude で画像生成

コネクタが整うと、結果は明快だ。Web Claude のセッションで「画像を生成して」と言えば、ツール呼び出しが発火し、中解像度 JPEG のプレビューが会話内に直接現れる。ローカルインストールは不要だ。どのデバイスからログインしても、同じツールがそこにある。

同じサーバーが複数のプロバイダにまたがってルーティングするため、素早い下書きには安価なモデルを、最終版には高品質なモデルを使える。重い作業 — 一貫したキャラクター生成、四コマ漫画、参照ベースの編集 — も、別のツールへ寄り道するのではなく、Web Claude のセッション内にとどまる。それが当初の目標だった。

デモ 1 — Web Claude セッション内でのインライン画像レンダリング

Image generation tool call result rendering inline in a web Claude session — no local install required
Web Claude のセッションから画像生成ツールを呼ぶと、中解像度 JPEG のプレビューが会話内に直接レンダリングされる。ローカルインストールは不要。どのブラウザからでも動作する。

デモ 2 — 参照画像の自動判別による一貫したキャラクター生成

Reference-based generation — same character in school uniform (left) and futuristic spacesuit (right)
Web クライアントから参照画像を base64 として渡すと、サーバーがマジックバイトから形式を自動判別する。結果はローカルクライアントがファイルパスを渡すのと同じ — スタイルのバリエーションをまたいでキャラクターの同一性が保たれる。

📚 参考資料

✅ まとめ — 六つの教訓

  • stdio はローカル専用だ。ツールを Web クライアントに接続するのは、別個の意図的なステップである。コネクタを設定しても、ローカルサーバーが見えるようにはならない。
  • 画像の転送は、まずサイズの問題だ。中解像度のインライン JPEG + 署名付き URL の組み合わせは、「すべてをインラインに」と「サムネイルを送る」のどちらにも勝る。
  • 入力もリモートクライアントを扱う必要がある。参照画像は生の base64 を受け取れなければならない。リモートクライアントはサーバーのファイルシステムを指し示せない。
  • クライアントの実際の認証フローを早めに確認せよ。構築が最も簡単な認証が、クライアントの実装するものとは限らない。OAuth DCR は厄介だが避けられない。
  • 公開オリジンからファイルを配信した瞬間、content-type とアップロードパスはセキュリティ面になる。
  • フェイルクローズせよ。シークレットの欠如はエンドポイントを無効にすべきであり、開くべきではない。デフォルトは常により制限的であるべきだ。

Discover more from AI-Girls Lab

Subscribe to get our latest posts delivered to your inbox.


コメントを残す

AI-Girls Labをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む