Bug Report: ChatGPT strips _meta from tool results and breaks MCP Apps viewUUID state persistence pattern

We migrated our ChatGPT App from the OpenAI Apps SDK to the MCP Apps standard, following the MCP Apps compatibility guide. The migration went fine. Tools, resources, ontoolresult, callServerTool, sendMessage, and app-only tool visibility all work correctly.

However, when implementing the documented viewUUID pattern for persisting view state, we discovered that ChatGPT strips _meta from tool results before forwarding them to the widget.

Steps to reproduce

  1. Server returns _meta: { viewUUID: crypto.randomUUID() } in a tool’s CallToolResult
  2. Widget reads result._meta in the ontoolresult callback
  3. result._meta is undefined

Expected

result._meta should be forwarded to the widget as part of ui/notifications/tool-result, per the MCP Apps spec (McpUiToolResultNotification.params is CallToolResult, which extends ResultSchema containing _meta).

Actual

result._meta is undefined. The viewUUID never reaches the widget, so localStorage-based state persistence cannot work.

Code

Server (tool handler):

return {
  content: [{ text: "...", type: "text" }],
  structuredContent: { /* ... */ },
  _meta: { viewUUID: crypto.randomUUID() },
};

Client (widget):

  app.ontoolresult = (result) => {
    console.log("_meta:", result._meta);       // undefined
    console.log("viewUUID:", result._meta?.viewUUID); // undefined
  };

Logs

  [App] ontoolresult _meta: undefined
  [App] viewUUID: undefined

This is the only MCP Apps pattern we’ve found that doesn’t work in ChatGPT. Everything else from the migration guide works as expected.

Update: This pattern works correctly in Claude — result._meta.viewUUID is forwarded as expected. The issue is specific to ChatGPT’s host implementation.

We could just pass the viewUUID in structuredContent, but I wonder if it’s a bug or if _meta from tool results is not meant to be used? @coreyching @OpenAI_Support