Robutler

host.ui

Shipping soon, expanding. The external MCP-apps bridge is implemented and you can use it; the surface is still growing. See What's ready.

host.ui is the App SDK's MCP Apps UI bridge. It mirrors the MCP Apps ui/* interface (SEP-1865) so a bundle authored for an external MCP host (Claude, ChatGPT, MCP-UI) works inside Robutler unchanged. If you write a UI app to the MCP Apps spec, host.ui adapts those ui/* calls onto the Robutler runtime; if you target Robutler directly, you would normally use the dedicated namespaces (host.kv, host.commands, and so on) instead.

API

interface UiNamespace {
  bridge: UiBridge;
  App: typeof UiApp;
}

interface UiBridge {
  initialize(): Promise<{ hostContext: Record<string, unknown> }>;
  callTool(name: string, args?: unknown): Promise<unknown>;
  onToolResult(cb: (result: unknown) => void): () => void;
  requestDisplayMode(mode: 'inline' | 'pip' | 'fullscreen'): Promise<unknown>;
  openLink(url: string): Promise<unknown>;
  notifySizeChanged(size: { width: number; height: number }): Promise<void>;
  message(msg: unknown): Promise<unknown>;
  updateModelContext(ctx: Record<string, unknown>): Promise<void>;
  on(method: string, cb: (params: unknown) => void): () => void;
}

The UiApp class is a small convenience wrapper over bridge:

class UiApp {
  connect(): Promise<{ hostContext: Record<string, unknown> }>;
  callTool(name: string, args?: unknown): Promise<unknown>;
  onToolResult(cb: (result: unknown) => void): void;
  requestDisplayMode(mode: 'inline' | 'pip' | 'fullscreen'): Promise<unknown>;
}

Use it

const app = new host.ui.App();
const { hostContext } = await app.connect();

app.onToolResult((result) => render(result));

const out = await app.callTool('search', { query: hostContext.query });
await app.requestDisplayMode('fullscreen');

Or drive the bridge directly:

const bridge = host.ui.bridge;
await bridge.initialize();

const off = bridge.on('ui/render', (params) => render(params));
await bridge.callTool('lookup', { id });
await bridge.notifySizeChanged({ width: 640, height: 480 });

When to reach for it

  • You have an existing MCP Apps UI bundle and want it to run in Robutler without a rewrite.
  • You are building one app to ship to several MCP hosts and want a single code path.

For an app built only for Robutler, prefer the native namespaces; they expose more of the platform than the ui/* subset.

On this page