このスキルは、ユーザーが「OpenAI Apps SDK からの移行」「OpenAI アプリを MCP に変換」「window.openai からのポート」「skybridge からの移行」「openai/outputTemplate の変換」といった質問をする場合、または OpenAI Apps SDK アプリケーションを MCP Apps SDK に変換するためのガイダンスが必要な場合に使用します。API マッピング表を含めた段階的な移行ガイダンスを提供します。 **次のような場合に使用:** - 既存の OpenAI Apps SDK で作られたアプリを新しい MCP Apps SDK に移行したい - OpenAI アプリの書き直し方や変換手順を知りたい - API 仕様の対応関係を確認したい
This skill should be used when the user asks to "migrate from OpenAI Apps SDK", "convert OpenAI App to MCP", "port from window.openai", "migrate from skybridge", "convert openai/outputTemplate", or needs guidance on converting OpenAI Apps SDK applications to MCP Apps SDK. Provides step-by-step migration guidance with API mapping tables.
既存のOpenAI Apps SDKアプリケーションをMCP Apps SDK(@modelcontextprotocol/ext-apps)へ移行します。
MCP Apps SDKは、会話型クライアントにおけるインタラクティブUIのための、標準化されたオープンプロトコルを提供します。
npm install、pnpm add、yarn add など)を使って依存関係を追加してください。
これにより、パッケージマネージャーが最新の互換バージョンを自動解決します。バージョン番号を記憶で指定しないでください。完全な移行ドキュメントと動作例を確認するため、SDKリポジトリをクローンしてください:
git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-apps
「変更前/変更後」のマッピングテーブルを含む移行リファレンスガイドを参照してください:
/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md
/tmp/mcp-ext-apps/src/* のソースファイルからJSDocドキュメントを直接参照してください:
| ファイル | 内容 |
|---|---|
src/app.ts |
Appクラス、ハンドラー、ライフサイクル |
src/server/index.ts |
registerAppTool、registerAppResource |
src/spec.types.ts |
型定義 |
src/react/useApp.tsx |
Reactアプリ用useAppフック |
src/react/use*.ts* |
Reactアプリ用その他のuse*フック |
フロントエンドフレームワーク別に整理された基本的なSDK使用例は
/tmp/mcp-ext-apps/examples/basic-server-{framework}/ を参照してください:
| テンプレート | 主要ファイル |
|---|---|
basic-server-vanillajs/ |
server.ts、src/mcp-app.ts、mcp-app.html |
basic-server-react/ |
server.ts、src/mcp-app.tsx(useAppフックを使用) |
basic-server-vue/ |
server.ts、src/App.vue |
basic-server-svelte/ |
server.ts、src/App.svelte |
basic-server-preact/ |
server.ts、src/mcp-app.tsx |
basic-server-solid/ |
server.ts、src/mcp-app.tsx |
MCP AppsのHTMLはWebページとしてではなくMCPリソースとして配信され、同一オリジンのサーバーを持たないサンドボックス化されたiframe内で動作します。
JS/CSSバンドルを配信するオリジン(開発時はlocalhost、本番環境ではCDN)を含め、すべてのオリジンをCSPに宣言する必要があります。
宣言が漏れたオリジンはサイレントに失敗します。
移行コードを書き始める前に、アプリをビルドして参照しているすべてのオリジンを調査してください:
調査結果を以下の3つのリストとしてまとめ、各オリジンが「環境共通」「開発のみ」「本番のみ」のいずれかを記録してください:
オリジンが見つからない場合は、カスタムCSPドメインが不要な可能性があります。
MCPクライアントはクロスオリジンリクエストを行います。
Expressを使用している場合は app.use(cors()) で対応できます。
生のHTTPサーバーを使用している場合は、標準的なCORSの設定に加えて以下を行ってください:
mcp-session-id、mcp-protocol-version、last-event-idmcp-session-idserver.registerTool() / server.registerResource() を直接使うのではなく、
registerAppTool() および registerAppResource() ヘルパーを使用してください。
これらのヘルパーはMCP Appsのメタデータ形式を自動的に処理します。
サーバーサイドのマッピングテーブルは /tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md を参照してください。
根本的なパラダイムシフトがあります:
OpenAIはコードが実行される前に値が格納された同期的なグローバルオブジェクト
(window.openai.toolInput、window.openai.theme)を使用します。
MCP Appsは非同期イベントハンドラーを持つAppインスタンスを使用します。
主な違い:
connect() を呼び出す前に、Appインスタンスを作成してハンドラー(ontoolinput、ontoolresult、onhostcontextchanged)を登録してください。
(接続直後にイベントが発火する場合があるため、ハンドラーを先に登録する必要があります)window.openai.toolInput の代わりに app.ontoolinput を、
window.openai.toolOutput の代わりに app.ontoolresult を使用します。app.getHostContext() を使用します。Reactアプリの場合、useAppフックがこのライフサイクルを自動的に管理します。
パターンの詳細は basic-server-react/ を参照してください。
クライアントサイドのマッピングテーブルは /tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md を参照してください。
以下のOpenAI機能は、MCP上でまだ対応するものがありません:
サーバーサイド:
| OpenAI機能 | ステータス/回避策 |
|---|---|
_meta["openai/toolInvocation/invoking"] / _meta["openai/toolInvocation/invoked"] |
進捗インジケーターはまだ未対応 |
_meta["openai/widgetDescription"] |
動的なコンテキストには app.updateModelContext() を使用 |
クライアントサイド:
| OpenAI機能 | ステータス/回避策 |
|---|---|
window.openai.widgetState / setWidgetState() |
localStorage またはサーバーサイドの状態管理を使用 |
window.openai.uploadFile() / getFileDownloadUrl() |
ファイル操作はまだ未対応 |
window.openai.requestModal() / requestClose() |
モーダル管理はまだ未対応 |
window.openai.view |
まだ未対応 |
以下のチェックリストの各項目を落ち着いて丁寧に確認してください:
[ ] 残存するサーバーサイドのOpenAIパターンを検索して移行する:
| パターン | 内容 |
|---|---|
"openai/ |
古いメタデータキー → _meta.ui.* |
text/html+skybridge |
古いMIMEタイプ → RESOURCE_MIME_TYPE定数 |
text/html;profile=mcp-app |
新しいMIMEタイプだが、RESOURCE_MIME_TYPE定数を優先 |
_domains" または _domains: |
snake_case形式のCSP → camelCase形式へ(connect_domains → connectDomains) |
[ ] 残存するクライアントサイドのOpenAIパターンを検索して移行する:
| パターン | 内容 |
|---|---|
window.openai.toolInput |
古いグローバル変数 → ontoolinputハンドラー内のparams.arguments |
window.openai.toolOutput |
古いグローバル変数 → ontoolresult内のparams.structuredContent |
window.openai |
古いグローバルAPI → Appインスタンスのメソッド |
[ ] CSP調査で見つかった各オリジンについて、registerAppResource()のCSP設定のどこに記載されているかを示す。
CSP調査で判明したすべてのオリジン(環境共通・開発のみ・本番のみを問わず)をCSP設定に含める必要があります。
MCP AppsのHTMLは同一オリジンのサーバーを持たないサンドボックスiframe内で動作するためです。
CSP設定に含まれていないオリジンがあれば、今すぐ追加してください。
[ ] CSP調査で見つかった条件付きオリジン(開発のみ・本番のみ)それぞれについて、 実行時URLとCSPエントリの両方を同じ設定(環境変数、設定ファイルなど)で制御しているコード箇所を示す。 条件付きにすべきオリジンがCSPにハードコードされている場合は今すぐ修正してください。 アプリは本番環境対応の状態でなければなりません。
移行済みアプリをbasic-hostサンプルでテストしてください:
# ターミナル1:アプリをビルドして起動
npm run build && npm run serve
# ターミナル2:basic-hostを起動(クローンしたリポジトリから)
cd /tmp/mcp-ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
# http://localhost:8080 を開く
basic-hostでアプリが読み込まれたら、以下を確認してください:
ontoolinputハンドラーがツールの引数とともに発火するontoolresultハンドラーがツールの結果とともに発火するMigrate existing OpenAI Apps SDK applications to the MCP Apps SDK (@modelcontextprotocol/ext-apps). The MCP Apps SDK provides a standardized, open protocol for interactive UIs in conversational clients.
npm install, pnpm add, yarn add) instead of manually writing version numbers. This lets the package manager resolve the latest compatible versions. Never specify version numbers from memory.Clone the SDK repository for complete migration documentation and working examples:
git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-apps
Read the migration reference guide with "before/after" mapping tables: /tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md
Read JSDoc documentation directly from /tmp/mcp-ext-apps/src/*:
| File | Contents |
|---|---|
src/app.ts |
App class, handlers, lifecycle |
src/server/index.ts |
registerAppTool, registerAppResource |
src/spec.types.ts |
Type definitions |
src/react/useApp.tsx |
useApp hook for React apps |
src/react/use*.ts* |
Other use* hooks for React apps |
See /tmp/mcp-ext-apps/examples/basic-server-{framework}/ for basic SDK usage examples organized by front-end framework:
| Template | Key Files |
|---|---|
basic-server-vanillajs/ |
server.ts, src/mcp-app.ts, mcp-app.html |
basic-server-react/ |
server.ts, src/mcp-app.tsx (uses useApp hook) |
basic-server-vue/ |
server.ts, src/App.vue |
basic-server-svelte/ |
server.ts, src/App.svelte |
basic-server-preact/ |
server.ts, src/mcp-app.tsx |
basic-server-solid/ |
server.ts, src/mcp-app.tsx |
MCP Apps HTML is served as an MCP resource, not as a web page, and runs in a sandboxed iframe with no same-origin server. Every origin must be declared in CSP—including the origin serving your JS/CSS bundles (localhost in dev, your CDN in production). Missing origins fail silently.
Before writing any migration code, build the app and investigate all origins it references:
Document your findings as three lists, and note for each origin whether it's universal, dev-only, or prod-only:
If no origins are found, the app may not need custom CSP domains.
MCP clients make cross-origin requests. If using Express, app.use(cors()) handles this.
For raw HTTP servers, configure standard CORS and additionally:
mcp-session-id, mcp-protocol-version, last-event-idmcp-session-idUse registerAppTool() and registerAppResource() helpers instead of raw server.registerTool() / server.registerResource(). These helpers handle the MCP Apps metadata format automatically.
See /tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md for server-side mapping tables.
The fundamental paradigm shift: OpenAI uses a synchronous global object (window.openai.toolInput, window.openai.theme) that's pre-populated before your code runs. MCP Apps uses an App instance with async event handlers.
Key differences:
App instance and register handlers (ontoolinput, ontoolresult, onhostcontextchanged) before calling connect(). (Events may fire immediately after connection, so handlers must be registered first.)app.ontoolinput for window.openai.toolInput, app.ontoolresult for window.openai.toolOutput.app.getHostContext().For React apps, the useApp hook manages this lifecycle automatically—see basic-server-react/ for the pattern.
See /tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md for client-side mapping tables.
These OpenAI features don't have MCP equivalents yet:
Server-side:
| OpenAI Feature | Status/Workaround |
|---|---|
_meta["openai/toolInvocation/invoking"] / _meta["openai/toolInvocation/invoked"] |
Progress indicators not yet available |
_meta["openai/widgetDescription"] |
Use app.updateModelContext() for dynamic context |
Client-side:
| OpenAI Feature | Status/Workaround |
|---|---|
window.openai.widgetState / setWidgetState() |
Use localStorage or server-side state |
window.openai.uploadFile() / getFileDownloadUrl() |
File operations not yet available |
window.openai.requestModal() / requestClose() |
Modal management not yet available |
window.openai.view |
Not yet available |
Slow down and carefully follow each item in this checklist:
[ ] Search for and migrate any remaining server-side OpenAI patterns:
| Pattern | Indicates |
|---|---|
"openai/ |
Old metadata keys → _meta.ui.* |
text/html+skybridge |
Old MIME type → RESOURCE_MIME_TYPE constant |
text/html;profile=mcp-app |
New MIME type, but prefer RESOURCE_MIME_TYPE constant |
_domains" or _domains: |
snake_case CSP → camelCase (connect_domains → connectDomains) |
[ ] Search for and migrate any remaining client-side OpenAI patterns:
| Pattern | Indicates |
|---|---|
window.openai.toolInput |
Old global → params.arguments in ontoolinput handler |
window.openai.toolOutput |
Old global → params.structuredContent in ontoolresult |
window.openai |
Old global API → App instance methods |
[ ] For each origin from your CSP investigation, show where it appears in the registerAppResource() CSP config. Every origin from the CSP investigation (universal, dev-only, prod-only) must be included in the CSP config—MCP Apps HTML runs in a sandboxed iframe with no same-origin server. If an origin was not included in the CSP config, add it now.
[ ] For each conditional (dev-only, prod-only) origin from your CSP investigation, show the code where the same configuration setting (env var, config file, etc.) controls both the runtime URL and the CSP entry. If the CSP has a hardcoded origin that should be conditional, fix it now—the app must be production-ready.
Test the migrated app with the basic-host example:
# Terminal 1: Build and run your server
npm run build && npm run serve
# Terminal 2: Run basic-host (from cloned repo)
cd /tmp/mcp-ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
# Open http://localhost:8080
Once the app loads in basic-host, confirm:
ontoolinput handler fires with tool argumentsontoolresult handler fires with tool result原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。