Core Concepts
Tools
Define a tool, return data, and test it in the preview.
A tool is a server function exposed to the model through MCP.
Create a tool folder
Add a tool folder under src/tools/ (see Project structure). Each folder needs tool.ts; add view.tsx beside it for a View.
Define the tool
import { z } from "zod";
import { defineTool } from "bitmcp";
export default defineTool({
description: "Get a forecast and show an interactive chart",
input: z.object({ city: z.string() }),
output: z.object({
city: z.string(),
summary: z.string(),
points: z.array(z.object({ t: z.string(), temp: z.number() })),
}),
async execute({ city }) {
return {
city,
summary: `Mild in ${city}`,
points: [
{ t: "Mon", temp: 68 },
{ t: "Tue", temp: 72 },
{ t: "Wed", temp: 70 },
],
};
},
});For a read-only list tool, the same pattern applies:
import { z } from "zod";
import { defineTool } from "bitmcp";
export default defineTool({
description: "Get recent blog posts",
input: z.object({ tag: z.string().optional() }),
output: z.object({
posts: z.array(
z.object({
id: z.string(),
title: z.string(),
excerpt: z.string(),
}),
),
}),
async execute({ tag }) {
const posts = await fetchPosts(tag);
return { posts };
},
});Return data
Returning an object produces structuredContent for the View and text for every host.
Custom text:
import { result } from "bitmcp";
return result(data, `Forecast for ${city}: ${data.summary}`);Test in preview
pnpm devCall the tool from the local preview or an MCP client. Confirm you receive text and structured content.
Reference
Schemas
inputvalidates tool arguments (Zod or Standard Schema)outputvalidates the return value and types the View result
CSP allowlists
Default CSP is deny-all for iframe network access.
connect—connect-srcallowlist for fetch from the Viewresources— asset src allowlist for CDN scripts or styles
defineTool({
connect: ["https://api.example.com"],
// ...
});Visibility and scopes
Defaults to ["model", "app"]. Use Actions for app-only tools.
requiredScopes gates a tool behind OAuth scopes. See Supabase and other auth pages.
Rules
executeruns on the server only- Text is always produced
- Presence of
view.tsxattaches UI. Do not setresourceUrimanually executemust not returnundefinedconfirmsetsdestructiveHint: trueunless you overrideannotations. See Confirmations
defineTool options
| Field | Description |
|---|---|
description | Required. Shown in tools/list |
input | Argument schema |
output | Return schema and View typing |
execute | Server handler |
connect | CSP connect-src allowlist |
resources | CSP asset allowlist |
visibility | ["model", "app"] default |
requiredScopes | OAuth scopes required to call the tool |
annotations | MCP tool hints (readOnlyHint, destructiveHint, etc.) |
confirm | MRTR gate before execute. See Confirmations |
ToolContext
| Field | Description |
|---|---|
ask(schema, message?) | MRTR continuation inside execute |
inputRequired(spec) | Raw MRTR escape hatch |
inputResponses | Answers from a prior ask |
handle() | Mint opaque handle id |
user | Authenticated user when OAuth is enabled |
request | Incoming HTTP request or stdio envelope |
Result helpers
result(data, text): Result<T>
isResult(value): booleanMRTR flow: Connecting.