chatgpt-app-builder について
mcp-use と OpenAI Apps SDK を使い、インタラクティブな React ウィジェットを備えた ChatGPT アプリを開発するスキルです。ウィジェットを自動登録し、MCP Apps と ChatGPT の両プロトコルに対応します。
主な機能
- 01テンプレートからアプリを作成
- 02React ウィジェットの自動登録
- 03useWidget による状態管理とツール呼び出し
- 04自動バンドルとホットリロード
- 05CSP 設定と Inspector によるテスト
- 06MCP Apps と ChatGPT に対応
活用シーン
- 01インタラクティブな ChatGPT アプリの作成
- 02MCP ツールを呼び出すウィジェットの構築
- 03Inspector でのウィジェットテスト
- 04MCP Apps クライアントへの対応
MCP 対応
mcp-use を使った MCP サーバーの構築方法を案内し、ウィジェットを MCP ツールとリソースとして登録して MCP Apps クライアントに公開します。ChatGPT Apps SDK プロトコルにも対応します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mcp-use/ skills --skill chatgpt-app-builderインストール後、Claude Code で/chatgpt-app-builderを入力して読み込まれたか確認します。
同梱ファイルLICENSE.txt
詳細
ChatGPT App Builder
mcp-use フレームワークと OpenAI Apps SDK を使用して、インタラクティブウィジェットを備えた本番環境向けの ChatGPT アプリを構築できます。このスキルでは、自動登録と React フックを標準で備えた、設定不要のウィジェット開発を実現します。
クイックスタート
必ず MCP Apps テンプレートでブートストラップしてください:
npx create-mcp-use-app my-chatgpt-app --template mcp-apps
cd my-chatgpt-app
yarn install
yarn dev
これにより、次のプロジェクト構成が作成されます:
my-chatgpt-app/
├── resources/ # React widgets (auto-registered!)
│ ├── display-weather.tsx # Example widget
│ └── product-card.tsx # Another widget
├── public/ # Static assets
│ └── images/
├── index.ts # MCP server entry
├── package.json
├── tsconfig.json
└── README.md
ChatGPT Apps に mcp-use を使う理由
従来の OpenAI Apps SDK では、かなりの手動設定が必要です:
- プロジェクト構成の分離(
server/とweb/フォルダー) - esbuild/webpack の手動設定
- カスタムの useWidgetState フックの実装
- React のマウントコードの手動作成
- CSP の手動設定
- ウィジェットの手動登録
mcp-use なら、すべてを簡素化できます:
- ✅ コマンド 1 つでセットアップ
- ✅
resources/フォルダーにウィジェットを配置するだけで自動登録 - ✅ state、props、ツール呼び出しに対応した
useWidget()フックを標準搭載 - ✅ ホットリロード対応の自動バンドル
- ✅ CSP の自動設定
- ✅ テスト用の Inspector を標準搭載
- ✅ 2 つのプロトコルに対応(ChatGPT と MCP Apps クライアントの両方で動作)
MCP Apps と ChatGPT Apps SDK の比較
mcp-use は複数のウィジェットプロトコルに対応しており、最大限の互換性を実現します:
| プロトコル | 用途 | 互換性 | ステータス |
|---|---|---|---|
MCP Apps(type: "mcpApps") | 最大限の互換性 | ✅ ChatGPT + MCP Apps クライアント | 推奨 |
ChatGPT Apps SDK(type: "appsSdk") | ChatGPT 専用機能 | ✅ ChatGPT のみ | サポート対象 |
| MCP-UI | シンプルな静的コンテンツ | ✅ MCP クライアントのみ | 特定用途向け |
MCP Apps が選ばれる理由
MCP Apps は、Model Context Protocol におけるインタラクティブウィジェットの公式標準(SEP-1865)です:
- 汎用性:ChatGPT、Claude Desktop、Goose、およびすべての MCP Apps クライアントで動作します
- 将来性:オープンな仕様に基づいており、長期的な互換性を確保します
- 安全性:きめ細かな CSP 制御を備えた二重 iframe サンドボックスを採用しています
- 設定不要:
type: "mcpApps"を指定すると、mcp-use が両方のプロトコル向けのメタデータを自動生成します
重要なポイント:サーバー設定で type: "mcpApps" を使用すると、ウィジェットは ChatGPT(Apps SDK プロトコル)と MCP Apps クライアントの両方で自動的に動作します。ウィジェットを一度作成すれば、プロトコルの変換は mcp-use が処理します。
ウィジェットの作成
シンプルなウィジェット(単一ファイル)
resources/weather-display.tsx を作成します:
import { McpUseProvider, useWidget, type WidgetMetadata } from "mcp-use/react";
import { z } from "zod";
// Define widget metadata
export const widgetMetadata: WidgetMetadata = {
description: "Display current weather for a city",
props: z.object({
city: z.string().describe("City name"),
temperature: z.number().describe("Temperature in Celsius"),
conditions: z.string().describe("Weather conditions"),
humidity: z.number().describe("Humidity percentage"),
}),
};
const WeatherDisplay: React.FC = () => {
const { props, isPending } = useWidget();
// Always handle loading state first
if (isPending) {
return (
<McpUseProvider autoSize>
<div className="animate-pulse p-4">Loading weather...</div>
</McpUseProvider>
);
}
return (
<McpUseProvider autoSize>
<div className="weather-card p-4 rounded-lg shadow">
<h2 className="text-2xl font-bold">{props.city}</h2>
<div className="temp text-4xl">{props.temperature}°C</div>
<p className="conditions">{props.conditions}</p>
<p className="humidity">Humidity: {props.humidity}%</p>
</div>
</McpUseProvider>
);
};
export default WeatherDisplay;
これで完了です!ウィジェットは自動的に次のように処理されます:
- MCP ツール
weather-displayとして登録 - MCP リソース
ui://widget/weather-display.htmlとして登録 - Apps SDK との互換性を考慮してバンドル
- ChatGPT ですぐに使用可能
複雑なウィジェット(フォルダー構成)
複数のコンポーネントを含むウィジェットの場合:
resources/
└── product-search/
├── widget.tsx # Entry point (required name)
├── components/
│ ├── ProductCard.tsx
│ └── FilterBar.tsx
├── hooks/
│ └── useFilter.ts
├── types.ts
└── constants.ts
エントリーポイント(widget.tsx):
import { McpUseProvider, useWidget, type WidgetMetadata } from "mcp-use/react";
import { z } from "zod";
import { ProductCard } from "./components/ProductCard";
import { FilterBar } from "./components/FilterBar";
export const widgetMetadata: WidgetMetadata = {
description: "Display product search results with filtering",
props: z.object({
products: z.array(
z.object({
id: z.string(),
name: z.string(),
price: z.number(),
image: z.string(),
})
),
query: z.string(),
}),
};
const ProductSearch: React.FC = () => {
const { props, isPending, state, setState } = useWidget();
if (isPending) {
return (
<McpUseProvider autoSize>
<div>Loading...</div>
</McpUseProvider>
);
}
return (
<McpUseProvider autoSize>
<div>
<h1>Search: {props.query}</h1>
<FilterBar onFilter={(filters) => setState({ filters })} />
<div className="grid grid-cols-3 gap-4">
{props.products.map((p) => (
<ProductCard key={p.id} product={p} />
))}
</div>
</div>
</McpUseProvider>
);
};
export default ProductSearch;
ウィジェットのメタデータ
自動登録に必要なメタデータ:
export const widgetMetadata: WidgetMetadata = {
// Required: Human-readable description
description: "Display weather information",
// Required: Zod schema for widget props
props: z.object({
city: z.string().describe("City name"),
temperature: z.number(),
}),
// Optional: Disable automatic tool registration
exposeAsTool: true, // default
// Optional: Unified metadata (works for BOTH ChatGPT and MCP Apps)
metadata: {
csp: {
connectDomains: ["https://api.weather.com"],
resourceDomains: ["https://cdn.weather.com"],
},
prefersBorder: true,
autoResize: true,
widgetDescription: "Interactive weather display",
},
};
重要:
description:ツールとリソースの説明に使用されますprops:Zod スキーマでウィジェットの入力パラメーターを定義しますexposeAsTool:カスタムツール経由でのみウィジェットを使用する場合は、falseに設定しますmetadata:両方のプロトコルで機能する統一設定です(推奨)
コンテンツセキュリティポリシー(CSP)
CSP 設定を使用して、ウィジェットがアクセスできる外部リソースを制御します:
export const widgetMetadata: WidgetMetadata = {
description: "Weather widget",
props: z.object({ city: z.string() }),
metadata: {
csp: {
// APIs your widget needs to call
connectDomains: ["https://api.weather.com", "https://weather-backup.com"],
// Static assets (images, fonts, stylesheets)
resourceDomains: ["https://cdn.weather.com"],
// External content to embed in iframes
frameDomains: ["https://embed.weather.com"],
// Script CSP directives (use carefully!)
scriptDirectives: ["'unsafe-inline'"],
},
},
};
CSP フィールドのリファレンス:
connectDomains:fetch、WebSocket、XMLHttpRequest 経由で呼び出す APIresourceDomains:読み込む画像、フォント、スタイルシート、動画frameDomains:iframe に埋め込む外部コンテンツscriptDirectives:script-src CSP ディレクティブ(本番環境では'unsafe-eval'を避けてください)
セキュリティのベストプラクティス:
- ✅ 正確なドメインを指定します:
https://api.weather.com - ❌ ワイルドカードは避けます:
https://*.weather.com(安全性が低くなります) - ❌ 絶対に必要な場合を除き、
'unsafe-eval'は使用しないでください - ✅ デプロイ前に開発環境で CSP をテストしてください
メタデータ設定オプション
モダンな統合アプローチ(推奨)
metadata フィールドを使用して、2 つのプロトコルをサポートします。
export const widgetMetadata: WidgetMetadata = {
description: "Weather widget",
props: propSchema,
metadata: {
// Works for BOTH MCP Apps AND ChatGPT
csp: {
connectDomains: ["https://api.weather.com"],
resourceDomains: ["https://cdn.weather.com"],
},
prefersBorder: true,
autoResize: true,
widgetDescription: "Displays current weather",
},
};
レガシー Apps SDK アプローチ(非推奨)
古い ChatGPT 専用フォーマットです(引き続きサポートされていますが、推奨されません)。
export const widgetMetadata: WidgetMetadata = {
description: "Weather widget",
props: propSchema,
appsSdkMetadata: {
// ChatGPT only - snake_case with openai/ prefix
"openai/widgetCSP": {
connect_domains: ["https://api.weather.com"],
resource_domains: ["https://cdn.weather.com"],
},
"openai/widgetPrefersBorder": true,
"openai/toolInvocation/invoking": "Loading...",
"openai/toolInvocation/invoked": "Loaded",
},
};
移行に関する注意:古いフォーマットでは、openai/ プレフィックスとスネークケース(例:connect_domains)を使用する appsSdkMetadata を使います。新しいフォーマットでは、キャメルケース(例:connectDomains)を使用する metadata を使い、どちらのプロトコルにも対応します。
カスタム ChatGPT 機能で両方を使用する
両方のフィールドを組み合わせて、標準のメタデータと ChatGPT 固有のオーバーライドを使用できます。
export const widgetMetadata: WidgetMetadata = {
description: "Weather widget",
props: propSchema,
// Unified metadata (dual-protocol)
metadata: {
csp: { connectDomains: ["https://api.weather.com"] },
prefersBorder: true,
},
// ChatGPT-specific overrides/additions
appsSdkMetadata: {
"openai/widgetDescription": "ChatGPT-specific description",
"openai/customFeature": "some-value", // Any custom OpenAI metadata
"openai/locale": "en-US",
},
};
ユースケース:統合フォーマットに存在しないカスタムの OpenAI 固有メタデータを渡す必要がある場合は、appsSdkMetadata に追加します。フィールドは openai/ プレフィックス付きで ChatGPT に直接渡されます。
useWidget フック
useWidget フックでは、必要な機能をすべて利用できます。
const {
// Widget props from tool input
props,
// Loading state (true = tool still executing)
isPending,
// Persistent widget state
state,
setState,
// Theme from host (light/dark)
theme,
// Call other MCP tools
callTool,
// Display mode control
displayMode,
requestDisplayMode,
// Additional tool output
output,
} = useWidget<MyPropsType, MyOutputType>();
Props と読み込み状態
重要: ツールの実行が完了する前にウィジェットがレンダリングされます。必ず isPending を処理してください。
const { props, isPending } = useWidget<WeatherProps>();
// Pattern 1: Early return
if (isPending) {
return <div>Loading...</div>;
}
// Now props are safe to use
// Pattern 2: Conditional rendering
return <div>{isPending ? <LoadingSpinner /> : <div>{props.city}</div>}</div>;
// Pattern 3: Optional chaining (partial UI)
return (
<div>
<h1>{props.city ?? "Loading..."}</h1>
</div>
);
ウィジェットの状態
ウィジェットの操作間でデータを保持します。
const { state, setState } = useWidget();
// Save state (persists in ChatGPT localStorage)
const addFavorite = async (city: string) => {
await setState({
favorites: [...(state?.favorites || []), city],
});
};
// Update with function
await setState((prev) => ({
...prev,
count: (prev?.count || 0) + 1,
}));
MCP ツールの呼び出し
ウィジェットからほかのツールを呼び出せます。
const { callTool } = useWidget();
const refreshData = async () => {
try {
const result = await callTool("get-weather", {
city: "Tokyo",
});
console.log("Result:", result.content);
} catch (error) {
console.error("Tool call failed:", error);
}
};
表示モードの制御
異なる表示モードをリクエストします。
const { displayMode, requestDisplayMode } = useWidget();
const goFullscreen = async () => {
await requestDisplayMode("fullscreen");
};
// Current mode: 'inline' | 'pip' | 'fullscreen'
console.log(displayMode);
ウィジェット付きカスタムツール
2 つのプロトコルをサポートする、ウィジェットを返すツールを作成します。
import { MCPServer, widget, text } from "mcp-use/server";
import { z } from "zod";
const server = new MCPServer({
name: "weather-app",
version: "1.0.0",
});
server.tool(
{
name: "get-weather",
description: "Get current weather for a city",
schema: z.object({
city: z.string().describe("City name"),
}),
// Widget config (registration-time metadata)
widget: {
name: "weather-display", // Must match widget in resources/
invoking: "Fetching weather...",
invoked: "Weather data loaded",
},
},
async ({ city }) => {
// Fetch data from API
const data = await fetchWeatherAPI(city);
// Return widget with runtime data
return widget({
props: {
city,
temperature: data.temp,
conditions: data.conditions,
humidity: data.humidity,
},
output: text(`Weather in ${city}: ${data.temp}°C`),
message: `Current weather for ${city}`,
});
}
);
server.listen();
ポイント:
- サーバー設定の
baseUrlにより、アセットを適切に読み込めます - ウィジェットは ChatGPT と MCP Apps クライアントの両方で自動的に動作します
- ツール定義に
widget: { name, invoking, invoked }を指定します widget({ props, output })ヘルパーは実行時データを返しますpropsはウィジェットに渡され、outputはモデルに表示されます- ウィジェットは
resources/フォルダー内に配置する必要があります
静的アセット
画像やフォントなどには public/ フォルダーを使用します。
my-app/
├── resources/
├── public/ # Static assets
│ ├── images/
│ │ ├── logo.svg
│ │ └── banner.png
│ └── fonts/
└── index.ts
ウィジェットでのアセットの使用:
import { Image } from "mcp-use/react";
function MyWidget() {
return (
<div>
{/* Paths relative to public/ folder */}
<Image src="/images/logo.svg" alt="Logo" />
<img src={window.__getFile?.("images/banner.png")} alt="Banner" />
</div>
);
}
コンポーネント
McpUseProvider
一般的なセットアップを統合したプロバイダーです。
import { McpUseProvider } from "mcp-use/react";
function MyWidget() {
return (
<McpUseProvider
autoSize // Auto-resize widget
viewControls // Add debug/fullscreen buttons
debug // Show debug info
>
<div>Widget content</div>
</McpUseProvider>
);
}
Image コンポーネント
データ URL と公開パスの両方を処理します。
import { Image } from "mcp-use/react";
function MyWidget() {
return (
<div>
<Image src="/images/photo.jpg" alt="Photo" />
<Image src="data:image/png;base64,..." alt="Data URL" />
</div>
);
}
ErrorBoundary
エラーを適切に処理します。
import { ErrorBoundary } from "mcp-use/react";
function MyWidget() {
return (
<ErrorBoundary
fallback={<div>Something went wrong</div>}
onError={(error) => console.error(error)}
>
<MyComponent />
</ErrorBoundary>
);
}
テスト
Inspector の使用
-
開発サーバーを起動します。
yarn dev -
Inspector を開きます。
http://localhost:3000/inspectorに移動します
-
ウィジェットをテストします。
- Tools タブをクリックします
- ウィジェット用のツールを探します
- テスト用パラメーターを入力します
- 実行してウィジェットのレンダリングを確認します
-
インタラクションをデバッグします。
- ブラウザーのコンソールを使用します
- RPC ログを確認します
- 状態の保持をテストします
- ツール呼び出しを確認します
ChatGPT でのテスト
-
開発者モードを有効にします。
- Settings → Connectors → Advanced → Developer mode
-
サーバーを追加します。
- Connectors タブに移動します
- リモート MCP サーバーの URL を追加します
-
会話でテストします。
- Plus メニューから Developer Mode を選択します
- コネクターを選択します
- ChatGPT にツールを使うよう依頼します
プロンプトのヒント:
- 明確に指定します:「weather-app コネクターの get-weather ツールを使用してください……」
- 別の手段を使わないよう指定します:「組み込みツールは使用せず、自分のコネクターだけを使用してください」
- 入力を指定します:「{ city: 'Tokyo' } を指定して get-weather を呼び出してください」
2 つのプロトコルに関する注意:サーバー設定で type: "mcpApps" を使用すると、ウィジェットは ChatGPT(Apps SDK 経由)と MCP Apps クライアント(Claude Desktop、Goose など)の両方で自動的に動作します。コードを変更せずに、同じウィジェットを複数のクライアントでテストできます。
ベストプラクティス
スキーマ設計
分かりやすいスキーマを使用します。
// ✅ Good
const schema = z.object({
city: z.string().describe("City name (e.g., Tokyo, Paris)"),
temperature: z.number().min(-50).max(60).describe("Temp in Celsius"),
});
// ❌ Bad
const schema = z.object({
city: z.string(),
temp: z.number(),
});
テーマのサポート
常に両方のテーマをサポートします。
const { theme } = useWidget();
const bgColor = theme === "dark" ? "bg-gray-900" : "bg-white";
const textColor = theme === "dark" ? "text-white" : "text-gray-900";
読み込み状態
最初に必ず isPending を確認します。
const { props, isPending } = useWidget<MyProps>();
if (isPending) {
return <LoadingSpinner />;
}
// Now safe to access props.field
return <div>{props.field}</div>;
ウィジェットの焦点
ウィジェットの焦点を保ちます。
// ✅ Good: Single purpose
export const widgetMetadata: WidgetMetadata = {
description: "Display weather for a city",
props: z.object({ city: z.string() }),
};
// ❌ Bad: Too many responsibilities
export const widgetMetadata: WidgetMetadata = {
description: "Weather, forecast, map, news, and more",
props: z.object({
/* many fields */
}),
};
エラー処理
エラーを適切に処理します。
const { callTool } = useWidget();
const fetchData = async () => {
try {
const result = await callTool("fetch-data", { id: "123" });
if (result.isError) {
console.error("Tool returned error");
}
} catch (error) {
console.error("Tool call failed:", error);
}
};
設定
本番環境のセットアップ
本番環境用のベース URL を設定します。
const server = new MCPServer({
name: "my-app",
version: "1.0.0",
baseUrl: process.env.MCP_URL || "https://myserver.com",
});
環境変数
# Server URL
MCP_URL=https://myserver.com
# For static deployments
MCP_SERVER_URL=https://myserver.com/api
CSP_URLS=https://cdn.example.com,https://api.example.com
変数の用途:
MCP_URL:ウィジェットのアセットと CSP のベース URLMCP_SERVER_URL:ツール呼び出しに使用する MCP サーバーの URL(静的デプロイの場合)CSP_URLS:コンテンツセキュリティポリシーに追加するドメイン
デプロイ
mcp-use Cloud へのデプロイ
# Login
npx mcp-use login
# Deploy
yarn deploy
本番環境向けビルド
# Build
yarn build
# Start
yarn start
ビルドプロセス:
- TypeScript をコンパイルします
- React ウィジェットをバンドルします
- アセットを最適化します
- 本番環境用の HTML を生成します
よく使われるパターン
データ取得ウィジェット
const DataWidget: React.FC = () => {
const { props, isPending, callTool } = useWidget();
if (isPending) {
return <div>Loading...</div>;
}
const refresh = async () => {
await callTool("fetch-data", { id: props.id });
};
return (
<div>
<h1>{props.title}</h1>
<button onClick={refresh}>Refresh</button>
</div>
);
};
状態を持つウィジェット
const CounterWidget: React.FC = () => {
const { state, setState } = useWidget();
const increment = async () => {
await setState({
count: (state?.count || 0) + 1,
});
};
return (
<div>
<p>Count: {state?.count || 0}</p>
<button onClick={increment}>+1</button>
</div>
);
};
テーマ対応ウィジェット
const ThemedWidget: React.FC = () => {
const { theme } = useWidget();
return (
<div className={theme === "dark" ? "dark-theme" : "light-theme"}>
Content
</div>
);
};
トラブルシューティング
ウィジェットが表示されない
問題: ウィジェットファイルは存在するのに、ツールが表示されません
解決策:
.tsx拡張子であることを確認しますwidgetMetadataオブジェクトをエクスポートします- React コンポーネントをデフォルトエクスポートします
- サーバーログでエラーを確認します
- ウィジェット名がファイル名/フォルダー名と一致していることを確認します
Props が受け取れない
問題: コンポーネントが空の props を受け取ります
解決策:
- まず
isPendingを確認します(保留中は props が空です) useWidget()フックを使用します(React props ではありません)widgetMetadata.propsが有効な Zod スキーマであることを確認します- ツールのパラメーターがスキーマと一致していることを確認します
CSP エラー
問題: ウィジェットは読み込まれるものの、アセットの読み込みに失敗します
解決策:
- サーバー設定で
baseUrlを設定します metadata.csp(新方式)またはappsSdkMetadata['openai/widgetCSP'](旧方式)を使って、ドメインを CSP に追加します- すべてのリソースで HTTPS を使用します
- ブラウザーのコンソールで CSP 違反を確認します
本番環境での CSP エラー
問題: 本番環境でコンテンツセキュリティポリシーによってリソースがブロックされます
解決策:
- CSP 違反メッセージがないか、ブラウザーのコンソールを確認します
- CSP 設定に不足しているドメインを追加します:
metadata: { csp: { connectDomains: ['https://api.example.com'], // Add missing API domain resourceDomains: ['https://cdn.example.com'], // Add missing CDN domain } } - 正確なドメインを使用します。本番環境ではワイルドカードを避けてください
- デプロイ前にInspector でテストして、CSP の問題を早期に検出します
- 環境変数を使う方法:カンマ区切りのドメインを指定して、環境変数
CSP_URLSを設定します
プロトコルの互換性に関する問題
問題: ウィジェットが ChatGPT では動作するものの MCP Apps クライアントでは動作しません(またはその逆)
解決策:
- デュアルプロトコルに対応するには
type: "mcpApps"を使用します(推奨) - サーバー設定で
baseUrlが正しく設定されていることを確認します - メタデータの形式を確認します。デュアルプロトコルでは
appsSdkMetadata(snake_case)ではなくmetadata(camelCase)を使用します - 両方のプロトコルに対応する Inspector でテストします
各タイプを使う場面:
type: "mcpApps"- 最大限の互換性(推奨)type: "appsSdk"- ChatGPT のみ(仕様にない ChatGPT 固有の機能が必要な場合に使用)
詳細情報
- ドキュメント:https://docs.mcp-use.com
- MCP Apps 標準:https://docs.mcp-use.com/typescript/server/mcp-apps (デュアルプロトコルガイド)
- ウィジェットガイド:https://docs.mcp-use.com/typescript/server/ui-widgets
- Apps SDK チュートリアル:https://docs.mcp-use.com/typescript/server/creating-apps-sdk-server
- テンプレート:https://docs.mcp-use.com/typescript/server/templates
- ChatGPT Apps のフロー:https://docs.mcp-use.com/guides/chatgpt-apps-flow
- Inspector でのデバッグ:https://docs.mcp-use.com/inspector/debugging-chatgpt-apps
- GitHub:https://github.com/mcp-use/mcp-use
クイックリファレンス
コマンド:
npx create-mcp-use-app my-app --template mcp-apps- プロジェクトを作成yarn dev- ホットリロードを有効にして開発yarn build- 本番環境向けにビルドyarn start- 本番サーバーを起動yarn deploy- mcp-use Cloud にデプロイ
ウィジェットの構成:
resources/widget-name.tsx- 単一ファイルのウィジェットresources/widget-name/widget.tsx- フォルダー形式のウィジェットエントリーポイントpublic/- 静的アセット
ウィジェットのメタデータ:
description- ウィジェットの説明props- 入力用の Zod スキーマexposeAsTool- ツールとして自動登録(デフォルト:true)metadata- 統合設定(デュアルプロトコル、推奨)metadata.csp- コンテンツセキュリティポリシーの設定appsSdkMetadata- ChatGPT 固有のオーバーライド(任意)
CSP フィールド:
connectDomains- 呼び出す APIresourceDomains- 読み込む静的アセットframeDomains- 埋め込む iframescriptDirectives- スクリプトポリシー
useWidget フック:
props- ウィジェットの入力パラメーターisPending- 読み込み状態フラグstate, setState- 永続状態callTool- 他のツールを呼び出すtheme- 現在のテーマ(ライト/ダーク)displayMode, requestDisplayMode- 表示を制御する