Skip to content

Bindings

How a GistUI program travels - over HTTP and SSE streams, inside MCP resources and tool results, in AG-UI events - and how it maps to A2UI.

Updated View as Markdown

GistUI Format says what a program means. A binding says how one travels. The bindings are drafts and non-normative; the texts are in spec/bindings/.

HTTP and SSE streams

The simplest binding, and the one the library uses.

  • A plain text response. The body is the program, Content-Type: text/vnd.gistui; charset=utf-8 (or text/plain until the type is registered), sent in chunks as the model produces it.
  • Server-sent events. A provider’s own SSE format (OpenAI, Anthropic, the AI SDK’s UI message stream) carries the program as its text deltas. The client, or your server, concatenates them.
  • Inline mode. The text is Markdown chat with programs in gistui fences.
// Server: any provider's events to text
return new Response(toReadable(textDeltas(res, "openai")));
// Client: the body is the program
<GistUI library={ui} stream={res.body} />

MCP

Three ways to use GistUI with the Model Context Protocol.

A program as a resource

{
  "contents": [
    { "uri": "gistui://reports/q3", "mimeType": "text/vnd.gistui", "text": "root = Page(…)\n…" }
  ]
}

A program as a tool result

A tool returns a program as an embedded resource next to a plain-text fallback, so a host that does not know GistUI still has something to show.

{
  "content": [
    { "type": "text", "text": "Q3 revenue was $1.2M, up 8%." },
    { "type": "resource",
      "resource": { "uri": "gistui://result/1", "mimeType": "text/vnd.gistui", "text": "root = Page(…)\n…" } }
  ]
}

A GistUI view as an MCP App

The MCP Apps extension lets a server ship an HTML view that the host shows in a sandboxed iframe. A GistUI renderer fits in such a view, and the host needs no GistUI support. This is the most practical MCP binding today.

MCP tools as GistUI tools

In the other direction, an MCP client can be the tools of a renderer: any object with callTool({ name, arguments }) works. Keep the read/write split: only tools without side effects belong under tools.

AG-UI

AG-UI carries an agent’s text as TEXT_MESSAGE_CONTENT events. The program is the text of a message.

return new Response(toReadable(textDeltas(res, "agui")));

A person’s action goes back as the next user message, marked as coming from the UI. See AG-UI agents.

A2UI

A2UI and GistUI both keep components in a flat, id-addressed set that can be filled in any order, so a static mapping is direct.

GistUI Format A2UI 0.9.1
What the model writes line-based text JSON messages
Units statements with ids; nested calls allowed a flat list of components with ids
Root the statement root the component with id root
Component set a catalog manifest a catalog named by catalogId
Data tables, inlined into props a data model per surface, bound by path
State and logic client-side state and expressions data model updates from the agent; client functions
Updates later statements replace earlier ones updateComponents, updateDataModel
User input action envelopes action messages to the agent

Compiling a tree to A2UI: createSurface, then updateComponents with one entry per node (the node id, the mapped component name, converted props, child ids). Tables go into the data model with updateDataModel, and the component binds to that path.

What does not map statically: runtime expressions and @each need either the compiler’s own GistUI runtime or a mapping to A2UI bindings for the simple cases; @set and @run need a runtime or A2UI client functions; diagnostics have no A2UI counterpart.

So a GistUI program can be shown by an A2UI renderer, and an A2UI catalog can be used from GistUI, with documented losses on both sides.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close