carousel mounted by search-products, next to a minimal version of the tools it talks to:
The Component
A view is a.tsx file with a default-exported React component in views/. The binding happens when you register the tool:
server.ts
Read the Tool Call
The host mounts the view as soon as the model calls the tool, often before your handler returns.useToolInfo tracks that lifecycle: status moves from "pending" to "success", with isPending and isSuccess as shortcuts.
views/carousel.tsx
input: the tool call arguments, validatedoutput: the responsestructuredContent, also surfaced to the modelresponseMetadata: the response_meta, not surfaced to the model
Call Tools Back
useCallTool lets the view call any tool on your server without involving the model. It returns the trigger and the mutation state:
views/carousel.tsx
status runs idle, pending, then success (read the result on data) or error.
Tool calls initiated from a view happen outside the conversation: the model sees neither the call nor its result, and no view gets mounted. The response goes to the calling view alone.
Generate Type-Safe Hooks
The hooks above aren’t imported fromskybridge/web directly: they come from helpers.ts, a bridge file that infers every type from your server. Projects scaffolded with npx skybridge create include it out of the box:
helpers.ts
useToolInfo and useCallTool from helpers.ts everywhere, and you get autocomplete on tool names, plus typed inputs, outputs, and metadata on both hooks.
Type-safe hooks are generated using generateHelpers.
Match the Host Styles
A view feels native when it borrows the host’s own look: its palette, typography, and light or dark theme. On the MCP Apps runtime, hosts like Claude can hand your view a set of design tokens for exactly this. Opt in with thehostStyles option on the Vite plugin:
vite.config.ts
- CSS variables on
:root, a standardized set you reference withvar(…), covering colors (--color-background-primary,--color-text-primary,--color-border-primary, andinfo/danger/success/warningvariants), typography (--font-sans,--font-mono,--font-weight-medium,--font-text-md-size…), radii (--border-radius-sm…--border-radius-full), and shadows (--shadow-sm…--shadow-lg). color-schemeon the document, so the host’slight-dark()color values resolve to the right branch and native controls (scrollbars, form fields) match the theme.- Fonts the host ships, injected so
var(--font-sans)renders in the host’s typeface.
views/carousel.tsx
hostStyles is off by default. Turning it on lets the host set those variables on :root and flip color-scheme, restyling your view. Because the variables are applied inline on the document root, a :root { --color-text-primary: … } of your own is overridden by the host’s value; scope your overrides below the root (on a wrapper element) if you need them to win. Opt in once your view is ready to inherit the host’s styling.Open the Sandbox
The iframe ships with a strict Content Security Policy: your server’s domain is allowed automatically, and everything else is blocked. If the view fetches from an external API or loads assets from the outside world, declare the domains on the view config, server side:server.ts
frameDomains (embedded iframes) and redirectDomains (external redirects) follow the same pattern. See Configure CSP for the full walkthrough.
Go Further
Register Tools
Define what humans and agents can do
Manage State
Decide what the model sees
Authenticate Users
Know who’s behind every tool call