MCP Apps
    Preparing search index...
    • React hook that keeps a piece of state and saves it with the host, so that it comes back the next time the View is rendered (for example after a reload, or in a reopened conversation).

      It works like useState. The state starts as initial; once app is connected, it becomes the state that the host has saved for this View, if any (viewState in App.getHostContext). Each call of the setter changes the state at once and, after debounceMs without another change, saves it with App.setViewState.

      • No host support: when the host does not advertise the viewState capability, nothing is saved and the hook behaves like plain useState.
      • Failed saves: a save that the host refuses (for example because the state is larger than the host's maxBytes) is reported with console.warn and otherwise ignored; the state on screen is kept, and the next change is saved as usual.
      • Only changes are saved: the initial value and the restored value are not saved by themselves.
      • Changes before app is connected are kept: they win over the state that the host has saved, and are saved once app is connected.
      • Unmount: a save that is still waiting is sent at once when the component unmounts (unless app has been closed), so that the last change is not lost. If the host removes the View before the wait is over, that change is lost.

      One hook per View. A save replaces everything that is saved for the View, so two useViewState hooks on the same app would overwrite each other. Keep all the state to save in one object, in one hook. For the same reason, do not mix this hook with your own calls of App.setViewState.

      Version and check the state. The saved state may have been written by an older version of your View. The hook cannot check it against T: it returns what the host saved as it is. Put a version in the state, and check it before you use the state, as the example below does.

      Type Parameters

      • T extends Record<string, unknown>

        The state: a JSON object. Values that JSON cannot hold (functions, undefined, Date, Map, ...) do not come back as they were. Declare it with type, not interface: TypeScript does not accept an interface as a Record<string, unknown> unless it has an index signature.

      Parameters

      Returns [T, Dispatch<SetStateAction<T>>]

      The current state and a function to change it, as useState does

      type Draft = { version: 1; text: string };
      const EMPTY_DRAFT: Draft = { version: 1, text: "" };

      function MyApp() {
      const { app } = useApp({
      appInfo: { name: "MyApp", version: "1.0.0" },
      capabilities: {},
      });

      const [saved, setDraft] = useViewState<Draft>(app, EMPTY_DRAFT);
      // The saved state may come from an older version of this View
      const draft = saved.version === 1 ? saved : EMPTY_DRAFT;

      return (
      <textarea
      value={draft.text}
      onChange={(e) => setDraft({ ...draft, text: e.target.value })}
      />
      );
      }