Skip to main content
Tools are the executable actions an MCP server exposes to clients and models. You register a tool with server.tool(), passing a ToolDefinition (name, optional Zod schema, optional outputSchema, annotations, and widget config) plus a ToolCallback that runs when the tool is invoked. This page documents the registration method and the related types: ToolDefinition, ToolCallback, ToolAnnotations, InputDefinition, and the per-tool widget config.

Methods

Registers a tool on the server and returns the server instance for chaining.
import { MCPServer } from "mcp-use/server"

tool

Registers a tool that MCP clients and models can invoke to perform actions such as reading files, calling APIs, running commands, or rendering widgets. Each tool has a name, an optional input schema, an optional output schema, and a callback. The callback may be supplied either as the cb field inside the definition or as the second callback argument. When both are present, the second argument wins (callback || toolDefinition.cb). If neither is supplied, the tool is still registered with the MCP SDK but without a handler. Calling tool() again with the same name re-registers (overwrites) that tool, which is how hot module reloading updates a tool during mcp-use dev. The input type passed to the callback is inferred from the definition’s schema via InferToolInput, and the structured output type is inferred from outputSchema via InferToolOutput, so destructured parameters and structuredContent are fully typed. The HasOAuth type parameter on the server controls whether ctx.auth is available in the callback. If the definition includes a widget config, tool() automatically attaches widget metadata (for example openai/outputTemplate, openai/toolInvocation/invoking, openai/toolInvocation/invoked, openai/widgetAccessible, and openai/resultCanProduceWidget) to the tool’s _meta, and wraps the callback so an empty text content entry is backfilled with Displaying {widgetName}. See the per-tool widget config below for defaults.
import { MCPServer, text } from "mcp-use/server"
import { z } from "zod"

const server = new MCPServer({
  name: "simple-example-server",
  version: "1.0.0",
  description: "A simple MCP server example",
})

server.tool(
  {
    name: "hello-world",
    description: "A simple tool that returns hello world",
  },
  async () => text("Hello World!"),
)
Type Parameters
T
ToolDefinition<any, any, HasOAuth>
The tool definition type. Its schema and outputSchema drive input/output inference for the callback.
Parameters
toolDefinition
T & ToolDefinition<any, any, HasOAuth>
required
The tool configuration object. See ToolDefinition for every field.
callback
ToolCallback<InferToolInput<T>, InferToolOutput<T>, HasOAuth>
Optional handler invoked when the tool is called. Alternative to toolDefinition.cb; if provided it takes precedence over cb.
Returns
returns
this
The server instance, enabling method chaining.
Signature
public tool: <T extends ToolDefinition<any, any, HasOAuth>>(toolDefinition: T & ToolDefinition<any, any, HasOAuth>, callback?: ToolCallback<InferToolInput<T>, InferToolOutput<T>, HasOAuth>) => this

Types

ToolDefinition

Describes a single tool: its identity, schemas, callback, annotations, metadata, and optional widget config. This is the object passed as the first argument to server.tool(). Both schema and outputSchema are Zod schemas, and the type parameters TInput, TOutput, and HasOAuth flow into the cb callback so its parameters and structured output are typed.
import type { ToolDefinition } from "mcp-use/server"
Fields
name
string
required
Unique identifier for the tool. Must match the name passed to useCallTool("name") in widget components. Example: "search-products".
title
string
Human-readable title displayed in clients and the inspector. If omitted, name is used.
description
string
LLM-facing description of what the tool does. Helps the model decide when to invoke it.
inputs
InputDefinition[]
Deprecated. Legacy input parameter definitions. Use schema instead.
schema
z.ZodTypeAny
Zod schema for input validation. Use .describe() on each field for model hints. Preferred over inputs for type safety.
outputSchema
z.ZodTypeAny
Zod schema for structured output. Enables output type inference in useCallTool(); types are generated to .mcp-use/tool-registry.d.ts when running mcp-use dev.
cb
ToolCallback<TInput, TOutput, HasOAuth>
Async callback that executes the tool. May be omitted here and passed as the second argument to server.tool() instead.
annotations
ToolAnnotations
Behavior hints for clients (read-only, destructive, etc.). See ToolAnnotations.
_meta
Record<string, unknown>
Arbitrary metadata for the tool. When a widget config is present, server.tool() augments this with widget-related keys.
widget
ToolWidgetConfig
Configuration for tools that return a widget via the widget() helper. Sets up widget metadata at registration time. See the per-tool widget config below.
Signature
interface ToolDefinition<TInput = Record<string, any>, TOutput extends Record<string, unknown> = Record<string, unknown>, HasOAuth extends boolean = false> {
  name: string
  title?: string
  description?: string
  inputs?: InputDefinition[]
  schema?: z.ZodTypeAny
  outputSchema?: z.ZodTypeAny
  cb?: ToolCallback<TInput, TOutput, HasOAuth>
  annotations?: ToolAnnotations
  _meta?: Record<string, unknown>
  widget?: ToolWidgetConfig
}
A definition using schema, outputSchema, and annotations together (lifted from the everything example):
import { object, error } from "mcp-use/server"
import { z } from "zod"

server.tool(
  {
    name: "calculate-stats",
    description: "Calculate statistics with validated output structure",
    schema: z.object({
      numbers: z.array(z.number()).min(1).describe("Numbers to analyze"),
    }),
    outputSchema: z.object({
      count: z.number(),
      sum: z.number(),
      mean: z.number(),
      min: z.number(),
      max: z.number(),
    }),
  },
  async ({ numbers }) => {
    if (numbers.length === 0) {
      return error("Cannot calculate statistics on empty array")
    }
    const sorted = [...numbers].sort((a, b) => a - b)
    const sum = numbers.reduce((a, b) => a + b, 0)
    return object({
      count: numbers.length,
      sum,
      mean: sum / numbers.length,
      min: sorted[0],
      max: sorted[sorted.length - 1],
    })
  },
)

ToolCallback

The async handler that runs when a tool is invoked. It receives the validated input parameters as its first argument and an enhanced context object as its second, and must resolve to a tool result. The result may be a TypedCallToolResult<TOutput> (produced by helpers like object() when outputSchema is set) or a plain CallToolResult (produced by helpers like text(), markdown(), mix(), error()), since the SDK validates structuredContent at runtime only when present. The context exposes LLM sampling via ctx.sample(), progress reporting via ctx.reportProgress(), elicitation via ctx.elicit(), authentication info via ctx.auth (when OAuth is configured, gated by the HasOAuth type parameter), the HTTP request via ctx.req, and all other Hono Context properties. The type is defined through a method-signature helper to enable bivariant parameter checking, which lets callbacks destructure optional fields without explicitly marking them optional.
import type { ToolCallback } from "mcp-use/server"
Type Parameters
TInput
Record<string, any>
default:"Record<string, any>"
Input parameters type, normally inferred from the definition’s schema.
TOutput
Record<string, unknown>
default:"Record<string, unknown>"
Output type that constrains structuredContent when outputSchema is defined.
HasOAuth
boolean
default:"false"
Whether OAuth is configured, which controls availability of ctx.auth.
Parameters (of the callback)
params
TInput
required
The validated tool input.
ctx
EnhancedToolContext<HasOAuth>
required
The enhanced context combining ToolContext (sampling, progress, elicitation) with the Hono request context.
Returns
returns
Promise<TypedCallToolResult<TOutput> | CallToolResult>
The tool result, typically built with a response helper from mcp-use/server.
Signature
type ToolCallback<TInput = Record<string, any>, TOutput extends Record<string, unknown> = Record<string, unknown>, HasOAuth extends boolean = false> = (params: TInput, ctx: EnhancedToolContext<HasOAuth>) => Promise<TypedCallToolResult<TOutput> | CallToolResult>

ToolAnnotations

Behavior hints that describe a tool to clients so they can decide how to present or guard it (for example, marking a tool read-only or warning before a destructive call). ToolAnnotations is re-exported from @modelcontextprotocol/sdk/types.js for convenience and assigned to ToolDefinition.annotations. All fields are optional and act as hints only; they do not change server-side behavior.
import type { ToolAnnotations } from "mcp-use/server"
Fields
title
string
Human-readable title for the tool, for display purposes.
readOnlyHint
boolean
If true, the tool does not modify its environment.
destructiveHint
boolean
If true, the tool may perform destructive updates (only meaningful when readOnlyHint is false).
idempotentHint
boolean
If true, repeated calls with the same arguments have no additional effect (only meaningful when readOnlyHint is false).
openWorldHint
boolean
If true, the tool may interact with an open, external set of entities (for example, the web).
Usage (lifted from the everything example):
import { error, text } from "mcp-use/server"
import { z } from "zod"

server.tool(
  {
    name: "delete-item",
    description: "Delete an item permanently",
    schema: z.object({
      itemId: z.string().describe("Item ID to delete"),
    }),
    annotations: {
      destructiveHint: true,
      readOnlyHint: false,
      openWorldHint: false,
    },
  },
  async ({ itemId }) => {
    if (!items.has(itemId)) {
      return error(`Item not found: ${itemId}`)
    }
    const item = items.get(itemId)
    items.delete(itemId)
    return text(`Deleted: ${item?.name}`)
  },
)

InputDefinition

A single legacy input parameter definition, used by ToolDefinition.inputs (and by prompt args). It predates Zod schema support. Prefer a Zod schema with .describe() on the ToolDefinition instead, which gives full type inference and richer model guidance. InputDefinition remains available for cases that build parameter lists dynamically.
import type { InputDefinition } from "mcp-use/server"
Fields
name
string
required
Parameter name (camelCase or kebab-case). Example: "maxResults".
type
"string" | "number" | "boolean" | "object" | "array"
required
Parameter type.
description
string
Human-readable description that helps the model understand the parameter.
required
boolean
Whether the parameter is required. Defaults to false.
default
unknown
Default value used when the parameter is omitted. Example: 10.
Signature
interface InputDefinition {
  name: string
  type: "string" | "number" | "boolean" | "object" | "array"
  description?: string
  required?: boolean
  default?: unknown
}

ToolWidgetConfig

The per-tool widget configuration, set as the widget field of a ToolDefinition. It configures the metadata the server emits so a tool’s result renders as a widget in the inspector and in clients such as ChatGPT. When this config is present and has a name, server.tool() resolves the widget output template (ui://widget/{name}.html, with the server build id appended when set), attaches widget keys to the tool’s _meta, and wraps the callback to backfill an empty text content entry.
import type { ToolDefinition } from "mcp-use/server"
// The widget field type is ToolDefinition["widget"].
This shape is the type of ToolDefinition.widget. A separate exported WidgetConfig type exists in mcp-use/server, but that one describes a discovered widget directory (its name, path, manifest, and component) and is not the per-tool config used here.
Fields
name
string
required
Widget name. Must match a file in resources/ (for example resources/weather-display.tsx). Example: "weather-display".
invoking
string
default:"\"Loading {name}...\""
Status text shown while the tool is running. Defaults to Loading {name}... when omitted.
invoked
string
default:"\"{name} ready\""
Status text shown after the tool completes. Defaults to {name} ready when omitted.
widgetAccessible
boolean
default:"true"
Whether the widget can initiate tool calls (for example via useCallTool). Defaults to true.
resultCanProduceWidget
boolean
default:"true"
Whether this tool result can produce a widget. Defaults to true.
Signature
interface ToolWidgetConfig {
  name: string
  invoking?: string
  invoked?: string
  widgetAccessible?: boolean
  resultCanProduceWidget?: boolean
}
Usage (lifted from the everything example):
import { widget, text } from "mcp-use/server"
import { z } from "zod"

server.tool(
  {
    name: "browse-items",
    description: "Browse items with a visual widget interface",
    schema: z.object({
      query: z.string().optional().describe("Optional search query"),
    }),
    widget: {
      name: "everything-widget",
      invoking: "Loading items...",
      invoked: "Items loaded",
    },
  },
  async ({ query }) => {
    let results = Array.from(items.values())
    if (query) {
      const q = query.toLowerCase()
      results = results.filter((i) => i.name.toLowerCase().includes(q))
    }
    const categories = [...new Set(results.map((i) => i.category))]
    return widget({
      props: { items: results, categories, totalCount: results.length },
      output: text(
        `Found ${results.length} items across ${categories.length} categories`,
      ),
    })
  },
)

See also

Server

The MCPServer class that hosts these tools, plus its constructor and lifecycle methods.