
MCP Appsでチャット内で実行確認ができる勉強のアプリを作ってみた!
こんにちは、リテールアプリ共創部の戸田駿太です。
MCP Apps × Next.js × Monaco Editor で、AIチャットの中でJavaScriptコードを編集・実行できるVS Code風プレイグラウンドを作りました。
これを使うことで、JSの構文を学習する際にAIへの質問からコードの実行・修正・再質問までをチャット内で完結できるようになります。
作ったもの
AIに「スプレッド構文の使い方を教えて」などと聞くと、テキストの解説に加えて、編集・実行可能なコードウィジェットがチャット内に表示されます。

従来はコードブロックをコピーしてDevToolsなどに貼り付けて実行する必要がありましたが、このアプリではその場でコードを書き換えてRunボタンを押すだけで結果を確認できます。
従来の体験
- AIに質問する
- コードブロックで回答が返ってくる
- コードをコピーする
- DevToolsなど別の環境に貼り付けて実行する
- 修正したらまたコピペ…(3に戻る)
このアプリでの体験
- AIに質問する
- チャット内にVS Code風のエディタ+ターミナルのウィジェットが表示される
- その場でコードを編集して ▶ Run で実行
- わからなければ 💬 Ask AI でそのままAIに質問(2に戻る)
MCP Appsとは
MCP Apps は、MCPツールの呼び出し結果にカスタムHTML/React UIをインライン表示できる仕組みです。Claude Desktop、ChatGPT などが対応しています。
通常のMCPツールはテキストを返すだけですが、MCP Appsを使うとサンドボックスiframe内にReact UIを表示できます。
Claude Desktop のチャット画面
│
├── ユーザーの質問(通常のチャット)
├── AIの応答テキスト(通常のチャット)
└── MCPツール呼び出し
└── structuredContent を返す
└── MCP Apps ウィジェット (iframe) がチャット内に描画される
MCP Appsを詳しく知りたい方はこちらの記事をご覧ください。
アーキテクチャ
技術スタック
| 技術 | 用途 |
|---|---|
| Next.js 16 (App Router) | フレームワーク |
@modelcontextprotocol/ext-apps |
MCP Apps SDK |
mcp-handler |
Next.js 用 MCP ハンドラ(Vercel製) |
@monaco-editor/react |
VS Codeのエディタエンジン |
| Tailwind CSS 4 | スタイリング |
| Zod | スキーマバリデーション |
| Vercel | ホスティング |
ディレクトリ構成
study-programming-mcp-apps/
├── app/
│ ├── mcp/
│ │ └── route.ts # MCPサーバー + playgroundツール定義
│ ├── components/
│ │ ├── PlaygroundWidget.tsx # ウィジェット全体
│ │ ├── MonacoEditor.tsx # Monaco Editor (dynamic import)
│ │ ├── TabBar.tsx # script.js タブ
│ │ ├── Terminal.tsx # ターミナル出力パネル
│ │ └── Toolbar.tsx # Run / Clear / Copy / Ask AI ボタン
│ ├── hooks/
│ │ ├── use-mcp-app.ts # MCP接続ブリッジ
│ │ └── useCodeExecution.ts # コード実行管理
│ ├── lib/
│ │ └── vscode-theme.ts # VS Code風カラーパレット
│ ├── page.tsx # エントリーポイント
│ └── layout.tsx # iframe対応レイアウト
├── baseUrl.ts
├── middleware.ts
└── next.config.ts
実装のポイント
MCPツール定義 — AI → ウィジェットへのデータの流れ
MCP Apps では、サーバー側に2つのものを登録します。
- ツール — AIが呼び出す関数。今回は
playgroundという名前で、codeとautoRunを引数に取る - リソース — ウィジェットのHTML。ツールが呼ばれたときにチャット内に表示されるUI本体
この2つを resourceUri でひも付けることで、「AIがツールを呼ぶ → 対応するUIが表示される」という流れになります。
ツールの戻り値にはcontent と structuredContent の2種類があります。contentはAIの会話コンテキストに残るテキスト、structuredContentはAIには見えずウィジェットだけに届くデータです。今回はウィジェットに表示したいコードを structuredContent 経由で渡しています。
ウィジェット側の受信 — useApp フックとステート管理
ウィジェット側のデータを受け取りのため、公式SDKの useApp フックに ontoolinput と ontoolresult のハンドラを登録します。
ここで1点注意があり、ハンドラは onAppCreated コールバック内で登録しなければなりません。useApp が内部で connect() の前にハンドラを設定してくれるため、接続直後のイベントも取りこぼさずに済みます。
開発中にハマったのが、MCPデータが届く前にデフォルトコードでMonaco Editorをマウントしてしまうという問題でした。一度マウントされたMonaco Editorは、propsが変わっても表示を更新してくれません。
対処としては、connected && !data(接続済みだがデータ未着)の間はウィジェットをマウントせず、データが届いてから初めて PlaygroundWidget を描画するようにしました。
コード実行 — consoleを乗っ取る
▶ Run ボタンを押したときの処理を見ていきます。
console.log 等を一時的に上書きして、出力をReactのstateに流し込んでからターミナルパネルに表示し、実行後に元に戻す——というのが基本の流れです。コードの実行には AsyncFunction コンストラクタを使っており、await を含むコードにも対応できます。
MCP Appsのウィジェットはもともとホスト側のサンドボックスiframe内で動いているので、この eval ベースの方式でもセキュリティ上のリスクは限定的です。
ウィジェット → AIへの双方向通信 — sendMessage
ここまでの流れは AI → ウィジェット の一方向でした。ただ、せっかくコードを書き換えて実行できるなら、その結果についてAIに質問できたほうが学習体験として完成します。
app.sendMessage() を使うと、ウィジェットからClaudeの会話にメッセージを送れます。
「💬 Ask AI」ボタンを押すと、エディタの現在のコードと実行結果をまとめてClaudeに送信します。コードを書き換えて実行してみたけど結果がよくわからない、というときにそのままAIに聞ける。AIがコードを提示 → ユーザーが試す → わからなければAIに聞く、という学習ループがチャット内で完結します。
開発中に気をつけたこと
Monaco EditorのCDN読み込みとCSP
MCP Appsのiframe sandboxは厳しいCSPがかかっています。Monaco Editorはデフォルトで cdn.jsdelivr.net からワーカーファイルを読み込むため、CSP設定で明示的に許可する必要がありました。
これを忘れると、エディタが永遠に「Loading...」のままになります。
試してみる
Vercelにデプロイ済みなので、Claude Desktopからすぐに試せます。claude_desktop_config.json に以下を追加して、Claude Desktopを再起動してください。
{
"mcpServers": {
"js-playground": {
"command": "npx",
"args": ["mcp-remote", "https://study-programming-mcp-apps.vercel.app/mcp"]
}
}
}
あとはClaudeに「スプレッド構文の使い方を教えて」などとJavaScriptについて質問すれば、playground ツールが呼ばれてウィジェットが表示されます。
まとめ
MCP Appsを使うことで、AIとの会話の中にインタラクティブなUIを埋め込むことができます。今回はJavaScriptのPlaygroundを作りましたが、同じ仕組みでグラフ描画ツール、フォームビルダー、データビジュアライザーなど、様々なウィジェットが実現できます。
今回紹介したアプリでは「AIにコードを聞いてコピペして実行」という往復が不要になり、チャットの中で完結する学習体験が作れました。
皆さんの参考になれば幸いです。
参考









