Build

The Screen as a Resource — a Document the Server Hands Out, Not Code

By makemind · Feb 26, 2026

So far the server answered with values. Now it answers with a screen.

The screen is a file

{ "type": "page", "title": "Desk",
  "content": { "type": "center",
    "child": { "type": "linear", "direction": "vertical", "spacing": 14, "alignment": "center", "children": [
      { "type": "text", "text": "WAITING", "style": { "fontSize": 16, "letterSpacing": 4, "color": "#6b7280" } },
      { "type": "text", "text": "{{waiting}}", "style": { "fontSize": 88, "fontWeight": "bold", "color": "#111827" } },
      { "type": "button", "label": "Admit one", "onTap": { "type": "tool", "tool": "desk.admit", "params": { "count": 1 } } } ] } } }

Six lines. A value lands where {{waiting}} is, and the button calls the tool built in part 3.

The server hands it over

server.addResource(
  uri: 'ui://desk',
  name: 'Desk screen',
  description: 'The desk screen, served as a document',
  mimeType: 'application/json',
  handler: (uri, params) async => ReadResourceResult(contents: [
    ResourceContentInfo(
      uri: 'ui://desk',
      mimeType: 'application/json',
      text: File(_screenPath).readAsStringSync(),
    )
  ]),
);

ResourcesCapability has to be on too.

capabilities: ServerCapabilities(
  tools: ToolsCapability(listChanged: true),
  resources: ResourcesCapability(listChanged: true),
),

Reading it on every request is the point

readAsStringSync() sits inside the handler. Reading once at boot into a variable is obviously faster, and that is not what this does.

Hold it and the server has to restart every time the screen changes. At that moment the claim this piece makes — edit the file, get a different app — becomes false.

/// Read fresh on every request, deliberately. A screen cached at boot is a
/// screen you have to restart the server to change, and then the claim above
/// stops being true.

When performance does become the problem, cache it — but invalidate on file change. Simply holding it is losing the feature.

This content requires Developer or above

Sign in and upgrade your plan to continue reading.

View Plans
Twitter