OpenAI Apps SDKは、ChatGPTの会話内に「ツール実行」と「埋め込みUI」を同居させるための開発キットです。2026年5月19日時点の公式ドキュメントでは、Apps SDKはMCP(Model Context Protocol)サーバーを土台にし、ChatGPTが呼び出すツール、iframeで表示するウィジェット、OAuthやCSPなどの安全設定をまとめて扱う設計になっています。
この記事では、公式のApps SDK概要、Quickstart、MCP server構築ガイド、Referenceを確認したうえで、AIエージェント開発チームが最初に作るべき最小構成を整理します。MCPそのものの背景は、公式のModel Context Protocol入門も併読してください。
OpenAI Apps SDKとは何か
一言で言うと、OpenAI Apps SDKは「ChatGPTから呼べるMCPアプリ」を作るための実装レイヤーです。従来の外部ツール連携は、モデルが関数を呼び出し、その結果をテキストで返すだけになりがちでした。Apps SDKでは、ツール結果のstructuredContentをモデルに渡しつつ、より詳細なデータや状態を_metaとしてウィジェット側へ渡せます。つまり、モデルには要約しやすい最小限の情報を、UIには操作に必要なリッチデータを渡す分離ができます。
OpenAIの公式Quickstartでも、Todoアプリの例として、MCPサーバー、ツール、HTMLウィジェットを組み合わせています。ここで重要なのは、Apps SDKが独自プロトコルだけで閉じていない点です。基盤はMCPなので、AIアプリと外部システムを接続する標準化の流れに乗れます。Agent Labで扱ってきたMCP Registry公開ガイドやMCP認可の実装ガイドを読んでいる人なら、かなり理解しやすいはずです。
全体像:MCPサーバー、ツール、UIの3層で考える
Apps SDKの構成は、最初から大きく作るより3層に分けると失敗しにくいです。
- MCPサーバー:ChatGPTからHTTPで接続され、ツール定義と実行ハンドラを提供する。
- ツール:検索、予約、タスク更新、社内データ取得など、モデルが呼び出す処理単位。
- UIコンポーネント:ツール結果をChatGPT内のiframeで表示するHTML/React等の画面。
実装時の勘所は、モデルに見せる情報とUIだけが持つ情報を混ぜないことです。公式Referenceでは、ツール結果としてstructuredContent、content、_metaを扱う例が示されています。structuredContentはモデルが読むため簡潔にし、詳細データや内部IDのマップは_metaへ寄せるのが実務向きです。
5ステップで作る最小構成
ここでは、社内ナレッジ検索アプリを想定して、最小のApps SDK構成を作ります。動作環境はNode.js 20系、TypeScript想定です。注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。
まず依存関係を用意します。公式Quickstartでは@modelcontextprotocol/sdk、@modelcontextprotocol/ext-apps、zodを使う例が提示されています。
{
"type": "module",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.20.2",
"@modelcontextprotocol/ext-apps": "^1.0.1",
"zod": "^3.25.76"
},
"devDependencies": {
"typescript": "^5.0.0"
},
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
}
}
次に、MCPサーバーへUIテンプレートと検索ツールを登録します。実際の検索処理は、自社APIやベクトルDBに差し替えてください。
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
import { z } from "zod";
const server = new McpServer({ name: "internal-knowledge", version: "0.1.0" });
const widgetHtml = `<div id="root">検索結果を表示します</div>`;
registerAppResource(
server,
"knowledge-widget",
"ui://widget/knowledge.html",
{},
async () => ({
contents: [{
uri: "ui://widget/knowledge.html",
mimeType: RESOURCE_MIME_TYPE,
text: widgetHtml,
_meta: {
ui: {
prefersBorder: true,
csp: { connectDomains: ["https://api.example.com"] }
}
}
}]
})
);
registerAppTool(
server,
"search_knowledge",
{
title: "社内ナレッジ検索",
description: "社内FAQとドキュメントを検索します。",
inputSchema: { q: z.string().min(1) },
outputSchema: {
results: z.array(z.object({ title: z.string(), url: z.string() }))
},
_meta: { ui: { resourceUri: "ui://widget/knowledge.html" } }
},
async ({ q }) => {
const results = await searchInternalDocs(q);
return {
structuredContent: { results: results.slice(0, 5) },
content: [{ type: "text", text: `${results.length}件の候補を見つけました。` }],
_meta: { allResults: results }
};
}
);
async function searchInternalDocs(q: string) {
// 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。
return [{ title: `検索: ${q}`, url: "https://example.com/docs/1" }];
}
最後にローカルで起動し、MCP InspectorでツールとUIの疎通を確認します。ChatGPTに接続する前に、ここでエラーを潰すのが一番安いです。
# ビルドして起動
npm run build
npm run start
# 別ターミナルでMCP Inspectorを起動
npx @modelcontextprotocol/inspector@latest --server-url http://localhost:8787/mcp --transport http
# ChatGPT接続用にHTTPSトンネルを用意する例
ngrok http 8787
ChatGPTへ接続する前に確認すること
OpenAIの「Connect from ChatGPT」ガイドでは、開発者モードを有効化し、Settings → Connectors → CreateからMCPサーバーのURLを登録する流れが説明されています。ローカル開発ではngrokやCloudflare TunnelのようなHTTPSトンネルを使い、本番ではVercel、Cloudflare Workers、Fly.io、AWSなど低レイテンシのHTTPS環境に置くのが現実的です。
接続前のチェックリストは次の通りです。
- MCPエンドポイントがHTTPSで到達可能か。
- ツール名、説明、入力スキーマがモデルに誤解されにくいか。
- 読み取り専用ツールには
readOnlyHintなどの注釈を付けたか。 - UIテンプレートの
resourceUriがツールの_metaから参照できるか。 - CSPの
connectDomainsやresourceDomainsが必要最小限か。
この段階で、Claude Agent SDK実践ガイドのような自律実行エージェントとは発想を分けてください。Apps SDKは「ChatGPT内で人間が確認しながら操作するアプリ」に強い一方、完全自律のバックグラウンド処理基盤そのものではありません。
セキュリティと審査で見落としやすい論点
Apps SDKはChatGPTのUI内で動くため、便利な反面、ユーザーデータ・外部API・書き込み操作を扱うリスクがあります。OpenAIのSecurity & Privacyガイドでは、OAuth 2.1の利用、明示的なユーザー同意、最小権限、ログと監査、コンポーネントに渡すデータの絞り込みが強調されています。
特に注意したいのは「便利だから全部_metaに入れる」実装です。_metaはモデルに読ませないデータの置き場として有用ですが、ウィジェットから見える以上、秘密情報や長期トークンを入れるべきではありません。必要なデータだけを短命なセッションで渡し、外部サービス連携はOAuthで明示的に認可させるのが基本です。
また、公式のApp submission guidelinesでは、外部システムに影響するツールや公開コンテンツを作るツールには、適切なラベル付けとユーザー確認が必要だとされています。タスク作成、予約確定、メール送信、決済のような操作は、読み取り専用ツールと同じ扱いにしないでください。
【要注意】よくある失敗パターンと回避策
失敗1:MCPサーバーを単なるAPIプロキシにしてしまう
❌ 外部APIの全エンドポイントをそのままツール化する。
⭕ ユーザーがChatGPT上で達成したいタスク単位に絞って、入力スキーマと戻り値を設計する。
モデルは「API一覧」よりも「何を達成できるか」を手がかりにツールを選びます。ツール説明は短く、具体的に書くのが効果的です。
失敗2:structuredContentに情報を詰め込みすぎる
❌ 100件分の検索結果、内部ID、スコア、全文をすべてstructuredContentに返す。
⭕ モデルに読ませる上位5件だけをstructuredContentへ、UI表示用の詳細は_metaへ分ける。
これはトークンコストの問題だけでなく、モデルの判断ノイズを減らす意味でも重要です。
失敗3:CSPとOAuthを後回しにする
❌ ローカルでは動いたので、本番直前にCSPと認可を足す。
⭕ 初期プロトタイプの段階から接続先ドメイン、権限スコープ、ユーザー確認フローを決める。
Apps SDKはUIと外部APIが絡むため、セキュリティ設計の後付けが重くなりがちです。最初から「読み取り専用」「書き込みあり」「外部公開あり」を分類しておきましょう。
導入判断:どんなチームに向いているか
OpenAI Apps SDKが向いているのは、すでに社内APIやSaaS連携を持っていて、ChatGPT上で業務画面の一部を動かしたいチームです。たとえば、営業の商談メモからCRM候補を表示する、CS担当が問い合わせ履歴を確認する、PMがチケット一覧を見ながら優先度を更新する、といった用途です。
一方で、単純なFAQ回答だけなら通常のRAGやMCPツールで十分な場合があります。UIが必要か、外部状態を変更するか、人間の確認を挟む価値があるか。この3点を満たすなら、Apps SDKを検討する価値があります。
まとめ:まずは読み取り専用アプリから始める
OpenAI Apps SDKは、ChatGPTを「会話だけの窓口」から「操作できる業務UI」に近づける選択肢です。ただし、最初から予約・送信・決済のような書き込み操作へ進むのはおすすめしません。まずは読み取り専用の検索・一覧・プレビュー系アプリで、MCPサーバー、ツールスキーマ、UIコンポーネント、CSP、OAuthの基本を確認してください。
実装順は、MCPサーバーを作る、ツールを1つ登録する、UIテンプレートを紐付ける、Inspectorで検証する、ChatGPT開発者モードで接続する。この5ステップで十分です。小さく作って、失敗ログを見ながら拡張する方が、結果的に安全で速いです。
この記事を読んで導入イメージが固まってきた方へ
UravationではAIエージェント導入の研修・コンサルを行っています。
