Lesson 2 of 3 · Building ChatGPT Apps
Anatomy of a ChatGPT App
Every ChatGPT App is made of two layers: the MCP Server (mandatory) and the Web Widget (optional). Understanding how these layers communicate -- and what each is responsible for -- is the foundation for everything else in this course.
The MCP Server Layer
Your MCP server is the brain of your app. It defines:
- Tools: Functions the model can call. Each tool has a name, description, input schema, and handler.
- Resources: Data the model can read. Think of these as read-only endpoints -- configuration files, documentation, knowledge bases.
- Prompts: Pre-written templates the model can use. Useful for complex workflows with specific output formats.
For most ChatGPT Apps, you will primarily use tools. Resources and prompts are useful for advanced scenarios.
The Single Endpoint
Unlike traditional REST APIs with multiple routes, an MCP server exposes a single endpoint: /mcp. All communication flows through this endpoint using JSON-RPC 2.0:
JSON-RPC is a lightweight remote procedure call protocol. The key concepts: every request has a method and params. Every response has a result or error. The id field correlates requests with responses. It is simpler than REST (no URL routing, no HTTP method semantics) and well-suited for tool-style interactions.
The MCP Apps Bridge
ChatGPT does not connect to your MCP server using the standard MCP transport (stdio or SSE). Instead, it uses the MCP Apps Bridge -- a server-sent events (SSE) transport optimized for the ChatGPT environment.
The bridge handles:
- Connection management (keep-alive, reconnection)
- Authentication token injection
- Rate limiting and abuse prevention
- Message routing between the model and your server
You do not need to implement the bridge yourself. The @modelcontextprotocol/sdk handles it when you configure the transport as sse.
The Web Widget Layer
The widget is an HTML page rendered in a sandboxed iframe inside the ChatGPT interface. It communicates with ChatGPT through the window.openai API -- a JavaScript bridge injected into the iframe.
The widget can:
- Call your MCP tools through
window.openai.callTool() - Send follow-up messages to the conversation through
window.openai.sendFollowUpMessage() - Upload files through
window.openai.uploadFile() - Request different display sizes through
window.openai.requestDisplayMode() - Share state with the model through
window.openai.setWidgetState()
This is the most common mistake new developers make. The widget iframe is sandboxed. It cannot make fetch calls to your server. All communication goes through the window.openai bridge, which routes tool calls through ChatGPT to your MCP server. This is a security boundary, not a bug.
Component Types
ChatGPT can render tool responses as rich UI components without any widget code. These components are defined by the _meta field in your tool response:
| Component | Use Case | Best For |
|---|---|---|
| List | Ordered collections with titles and descriptions | Search results, task lists, playlists |
| Map | Geographic data with markers and routes | Location search, delivery tracking, travel |
| Album | Image galleries with captions | Product photos, portfolio, media |
| Carousel | Horizontal scrolling cards | Product browsing, recommendations |
| Shop | Product cards with prices and buy buttons | E-commerce, marketplace |
| Chart | Data visualization | Analytics, dashboards, reports |
Using components, you can build a rich, interactive app without writing any frontend code. The model calls your tools, your tools return structured data with component hints, and ChatGPT renders them beautifully.
Example: A Product Search Tool Response
ChatGPT renders this as a styled product card with image, price, and a buy button -- no HTML or CSS required from you.
When You Need a Widget vs When You Don't
This is the most important architectural decision you will make:
Start without a widget. Use MCP tools + component types. Build a widget only when you need interaction that components cannot express: custom forms, drag-and-drop, real-time updates, complex visualizations, or multi-step workflows.
Build a widget from day one because it feels more like 'real development.' Many successful ChatGPT Apps use only MCP tools with component responses. The widget adds complexity -- both in code and in the review process for App Store submission.
Architecture Decision:
- Take the app idea from the previous lesson
- List every piece of data the model would need to see (tool response content)
- For each data type, decide: can a built-in component (List, Map, Shop, Chart, Album, Carousel) render it well enough?
- List any interactions that cannot be expressed through components alone
- Make your decision: tools-only or tools + widget? Write one paragraph justifying the choice.
Use ← → to navigate, Space to mark complete