Skip to main content
Glama
TejasQ

CityJS London 2026 Companion

by TejasQ

基本上,MCP Apps

你知道 MCP 服务器是如何返回文本、JSON 等内容的吗?嗯,MCP Apps 更进一步:你的工具可以返回完整的 HTML 小部件,并直接在 ChatGPT 内部渲染。模型不再向用户倾倒一堆 JSON,而是看到一个实际的 UI。卡片、网格、时间轴——随你所想。

这仅仅是一个概念验证(POC),并不打算用于严肃场景。这是一个 CityJS London 2026 会议伴侣应用:日程安排、演讲者、演讲搜索——所有内容都作为丰富的主题 UI 在 ChatGPT 中渲染。

运行它

./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 一些问题,比如 "show me the speakers"(给我看看演讲者)、"tell me about Douglas Crockford's talk"(告诉我关于 Douglas Crockford 的演讲)或 "find talks about AI"(查找关于 AI 的演讲),然后看着小部件出现。

Related MCP server: Hello Widget Example

好吧,但我该如何学习 MCP Apps

源代码并不可怕!去看看吧。基本上只有 3 个相关文件(而且它们很小!):

文件

功能

server.js

MCP 服务器。注册小部件、注册工具、将它们绑定在一起。从这里开始。

widgets/schedule.html

一个渲染会议时间轴的 HTML 小部件。阅读底部的 <script> 标签。

widgets/speakers.html

一个渲染演讲者卡片网格的 HTML 小部件。模式与上面相同。

widgets/speaker-detail.html

用于单个演讲者完整资料卡片的 HTML 小部件。

去读读它们吧。真的很有趣!

它基本上是如何工作的

MCP App 只是一个同时也提供 HTML 小部件服务的 MCP 服务器。当 ChatGPT 调用你的工具时,它会渲染你的小部件并将工具的输出数据传入其中。三件事促成了这一点:

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 是为尚不支持 UI 的主机(如 Claude)提供的文本回退。请务必同时返回两者。

基本上就是这样。小部件 + 资源 + 工具绑定 = 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

依赖项

没有 React,没有构建步骤,没有打包器,没有框架。只有 HTML 文件和一个 Node 服务器。

Happy hacking!

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A 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.
    -
  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    A 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.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    An 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.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    An 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.
    -