MCP Appの作り方 — create-mcp-appスキルで雛形を生成する
create-mcp-appスキルをAIコーディングエージェントに入れると、MCP Appのサーバー・UI・設定ファイル一式が自動生成されます。導入からローカル動作確認までの手順です。
MCP Appを一から手作業で構築すると、サーバー・UI・ビルド設定を揃えるだけで何ファイルも書くことになり、動かすまでに時間がかかります。create-mcp-app スキルをAIコーディングエージェントに入れると、この雛形生成を1回の指示で終わらせられます。Claude Codeなら公式プラグインとして配布されており、インストールから動作確認までを本記事で順番に追います。
この手順でできること
create-mcp-app はMCP Appsのアーキテクチャ・ベストプラクティス・動くサンプルコードを含んだスキルで、エージェントがこれを読み込んでプロジェクトを生成します。実行環境にはNode.js 18以上が必要で、事前にインストールしておきます。MCPのツールとリソースの両方を組み合わせる仕組みのため、事前にMCPのツール・リソースの基本を知っていると読みやすくなります。
全体の流れは次の4段階です。
スキルでMCP Appを動かすまで
- 1
スキルを入れる
Claude Codeならプラグインマーケットプレイスから2コマンドで入ります。他のエージェントではスキルフォルダにコピーします。
- 2
作りたいアプリを自然文で頼む
「色を選ぶUIを持つMCP Appを作って」のように頼むと、サーバー・UI・設定ファイルが生成されます。
- 3
アプリのフォルダで起動する
アプリのフォルダでビルドして起動すると、
http://localhost:3001/mcpにサーバーが立ちます。 - 4
MCP Apps対応ホストで表示する
Claude(cloudflaredで公開)か、リポジトリ同梱のbasic-hostで画面を確かめます。
手作業でセットアップすることもでき、後半の「手動セットアップの流れ」で扱います。まずはスキルを使う経路から進めます。
スキルをインストールする
Claude Codeでは、公式プラグインマーケットプレイスから直接インストールできます。
/plugin marketplace add modelcontextprotocol/ext-apps
/plugin install mcp-apps@modelcontextprotocol-ext-appsVercel Skills CLIを使う方法もあります。
npx skills add modelcontextprotocol/ext-apps手動でインストールする場合は、リポジトリをクローンしてスキルフォルダをコピーします。
git clone https://github.com/modelcontextprotocol/ext-apps.git
mkdir -p .claude/skills
cp -r ext-apps/plugins/mcp-apps/skills/create-mcp-app .claude/skills/create-mcp-appグローバルに入れたい場合は .claude/skills/ の代わりに ~/.claude/skills/ へコピーすれば、全プロジェクトで使えるようになります。プロジェクト単位でしか使わないなら .claude/skills/ へのコピーで十分です。Windowsでは %USERPROFILE%\.claude\skills\ が配置先で、コピーには Copy-Item -Recurse を使います。
インストール後は「使えるスキルを教えて」とエージェントに聞き、create-mcp-app が一覧に出ることを確認します。
他のエージェントでのスキル配置先
Claude Code以外のエージェントでもスキルディレクトリの規約に沿えば動きます。配置先はエージェントごとに異なります。
| エージェント | スキルディレクトリ(macOS/Linux) |
|---|---|
| Claude Code | スキルディレクトリ(macOS/Linux)~/.claude/skills/ |
| VS Code / GitHub Copilot | スキルディレクトリ(macOS/Linux)~/.copilot/skills/ |
| Gemini CLI | スキルディレクトリ(macOS/Linux)~/.gemini/skills/ |
| Cline | スキルディレクトリ(macOS/Linux)~/.cline/skills/ |
| Goose | スキルディレクトリ(macOS/Linux)~/.config/goose/skills/ |
| Codex | スキルディレクトリ(macOS/Linux)~/.codex/skills/ |
| Cursor | スキルディレクトリ(macOS/Linux)~/.cursor/skills/ |
このリストは網羅的ではなく、他のエージェントもスキルをサポートしている場合があります。各エージェントのドキュメントで配置先を確認してください。
スキルは何を読んで何を生成するのか
スキルの実体は SKILL.md 1本です。エージェントは指示を受けると、まずこの SKILL.md を読みます。中身を知っておくと、生成物が思ったものと違ったときに頼み方を直しやすくなります。
最初に決めさせるのは構成です。SKILL.md は「既存のMCPサーバーに足すのか、新しいサーバーを作るのか」と「UIのフレームワークは何か」を判断の軸に置いています。フレームワークごとに、参照用のテンプレートが決まっています。
| フレームワーク | 参照テンプレート | クライアント側の書き方 |
|---|---|---|
| Vanilla JS | 参照テンプレートbasic-server-vanillajs/ | クライアント側の書き方手動でライフサイクルを書く |
| React | 参照テンプレートbasic-server-react/ | クライアント側の書き方useApp フックが使える |
| Vue / Svelte / Preact / Solid | 参照テンプレートbasic-server-{名前}/ | クライアント側の書き方手動でライフサイクルを書く |
エージェントは ext-apps リポジトリをバージョンを合わせて /tmp/mcp-ext-apps へクローンし、そこのサンプルとAPIのJSDocを読んで雛形を組み立てます。クローンは git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" というコマンドで、npmの最新版に合わせたタグを取ります。
どのテンプレートにも、server.ts・HTTPとstdio両対応の main.ts・src/global.css・vite.config.ts・package.json・.gitignore が含まれます。標準のサーバー実行には、SDKのサンプルが使う bun ではなく tsx を使う方針です。
SKILL.md は、生成時の落とし穴も5つ挙げています。
- テキストの
contentを必ず返す(MCP Apps非対応のホストでも結果が読めるようにするため) - ネットワーク通信は
localhost宛てでも、CSPの設定が必要になる _meta.ui.cspと_meta.ui.domainは、registerAppResource()の設定オブジェクトではなく、読み取り用コールバックが返すcontents[]の中に置く- ハンドラはすべて
app.connect()の前に登録する - 長い入力には
ontoolinputpartialで途中経過を見せる
ハンドラの順序は、生成後のコードを自分で直すときに特に効きます。
const app = new App({ name: "My App", version: "1.0.0" });
app.ontoolinput = (params) => { /* 入力を受け取る */ };
app.ontoolresult = (result) => { /* 結果を受け取る */ };
app.onhostcontextchanged = (ctx) => { /* テーマ等の変更 */ };
await app.connect(); // 登録は必ずこの前同じリポジトリには、create-mcp-app のほかにスキルが3つあります。既存のMCPサーバーのツールにUIを足す add-app-to-server、OpenAI AppsのアプリをMCP Appsへ変換する migrate-oai-app、既存のWebアプリをWeb兼MCP Appにする convert-web-app です。新規に作るのか、手持ちの資産を載せ替えるのかで使い分けます。
アプリを作らせて動かす
スキルが入った状態で、作りたいアプリを自然文で指示します。
Create an MCP App that displays a color pickerエージェントは create-mcp-app スキルが関係すると判断してその指示を読み込み、サーバー・UI・設定ファイル一式を含む完全なプロジェクトを組み立てます。生成後は依存関係をインストールし、ビルドしてサーバーを起動します。
npm install && npm run build && npm run serveWindowsのPowerShellでは、公式の手順が npm install; npm run build; npm run serve とセミコロンで区切っています。コマンドは生成されたアプリのフォルダ内で実行します。公式のビルドガイドも、実行前にアプリのフォルダにいることを確かめるよう注意しています。
テストする
ローカルで起動しただけでは、MCP Apps対応ホストがないと画面は見られません。テスト方法は主に2つあります。
Claudeでテストする
ClaudeとClaude Desktopは両方ともMCP Appsに対応しています。ローカルサーバーをインターネットに公開する必要があり、cloudflared でトンネルするのが手早い方法です。
npx cloudflared tunnel --url http://localhost:3001生成されたURL(https://random-name.trycloudflare.com のような形式)を、Claudeの設定からカスタムコネクタとして追加します。プロフィール → 設定 → コネクタ → カスタムコネクタを追加、の順です。カスタムコネクタはFree(1件まで)・Pro・Max・Team・Enterpriseで利用できます。カスタムコネクタ自体の作り方はCoworkカスタムコネクタ自作ガイドで扱っています。
basic-hostでテストする
ext-apps リポジトリには開発用のテストホストが同梱されています。
git clone https://github.com/modelcontextprotocol/ext-apps.git
cd ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm starthttp://localhost:8080 にアクセスすると、ツールを選んで呼び出せるシンプルなインターフェースが表示されます。ツールを呼ぶとホストがUIリソースを取得し、サンドボックスiframe内にレンダリングします。SERVERS を省くと、接続先は http://localhost:3001/mcp です。
basic-hostのサンドボックスは二重のiframeです。ホスト本体(8080番)の中に、別オリジン(8081番)の外側iframeがあり、その中の srcdoc iframeにツールのUIが入ります。外側が別オリジンなので、ツールのUIがホストのDOMやCookieに触れません。メッセージは外側iframeが検証して中継します。
どちらを軸にテストするか
basic-host
npm start だけで動き、Claudeのアカウントもトンネルも要りません。UIの見た目やツール呼び出しのロジックを、再読み込みだけで往復できます。
cloudflared + Claude
Claudeでの実際の見え方を確かめられます。トンネルの公開とカスタムコネクタの登録が前提です(Freeは1件まで)。
basic-hostは、あくまでMCP Appsを動かせるホストの一例です。SKILL.md も、Claude Desktopのような実際のホストはもっと作り込まれているため、basic-hostはローカルテストとプロトコルの理解に使い、ホストの挙動の保証とは考えないよう書いています。プロジェクト構成そのものは共通なので、途中でテスト方法を切り替えてもサーバー・UIのコードを書き直す必要はありません。
手動セットアップの流れ
エージェントを使わず自分で構成したい場合、プロジェクトはサーバー用コードとUI用コードを分けて置くのが典型的な構成です。package.json / tsconfig.json / vite.config.ts / server.ts(ツールとリソースを持つMCPサーバー)/ mcp-app.html(UIのエントリポイント)/ src/mcp-app.ts(UIロジック)という6ファイルが基本セットになります。
UIリソースは、最終的にデフォルトで外部通信を許さないCSPのiframeに入ります。JSやCSSのアセットを別ファイルで持つ場合はCSPの設定が要るため、公式のチュートリアルは vite-plugin-singlefile でUIを1つのHTMLにまとめる構成を採っています。必須ではありませんが、CSPの個別設定を避けたいときに便利です。
依存パッケージの食い違い
依存パッケージの指定は、公式の2か所で食い違っています。
依存パッケージの指定
ビルドガイドの手動手順
@modelcontextprotocol/ext-apps と @modelcontextprotocol/sdk をインストールします。サーバーのコード例も @modelcontextprotocol/sdk/server/mcp.js からインポートしています。
スキル(SKILL.md)の指示
@modelcontextprotocol/client / server / node / express を ^2.0.0 で入れ、zod は ^4.2.0 です。旧式の @modelcontextprotocol/sdk(v1)は追加しないよう明記しています。
npm上の @modelcontextprotocol/ext-apps 2.x系も、peerDependencies に @modelcontextprotocol/client と core(いずれも ^2.0.0)、zod(^4.2.0)を要求し、server は任意のpeerです。スキルの指示は、この2.x系に合わせたものです。手動で組むときは、ビルドガイドの sdk 指定をそのまま写さず、使う ext-apps のバージョンと peerDependencies を見て揃えるのが確実です。
npm install @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 express cors
npm install -D typescript vite vite-plugin-singlefile concurrently cross-env @types/node @types/express @types/cors tsxext-apps パッケージはサーバー側(ツールとリソースの登録)とクライアント側(ホストとの通信を担う App クラス)の両方のヘルパーを提供します。
設定ファイルの役割
設定ファイルの役割も押さえておくと迷いにくくなります。package.json は "type": "module" でESモジュール構文を有効にします。書き忘れると、import.meta.dirname などESモジュール前提のコードが動かないことがあります。また build スクリプトが INPUT 環境変数でどのHTMLファイルを束ねるかをViteに伝えます。serve スクリプトは tsx でサーバーを動かします。
tsconfig.json は ES2022 をターゲットにモジュール解決を bundler に設定し、ルートのサーバーコードと src/ 配下のUIコードの両方を include に含めます。vite.config.ts では viteSingleFile() プラグインを有効にし、ビルド出力先を dist に、入力ファイルを環境変数 INPUT 経由で指定します。
サーバーとUIの実装
サーバー側では registerAppTool でツールに _meta.ui.resourceUri を持たせ、registerAppResource で同じURIに対応するビルド済みHTMLを返す実装にします。公式サンプルでは、現在時刻を返すシンプルなツールを例に、McpServer インスタンスを作り、ui://get-time/mcp-app.html というURIをツールとリソースの両方に紐づけます。URIのパス構造は任意で、ui:// スキームがMCP Appのリソースだとホストに伝えます。サーバー自体はExpressでHTTP経由に公開し、/mcp エンドポイントに StreamableHTTPServerTransport を接続する構成が定番です。
UI側は App クラスの connect() でホストとの通信を確立し、ontoolresult コールバックでツール結果を受け取り、callServerTool() でユーザー操作に応じてサーバーのツールを呼び出します。サンプルの mcp-app.ts では、ボタンのクリックイベントに callServerTool() を紐づけ、返ってきた結果をDOM要素に反映する流れになっています。ツール呼び出しはサーバーへの往復が発生するため、レイテンシーを前提にUIを設計する必要があります。App クラスにはこのほか、ログ出力・URLを開く・モデルの文脈を構造化データで更新するメソッドも用意されています。
まとめ
雛形づくりはエージェントに任せ、手を入れるのは依存パッケージのバージョンとCSPの置き場所に絞る、という分担になります。画面の確認は、ローカルならbasic-host、公開前の見え方ならClaudeと使い分けます。MCP Apps自体の仕組みはMCP Appsとはで解説しています。