MCP Apps v1.2の新機能 「リソース読み取りAPI」 を試してみた

MCP Apps v1.2の新機能 「リソース読み取りAPI」 を試してみた

v1.2.0 で追加された「app.readResource()」「app.listResources()」などの新機能を実際に試しながら解説します。読者としては、MCPサーバーを開発中の方や、これから MCP Apps を導入したいエンジニアの方を想定しています。
2026.03.16

はじめに

MCP Apps は、AIチャットの会話内にインタラクティブなUI(ダッシュボード、フォーム、可視化など)を埋め込むための Model Context Protocol(MCP)の公式拡張仕様です。2026年1月26日に v1.0.0 として正式リリースされてから約2ヶ月、すでに v1.2.2 まで進化しています。

v1.2.0 で追加された app.readResource() / app.listResources() によって、MCP Apps のUI側からサーバーリソースへ直接アクセスできるようになりました。従来はツール呼び出し経由でしか取得できなかったデータを、UIが能動的に取得できる設計が可能になっています。

この記事では、このリソース読み取り/一覧APIを中心に、v1.2.x 系の新機能を実際に試しながら解説します。読者としては、MCPサーバーを開発中の方や、これから MCP Apps を導入したいエンジニアの方を想定しています。

MCP Apps v1.0〜v1.2 の進化を振り返る

まず、v1.0.0 から v1.2.2 までの変更を一覧で確認してみましょう。

バージョン リリース日 主な変更
v1.0.0 2026-01-26 正式仕様リリース。ui:// URIスキーム、Tool-UI Linkage、サンドボックスセキュリティモデル
v1.0.1 2026-01-26 依存パッケージ更新、ドキュメント修正
v1.1.0 2026-02-22 PDF検索、フルスクリーン対応
v1.1.1 2026-02-24 音声/動画サポート、PDF改善、MCPBパッケージング
v1.1.2 2026-02-25 PDFサーバーのパス検証、download-file メソッド追加
v1.2.0 2026-03-06 リソース読み取り/一覧API追加、autoResize修正
v1.2.1 2026-03-10 ビルド修正、E2Eテスト改善、セキュリティパッチ
v1.2.2 2026-03-10 zod/v4 からのスキーマインポート修正

特に注目すべきマイルストーンは3つあります。

1つ目は v1.1.0 でのPDF検索・フルスクリーン対応です。MCP Apps のUIが全画面表示に対応し、PDFビューアのような本格的なアプリケーションが実現可能になりました。

2つ目は v1.1.1 での音声/動画サポートです。テキストやグラフだけでなく、メディアリッチなUIが構築できるようになっています。

3つ目が今回のメインテーマである v1.2.0 でのリソース読み取り/一覧API です。これが MCP Apps の設計パターンを大きく広げる重要な追加機能です。

v1.2.0の目玉機能「リソース読み取り/一覧API」とは

従来の MCP Apps の制約

v1.2.0 以前の MCP Apps では、UIがサーバーからデータを取得するには、ツール呼び出しの結果として渡されるデータに依存していました。つまり、LLMがツールを呼び出す → ツールがデータと共にUIリソースを返す → UIがそのデータを表示する、という一方向の流れでした。

UIが追加のデータを必要とする場合、ホスト経由でツールを再度呼び出す必要があり、LLMの介在が必須でした。

v1.2.0 で変わったこと

app.readResource()app.listResources() の追加により、UIからサーバーリソースへ直接アクセスできるようになりました。これはMCPの「リソース」プリミティブ(MCP サーバーが公開するデータソース)をUI側から利用できるようにしたものです。

従来(v1.1.x以前):

  1. LLM がツールを呼び出す
  2. ツールがデータ付きで UI リソースを返す
  3. UI がそのデータを表示する(データは固定、追加取得にはLLMの再介在が必要)

v1.2.0 以降:

  1. LLM がツールを呼び出す
  2. ツールが UI リソースを返す
  3. UI が表示される
  4. UI が app.listResources() でリソース一覧を取得(LLM不要)
  5. UI が app.readResource(uri) で個別リソースを読み取り(LLM不要)
  6. UI が動的にデータを更新

ポイントは、ステップ4〜6が LLM を介さずにUI主導で実行できるようになった点です。

ユースケース例

この新APIが活きるシーンをいくつか挙げてみます。

  • 設定ファイルの動的読み込み: UIからサーバー上の設定リソースを取得して、ユーザーが編集・保存できるフォームを構築
  • データブラウジング: ファイル一覧をリソースとして公開し、UIでファイルブラウザを実現
  • ダッシュボードの自動更新: 定期的にリソースを再取得して、リアルタイムデータを表示

なお、リソースの読み取りはホスト側の許可ポリシーに依存します。すべてのリソースに無条件でアクセスできるわけではなく、ホストがどのリソースへのアクセスを許可するかを制御する点にご注意ください。

実際に試してみた ─ 環境構築とクイックスタート

前提条件

  • Node.js(v18以上推奨)
  • pnpm

参考にしたスターターテンプレート

今回は Vercel Labs が公開している mcp-apps-nextjs-starter を参考に、Claude Code に実装を依頼しました。このスターターは Next.js ベースの MCP Apps の最小構成で、MCPサーバーとウィジェットUIを1つの Next.js アプリに同居させるアーキテクチャを採用しています。

プロジェクト構成

実装したプロジェクトの構成は以下のとおりです。

demo-mcp-apps-v1.2.0/
├── app/
│   ├── globals.css              — グローバルスタイル
│   ├── hooks/
│   │   └── use-mcp-app.ts      — MCP Apps 接続フック
│   ├── layout.tsx               — ルートレイアウト(iframe ブートストラップ含む)
│   ├── mcp/
│   │   └── route.ts            — MCP サーバーエンドポイント
│   ├── page.tsx                 — メイン UI(Resource Browser)
│   └── types/
│       └── global.d.ts          — Window 型拡張
├── lib/
│   └── sample-resources.ts      — サンプルリソース定義
├── baseUrl.ts                   — 公開 URL 解決(トンネル / Vercel)
├── middleware.ts                — CORS ヘッダー付与
├── next.config.ts               — assetPrefix 設定
├── package.json
└── tsconfig.json

Next.js のルートページ(app/page.tsx)がそのままウィジェットUIとなり、app/mcp/route.ts がMCPサーバーとして機能します。MCPサーバーは起動時に / のHTMLをself-fetchし、UIリソースとしてホストに返す仕組みです。

依存パッケージ

package.json の主要な依存パッケージです。

{
  "dependencies": {
    "@modelcontextprotocol/ext-apps": "^1.2.2",
    "@modelcontextprotocol/sdk": "1.25.2",
    "mcp-handler": "^1.0.7",
    "next": "16.1.6",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "zod": "^4.3.6"
  }
}
  • @modelcontextprotocol/ext-apps — MCP Apps のクライアント/サーバーSDK。registerAppToolregisterAppResource などを提供
  • @modelcontextprotocol/sdk — MCP プロトコル本体
  • mcp-handler — Next.js の Route Handler で MCP サーバーを動かすためのハンドラ
  • zod — ツール引数のスキーマバリデーション

ホストへの接続

Vercelにデプロイして起動したMCPサーバーのURLを、MCP Apps 対応ホストに登録します。

https://xxxx-xxx-xxx/mcp

(xxxx-xxx-xxxはVercelデプロイ後に取得可能なドメイン)

Claude.ai、ChatGPT、Cursor のいずれでも、設定画面の MCP / Apps セクションにこのURLを追加するだけで接続できます。
接続方法はこちらの記事をご参照ください。

https://dev.classmethod.jp/articles/mcpapps-20260309/

app.readResource() の基本的な使い方

v1.2.0 で追加された app.readResource() を使うと、UIからサーバーのリソースを直接読み取れます。

注意: 以下のコード例は SDK v1.2.2 時点の API に基づく記述です。API の詳細は変更される可能性があるため、最新の仕様は 公式APIドキュメント を参照してください。

(画像を差し込む)

// MCP App(UI側): リソースの読み取り
import { App } from "@modelcontextprotocol/ext-apps";

const app = new App();

// ホストとの通信を確立(必須!)
await app.connect();

// サーバーリソースを読み取る
const resource = await app.readResource("config://app-settings");

console.log(resource);
// {
//   contents: [
//     {
//       uri: "config://app-settings",
//       mimeType: "application/json",
//       text: '{"theme": "dark", "language": "ja", ...}'
//     }
//   ]
// }

// 取得したデータをUIに反映
const settings = JSON.parse(resource.contents[0].text);
document.getElementById("theme-select").value = settings.theme;

app.listResources() でリソース一覧を取得

利用可能なリソースの一覧を取得する app.listResources() も追加されています。

スクリーンショット 2026-03-16 16.09.28

ソースコードの例は次の通りです。

// MCP App(UI側): リソース一覧の取得
const { resources } = await app.listResources();

console.log(resources);
// [
//   { uri: "config://app-settings", name: "アプリ設定", mimeType: "application/json" },
//   { uri: "data://metrics/cpu", name: "CPU使用率", mimeType: "application/json" },
//   { uri: "data://metrics/memory", name: "メモリ使用率", mimeType: "application/json" },
// ]

// UIにリソース一覧を表示
resources.forEach((res) => {
  const option = document.createElement("option");
  option.value = res.uri;
  option.textContent = res.name;
  document.getElementById("resource-selector").appendChild(option);
});

React での利用例

React を使っている場合は、useApp() フックを組み合わせて利用できます。

// MCP App(React): useApp() + リソースAPI
import { useApp } from "@modelcontextprotocol/ext-apps/react";
import { useState, useEffect } from "react";

function Dashboard() {
  const app = useApp();
  const [resources, setResources] = useState([]);
  const [selectedData, setSelectedData] = useState(null);

  useEffect(() => {
    // リソース一覧を取得
    app.listResources().then(({ resources }) => {
      setResources(resources);
    });
  }, [app]);

  const handleSelect = async (uri) => {
    // 選択されたリソースを読み取り
    const result = await app.readResource(uri);
    setSelectedData(JSON.parse(result.contents[0].text));
  };

  return (
    <div>
      <h2>利用可能なリソース</h2>
      <select onChange={(e) => handleSelect(e.target.value)}>
        <option value="">選択してください</option>
        {resources.map((res) => (
          <option key={res.uri} value={res.uri}>
            {res.name}
          </option>
        ))}
      </select>
      {selectedData && (
        <pre>{JSON.stringify(selectedData, null, 2)}</pre>
      )}
    </div>
  );
}

export default Dashboard;

ダウンロード機能

v1.1.2 で追加された download-file メソッド(SDK上は app.downloadFile())を使うと、MCP Apps のUI内からホスト経由でファイルをダウンロードさせることができます。通常のブラウザとは異なり、MCP Apps はサンドボックスiframe内で動作するため、<a download>Blob URL による直接ダウンロードはできません。代わりに、ホストにダウンロードリクエストを送り、ホスト側がファイル保存を処理する仕組みです。

今回の実装では、リソースブラウザで選択中のリソースをダウンロードできるようにしました。

スクリーンショット 2026-03-16 16.09.41

ソースコードの例は次の通りです。

// app/hooks/use-mcp-app.ts — ダウンロードヘルパー
export async function requestFileDownload(options: {
  filename: string;
  content: string;
  mimeType: string;
}) {
  if (!singletonApp) throw new Error("Not connected to MCP host");
  return singletonApp.downloadFile({
    contents: [
      {
        type: "resource" as const,
        resource: {
          uri: `file:///${options.filename}`,
          text: options.content,
          mimeType: options.mimeType,
        },
      },
    ],
  });
}

downloadFile の引数は MCP のリソース形式に準拠しており、uritextmimeType を持つリソースオブジェクトを contents 配列で渡します。uri には file:/// スキームでファイル名を指定します。

UI側からの呼び出しは以下のようになります。

// app/page.tsx — ダウンロードボタンのハンドラ
const handleDownload = useCallback(async () => {
  if (!content?.text) return;
  const resource = resources.find((r) => r.uri === selectedUri);
  const ext = content.mimeType === "application/json" ? ".json" : ".md";
  const filename = (resource?.name ?? "resource").replace(/\s+/g, "-") + ext;
  try {
    await requestFileDownload({
      filename,
      content: content.text,
      mimeType: content.mimeType ?? "text/plain",
    });
    setStatus(`${filename} をダウンロードしました`);
  } catch (err) {
    console.error("Download failed:", err);
    setStatus("ダウンロードに失敗しました");
  }
}, [content, selectedUri, resources]);

リソース名からファイル名を生成し、MIME タイプに応じて拡張子(.json / .md)を付与しています。requestFileDownload が内部で app.downloadFile() を呼び出し、ホストにファイルデータを送信します。

なお、downloadFile はホスト側の対応が必要なため、すべてのMCPホストで動作するわけではない点に注意してください。対応状況はホストごとに異なります。

まとめ

MCP Apps v1.2.x の主なポイントを整理します。

  • v1.2.0 でリソース読み取り/一覧APIが追加され、UIからサーバーリソースへの直接アクセスが可能になった
  • app.readResource() / app.listResources() により、LLMを介さないデータ取得が実現し、より動的なUI設計パターンが使える
  • v1.1.x 系では PDF検索、フルスクリーン、音声/動画サポートなど、メディア系機能が大幅に強化
  • エコシステムも急速に拡大中: FastMCP 3.0 Beta 2 での対応、Microsoft Power Apps MCP Server のプレビュー、Google Cloud MCP サーバー自動有効化など

今後もクラスメソッドではMCP Appsの機能追加を追っていきます。Xでも発信していきますのでお楽しみに。

https://x.com/mach_asset_pro?s=20

参考リンク

この記事をシェアする

FacebookHatena blogX

関連記事