The MCP server instance
Tool name/identifier
Tool configuration with _meta field containing UI metadata
Tool handler function
registerAppTool(
server,
"get-weather",
{
title: "Get Weather",
description: "Get current weather for a location",
inputSchema: z.object({ location: z.string() }),
_meta: {
ui: { resourceUri: "ui://weather/view.html" },
},
},
async (args) => {
const weather = await fetchWeather(args.location);
return { content: [{ type: "text", text: JSON.stringify(weather) }] };
},
);
registerAppTool(
server,
"show-cart",
{
description: "Display the user's shopping cart",
_meta: {
ui: {
resourceUri: "ui://shop/cart.html",
visibility: ["model"],
},
},
},
async () => {
const cart = await getCart();
return { content: [{ type: "text", text: JSON.stringify(cart) }] };
},
);
registerAppTool(
server,
"update-quantity",
{
description: "Update item quantity in cart",
inputSchema: z.object({ itemId: z.string(), quantity: z.number() }),
_meta: {
ui: {
resourceUri: "ui://shop/cart.html",
visibility: ["app"],
},
},
},
async ({ itemId, quantity }) => {
const cart = await updateCartItem(itemId, quantity);
return { content: [{ type: "text", text: JSON.stringify(cart) }] };
},
);
registerAppTool(
server,
"show-cart",
{
title: "Shopping Cart",
description: "Display the user's shopping cart",
// Opened with `{}`: no required arguments, and nothing changes
annotations: { readOnlyHint: true },
_meta: {
ui: {
resourceUri: "ui://shop/cart.html",
entrypoints: [{ type: "global" }],
},
},
},
async () => {
const cart = await getCart();
return { content: [{ type: "text", text: JSON.stringify(cart) }] };
},
);
registerAppTool(
server,
"open-spreadsheet",
{
title: "Spreadsheet",
description: "Show a spreadsheet file",
inputSchema: z.object({
// The one file argument, marked for the File Uploads extension.
// The host binds it to the file that the user opened.
file: z
.object({
id: z.string(),
name: z.string().optional(),
mimeType: z.string(),
size: z.number(),
digest: z.object({
algorithm: z.literal("sha-256"),
value: z.string(),
}),
data: z.string().optional(),
})
.meta({ "x-mcp-file": { accept: [".csv", "text/csv"] } }),
}),
annotations: { readOnlyHint: true },
_meta: {
ui: {
resourceUri: "ui://sheets/viewer.html",
entrypoints: [
{ type: "file", extensions: [".csv"], mimeTypes: ["text/csv"] },
],
},
},
},
async ({ file }) => {
// Checks the size and digest, then decodes the bytes
const rows = parseCsv(file);
// The view renders from the result: its tool input may lack the bytes
return {
content: [{ type: "text", text: `Opened ${file.name}` }],
structuredContent: { rows },
};
},
);
registerAppResource to register the HTML resource referenced by the tool
Register an app tool with the MCP server.
This is a convenience wrapper around
server.registerToolthat normalizes UI metadata: if_meta.ui.resourceUriis set, the legacy_meta["ui/resourceUri"]key is also populated (and vice versa) for compatibility with older hosts.