Claw field notebook
last updated 2026-05-15 edit on GitHub colophon
OpenAI / Apps SDK / APPS.1 · 3 min read

OpenAI Apps SDK, plainly

Five-minute orientation to the OpenAI Apps SDK — what it is (a framework for building apps that run inside ChatGPT with rich UI), what it's not (Custom GPTs, GPT Actions, or the old plugins system), and how it uses MCP under the hood.

The thirty-second version#

The OpenAI Apps SDK lets you build apps that run inside ChatGPT — full-stack experiences with custom UI, auth, and network access that users interact with through a conversation. Under the hood: every app is an MCP server, plus a UI bundle that ChatGPT renders in a sandboxed iframe alongside the chat.

Three things to know:

  1. It’s MCP-native. Apps SDK was the early implementation of what’s now the open MCP Apps standard. Build once, run across MCP-Apps-compatible hosts.
  2. It’s different from Custom GPTs and the old plugins. Apps SDK is code-first, generates rich custom UI, and ships as MCP servers. §GPT.1 Custom GPTs are no-code chat assistants. The original 2023 ChatGPT Plugins system was deprecated in 2024.
  3. Distribution is gated today. Public apps go through OpenAI submission review. Approved apps land in the ChatGPT apps store, and OpenAI also creates a plugin version for Codex distribution. Self-serve publishing is on the roadmap (as of 15 May 2026).

The three components of a ChatGPT App#

Per the official docs, every Apps SDK app has three parts:

ComponentWhat it does
MCP serverDefines tools, enforces auth, returns structured data, points each tool to a UI bundle.
Widget / UI bundleRenders inside ChatGPT’s iframe. Talks to the host via the MCP Apps bridge (JSON-RPC over postMessage).
The modelDecides when to call your tools, narrates the experience using the structured data your server returns.

You build the first two. ChatGPT supplies the third and decides when your tools fire based on the metadata you provide.

The conversation loop#

User prompt

ChatGPT model ──► tools/call ──► Your MCP server ──► Tool response
   │                                                    (structuredContent + _meta + content)
   │                                                       │
   └────── narrates ◄──── widget iframe ◄──────────────────┘
                       (HTML template + MCP Apps bridge)
  1. User asks something.
  2. ChatGPT model decides one of your tools fits, calls it via tools/call.
  3. Your server runs the handler, returns structuredContent (data the model + widget can read), _meta (UI metadata, CSP, domain hints), and content (the model-narrated summary).
  4. ChatGPT loads the HTML template linked in the tool descriptor (served as text/html;profile=mcp-app) and delivers tool inputs/results to the iframe over the MCP Apps bridge.
  5. Widget renders. Model reads structuredContent and narrates.

The widget can also call tools itself (tools/call), post follow-up messages (ui/message), and update context the model sees (ui/update-model-context).

A real example — a Kanban app#

You build:

  • An MCP server (Node/Python) with one tool kanban-board that returns the columns + tasks for a workspace.
  • A widget (React + Vite) bundled as web/dist/kanban.{js,css} that renders a draggable Kanban board.

The server registers the widget as an MCP resource:

import {
  registerAppResource,
  RESOURCE_MIME_TYPE,  // = "text/html;profile=mcp-app"
} from "@modelcontextprotocol/ext-apps/server";

registerAppResource(server, "kanban-widget", "ui://widget/kanban-board.html", {}, async () => ({
  contents: [{
    uri: "ui://widget/kanban-board.html",
    mimeType: RESOURCE_MIME_TYPE,
    text: `<div id="kanban-root"></div><style>${CSS}</style><script type="module">${JS}</script>`,
    _meta: {
      ui: {
        prefersBorder: true,
        domain: "https://kanban.example.com",
        csp: {
          connectDomains: ["https://api.kanban.example.com"],
          resourceDomains: ["https://*.oaistatic.com"],
        },
      },
    },
  }],
}));

Then the tool itself:

registerAppTool(server, "kanban-board", {
  title: "Show Kanban Board",
  inputSchema: { workspace: z.string() },
  outputSchema: { columns: z.array(/* ... */) },
  _meta: { ui: { resourceUri: "ui://widget/kanban-board.html" } },
}, async ({ workspace }) => {
  const columns = await fetchKanban(workspace);
  return { structuredContent: { columns } };
});

A user asks ChatGPT “Show my Kanban.” The model decides kanban-board fits, calls the tool with { workspace: "..." }. Your server returns the columns; ChatGPT renders the widget inline, and the model narrates (“Here’s your board — 3 columns, 7 tasks”).

Why this matters#

The Apps SDK is OpenAI’s bet on conversations as the front end — instead of users opening a separate web app, the app appears inside their chat. Three implications:

  • Distribution is OpenAI-owned. Your app lives in the ChatGPT apps store. Discovery, auth, and trust live with OpenAI. Good for reach; bad for control.
  • The UX surface is constrained. Widgets render in a sandboxed iframe with a CSP. You declare connectDomains, resourceDomains, optional frameDomains. Browsers without these guarantees aren’t supported.
  • MCP is the wire format. If you’ve already built an MCP server (for Claude, for Cursor, for VS Code), most of the work is reusable. You add text/html;profile=mcp-app resources and tool _meta.ui hints.

How it compares#

Apps SDKCustom GPTsGPT ActionsOriginal Plugins (deprecated)
ShapeMCP server + widgetNo-code editorOpenAPI specOpenAPI spec
UIRich, custom HTML/JSChat-onlyChat-onlyChat-only
Code requiredYesNoOptionalYes
DistributionChatGPT apps store + Codex pluginsGPT StoreTied to a Custom GPTRemoved 2024
AuthYours (via MCP)OpenAI handlesOAuth, API keyOAuth
Tier requiredApps store review (no user tier)ChatGPT (Free can use public GPTs; building requires Plus / Team / Enterprise)ChatGPT (Free can use public GPTs that include Actions; building requires Plus / Team / Enterprise)n/a

Sush’s honest take (sourced, not yet tried): the MCP standardisation is the most interesting bit. The same protocol that powers Claude’s tool catalogue powers ChatGPT’s apps. The cross-vendor portability is real at the protocol level — Apps SDK builds on the open MCP Apps standard — though today ChatGPT is the host with the most-complete bridge implementation, so portability claims should be tested case-by-case. The trade-off: distribution still flows through OpenAI’s review process.

What to do next#

Sources