Skip to content
OpenAI Apps SDK commentary: Why ChatGPT apps should design MCP tool contracts, permissions, and UI boundaries before widgets
← Back to blog

OpenAI Apps SDK commentary: Why ChatGPT apps should design MCP tool contracts, permissions, and UI boundaries before widgets

Development·13 min read

From a practical perspective, we summarize why the OpenAI Apps SDK should be designed with an MCP server, tool descriptor, permissions, structuredContent, and iframe UI boundary rather than a ChatGPT widget creation tool.

OpenAI Apps SDK commentary: Why ChatGPT apps should design MCP tool contracts, permissions, and UI boundaries before widgets
The quality of a ChatGPT app is determined by the accuracy of MCP tool contracts, permissions, and UI boundaries rather than the flashiness of widgets.

1. One-line problem definition

Key summary: The essence of Apps SDK is not to put pretty screens in ChatGPT, but to create a contract between tools that models can call and UI that users can trust and operate.

OpenAI Apps SDK is a framework for creating apps that run within ChatGPT. Based on the official documentation, the app consists of tools provided by the MCP server and optionally UI components rendered within a ChatGPT iframe. Therefore, the target audience for this article is developers who want to create ChatGPT apps, in-house business connectors, customer support assistants, and data inquiry/edit assistants.

Scope of application is a product in which the model reads or writes data from an external system and displays the results as a widget in ChatGPT. Conversely, in cases where external tool calls or user interaction UI are not required, such as simple Q&A, document summaries, or internal FAQs, the Apps SDK may be overkill. This article focuses on “what boundaries should be designed before registration to reduce accidents” rather than “how to register an app.”

2. First, conclusion

Key takeaway: Teams that can adopt the Apps SDK right away are those that are ready to take responsibility for MCP tooling contracts, permission validation, and UI state recovery in code.

I think it is better to view the Apps SDK as an “interactive MCP product surface” rather than a “front-end SDK for ChatGPT”. The server declares the tool name, input schema, output schema, read/write hints, authentication scope, and UI resource location. The ChatGPT model looks at this information to determine which tool to call and when. The widget displays the results in a form that the user can manipulate.

The case for recommending the introduction of

is clear. This is a team that already has an API, a per-user permission model, can distinguish between readers and writers, and can leave failure logs. If the data model is still unstable and the goal is “let’s show it like an app on ChatGPT,” it is better to first experiment with only the MCP server and tool schema in a small way. Screens can be added later, but poorly designed tool contracts undermine app review, security, and user trust at the same time.

3. Decomposition of core structure

Key summary: Apps SDK apps are easy to understand by dividing them into five parts: MCP server, tool descriptor, structuredContent, widget iframe, and MCP Apps bridge.

The first layer is the MCP server. The server provides a list of tools and call results through the /mcp endpoint. The official quickstart document explains that an MCP server is required to create a ChatGPT app, and the UI component is optional. This means that “the center of the app is not the screen, but the capabilities provided by the server.”

The second layer is the tool descriptor. This contains the tool name, description, input schema, output schema, authentication information, read/write hints, and UI resource URI. This descriptor is like an instruction manual that the model reads. If the name is ambiguous or the description is exaggerated, the model will call the tool at the wrong moment, and it will be difficult to explain to the user why the permission request is displayed.

The third layer is the tool response. Responses are usually divided into structuredContent, content, and _meta. structuredContent and content should be small and clear so the model can read them. It is important that _meta is used as widget-only data and is not visible to the model. It is safer to place large raw data, internal ID maps, and detailed information for UI rendering here.

The fourth layer is UI resources. ChatGPT implements the MCP Apps UI standard, and widgets run inside an iframe. The fifth layer is the bridge between the iframe and ChatGPT host. The official reference describes JSON-RPC 2.0 over postMessage and ui/* methods/notifications, and tools/call calls in their basic structure. Simply put, the widget looks like a standalone web app, but actually communicates with the ChatGPT host using the promised messaging protocol.

4. Description of design intent

Key takeaway: The reason OpenAI built the Apps SDK on top of the MCP is to avoid forcing app functionality into either the model, server, or UI.

In the traditional plug-in structure, the server API explains everything, and the chatbot often summarizes the API call results in text. The Apps SDK adds a UI layer to this. However, the UI does not take over the server's responsibilities. The server must still check permissions, verify tool calls, run side effects, and leave audit logs.

The advantage of this structure is the separation of roles. The model determines which tools are needed. The server processes the actual data. Widgets provide a screen that can be manipulated. However, there are also costs. Developers must consider API, dialog, iframe UI, MCP bridge, authentication, and screening guidelines simultaneously. So the approach of “just embedding” a simple web app into ChatGPT is risky.

The key design intent I see is reusability. The official reference recommends that ChatGPT implements the MCP Apps standard and uses the MCP Apps standard fields and ui/* bridge by default. This is a signal to stop relying solely on the ChatGPT-specific APIs and to elevate your apps on top of the MCP Apps standard whenever possible. It is operationally advantageous to attach the ChatGPT-only window.openai extension only when you really need special features such as file selection, modals, and payments.

5. Evidence and Comparison

Key summary: Apps SDK's competitors are “generic web apps”, “text-only MCP connectors”, and “in-house chatbot UI”, and the selection criteria is permissions and side effect management rather than UI needs.

ApproachCorrect situationAdvantagesCost/LimitationsJudgment criteria
Apps SDK + MCP UIWhen you need to view, edit, select, or approve screens within a ChatGPT conversationModel call and widget manipulation can be connected in one flowMCP server, UI bridge, CSP, and screening standards must be designedDoes the user have to operate within ChatGPT to reduce work time
Text-only MCP serverRead-centric tools, simple status queries, internal automationSmall implementation and easy verificationComplex selection/comparison/editing UI is inconvenientAre the results sufficient in tables or short summaries
Existing web app + linkWhen there is already a completed screen and login/permission systemUse existing UX, analysis, and distribution system as isDialogue context and tool calls are separatedIs there a weak reason to finish within ChatGPT
Own chatbot UIWhen brand experience, detailed authority flow, and own customer channels are importantDirectly control the entire UI and policiesManage model selection, tool call, user authentication, and UI directlyIs controlling your own channel more important than distributing ChatGPT

There are three important reasons for the official document. First, an MCP server is required for Apps SDK apps and UI is optional. Second, tool responses distinguish between data that the model reads and data that only the widget receives. Third, security documentation repeatedly emphasizes least privilege, explicit consent, server-side input validation, audit logs, and PII redaction. Put these three things together and the conclusion is clear. The quality of an Apps SDK is determined by the accuracy of its tool contracts, not the flashiness of its widgets.

6. Actual operation flow / step-by-step execution method

Key takeaway: Don't build a complete app from scratch, it's safer to verify the contract with one reader and at least one widget, then add the writing tool in that order.

  1. Choose one business intent Start with a reading tool, for example list_customer_tickets. Avoid big names like “Total Customer Support Management”
  2. Narrow down the input schema. Only accept fields needed for actual processing, such as customer_id, status, limit. We do not receive full conversation history, free-form context, or unnecessary location information.
  3. Fix the output schema first.Keep structuredContent small for widgets and models to read together. Example: Summary of 5 tickets, status, last update time.
  4. Widget-specific detailed data is separated by _meta. Internal ID maps, pagination cursors, and the entire array for UI rendering do not need to be shown to the model.
  5. Versions the UI resource URI. As the documentation recommends, if there is a breaking change, write a new URI like ui://widget/tickets-v2.html. The URI is effectively a cache key:
  6. Call first with MCP Inspector Before connecting to ChatGPT, check tool list, schema, and response as npx @modelcontextprotocol/inspector@latest --server-url localhost:8787/mcp --transport http. When actually running, add the necessary protocol in front of the server URL.
  7. Attach the connector in Developer Mode. If local, create an HTTPS MCP URL through a tunnel such as ngrok, and register the connector in ChatGPT settings.
  8. Writing tools are added last. Tools that change external states, such as update_ticket_status, are released after adding approval, idempotency key, audit log, and rollback policy.
registerAppTool(server, "list_customer_tickets", {
  title: "List customer tickets",
  description: "Returns recent support tickets for a customer without modifying them.",
  inputSchema: { customerId: z.string(), limit: z.number().min(1).max(10) },
  outputSchema: {
    tickets: z.array(z.object({
      id: z.string(),
      title: z.string(),
      status: z.string(),
      updatedAt: z.string()
    }))
  },
  annotations: {
    readOnlyHint: true,
    destructiveHint: false,
    openWorldHint: false
  },
  _meta: { ui: { resourceUri: "ui://widget/tickets-v1.html" } }
}, async ({ customerId, limit }) => {
  const rows = await db.tickets.list({ customerId, limit });
  return {
    structuredContent: {
      tickets: rows.map(({ id, title, status, updatedAt }) => ({ id, title, status, updatedAt }))
    },
    content: [{ type: "text", text: `Found ${rows.length} recent tickets.` }],
    _meta: { rowsById: Object.fromEntries(rows.map((row) => [row.id, row])) }
  };
});

7. Mistake/Trap

Key summary: Most common problems in Apps SDK are caused by trusting the model too much, trusting the widget too much, or using descriptors roughly.

Pitfall 1: When the description is written like a marketing phrase

Putting phrases like “best”, “use unconditionally”, or “in all situations” in the tool description will distort model selection and put you at a disadvantage in evaluation. A precaution is to write only the verb form of the name and the actual action. Recovery is simple. For each tool, rewrite “what to read/what to change/when not to use” in one sentence.

Plot 2: Putting too much data in structuredContent

Putting original records, personal information, internal tokens, and long HTML in the area read by the model increases both cost and security risk. A precaution is to place only the summary the model needs to make decisions in structuredContent, and place detailed data for widget rendering in _meta. If they are already mixed, divide the response objects into three groups: “For Model/For Widget/For Log”.

Pit 3: Not making your writing tool retry-safe

The official documentation says to design the handler to be idempotent since the model may retry the tool call. Tools such as creating an order, sending a message, or generating a payment link are retried and run redundantly, resulting in user harm. Preventive measures include idempotency key, server-side duplicate detection, explicit authorization, and post-execution status query.

Trap 4: When widget iframe security is mistaken for a regular web app

The widget runs in a sandboxed iframe and is subject to CSP constraints. If you expect some privileged browser APIs, such as clipboard, prompt, and confirm, they may not work. A preventative measure is to declare only the connect/resource/frame domain required in the official CSP metadata, and use the supported host API feature-detect for external links or file processing.

8. Strengths and Limitations

Key takeaway: The strength of the Apps SDK is that it combines conversation and operational UI, but the limitation is that app quality responsibility is shifted to the developer server, not ChatGPT.

The strengths are clear. Users can interact with ChatGPT and manipulate tables, cards, forms, and lists on the same screen. The model reads and describes the tool results, and the widgets take on the complex selection and modification tasks. It is especially well suited to tasks that require a combination of conversation and structured UI, such as customer support, reservations, in-house operations, data inquiry, and catalog navigation.

The limits are also clear. The Apps SDK does not automatically resolve permission issues. The security documentation says servers should validate all input, check token scope on each call, clear PII from logs, and honor deletion requests. In other words, the attitude is not “It must be safe because it runs inside ChatGPT,” but the attitude is “Even if ChatGPT calls, our server is the last line of defense.”

Another limitation is review and distribution costs. App name, description, tool annotation, minimum input, side effect description, and authentication flow are all subject to review. If it is an internal experiment connector, you can run it quickly, but if you are aiming for public distribution, you need to prepare product documentation, privacy policy, test account, and error handling.

9. Points to study more deeply

Key summary: The least confusing learning order is Apps SDK Quickstart, MCP server guide, Reference, Security & Privacy, Submission guidelines.

10. Action Checklist + Author's Perspective

Key summary: I judge the introduction of Apps SDK not by “can I create a screen” but by “can I operate the tool call in an auditable manner?”

  • Is the first tool in the app linked to a single, clear user intent?
  • Are reading and writing tools clearly distinguished in name, description, and annotation?
  • Does
  • structuredContent contain only the minimum data that the model can read?
  • Widget-specific detailed data is in _meta and does not include tokens or secret values?
  • Does the writing tool have an idempotency key, approval flow, audit log, and failure recovery criteria?
  • Are OAuth scope and server-side authorization verification applied to each tool call?
  • Is the connect/resource/frame domain of the widget CSP limited to the necessary range?
  • Have you tested for representative input, empty input, unauthorized input, and network failure in MCP Inspector and ChatGPT Developer Mode?
  • If it is for public distribution, are you prepared to respond to app name, description, screenshots, test account, privacy policy, and submission guidelines?

Definition of Done: If one reader tool and one writer tool pass with the same schema in MCP Inspector and ChatGPT Developer Mode, and the author/duplicate prevention/audit log of the writer tool is confirmed to be a real server log, it is ready for the first internal beta. View.

My recommendation is step by step. In week 1, we verify descriptors and permissions using the text-only MCP tool. In week 2, we attach a minimum widget to verify the separation of structuredContent and _meta. Only in the third week will writing tools be attached. The Apps SDK can create demos quickly, but long-lasting apps have a solid tool contract before widgets.

Share this article

Related articles

Take the AQ test

See your AI capability in three minutes. Assess recognition, utilization, verification, integration, and ethics at once, then receive practical insights.

Start the free AQ test