There isn’t much content out there to help developers build their embedded ChatGPT Apps, so I figured I’d do a quick consolidation & write-up. As far as I’ve seen, this is the extent of the official tooling:
- OpenAI Apps SDK Documentation (launched 10/6) - overall documentation.
- openai/openai-apps-sdk-examples (launched 10/6) - 7 example apps.
- openai/apps-sdk-ui (launched 11/21) - low-level React component library consistent with the design requirements.
- MCP App Extension protocol (launched 11/21) - generic protocol of the ChatGPT App runtime/interface.
I won’t rehash the documentation basics. Instead, I’ll review my biggest takeaways after building a few apps.
Lesson 1: Embrace MCP
The ChatGPT App documentation makes Apps sound like they use MCP, but they’re not MCP themselves. That’s not quite right. Think of these apps as a GUI feature of MCP, and architect your apps entirely according to MCP concepts. Every UI/page is just a Resource and every API is just a Tool. Get comfortable with those abstractions. An App has one or more Resources, a Resource has one or more Tools.
My original toy apps didn’t properly adhere to those boundaries, and I found the abstractions I naturally built broke down when they came in contact with production ChatGPT. It’s a bit easier to recognize the core abstraction now that MCP started adding these interfaces to the protocol, but it’s only been a week and a half since they started, and the interfaces are still highly unstable.
Lesson 2: Invalidate all the caches
When deploying your App to ChatGPT, it can be difficult to tell if your Resource changes have been picked up. To make sure you’re always interacting with the latest version, you have to update the Resource URI on your MCP server AND “Refresh” your App from the ChatGPT Connector modal on every single change. I set up my project to append a base-32 timestamp to Resource URIs on every build so they always cache-bust on the ChatGPT side, but I still always have to refresh the connection on every UI change.
Lesson 3: But Wait! There’s More!
The official OpenAI documentation lists only about 2/3 of the actual runtime API. I’m not God or sama, so I can’t say that these undocumented fields are here to stay, but you can build more functionality than currently explained. Here’s the complete global runtime list that I just queried from my app running in ChatGPT:
- callCompletion: (...i)=> {…}
- callTool: (...i)=> {…}
- displayMode: "inline"
- downloadFile: (...i)=> {…}
- locale: "en-US"
- maxHeight: undefined
- notifyEscapeKey: (...i)=> {…}
- notifyIntrinsicHeight: (...i)=> {…}
- notifyNavigation: (...i)=> {…}
- notifySecurityPolicyViolation: (...i)=> {…}
- openExternal: (...i)=> {…}
- openPromptInput: (...i)=> {…}
- requestCheckout: (...i)=> {…}
- requestClose: (...i)=> {…}
- requestDisplayMode: (...i)=> {…}
- requestLinkToConnector: (...i)=> {…}
- requestModal: (...i)=> {…}
- safeArea: {insets: {…}}
- sendFollowUpMessage: (...i)=> {…}
- sendInstrument: (...i)=> {…}
- setWidgetState: u=> {…}
- streamCompletion: (...l)=> {…}
- subjectId: "v1/…"
- theme: "dark"
- toolInput: {}
- toolOutput: {text: 'Rendered Show a simple counter tool!'}
- toolResponseMetadata: null
- updateWidgetState: (...i)=> {…}
- uploadFile: (...i)=> {…}
- userAgent: {device: {…}, capabilities: {…}}
- view: {params: null, mode: 'inline'}
- widget: {state: {…}, props: {…}, setState: ƒ}
- widgetState: {count: 0}
Be careful with the example apps. They don’t respect all of these platform globals, documented or not. They also still don’t use the apps-sdk-ui React component library (as of this writing), so they’re already pretty outdated.
Hope that was helpful! If you’re interested in playing around with ChatGPT Apps, I built an open-source quickstart & local ChatGPT simulator that I’ve found really helpful for visualizing the runtime & iterating quickly. I hosted it here if you want to play around with it!
Would really appreciate a star if you can spare one!
Top comments (0)