Build with AI

How do you build an app inside ChatGPT with the Apps SDK?

· By Robert Scales · 3 min read

Short answer

You build an MCP server that offers one or more tools, register a small HTML component for ChatGPT to display, and link each tool to that component. Then you expose the server over HTTPS and add it as a connector in ChatGPT's developer mode to test it in a real conversation.

Apps in ChatGPT, introduced on October 6, let a conversation show something more than text: a playlist you can play, a map, a board of tasks. Users call an app by name or ChatGPT suggests one, and the app's interface appears inside the chat. The Apps SDK, the open-source toolkit for building these apps, is in preview, and developers can already test their own apps in ChatGPT's developer mode.

An app has two halves. The server holds your logic and data, and offers tools, named actions the model can call, such as "show the book club picks". The component (OpenAI also calls it a widget) is a small web page that ChatGPT displays in a sandboxed frame inside the conversation. The tool's result fills the component with data.

A worked example: a book club app

This minimal app has one tool that returns three book picks and one component that lists them. It uses the official TypeScript SDK for MCP and zod, a library for describing input shapes. The structure follows OpenAI's server-setup guide.

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({ name: "book-club", version: "1.0.0" });

// 1. The component: plain HTML that reads the data ChatGPT injects.
const WIDGET_HTML = `
<ul id="list"></ul>
<script type="module">
  const output = (window.openai && window.openai.toolOutput) || {};
  const list = document.getElementById("list");
  for (const book of output.books || []) {
    const item = document.createElement("li");
    item.textContent = book.title + " by " + book.author;
    list.appendChild(item);
  }
</script>`.trim();

server.registerResource("book-list", "ui://widget/book-list.html", {}, async () => ({
  contents: [{
    uri: "ui://widget/book-list.html",
    mimeType: "text/html+skybridge",
    text: WIDGET_HTML,
  }],
}));

// 2. The tool: linked to the component through _meta.
server.registerTool(
  "list-books",
  {
    title: "Show book club picks",
    description: "Lists the book club's next three reading picks.",
    inputSchema: { month: z.string().optional() },
    annotations: { readOnlyHint: true },
    _meta: {
      "openai/outputTemplate": "ui://widget/book-list.html",
      "openai/toolInvocation/invoking": "Fetching the picks",
      "openai/toolInvocation/invoked": "Here are the picks",
    },
  },
  async () => {
    const books = [
      { title: "Frankenstein", author: "Mary Shelley" },
      { title: "Pride and Prejudice", author: "Jane Austen" },
      { title: "The Time Machine", author: "H. G. Wells" },
    ];
    return {
      structuredContent: { books },
      content: [{ type: "text", text: "Three picks are on the list." }],
    };
  }
);

Three details carry the whole design:

  • The resource's mimeType of text/html+skybridge tells ChatGPT this is a component to render, and its ui:// address is the component's ID.
  • openai/outputTemplate connects the tool to that component.
  • The result's structuredContent is what the component receives as window.openai.toolOutput. The model can read it too, and content is extra text for the model. A third field, _meta, goes to the component only, which is useful for data the model does not need.

The readOnlyHint annotation tells ChatGPT the tool only reads data and changes nothing.

Running and testing it

The server still needs a transport, the part that carries messages over the network. The protocol allows either Server-Sent Events or streaming HTTP, and OpenAI's examples repository includes a complete Node server you can copy that wiring from. Then:

  1. Start the server and open MCP Inspector, a testing tool, at http://localhost:<port>/mcp. List the tools and call list-books; the Inspector checks the response and renders the component.
  2. ChatGPT only connects over HTTPS, so during development run a tunnel such as ngrok http <port> to get a public address.
  3. In ChatGPT, enable developer mode and add the tunnel URL, ending in /mcp, under Settings > Connectors.
  4. In a chat, add the app from the "More" options and ask something like "What is my book club reading next?"

Try it: Change the tool so it accepts a genre input and returns different picks for "mystery" and "science fiction". Ask ChatGPT for each and check which value it passes.

Before anyone else uses it

OpenAI's rules for apps ask for a clear privacy policy, content suitable for all audiences, and collecting only the data the app needs. Components also need a strict content security policy, a list of the outside domains the page may load from or connect to, before broad distribution. If the app needs to know who the user is, the guides cover adding OAuth 2.1 sign-in. OpenAI says submissions and an app directory will open later this year.

How does it relate to MCP?

The Model Context Protocol, or MCP, is an open standard for connecting AI applications to tools and data. The Apps SDK is built on it: your app's server is an MCP server. It lists its tools with JSON Schema descriptions, answers tool calls, and returns results, exactly as it would for any MCP client.

What the Apps SDK adds are extensions for interfaces: the text/html+skybridge component resources and the openai/... keys inside _meta, which tell ChatGPT what to display and what status messages to show. OpenAI's documentation points out that not every MCP client renders components, so a well-built tool should still return useful content and structuredContent on its own. That way the same server can serve ChatGPT with a rich interface and other MCP clients with plain results.

Sources

  1. Set up your server (Apps SDK documentation) — OpenAI, October 6, 2025
  2. Apps SDK Examples Gallery, README — OpenAI on GitHub, October 16, 2025
  3. Introducing apps in ChatGPT and the new Apps SDK — OpenAI, October 6, 2025

Get the free Guide to Artificial Intelligence

Sign up for the weekly newsletter and receive the free guide: what changed in AI this week, one lesson, one prompt to try. Unsubscribe in one click.

How we handle your address

Back to top

Display

Your choices are saved in this browser only. No data is sent.

Text size
100%
Colours
Reading
More settings
Accessibility statement