server.ts
Create the Server
McpServer takes your app’s identity and returns a chainable server. Chain every registerTool call, then run():
server.ts
AppType is what makes the generated view hooks type-safe end to end.
Describe It to the Model
server.ts
nameidentifies the tool. Keep it kebab-case and verb-led:search-products,create-checkout.titleis the human-readable display name.descriptionis read to decide when to call the tool.
Type the Contract
Schemas are plain Zod shapes.inputSchema declares what the model must provide. outputSchema is optional and declares the shape of the structured content returned to the model.
server.ts
.describe() on a field is more prompt surface: it tells the model how to fill the argument.
While it’s recommended to provide the output schema, it’s optional and isn’t used for type safety, which is inferred from the handler’s return type.
Write the Handler
The handler receives validated input and returns the tool’s response. Three fields, three audiences:server.ts
content and structuredContent concise, since they’re model context. Use _meta for data the model has no use for or isn’t supposed to know (image URLs, sensitive record fields): the view still accesses it, the model never sees it.
Handlers also receive an extra argument carrying additional data such as auth info or client hints.
Annotate Behavior
Annotations tell the host how cautious to be. They drive confirmation prompts before invocation, and app directories check them at review time:server.ts
readOnlyHint: only reads data, no side effectsdestructiveHint: deletes or overwrites user dataopenWorldHint: publishes content or reaches beyond the user’s account
Be honest with them: hosts trust these hints, and mislabeling a tool (claiming a write is read-only, hiding a destructive action) is a common cause of app directory rejection.
Tune the Host with _meta
Tool-level _meta (distinct from the response _meta above) carries host-specific configuration:
server.ts
Bind a View
Addingview to a tool makes the host mount a React component with the tool’s result. component names a file in views/:
view are headless: data, no UI.
Go Further
Create Views
Craft interactive UIs rendered in conversation
Manage State
Decide what the model sees
Authenticate Users
Know who’s behind every tool call