MCP.so
ログイン
ブログに戻る

MCP Apps 完全ガイド:MCP のインタラクティブ UI の仕組み(2026)

2026年10月15日MCP.so TeamMCP.so Team

MCP Apps は、MCP サーバーがインタラクティブな UI を ui:// リソースとして配信し、Claude・ChatGPT・VS Code・Goose のサンドボックス iframe で描画する仕組みです。仕様の現状、SDK、最小サンプルを解説します。

MCP Apps は、MCP サーバーがプレーンテキストの代わりにインタラクティブな UI(グラフ、フォーム、地図、ダッシュボード)を返せるようにする、Model Context Protocol の公式拡張です。ツールはメタデータで HTML ページを含む ui:// リソースを指し、ホスト(Claude、ChatGPT、VS Code、Goose など)がそのページをサンドボックス化された iframe で描画します。ページは JSON-RPC でホストとやり取りします。一度書けば、この拡張に対応したすべてのホストで動きます。

このガイドでは、仕様の現状、MCP Apps を描画できるクライアント、公式 SDK に基づく最小の動作サンプル、そして MCP Apps と OpenAI Apps SDK・MCP-UI の関係を解説します。

現状のまとめ(2026 年 10 月)

項目現在の状態
仕様SEP-1865「MCP Apps: Interactive User Interfaces for MCP」、Extensions トラック
ステータスStable(安定版)、バージョン 2026-01-26。draft 版も開発中
発表2026 年 1 月 26 日、初の公式 MCP 拡張として発表
リポジトリmodelcontextprotocol/ext-apps
SDK@modelcontextprotocol/ext-apps(サブパス /server・/react・/app-bridge)、v2.x
MIME タイプtext/html;profile=mcp-app
紐付けキーツールの _meta.ui.resourceUri

この SEP は 2025 年 11 月 21 日に初めて公開されました。著者には MCP-UI の開発者と、Anthropic・OpenAI のメンバーが含まれています。

MCP Apps の仕組み

ext-apps の README は流れを 4 つのステップで説明しています。

  1. ツール定義:ツールが HTML インターフェースを含む ui:// リソースを宣言します。
  2. ツール呼び出し:モデルはいつもどおりサーバー上のツールを呼び出します。
  3. ホストが描画:ホストがリソースを取得し、サンドボックス化された iframe に表示します。
  4. 双方向通信:ホストは通知でツールの入力と結果を UI に渡し、UI はホストを経由して別のツールを呼び出せます。

つまり UI はもう一つの MCP リソースにすぎません。だから MCP Apps は既存のプロトコルにそのまま収まります。ツールとリソースの違いを確認したい場合は MCP のリソースとツールの違い を参照してください。

プロトコルの構成要素

  • UI リソース:URI が ui:// で、MIME タイプが text/html;profile=mcp-app のリソースです。_meta.ui で csp(許可するオリジン)、permissions、domain、prefersBorder を宣言できます。
  • ツールとの紐付け:ツールの _meta.ui.resourceUri で描画するリソースを指定します。_meta.ui.visibility は ["model", "app"](デフォルト)か、UI からは呼べるがモデルには見えない補助ツール向けの ["app"] を指定できます。
  • ハンドシェイク:View が ui/initialize を送って hostContext(テーマ、表示モード、ロケールなど)を受け取り、続けて ui/notifications/initialized を送ります。
  • データの受け取り:ui/notifications/tool-input と ui/notifications/tool-result が呼び出しの引数と結果を届けます。
  • UI からのアクション:View は tools/call、ui/message(チャットにメッセージを投稿)、ui/open-link、ui/update-model-context を送れます。
  • 表示モード:inline(デフォルト)、fullscreen、pip(ピクチャーインピクチャー)。ホストが 3 つすべてに対応しているとは限りません。

セキュリティモデル

すべてはサンドボックス化された iframe 内で動き、CSP はデフォルトですべてを拒否します。リソースが ui.csp を宣言しない場合、仕様によりホストは connect-src 'none' を使うので、UI は外部 API を一切呼べません。外部オリジンを許可するには、connectDomains(fetch/WebSocket)、resourceDomains(スクリプト、画像、フォント、スタイル)、frameDomains(ネストした iframe)、baseUriDomains に列挙します。ホストはルールをさらに厳しくできますが、宣言されていないドメインを許可してはいけません。発表記事によると、UI とホスト間のメッセージはすべて監査可能な JSON-RPC で、UI が始めたツール呼び出しにユーザーの承認を求めることもできます。より広い脅威モデルについては MCP セキュリティのベストプラクティス を参照してください。

MCP Apps に対応しているクライアント

公式ドキュメントで確認できたホストだけを挙げます。

ホスト対応状況備考
Claude(Web とデスクトップ)対応(発表当日から)Claude ドキュメント:App を表示する前に許可を求めます(Allow / Always allow)。ui.domain を設定するリモート App は、Claude 独自のハッシュ形式 *.claudemcpcontent.com を使う必要があります
ChatGPT対応OpenAI の変更履歴によると、2026-02-22 から ChatGPT は「fully compatible with the MCP Apps spec」です。Add UI to your MCP server を参照
VS Code(GitHub Copilot エージェント)対応2026-01-26 に発表。まず Insiders、その後 Stable に提供
Goose対応公式発表で挙げられたローンチ時のホストの一つ
Postman、MCPJam、mcp-use Inspector、Alpic Playground掲載ありext-apps の README で対応ホストとして記載

個々の機能への対応はホストによってまだ違いがあり、特に表示モードとホスト独自の機能で差が出ます。MCP Apps に対応していないクライアントでも作業を終えられるよう、ツールは引き続き有用なテキストを返すようにしましょう。対応状況の一覧は modelcontextprotocol.io/clients にあり、MCP クライアントは当サイトの /clients でも探せます。

最小の MCP App を作る

以下のコードは公式の quickstart サンプル(ext-apps 2.x、Node.js 20+)からそのまま取ったものです。get-time というツールで、UI にはサーバー時刻と更新ボタンが表示されます。サーバーを作ったことがなければ、まず MCP サーバーの作り方 をご覧ください。

1. パッケージをインストール

npm install -S @modelcontextprotocol/ext-apps \
  @modelcontextprotocol/client@^2.0.0 \
  @modelcontextprotocol/server@^2.0.0 \
  @modelcontextprotocol/node@^2.0.0 \
  @modelcontextprotocol/express@^2.0.0 \
  zod@^4.2.0
npm install -D typescript vite vite-plugin-singlefile tsx

ホストは UI を 1 つの HTML リソースとして読み込むため、quickstart では Vite と vite-plugin-singlefile を使って JavaScript をインラインにバンドルします。

2. ツールと UI リソースを登録する(server.ts)

import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import {
  registerAppResource,
  registerAppTool,
  RESOURCE_MIME_TYPE,
} from '@modelcontextprotocol/ext-apps/server';
import { McpServer } from '@modelcontextprotocol/server';
import { z } from 'zod';

const DIST_DIR = path.join(
  path.dirname(fileURLToPath(import.meta.url)),
  'dist'
);

export function createServer(): McpServer {
  const server = new McpServer({
    name: 'Quickstart MCP App Server',
    version: '1.0.0',
  });

  // Tool + resource, tied together by the resource URI.
  const resourceUri = 'ui://get-time/mcp-app.html';

  registerAppTool(
    server,
    'get-time',
    {
      title: 'Get Time',
      description: 'Returns the current server time.',
      inputSchema: z.object({}),
      _meta: { ui: { resourceUri } }, // links this tool to its UI
    },
    async () => {
      const time = new Date().toISOString();
      return { content: [{ type: 'text', text: time }] };
    }
  );

  registerAppResource(
    server,
    resourceUri,
    resourceUri,
    { mimeType: RESOURCE_MIME_TYPE },
    async () => {
      const html = await fs.readFile(
        path.join(DIST_DIR, 'mcp-app.html'),
        'utf-8'
      );
      return {
        contents: [
          { uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html },
        ],
      };
    }
  );

  return server;
}

RESOURCE_MIME_TYPE は text/html;profile=mcp-app を表す定数です。文字列を手書きせずにこちらを使いましょう。ヘルパーの registerAppTool と registerAppResource はホストごとに必要なメタデータも生成してくれます。Claude のドキュメントがこれらを推奨しているのはそのためです。

3. View を作る(mcp-app.html + src/mcp-app.ts)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Get Time App</title>
  </head>
  <body>
    <p>
      <strong>Server Time:</strong> <code id="server-time">Loading...</code>
    </p>
    <button id="get-time-btn">Get Server Time</button>
    <script type="module" src="/src/mcp-app.ts"></script>
  </body>
</html>
import { App } from '@modelcontextprotocol/ext-apps';

const serverTimeEl = document.getElementById('server-time')!;
const getTimeBtn = document.getElementById('get-time-btn')!;

const app = new App({ name: 'Get Time App', version: '1.0.0' });

// Register handlers BEFORE connect() so you don't miss the first result.
app.ontoolresult = (result) => {
  const time = result.content?.find((c) => c.type === 'text')?.text;
  serverTimeEl.textContent = time ?? '[ERROR]';
};

getTimeBtn.addEventListener('click', async () => {
  const result = await app.callServerTool({ name: 'get-time', arguments: {} });
  const time = result.content?.find((c) => c.type === 'text')?.text;
  serverTimeEl.textContent = time ?? '[ERROR]';
});

app.connect();

main.ts(ポート 3001 の /mcp で Streamable HTTP、または --stdio で stdio)、vite.config.ts、package.json のスクリプトは quickstart フォルダ からコピーしてください。React を使う場合は、@modelcontextprotocol/ext-apps/react の useApp と useHostStyles が使えます。

4. テストする

  • basic-host:ext-apps をクローンし、npm install && npm start を実行して http://localhost:8080 を開きます。このリファレンスホストはデフォルトで http://localhost:3001/mcp に接続します。
  • Claude Desktop:Settings → Developer → Edit Config で stdio の設定を追加します。まず公開済みのサンプルを試すなら次のとおりです。
{
  "mcpServers": {
    "map": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-map", "--stdio"]
    }
  }
}
  • ChatGPT:接続できるのはリモートの HTTPS サーバーだけです。サーバーをデプロイするかトンネルを張ってから、カスタム MCP サーバーとして追加します。手順は ChatGPT MCP 設定ガイド と MCP サーバーのデプロイ を参照してください。
  • デバッグ:描画を調べる前に、MCP Inspector でツールの _meta とリソースが正しく返るか確認しましょう。

AI コーディングエージェントを使っていますか?リポジトリには Agent Skills(create-mcp-app、add-app-to-server、migrate-oai-app、convert-web-app)が同梱されています。Claude Code では /plugin marketplace add modelcontextprotocol/ext-apps を実行してから /plugin install mcp-apps@mcp-apps でインストールできます。

MCP Apps・OpenAI Apps SDK・MCP-UI の比較

3 つは同じ系譜にあります。発表記事によると、MCP Apps は MCP-UI と OpenAI Apps SDK を土台にしています。

MCP-UIOpenAI Apps SDK(ChatGPT)MCP Apps
何かMCP 上の UI を切り開いたコミュニティプロジェクトChatGPT 向けアプリを作る OpenAI の仕組み。現在は Plugins のドキュメントにまとめられている公式でベンダー中立の MCP 拡張
現状@mcp-ui/server と @mcp-ui/client は現在 MCP Apps 標準を実装ChatGPT は MCP Apps を実装。window.openai が ChatGPT 専用の機能を追加安定版仕様 2026-01-26
ツールと UI の紐付け埋め込み UI リソース_meta["openai/outputTemplate"](エイリアスとして存続)_meta.ui.resourceUri
動作環境MCP-UI ホスト、および MCP Apps ホストChatGPTClaude、ChatGPT、VS Code、Goose など

実際の開発では次のようになります。

  • 新規プロジェクト:MCP Apps(ui.resourceUri、text/html;profile=mcp-app、App クラス)を使いましょう。OpenAI の ドキュメントも共通の名前を使うよう求めており、window.openai は仕様にない機能にだけ使うよう案内しています。該当するのは requestCheckout、ファイルのアップロードと選択、requestModal、widgetState です。ホスト名で分岐せず、機能検出で使えるか判断してください。
  • 既存の ChatGPT アプリ:従来の window.openai.toolInput・toolOutput・callTool・sendFollowUpMessage はエイリアスとして引き続き動きます。migrate-oai-app スキルと 移行ガイド が、それぞれを ontoolinput・ontoolresult・callServerTool・ui/message に対応づけてくれます。
  • ホストを自作する場合:MCP-UI のクライアント SDK(AppRenderer)は機能のそろった MCP Apps レンダラーです。@modelcontextprotocol/ext-apps/app-bridge で View を自前で埋め込むこともできます。

よくあるトラブル

  • テキストは出るが UI が出ない:ツールに _meta.ui.resourceUri があるか、リソースが MIME text/html;profile=mcp-app で登録されているか、ホストが MCP Apps に対応しているかを確認します。
  • iframe が真っ白、またはリクエストが失敗する:原因はほぼ CSP です。バンドルが読み込んだり呼び出したりするオリジンは、開発時の localhost も含めてすべて resourceDomains か connectDomains に列挙する必要があります。漏れたオリジンは何も表示されずに失敗します。違反はブラウザのコンソールで確認できます。
  • 最初の結果が表示されない:ontoolresult と ontoolinput は app.connect() の前に設定します。
  • デプロイ後も UI が古いまま:OpenAI のドキュメントは、リソース URI をキャッシュキーとして扱うよう勧めています。互換性のない変更をしたら新しい URI を公開し、参照しているツールを更新します。
  • Claude が ui.domain を拒否する:Claude で使う値は、サーバー URL の SHA-256 の先頭 32 桁の 16 進数に .claudemcpcontent.com を付けたものです。詳しくは Claude のドキュメントを参照してください。

次のステップ

MCP Apps でツールの結果はクリックして操作できる画面になりますが、その裏のツール自体が良くなければ意味がありません。MCP サーバーディレクトリ で既存のサーバーがツールをどう設計しているかを見たり、おすすめの MCP サーバー からヒントを得たりしてください。App を公開したら、mcp.so に登録してほかの人に見つけてもらいましょう。

よくある質問

MCP Apps とは何ですか?

MCP Apps は Model Context Protocol の公式拡張(SEP-1865)で、MCP サーバーがインタラクティブな UI を配信できるようにします。ツールが ui:// の HTML リソースを指し、ホストがそれをサンドボックス iframe で描画して JSON-RPC でやり取りします。

MCP Apps の仕様は安定版ですか?

はい。MCP Apps の仕様はバージョン 2026-01-26 で安定版となり、2026 年 1 月 26 日に初の公式 MCP 拡張として発表されました。draft 版は modelcontextprotocol/ext-apps リポジトリで引き続き更新されています。

MCP Apps に対応しているクライアントは?

Claude(Web とデスクトップ)、ChatGPT、GitHub Copilot を使う VS Code、Goose が対応しており、Postman や MCPJam などでも描画できます。フルスクリーンやピクチャーインピクチャーなどの機能対応はホストごとに異なります。

MCP Apps と OpenAI Apps SDK の違いは?

OpenAI Apps SDK は ChatGPT 独自のアプリ UI の仕組みで、MCP Apps はそれを一部土台にしたオープン標準です。現在の ChatGPT は MCP Apps を実装し、window.openai の名前をエイリアスとして残しつつ、決済やファイルアップロードなど ChatGPT 専用の機能を追加しています。