CityJS London 2026 Companion
基本的には、MCP Apps
MCPサーバーがテキストやJSONなどを返すことはご存知ですよね?MCP Appsはそれをさらに一歩進めたものです。ツールがフルHTMLウィジェットを返し、それがChatGPT内で直接レンダリングされます。モデルがユーザーにJSONの壁を投げつける代わりに、実際のUIが表示されます。カード、グリッド、タイムラインなど、何でも好きなものを表示できます。
これはあくまで概念実証(POC)であり、真剣なプロジェクトではありません。CityJS London 2026カンファレンスのコンパニオンアプリとして、スケジュール、登壇者、トーク検索などをChatGPT内でリッチなテーマ付きUIとしてレンダリングします。
実行方法
./start.shこれだけです。コマンド一つで、依存関係のインストール、サーバーの起動、cloudflaredトンネルのオープンを行い、ChatGPTに貼り付けるためのURLを発行します。Node.js 18+とcloudflared(Macの場合はbrew install cloudflared)が必要です。
以下のような画面が表示されます:
┌─────────────────────────────────────────────────────────┐
│ │
│ YOUR MCP ENDPOINT: │
│ │
│ https://something-random.trycloudflare.com/mcp │
│ │
│ NOW GO ADD IT TO CHATGPT: │
│ │
│ 1. Open chatgpt.com │
│ 2. Click the tools icon (wrench) in the input bar │
│ 3. Click 'Add MCP Server' │
│ 4. Paste the URL above │
│ 5. Ask: 'What's the CityJS London schedule?' │
│ │
└─────────────────────────────────────────────────────────┘あとはChatGPTに「登壇者を見せて」や「Douglas Crockfordのトークについて教えて」、「AIに関するトークを探して」などと話しかけて、ウィジェットが表示されるのを確認してください。
Related MCP server: Hello Widget Example
MCP Appsについて学ぶには
ソースコードは怖くありません!中身を見てみましょう。関連するファイルは基本的には3つだけです(しかも小さいです!):
ファイル | 役割 |
MCPサーバー。ウィジェットとツールの登録、それらの紐付けを行います。ここから始めてください。 | |
カンファレンスのタイムラインをレンダリングするHTMLウィジェット。一番下の | |
登壇者のカードグリッドをレンダリングするHTMLウィジェット。上記と同じパターンです。 | |
登壇者個人の詳細プロフィールカード用HTMLウィジェット。 |
ぜひ読んでみてください。本当に楽しいですよ!
基本的にはどう動くのか
MCP Appは、HTMLウィジェットも提供するMCPサーバーに過ぎません。ChatGPTがツールを呼び出すと、ウィジェットがレンダリングされ、ツールの出力データがそこに流し込まれます。これを実現するのは以下の3点です:
1. HTMLウィジェットを書く
インラインCSSとJSを含む自己完結型のHTMLファイルです。ChatGPTからデータを受け取り、それをレンダリングします。それだけです。widgets/speakers.htmlを見てください。render(data)関数といくつかのCSSがあるだけです。
ウィジェットは以下のようにChatGPTからデータを受け取ります:
// ChatGPT puts tool output here when the widget loads
tryRender(window.openai?.toolOutput);
// Or fires this event slightly later
window.addEventListener("openai:set_globals", (e) => {
tryRender(e.detail?.globals?.toolOutput);
});また、テーマ(window.openai?.theme)も取得するため、ChatGPTのライト/ダークモードに自動的に合わせることができます。
2. ウィジェットをリソースとして登録する
server.jsで、MCPホストに「このウィジェットがあるよ」と伝えます:
server.registerResource(
"schedule-widget",
"ui://cityjs/schedule.html",
{ mimeType: "text/html;profile=mcp-app" }, // <-- this MIME type is the magic
async () => ({
contents: [{
uri: "ui://cityjs/schedule.html",
mimeType: "text/html;profile=mcp-app",
text: scheduleWidgetHtml, // the raw HTML string
}],
})
);MIMEタイプのtext/html;profile=mcp-appが、通常のMCPサーバーをMCP Appに変える鍵です。これはホストに対して「これは単なるファイルではなく、レンダリング可能なウィジェットだ」と伝えます。
3. ツールをウィジェットに紐付ける
ツールを登録する際、そのツールが呼び出されたときに「どのウィジェットをレンダリングするか」をホストに伝えます:
server.registerTool(
"get_schedule",
{
title: "Get Schedule",
description: "Get the CityJS London 2026 schedule...",
inputSchema: { day: z.enum(["day1", "day2", "day3", "all"]).optional() },
_meta: {
ui: { resourceUri: SCHEDULE_URI }, // MCP spec way
"openai/outputTemplate": SCHEDULE_URI, // ChatGPT-specific way
},
},
async ({ day }) => {
return {
structuredContent: { days }, // <-- your widget receives THIS
content: [{ type: "text", text: JSON.stringify({ days }) }], // fallback for non-UI hosts
};
}
);structuredContentはウィジェットがレンダリングするデータです。contentは(Claudeのように)まだUIに対応していないホストのためのテキストフォールバックです。常に両方を返すようにしてください。
基本的にはこれだけです。ウィジェット + リソース + ツールの紐付け = MCP Appです。
プロジェクト
basically-mcp-apps/
start.sh <- run this. that's it.
server.js <- the MCP server. START READING HERE.
package.json
data/
data.json <- raw conference data (speakers, talks, bios)
cityjs.js <- enriches the raw data with rooms, types, etc.
widgets/
schedule.html <- conference schedule timeline widget
speakers.html <- speaker grid widget
speaker-detail.html <- individual speaker profile card widget依存関係
@modelcontextprotocol/sdk-- MCPサーバーSDKzod-- 入力スキーマバリデーションcloudflared-- ローカルホストをインターネットにトンネルし、ChatGPTがアクセスできるようにしますNode.js 18+
Reactもビルドステップも、バンドラーもフレームワークも不要です。HTMLファイルとNodeサーバーだけです。
ハッピーハッキング!
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for OpenAI API (chat completions, image generation, embeddings) via AceDataCloud
Build your own tools from chat: design, test and host them on a shareable MCP server URL.
1MCP server for AI dialogue using various LLM models via AceDataCloud
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA minimal MCP server demonstrating how to build ChatGPT-compatible applications using Next.js with widget rendering capabilities. Provides a starter template for integrating Next.js applications with the ChatGPT Apps SDK through the Model Context Protocol.-
- FlicenseNot gradedqualityNot gradedmaintenanceA minimal ChatGPT app demonstrating interactive greeting widgets with confetti animations and theme support, built as a template for creating MCP servers with custom UI components.-
- FlicenseNot gradedqualityDmaintenanceAn MCP server template integrated with the OpenAI Apps SDK for building ChatGPT-compatible widgets with automatic tool registration. It provides a suite of interactive UI components and ecommerce examples for creating type-safe, theme-aware widgets.-
- FlicenseNot gradedqualityDmaintenanceAn MCP server that enables AI models to render GitHub's Primer React components directly within chat interfaces using a JSON component tree. It provides tools to list available components and display interactive UI elements with full GitHub theming support.-