MCP Appsとは — インタラクティブUIをチャットに埋め込む拡張機能
MCP AppsはMCPサーバーがサンドボックスiframeでHTML UIを返し、チャット内で双方向にツールを呼べるようにする拡張仕様です。仕組みと使いどころをまとめます。
MCP Appsは、MCPサーバーがテキストだけでなくインタラクティブなHTML UIをチャット内に返せるようにする拡張仕様です。サンドボックス化されたiframeの中でフォームやダッシュボード、3Dビューアーなどが動き、ユーザーはタブを切り替えずにその場で操作できます。ClaudeとClaude Desktopはすでにこの拡張に対応しています。
MCP Appsとは何か
MCP Appsは、MCPのツールとリソースという2つの既存プリミティブを組み合わせた拡張です。ツールの説明に _meta.ui.resourceUri フィールドでUIリソースへの参照を持たせ、ホスト側がそのリソースを取得してサンドボックスiframe内にレンダリングします。テキスト応答では表現しきれない、データの掘り下げや多数の設定項目を持つフォームに向いています。
普通のWebアプリとの違いは、会話から離れないことです。ユーザーはリンクを開いてタブを切り替える必要がなく、UIは会話の文脈の隣に留まり続けます。
既存のMCP応答形式との違い
従来のMCPツールは、テキスト・画像・リソース・構造化データのいずれかをホストに返し、ホストがそれを会話の一部として表示する仕組みでした。MCP Appsはこのパターンを拡張し、ツールの説明にインタラクティブなUIへの参照を持たせられるようにしたものです。既存の応答形式を置き換えるのではなく、選択肢を1つ増やす位置づけです。
| 応答形式 | ホストの扱い | 双方向性 |
|---|---|---|
| テキスト | ホストの扱い会話に文字列として表示 | 双方向性なし |
| 画像 | ホストの扱い会話に画像として表示 | 双方向性なし |
| 構造化データ | ホストの扱い会話にJSON等として表示、またはUIコンポーネントが解釈 | 双方向性なし |
| MCP App(UIリソース) | ホストの扱いサンドボックスiframeにHTMLとしてレンダリング | 双方向性あり(ツール呼び出し・push更新) |
テキストや画像はユーザーが読んで終わりますが、MCP Appsはレンダリング後もユーザーの操作を受け取り、サーバーへ新しいツール呼び出しを投げ返せます。この双方向性が、ダッシュボードやフォームのような継続的なやり取りを必要とするユースケースを可能にしています。
もう1つの違いは、ホストがUIリソースをツール呼び出しの前に先読みできる点です。ツール説明に _meta.ui.resourceUri が含まれていれば、ホストは実際にツールが呼ばれるより先にUIリソースの取得を始められます。これにより、ツールの入力がストリーミングされている間にもUIを表示し始めるといった体験が作れます。テキストや画像の応答ではこの種の先読みは意味を持たず、MCP Apps固有の設計です。
なぜ普通のWebアプリではダメなのか
MCP Appsの提供元は、単独のWebアプリを別リンクで案内するだけでは足りない理由を4点挙げています。それぞれの理由は、実装コストと安全性のどちらかに直結します。
| 利点 | 内容 |
|---|---|
| 文脈の保持 | 内容UIは会話の中に留まり、どのスレッドで何を開いたか迷わない |
| 双方向のデータ連携 | 内容アプリはサーバーの任意のツールを呼び、ホストは新しい結果をアプリにpushできる |
| ホスト機能への委譲 | 内容メール送信のような操作を、ユーザーが既に接続済みの機能へホスト経由で委譲できる |
| セキュリティの担保 | 内容サンドボックスiframeで動くため、親ページやCookieにアクセスできない |
単独のWebアプリでこれを実現しようとすると、独自のAPI・認証・状態管理を一式作ることになります。MCP Appsは既存のMCPパターンに乗るぶん、その負担を引き受けません。
内部の仕組み — UIプリロードからJSON-RPC通信まで
LLMがMCP Appsに対応したツールを呼び出すと、4つの段階が進みます。UIプリロードでは、ツール説明の _meta.ui.resourceUri を見て、ホストがツール呼び出し前に ui:// リソースをあらかじめ読み込みます。次にリソース取得で、JavaScriptとCSSを束ねたHTMLページをサーバーから取得します。外部スクリプトを読み込む場合は _meta.ui.csp で許可オリジンを指定します。
3段階目はサンドボックスレンダリングです。取得したHTMLは会話内のサンドボックスiframeに描画され、親ページのDOM・Cookie・ローカルストレージへのアクセスは遮断されます。マイクやカメラのような追加権限が必要な場合は、リソースの _meta.ui.permissions で個別に要求します。
最後が双方向通信です。アプリとホストはJSON-RPCベースの独自ダイアレクトで会話し、tools/call のようにコアMCPと共通のメッセージもあれば、ui/initialize のように ui/ プレフィックスを持つ新規メッセージもあります。アプリはツール呼び出しを要求したり、モデルの文脈を更新したりできます。
どんな場面で使うべきか
公式ドキュメントは5つの適用場面を挙げています。いずれも、テキスト応答だけでは往復のやり取りが増えてしまう場面です。
| 場面 | テキスト応答との違い |
|---|---|
| 複雑なデータの探索 | テキスト応答との違い地域別の売上をインタラクティブな地図でドリルダウンできる |
| 多数の選択肢を持つ設定 | テキスト応答との違いデプロイ設定のような相互依存する項目を、フォーム1画面でまとめて見せる |
| リッチメディアの閲覧 | テキスト応答との違いPDFや3Dモデルをパン・ズーム・回転しながら会話内で確認できる |
| リアルタイム監視 | テキスト応答との違いダッシュボードが常時接続を維持し、都度「今の状態は」と聞かずに更新される |
| 多段階のワークフロー | テキスト応答との違い経費申請の承認やコードレビューを、ナビゲーションと状態保持付きで1件ずつ処理できる |
逆に、これらの利点が活きない用途では、普通のWebアプリの方がシンプルです。
対応クライアントとセキュリティモデル
MCP Appsをサポートするホストは概要ドキュメントの時点でClaude、Claude Desktop、VS Code GitHub Copilot、Microsoft 365 Copilot、Goose、Postman、MCPJam、Archestra.AIの8つが挙がっています。ただし公式のクライアントマトリクスはこれより広く、ChatGPT・Cursor・PostHog Codeの3つも対応済みとして並んでいます。概要ページの一覧だけを見ると対応ホストを過小に見積もることになるため、最新の対応状況はクライアントマトリクス側で確認するのが確実です。
セキュリティモデルの核心はサンドボックスiframeです。アプリは親ウィンドウのDOMを読めず、ホストのCookieやローカルストレージにも触れません。親ページへのナビゲーションや親コンテキストでのスクリプト実行もできません。通信はすべてpostMessage API経由で行われ、どのツールを呼べるかや sendOpenLink のような機能を無効化できるかはホスト側が制御します。この設計により、ホストは開発元を完全には信頼していないサードパーティ製アプリでも安全にレンダリングできます。サンドボックスはアプリがホストやユーザーデータにアクセスする形での脱出を防ぐことを目的としており、機能の許可は既定で最小限に絞られています。マイクやカメラのような追加権限は、アプリ側が明示的に要求し、ホスト側がユーザーへの確認を経て許可する形になります。
自前のMCPクライアントを実装してMCP Appsに対応させたい場合は、選択肢が2つあります。ひとつは @mcp-ui/client パッケージのReactコンポーネントを使う方法、もうひとつはSDKに含まれるApp Bridgeモジュールをそのまま組み込む方法です。App Bridgeはサンドボックスiframeでのレンダリング、メッセージパッシング、ツール呼び出しのプロキシ、セキュリティポリシーの強制をまとめて引き受けます。どちらの経路でも、ホスト実装者がイチからpostMessageのハンドシェイクを設計し直す必要はありません。基本ホストの実装例(basic-host)がリファレンスとして公開されており、統合の進め方を確認できます。
対応フレームワークと実装の自由度
MCP Appsは特定のフレームワークを前提にしていません。転送方式はstdioやHTTPではなくpostMessageです。標準的なWeb技術の組み合わせなので、React・Vue・Svelte・Preact・Solid・素のJavaScriptのどれでも実装できます。
@modelcontextprotocol/ext-apps パッケージが提供する App クラスは、この通信を簡単に扱うための便利なラッパーであって必須ではありません。依存を増やしたくない場合や細かい制御が必要な場合は、postMessageプロトコルを直接実装する選択肢もあります。
公式のexamplesディレクトリには、カテゴリー別に実装例が揃っています。
| カテゴリー | 実装例 |
|---|---|
| 3D・可視化 | 実装例CesiumJSの地球儀、Three.jsのシーン、シェーダーエフェクト |
| データ探索 | 実装例コホートヒートマップ、顧客セグメンテーション、Wikipedia探索 |
| ビジネス用途 | 実装例シナリオモデラー、予算配分ツール |
| メディア | 実装例PDFビューアー、動画リソース、楽譜表示、音声合成 |
| ユーティリティ | 実装例QRコード生成、システム監視、音声認識(文字起こし) |
| 開発用スターター | 実装例React / Vue / Svelte / Preact / Solid / 素のJavaScript |
いずれもゼロから設計を考えなくても、近い用途のサンプルをそのまま出発点にできる構成です。実装を始める前に近いカテゴリーのサンプルを一通り眺めておくと、UIとサーバーの役割分担やツール設計の勘所がつかみやすくなります。既存のUIコンポーネントをプレビューに再利用する発想はStorybook MCPサーバーが実例です。
_meta.ui に書くフィールド
MCP Appsの設定は、ツール定義とリソース定義の _meta.ui オブジェクトに集約されています。実装時に迷いやすい3つのフィールドをまとめます。
| フィールド | 役割 | 例 |
|---|---|---|
resourceUri | 役割ツールが参照するUIリソースの場所。ui:// スキームで、パス構造は自由 | 例ui://get-time/mcp-app.html |
csp | 役割外部スクリプト・アセットを読み込む場合の許可オリジン | 例外部CDNのドメイン |
permissions | 役割マイクやカメラなど、サンドボックス既定では使えない権限の要求 | 例microphone、camera |
resourceUri はツール登録時に _meta.ui.resourceUri として指定し、registerAppResource 側で同じURIに対応するHTMLを返す実装になります。ツール定義の側は最小構成だと次のようになります。
{
"name": "get-time",
"_meta": {
"ui": {
"resourceUri": "ui://get-time/mcp-app.html"
}
}
}この resourceUri の値と、サーバー側で registerAppResource に渡すURIが一致していないと、ホストはUIリソースを解決できません。CSPとpermissionsは省略可能で、外部リソースを読み込まない・追加権限が不要なアプリでは書かなくても動きます。この3フィールドさえ押さえておけば、あとはツールとリソースというMCPの通常の実装作業に帰着します。UIそのものの作り込みが本題であり、MCP側の設定は最小限で済むように設計されています。
まとめ
MCP Appsが解いているのは、エージェントとの会話がテキストのやり取りに閉じていた問題です。これまでダッシュボードやフォームが必要な場面では、外部サービスへのリンクを渡すか、テキストで項目を1つずつ確認するかの二択でした。MCP Appsはその中間を埋め、会話の文脈を保ったままインタラクティブな操作面を差し込みます。
ホストへの機能委譲という設計も見逃せません。アプリ自身がメール送信や外部連携を実装する代わりに、「この結果でミーティングを予約して」とホストに依頼し、ユーザーが既に許可済みの接続を経由させられます。個々のMCPサーバー開発者が外部サービスとの統合を作り込む必要がなくなり、実装対象がUIそのものに絞られます。
対応ホストはClaude・Claude Desktop・ChatGPT・Cursorなど広がっている段階であり、どのホストでどこまで機能が揃うかはまだ流動的です。実際にアプリを配布する前提なら、クライアントマトリクスと権限モデルを都度確認する運用が要ります。
実際に手を動かして作る手順はMCP Appを実際に作ってみるで扱います。Claude Codeでのスキル・MCP・サブエージェントの使い分けはClaude Code SkillsとMCPの違いが参考になります。