There is a bit of a conundrum here. I’m trying to manage my apps state lifecycle across multiple instances and refreshes.
-
toolOutputis whatever the last MCP response was for this App instance (but sometimes it isn’t, after a refresh its the originaltoolOutputthat made the instance) -
widgetStateis something you set, it allows you to persist changes in its view across refreshes and instances.
In my app, currently I have it so we load from widgetState but whenever toolOutput changes we overwrite widgetState to persist it (a new MCP response came in because the user interacted or the initial response that created the instance came in). So whenever widgetState changes, the user sees that in the app instance basically.
User asks ChatGPT to draft a study:
-
widgetStatedoes not exist -
toolOutputdelivers the study -
we set
widgetState
User asks ChatGPT to edit the study:
-
we immediately close the old one instance
-
ChatGPT opens a new instance of our App
-
widgetStateexists so we render that while we wait fortoolOutput -
toolOutputcomes back with edit and then we updatewidgetSate
User deletes a step in the study with the button:
-
we optimistically update
widgetState -
new
toolOutputarrives -
we update
widgetState
Everything is correct until here. But then the user refreshes the window.
-
widgetStateexists and we load -
toolOutputexists too BUT it contains the originaltoolOutputfrom the edit (this is a quirk of how ChatGPT apps work) -
we overwrite
widgetStatewith the oldtoolOutput
User loses their delete on refresh (the step is actually deleted but in ChatGPT it looks like it isn’t)
Because of the fact that ChatGPT changes the definition of toolOutput on refresh, you have no way of knowing if toolOutput is newer or older without building in something like timestamping (which comes with its own issues) into your MCP output to handle this.
Anyone else found a more elegant solution?