ChatGPT Apps SDK: How Apps Inside ChatGPT Work
The ChatGPT Apps SDK now lives in OpenAI’s plugin documentation, but the idea is unchanged: an app is an MCP server, with optional UI that renders in the chat. The architecture, a minimal example, testing in developer mode, sign-in, review for the directory, and how an app differs from a connector and a custom GPT.
8 min read
The ChatGPT Apps SDK is how you build an app that runs inside ChatGPT, and an app is an MCP server. Your server defines tools the model can call and returns structured results; for tools where a picture helps, it can also return a small web page that ChatGPT renders in the conversation. The name has moved on: OpenAI’s old Apps SDK pages now redirect to its Plugins documentation, the app directory became the Plugin Directory, and a published app now ships inside a plugin that can also carry skills. The technology underneath is the same, and the UI part follows MCP Apps, an open standard, so the same component can run in other hosts that support it.
This is the builder’s view. For what apps and plugins can reach once they are installed, and what an admin controls, see ChatGPT connectors and apps. For every way OpenAI’s products speak MCP, from the API to Codex, see MCP with OpenAI.
The names, once
- Apps SDK: the original name for the toolkit. The
developers.openai.com/apps-sdkpages now redirect to the Plugins docs, although the names survive in OpenAI’s examples repository and its@openai/apps-sdk-uicomponent library. - App: a connection to a service, built on an MCP server. Connectors were renamed apps, and OpenAI’s admin documentation treats “app” and “MCP server” as the same thing.
- Plugin: the package people install. OpenAI’s plugin architecture (opens in a new tab) page says a plugin can hold skills, an MCP server, or both, and that ChatGPT and Codex share one plugin directory.
- Plugin Directory: where published plugins are listed. OpenAI’s help centre says the app directory moved to it in July 2026, and that existing app connections were unaffected.
The architecture
Three pieces, each optional except the first.
- An MCP server at a stable HTTPS address, using the streamable HTTP transport, usually at
/mcp. It lists tools, each with a name, description, input schema and, ideally, an output schema. - Tool results in three parts:
structuredContent, data the model reads and can use in later calls;content, text that helps the model answer; and_meta, data for the UI that the model does not see. - UI resources: an HTML page registered as an MCP resource with a
ui://address and the MIME typetext/html;profile=mcp-app. A tool points at it with_meta.ui.resourceUri, and ChatGPT renders it in an iframe beside the conversation.
The component talks to ChatGPT through the MCP Apps bridge, JSON-RPC messages over postMessage: it initialises with ui/initialize, receives a tool’s result through ui/notifications/tool-result, and can call your tools itself with tools/call. OpenAI’s guide to adding UI to an MCP server (opens in a new tab) says to build on that standard first, and to reach for ChatGPT’s own window.openai extensions, such as file uploads, modals, saved widget state and checkout, only when the standard does not cover what you need.
The same guide’s most useful rule: keep every tool useful without the UI. The model should be able to finish the job from the structured result alone, because not every client renders components, and many requests do not need one. A background lookup needs text; a comparison, a map or an editable list may earn a component.
A minimal example shape
OpenAI’s MCP server and UI quickstart (opens in a new tab) builds a small to-do app in Node with the official MCP TypeScript SDK, its MCP Apps helpers and zod. Stripped to its shape, one tool with a component looks like this:
const server = new McpServer({ name: "tasks", version: "0.1.0" });
server.registerResource("task-list", "ui://widget/tasks.html", {}, async () => ({
contents: [{
uri: "ui://widget/tasks.html",
mimeType: "text/html;profile=mcp-app",
text: taskListHtml, // your component: HTML, CSS and JS in one string
}],
}));
server.registerTool("list_tasks", {
title: "List tasks",
description: "List open tasks, optionally filtered by lane.",
inputSchema: { lane: z.string().optional() },
outputSchema: { tasks: z.array(z.object({ id: z.string(), title: z.string() })) },
annotations: { readOnlyHint: true },
_meta: { ui: { resourceUri: "ui://widget/tasks.html" } },
}, async ({ lane }) => {
const tasks = await loadTasks(lane);
return {
structuredContent: { tasks },
content: [{ type: "text", text: `${tasks.length} open tasks.` }],
};
});Serve it over streamable HTTP at /mcp and you have an app. Leave out the resource and the _meta.ui line and you still have an app, just one without a component. OpenAI keeps fuller examples, in Node and Python, in its apps SDK examples repository.
Set the annotations honestly. readOnlyHint is for tools that cannot change anything, destructiveHint for ones that can do something hard to undo, and openWorldHint for ones that reach the public internet. OpenAI says they guide ChatGPT’s confirmation behaviour but do not replace authorisation or confirmation in your own server. What each MCP building block is for is covered in MCP tools, resources and prompts.
Testing in developer mode
- Run the server locally and exercise every tool with MCP Inspector (
npx @modelcontextprotocol/inspector@latest), including empty results, missing IDs and auth errors. How to use MCP Inspector walks through it. - Give ChatGPT a way in: a public HTTPS tunnel such as ngrok, or OpenAI’s Secure MCP Tunnel for a server you do not want exposed.
- In ChatGPT, turn on developer mode under Settings, Security and login. Availability can depend on your account and workspace policy.
- Open Plugins, choose the plus button, enter the URL including
/mcp, name it and create it. Check the tools ChatGPT discovered. - Start a new chat, add the app from the plus menu, and try direct requests, indirect ones, follow-ups that reuse IDs, writes that need confirmation, and requests that should not call a tool at all.
- After changing tool names, descriptions, schemas or UI, redeploy and choose Refresh on the app’s page, then start a new chat and rerun the affected tests.
Authentication
An app that only reads public data can run anonymously. Anything that touches a user’s own data or acts for them should sign them in, and OpenAI’s authentication guide (opens in a new tab) expects OAuth 2.1 as the MCP authorization specification describes it: your MCP server is the resource server, your identity provider is the authorisation server, and ChatGPT is the client.
- Publish protected resource metadata at
/.well-known/oauth-protected-resource, naming your authorisation servers and scopes. - Let ChatGPT identify itself through a client ID metadata document, dynamic client registration or a client you register in advance, with PKCE.
- Declare each tool’s policy with
securitySchemes:noauthfor anonymous calls,oauth2with the scopes it needs, or both for “works signed out, better signed in”. - Verify the token, its scopes and its audience on every call. The declarations tell ChatGPT when to show its sign-in screen; they do not protect anything.
The same flow, independent of ChatGPT, is in how to add authentication to an MCP server.
Submission and review for the directory
Developer mode is for you and your testers. To appear in the Plugin Directory, OpenAI’s guide to submitting plugins (opens in a new tab) describes a review through its plugin submission portal on the OpenAI Platform.
- Access: the submitter needs the organisation permission the Platform labels Apps Management, set to Write.
- Identity: every public submission uses a verified individual or business identity, matching the listing’s name, website, support contact, privacy policy and terms.
- The server: a stable public HTTPS endpoint, domain verification, accurate tool metadata, and
readOnlyHint,openWorldHintanddestructiveHinton every tool. - Tests: at least five positive and three negative test cases, with demo credentials a reviewer can use without MFA, SMS or email confirmation.
- Review, then publish: approval does not publish the plugin. You choose when, and it then appears in the directory for both ChatGPT and Codex.
- After launch: OpenAI periodically re-reads your tools. New and changed tool definitions go live after automated checks pass; a change to the listing or skills needs a new version and review.
App vs connector vs custom GPT
- A connector is the older name for an app. What people used to call a connector, such as a data source for search and deep research, is now an app that exposes read-only tools. OpenAI’s build guide says an app becomes eligible as a company knowledge source by implementing standard
searchandfetchtools. - An app is your MCP server: live data and actions, optionally with UI, callable from any chat where it is enabled, and from Codex once published.
- A custom GPT is a configured assistant: instructions, knowledge files and custom actions that call outside REST APIs, which users open by name. OpenAI is retiring them. Its guide to moving custom GPTs to plugins (opens in a new tab) says instructions become a skill and knowledge becomes reference files, but custom actions do not transfer and need rebuilding as an app’s actions or a custom MCP server. OpenAI’s help centre gives 11 December 2026 as the standard retirement date.
So if you are choosing today, the answer to “app or custom GPT?” is an app, packaged in a plugin, with a skill for the instructions a GPT used to carry. How a GPT compares with a project is in Claude Projects vs custom GPTs.
Using an existing MCP server instead
You do not need to build an app to use a service that already runs a remote MCP server. fenbs, a small task board, is one: it lives at https://fenbs.ai/api/mcp with OAuth sign-in, so it can be added in developer mode where your plan allows it. ChatGPT then holds your role on the board narrowed by the scopes you tick, and every task it adds, moves or comments on is recorded in History under its own name. If you are building an app of your own, a board is also a practical place to track the tool list, the review test cases and what changed in each version.
Related
Connecting ChatGPT to a board: ChatGPT and fenbs. Building the server itself: how to build an MCP server. The risks to design against: MCP security risks.