
著者: Boxu Li at Macaron
ChatGPT内のアプリは現在、サードパーティの開発者がチャットインターフェース内で動作するインタラクティブなミニアプリケーションを構築できるようになっています。ユーザーをウェブサイトやモバイルアプリに誘導する代わりに、これらのアプリは会話内で実行され、モデルの推論を活用してアクションを駆動します。Canva、Coursera、Expedia、Zillowのような早期パートナーは、ユーザーがChatGPTを離れることなくプレイリストを依頼したり、ポスターをデザインしたり、不動産を検索したりする方法をデモンストレーションしました[1]。新しいApps SDKは、外部ツールやユーザーインターフェースとモデルが相互作用できるようにするオープンスタンダードである**Model Context Protocol (MCP)**に基づいて構築されています[2]。このブログでは、MCPベースのアプリのアーキテクチャを深く掘り下げ、SDKの機能を説明し、アプリをステップバイステップで構築する方法を紹介し、ユーザーがアプリを発見して使用する方法を探り、プライバシーとセキュリティの考慮事項について議論します。全体を通して、公式ドキュメントと信頼できるジャーナリズムを引用し、分析を信頼性のある情報源に基づけています。
「モデルコンテキストプロトコル」は、Apps SDKの基盤です。開発者向けドキュメントによれば、すべてのApps SDK統合はMCPサーバーを使用して「ツール」を公開し、認証を処理し、構造化データとHTMLの両方をパッケージ化してChatGPTに表示します[2]。MCPはオープンスタンダードであり、誰でも任意の言語でサーバーを実装し、GPT‑4やCodexのようなモデルを接続できます。オープンソースの性質により、ベンダーロックインがなく、同じアプリがプロトコルを実装する任意のAIプラットフォーム上で理論的に動作可能です。このオープン性はコミュニティの貢献を促し、HTTPのような標準が相互運用可能なウェブサイトを可能にした初期のウェブに類似したエコシステムを育成します。
MCPサーバーは一つ以上の「ツール」を公開します。ツールは、モデルが呼び出す可能性のあるアクションを定義します。例えば、「カンバンボードを作成する」、「家を検索する」、「プレイリストを生成する」などです。各ツールは「マシン名」、人間に優しいタイトル、およびモデルに受け入れる引数を伝える「JSONスキーマ」で記述されます。ChatGPTがツールを呼び出すべきだと判断した場合、構造化された呼び出しをサーバーに送信します。サーバーはAPIのクエリ、計算の実行、データベースとの対話などのロジックを実行し、その後「ツール応答」を返します。この応答には3つのフィールドが含まれます。
ツールは、ui:// URLを参照することで、HTMLテンプレートや画像などのリソースにもアクセスできます。サーバーは起動時にこれらのリソースを登録します。ドキュメントでは、OpenAIのインフラストラクチャによってリソースがキャッシュされるため、開発者はファイル名にビルドハッシュを含めてバージョン管理することを推奨しています[5]。そうでないと、ユーザーはデプロイ後に古いUIを見る可能性があります。
structuredContent と _meta の区別は非常に重要です。ドキュメントによると、structuredContent はモデルに可視であり、UIコンポーネントを活性化するために使用されます。一方、_meta はモデルから隠されており、ドロップダウンメニューのリストなど、UIのための追加データを含む可能性があります[3]。可視データと非可視データを分けることで、開発者はモデルから機密情報を保護しつつ、豊かなインターフェースを提供できます。この設計はまた、必要なデータだけを共有するという最小限のデータ共有を促進し、プライバシー原則に沿ったものです。
ユーザーが初めてアプリを呼び出すとき、サーバーはユーザーを認証する必要があります。Apps SDK は OAuth 2.1 フローをサポートしており、開発者はスコープを指定し、ユーザーをアイデンティティプロバイダーにリダイレクトします。ユーザーが同意を与えると、アプリはトークンを取得し、ユーザーのデータにアクセスできるようになります。サーバーの役割は、ユーザーの ChatGPT アカウントに関連付けられたデータベースにトークンを保存し、セッション状態を管理することです。これにより、後続のツール呼び出しがユーザーに再度プロンプトを表示することなくセッションを再利用できるようになります。
OpenAIは、最小限の特権、明示的なユーザーの同意、および深層防御を強調しています[6]。アプリは必要最小限の権限のみを要求すべきであり、ユーザーはデータ共有を明示的に許可しなければなりません。モデル自体は資格情報を推測してはなりません。データ保存は限定的で、構造化されたコンテンツはユーザーのプロンプトがアクティブである間のみ保持され、ログは開発者と共有される前に編集されます[6]。アプリコンポーネントのネットワークアクセスはコンテンツセキュリティポリシーによって制限され、iframeは任意のブラウザAPIにアクセスできず、すべてのHTTPリクエストはクライアントではなくサーバーから発信されなければなりません[7]。これにより、クロスサイトスクリプティングとトークンの漏洩が防止されます。

Apps SDKは、MCPを慣用的なクライアントライブラリ(現在はPythonとTypeScript)およびスキャフォルドツールでラップします。アプリを作成する際には、ツールを定義し、UIテンプレートを登録し、サーバーロジックを実装します。サーバーは独自のインフラストラクチャ上で実行でき、任意のフレームワーク(FastAPI、Expressなど)を使用しますが、MCPエンドポイントを実装する必要があります。OpenAIは開発サーバーとローカルでの呼び出しテスト用の「MCPインスペクター」を提供しています。
開発者はロジックとユーザーインターフェースの両方を設計します。UIは通常、Reactで記述され、静的リソースにコンパイルされます。これらは、ChatGPT内のサンドボックス化されたiframe内で提供されます。このiframe内では、開発者はホストと対話するためのグローバルなwindow.openaiオブジェクトにアクセスできます。「カスタムUXを構築する」ガイドによれば、このAPIは以下を提供します:
これらのAPIにより、開発者はモデルの推論と同期したリッチでインタラクティブなコンポーネントを構築できます。例えば、ユーザーがカンバンボードでタスクを新しい列にドラッグした場合、コンポーネントはcallToolを使ってサーバーを更新し、新しい状態を保持して、構造化された新しいコンテンツを返します。その間、モデルは高レベルのボード状態のみを確認し、UIはドラッグアンドドロップのような詳細を処理します。
In the server code you register a tool and its template. For instance, in a TypeScript server you might write:
import { Tool, StructuredToolResponse } from "@openai/apps";
// Register UI template
server.registerResource("ui://kanban-board/abc123", buildHtml());
// Define tool schema
const createBoard: Tool = {
name: "createKanbanBoard",
description: "Create a new kanban board with given tasks and columns",
inputSchema: z.object({
title: z.string(),
columns: z.array(z.object({ name: z.string() })),
tasks: z.array(z.object({ name: z.string(), columnIndex: z.number() }))
}),
async execute(input, ctx): Promise<StructuredToolResponse> {
// compute board state
const columns = input.columns.map((col, i) => ({
id: i,
title: col.name,
taskIds: input.tasks.filter(t => t.columnIndex === i).map((_t, idx) => idx)
}));
const tasksById = input.tasks.map((task, id) => ({ id, name: task.name }));
return {
content: `Created board '${input.title}'`,
structuredContent: { title: input.title, columns },
_meta: { tasksById, uiTemplate: "ui://kanban-board/abc123" }
};
}
};
The _meta field includes tasksById for hidden metadata and uiTemplate referencing the registered HTML. When ChatGPT receives this response, it will render the template with the structured content. The window.openai.toolOutput object in the component can then read the board data and display it.
UIテンプレートのようなリソースはOpenAIのサーバーにキャッシュされるため、開発者はui://識別子にユニークなハッシュやバージョンを含める必要があります。ドキュメントでは、パスを更新せずに新しいバージョンをデプロイすると、キャッシュの影響でユーザーが古いUIを見続ける可能性があると警告しています[5]。ベストプラクティスとして、コミットSHAやビルドIDをURLに埋め込むことが推奨されます。これにより、各デプロイメントで新しいリソースが確実に提供されます。
コンポーネントはしばしば状態を保持する必要があります。例えば、プレイリストアプリではユーザーがお気に入りの曲を選ぶことができ、そのお気に入りはユーザーが別の質問をしても保持されるべきです。setWidgetState()メソッドは、構造化されたコンテンツの外でデータを保存し、ターンをまたいで持続させます[8]。この状態はモデルに見られることはなく、プライバシーが確保されます。
時にはアプリがユーザーに明確な質問をする必要があることもあります。sendFollowupTurn()メソッドを使うと、コンポーネントがChatGPTに新しいプロンプトを送り返し、モデルが質問をしたかのようにトランスクリプトに表示されます[8]。これはマルチステップのワークフローに役立ちます。例えば、旅行予約アプリでは、ユーザーがホテルを選んだ後に「何泊されますか?」と尋ねることができます。
In this section we will build a simple Task Tracker app that demonstrates the core concepts of the Apps SDK. The app will let a user create tasks and organise them into categories. We choose this example because it is generic, easy to extend and showcases structured content, metadata, custom UI and tool calls.
First install the TypeScript SDK and scaffolding tool:
npm install -g @openai/apps-generator
apps init task-tracker
cd task-tracker
npm install
This command scaffolds a project with a server, a React frontend and build scripts. The server uses Express and the @openai/apps library. Run npm run dev to start the development server; the project includes an MCP Inspector that opens in your browser and simulates ChatGPT calling your app.
Open src/server.ts and define a tool called createTasks. The tool accepts an array of tasks and returns structured content grouping them by category. It also provides a summary in the content field.
import { Tool, StructuredToolResponse } from "@openai/apps";
export const createTasks: Tool = {
name: "createTasks",
description: "Create a list of tasks grouped by category",
inputSchema: z.object({ tasks: z.array(z.object({ name: z.string(), category: z.string() })) }),
async execute({ tasks }): Promise<StructuredToolResponse> {
const categories = Array.from(new Set(tasks.map(t => t.category)));
const grouped = categories.map(category => ({
name: category,
taskIds: tasks.filter(t => t.category === category).map((_, i) => i)
}));
const tasksById = tasks.map((task, id) => ({ id, name: task.name, category: task.category }));
return {
content: `Created ${tasks.length} tasks in ${categories.length} categories`,
structuredContent: { categories: grouped },
_meta: { tasksById, uiTemplate: "ui://task-tracker/1.0.0" }
};
}
};
Register the template before using it:
server.registerResource("ui://task-tracker/1.0.0", fs.readFileSync(path.join(__dirname, "../dist/index.html"), "utf8"));
server.registerTool(createTasks);
Next open src/frontend/App.tsx. This React component will read the structuredContent and display categories and tasks. It will also allow users to mark tasks as complete and persist that state using setWidgetState.
import { useEffect, useState } from "react";
declare global {
interface Window {
openai: any;
}
}
export default function App() {
const [complete, setComplete] = useState<{ [id: string]: boolean }>(() => window.openai.widgetState?.complete || {});
const output = window.openai.toolOutput;
const tasksById = output?._meta?.tasksById || [];
const categories = output?.structuredContent?.categories || [];
// 完了状態を保存
useEffect(() => {
window.openai.setWidgetState({ complete });
}, [complete]);
return (
<div className="task-tracker">
{categories.map((cat: any, ci: number) => (
<div key={ci} className="category">
<h3>{cat.name}</h3>
<ul>
{cat.taskIds.map((tid: number) => (
<li key={tid}>
<label>
<input type="checkbox" checked={complete[tid]} onChange={() => setComplete(prev => ({ ...prev, [tid]: !prev[tid] }))} />
{tasksById[tid].name}
</label>
</li>
))}
</ul>
</div>
))}
</div>
);
}
このコンポーネントは、window.openai.toolOutput を使って structuredContent と \_meta フィールドにアクセスします。完了状態を widgetState に保存しているため、チェックボックスにチェックを入れると、ユーザーが会話を続けてもその状態が保持されます。次回のツール呼び出し時に、新しいタスクを取得したり、既存のタスクを更新したりすることができます。これは、モデルの推論とクライアント側のインタラクションを組み合わせる方法を示しています。
* テストと反復
Run npm run dev again and open the MCP Inspector. In the prompt area, type:
```sql
@task‑tracker create a list of tasks: buy milk in shopping, finish report in work, call mom in personal
The inspector will show the structured content and render the task list UI. You can check tasks off; the state persists across turns. You can then ask ChatGPT: “Remind me of my tasks later.” Because the model retains context, it can call the tool again, display the UI and summarise your progress.

ChatGPT surfaces apps when it believes they can assist the user. There are two primary discovery modes. Named mention occurs when the user explicitly mentions the app name at the beginning of a prompt; in this case, the app will be surfaced automatically[9]. For instance, “@Spotify create a workout playlist” immediately invokes the Spotify integration. The user must place the app name at the start; otherwise the assistant may treat it as part of the conversation.
会話中の発見は、モデルがコンテキストに基づいてアプリが役立つと推測したときに発生します。ドキュメントでは、モデルが会話のコンテキスト、以前のツール結果、およびユーザーのリンクされたアプリを評価して、どのアプリが関連するかを決定する方法を説明しています[9]。たとえば、旅行計画について話し合っている場合、ChatGPTはフライトを予約するためにExpediaアプリを提案するかもしれません。アルゴリズムは、ツールの説明やキーワードなどのメタデータを使用して、会話と潜在的なアクションを一致させます[10]。開発者は、アクション指向の説明や明確なUIコンポーネント名を書くことで、発見性を向上させることができます。
OpenAIは、ユーザーが新しいアプリを閲覧して発見できるアプリディレクトリをリリースする予定です[10]。各リストには、アプリ名、説明、サポートされているプロンプト、オンボーディング指示が含まれます。ユーザーはチャット内の「+」ボタンを通じてランチャーにもアクセスでき、コンテキストに基づいて利用可能なアプリのメニューが表示されます。これらのエントリーポイントは、技術的な知識が少ないユーザーが名前を覚えなくてもアプリを見つけて有効にするのに役立ちます。
ユーザーが初めてアプリをアクティブにすると、ChatGPTがオンボーディングフローを開始します。モデルはユーザーにアカウントの接続を求め(必要に応じて)、アプリが必要とするデータを説明します。開発者ガイドラインは、アプリがユーザーのプライバシーを尊重し、予測可能に動作し、明確なポリシーを持つことを強調しています[11]。ユーザーは明示的に許可または拒否する必要があり、データのサイレントアクセスはありません。一度接続されると、アプリはその後のやり取りのためにリンクされたままにすることができますが、ユーザーはいつでも接続を解除し、許可を取り消すことができます。
OpenAI の「アプリ開発者ガイドライン」は、エコシステムが安全で信頼できるものであり続けるためのいくつかの原則を定めています。アプリは、正当なサービスを提供し、明確なプライバシーポリシーとデータ保持の実践を持ち、使用ポリシーに準拠する必要があります[11]。データの収集を最小限に抑え、個人の機密情報を保存せず、ユーザーデータを同意なしに共有してはなりません[12]。アプリは予測可能に動作しなければならず、モデルを操作して有害または誤解を招くコンテンツを生成してはなりません。
ガイドラインでは、アプリはその機能に必要なデータのみを収集し、健康記録や政府のIDのような機密データを要求または保存してはいけないことを強調しています[12]。モデルに送信される構造化コンテンツには秘密を含めてはいけません; 隠されたメタデータにユーザートークンやプライベートな詳細を保存してはいけません。開発者は、OAuthで取得したトークンに対して強力な暗号化と安全な保存を実施しなければなりません。サーバーはユーザーセッション間に厳格な境界を維持し、一人のユーザーのデータが他のユーザーのコンテキストに漏れることがあってはなりません。
「セキュリティとプライバシーガイド」は、プラットフォームに組み込まれた防御メカニズムを概説しています。中心的な原則として、最小特権と明示的なユーザー同意を強調しています[6]。データ保持は限定的で、開発者がアクセスできるログは個人を特定できる情報が削除されており、構造化されたコンテンツはプロンプトが必要とする限りのみ保持されます[6]。iframe内からのネットワークアクセスはコンテンツセキュリティポリシーで制限されており、外部へのフェッチはサーバーを経由しなければならず、無許可のクロスオリジンリクエストを防ぎます[7]。認証には業界標準のOAuthフローと短命のトークンが使用されます。開発者は、運用の準備を維持するためにセキュリティレビュー、バグ報告チャネル、およびインシデント監視を実装する必要があります[7]。
アプリは幅広いオーディエンスに適している必要があります。ガイドラインでは、長文コンテンツ、複雑な自動化、広告を提供するアプリを禁止しています[13]。例えば、アプリが30分のビデオを提供したり、ChatGPT内でソーシャルネットワーク全体を再現しようとするべきではありません。プラットフォームは、会話の流れを補完する簡潔なインタラクションを推奨しています。違反があった場合は、拒否や削除につながる可能性があります。
ChatGPTをサードパーティのアプリに開放することで、OpenAIはユーザーとサービスの間の「インテント層」としての地位を確立しています。開発者は、別々のウェブやモバイルアプリを作成することなく、チャットインターフェースを通じて何百万人ものユーザーにアクセスできるようになります。アプリは摩擦を減らす可能性があります。ユーザーはアプリをダウンロードしたりウェブサイトを訪問したりする代わりに、会話の中でサービスに言及するだけで済みます。これにより、ツールへのアクセスが民主化され、小規模な開発者にとって競争の場が平等になる可能性があります。
初期のパートナーシップは可能性を示しています。ユーザーはCourseraの講義を視聴しながらChatGPTに質問したり、Canvaでポスターをデザインしたり、Expediaで旅行オプションやZillowの不動産リスティングを閲覧したり、Spotifyのプレイリストを生成したり、Figmaでアイデアを図解したりできます。アプリはチャット内で実行されるため、モデルは静的なコンテンツをインタラクティブなレッスンに変えることができ、要約、分析、推奨を生成します。アプリはまた、インラインカード、フルスクリーン、ピクチャー・イン・ピクチャーなど、さまざまな表示モードを提供し、異なるタスクに柔軟性をもたらします。
アプリを切り替えずに使用できる能力は、人々のサービスとのインタラクションの方法を再構築する可能性があります。ChatGPTは単なるチャットボットではなく、意図のための普遍的なオペレーティングシステムとなります。Casey Newtonが観察したように、これは個別のアプリを起動するのではなく、ただ欲しいものを伝えるという形に移行させます[16]。一部のアナリストは、この変化をApp Storeやブラウザの登場に例えています。機能と競争を集約する単一のプラットフォームです。
しかし、この変革はコントロールと権力についての疑問を投げかけます。もしChatGPTがどのアプリを提示するかを決定する場合、それはゲートキーパーになる可能性があります。Newtonは、ユーザーの好みに基づいて構築された「AIグラフ」が、ソーシャルネットワークのものよりも深刻なプライバシーリスクを生む可能性があると警告しています[16]。経済的なインセンティブは、アプリの配置やランキングにおける「支払うことで優先される」形になる可能性があります。開発者はユーザーとの関係を所有するのではなく、ChatGPT向けに設計することを強いられるかもしれません。プラットフォームが透明性と公正さを維持し、信頼を保つことが重要です。
アプリは位置情報、連絡先、支払い方法などの個人データにアクセスできるため、規制当局がChatGPTを通じたデータの流れを詳細に調査する可能性があります。開発者は、プラットフォームがまだ欧州連合で利用できないにもかかわらず、GDPRなどのプライバシー法を遵守する必要があります[17]。OpenAIは、チャット内での即時チェックアウトを可能にするエージェントコマースプロトコルを含む、より詳細なプライバシーコントロールと収益化オプションを約束しています[18]。このエコシステムの成功は、強固なセキュリティ、明確なユーザーの同意、公正な経済モデルに依存しています。
Apps SDKはまだプレビュー段階で、多くの機能がまだ整備されていません。開発者のロードマップには次の項目が含まれています:
「Apps in ChatGPT」と「MCPベースのApps SDK」の導入は、ソフトウェアとのインタラクションにおける重要な転換点を示しています。OpenAIはサードパーティアプリケーションをチャットインターフェースに直接持ち込むことで、自然言語、推論、インタラクティブなUIを融合させた新しいプラットフォームを作り出しました。「モデルコンテキストプロトコル」は、モデルがツールを呼び出し、コンポーネントをレンダリングするためのオープンで標準化された方法を提供します。「Apps SDK」はサーバー通信、UI統合、状態管理を処理することで開発を簡素化します。「Task Tracker」のようなステップバイステップの例は、厳格なデータ境界とプライバシーを維持しながら役立つアプリを簡単に構築できることを示しています。
しかし、この革新には責任が伴います。開発者は、ユーザーのプライバシー、安全性、公平性を優先するガイドラインに従わなければなりません。セキュリティメカニズムとして、最小特権と明示的な同意がユーザーを保護します。同時に、業界の観察者は、このプラットフォームが新しい形のゲートキーピングやプライバシーリスクを生む可能性があると警告しています。エコシステムが成熟するにつれ、透明性、オープンスタンダード、コミュニティの関与が、ChatGPTのアプリプラットフォームが日常のタスクにおいて変革的で信頼されるレイヤーとなるかを決定するでしょう。
AI競争最新情報: ChatGPTがSpotifyやZillowとチャットで接続可能に
https://developers.openai.com/apps-sdk/build/mcp-server
https://developers.openai.com/apps-sdk/guides/security-privacy
[8] カスタムUXを構築する
https://developers.openai.com/apps-sdk/build/custom-ux
https://developers.openai.com/apps-sdk/concepts/user-interaction
https://developers.openai.com/apps-sdk/app-developer-guidelines/
[13] ChatGPTアプリが公開されました: こちらが最初に試せるものです | The Verge
https://www.theverge.com/news/793081/chagpt-apps-sdk-spotify-zillow-openai
[14] OpenAI DevDay 2025: ChatGPTがアプリを取得し、開発者向けのAgentKitと安価なGPTモデルを提供
[15] OpenAI、ChatGPTがZillow、Canva、Spotifyのようなサードパーティアプリを起動・実行できるApps SDKを発表 | VentureBeat
https://venturebeat.com/ai/openai-announces-apps-sdk-allowing-chatgpt-to-launch-and-run-third-party
[16] 新しいプラットフォーム、馴染みのリスク: ZillowとExpediaがOpenAIのChatGPTアプリの展開に賭ける – GeekWire
[17] OpenAI DevDay: ChatGPTアプリ、AgentKit、CodexのGAリリース - SD Times
https://sdtimes.com/ai/openai-devday-chatgpt-apps-agentkit-and-ga-release-of-codex/
[18] OpenAIはChatGPTをユニバーサルアプリのフロントエンドにしたいと考えている - Ars Technica
https://arstechnica.com/ai/2025/10/openai-wants-to-make-chatgpt-into-a-universal-app-frontend/