-
Notifications
You must be signed in to change notification settings - Fork 477
Description
Description
When migrating from the legacy OpenAI App SDK to the Model Context Protocol (MCP) Apps implementation, there is a significant regression in how UI components handle historical data.
In the legacy App SDK, revisiting a chat session allowed the widget to reliably maintain or re-access tool results. In the new MCP implementation, when a user exits and revisits a chat, the App component re-mounts in its initial state, but the ontoolresult event does not fire for the existing data. This leaves the UI in an empty or "loading" state despite the data existing in the chat history.
Steps to Reproduce
Trigger an MCP App tool call that returns structured data (e.g., a carousel of items).
Observe the App rendering correctly via the ontoolresult handler during the active session.
Navigate away from the chat or refresh the browser.
Return to the same chat session.
Expected Behavior
The App should be able to re-hydrate its state from the existing chat context. This could be achieved by:
The host re-emitting the ontoolresult event for the most recent tool output upon the App mounting.
Providing the historical structuredContent within the app instance or useApp hook during initialization.
Actual Behavior
The App component mounts with its initial React state (isLoaded: false). Although the ontoolresult listener is successfully attached in onAppCreated, it is never triggered for historical data. Consequently, the UI (e.g., the trips state) remains empty, and the carousel fails to render.
Technical Details
SDK: MCP Apps
Context: React implementation using useApp
Regression: This behavior was not present when using the legacy openai.toolInput methods.
Tested on developer's mode, and on published mode
Code Snippet
TypeScript
const { app, error } = useApp({
appInfo: { name: "TripsCarousel", version: "1.0.0" },
capabilities: {},
onAppCreated: (app) => {
// This fires correctly on the initial call,
// but is never invoked when revisiting the chat session.
app.ontoolresult = (result) => {
handleData(result.structuredContent);
};
app.onhostcontextchanged = (ctx) => {
if (ctx.theme) setTheme(ctx.theme);
};
},
});
Old Snippet:
useEffect(() => {
const applyToolOutput = (data?: ToolOutput | null) => {
const directItineraries = data?.foundDirectItinerariesForTrip;
const isArrayReturned = Array.isArray(directItineraries);
setTrips(isArrayReturned ? directItineraries : []);
setResponse(isArrayReturned);
setIsLoaded(true);
};
// Check if data already available
applyToolOutput(window.openai?.toolOutput);
// OpenAI Apps SDK: globals updated event
const onSetGlobals = () => {
const toolOutput = window.openai?.toolOutput;
if (toolOutput) applyToolOutput(toolOutput);
};
window.addEventListener("openai:set_globals", onSetGlobals);
return () => window.removeEventListener("openai:set_globals", onSetGlobals);
}, []);
Comparison
Legacy OpenAI SDK: Correctly persisted and rendered data on revisit.
Claude MCP Apps: Successfully persist/re-render UI across sessions.
OpenAI MCP Apps: Fails to trigger data events for historical tool results.