> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mcp-use.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools

> Design and register MCP tools with validated inputs and typed results.

Tools let a model call server-side code. Give each tool a focused description,
validate its input, declare its behavioral annotations, and return an official
MCP `CallToolResult`.

## Register a tool

`inputSchema` accepts a Standard Schema implementation that can produce JSON
Schema. Zod is one option; ArkType and Valibot are also supported.

```typescript theme={null}
import { MCPServer } from "mcp-use";
import { z } from "zod";

const server = new MCPServer({
  name: "inventory-server",
  version: "1.0.0",
});

server.tool(
  {
    name: "lookup-inventory",
    description: "Return available inventory for one SKU.",
    inputSchema: z.object({
      sku: z.string().describe("Inventory SKU"),
    }),
    annotations: {
      readOnlyHint: true,
      destructiveHint: false,
      openWorldHint: true,
    },
  },
  async ({ sku }) => {
    const count = await inventory.count(sku);
    return {
      content: [{ type: "text", text: `${count} units available.` }],
    };
  },
);

export default server;
```

Field descriptions become hints for clients and models. The schema validates
input before the callback runs and supplies the callback's inferred TypeScript
type.

## Return structured output

Declare `outputSchema` when clients need a typed structured result. Every
successful result from a schema-backed tool must include matching
`structuredContent`. An error result may instead set `isError: true`.

```typescript theme={null}
const availabilitySchema = z.object({
  sku: z.string(),
  available: z.number().int(),
});

server.tool(
  {
    name: "inventory-status",
    inputSchema: z.object({ sku: z.string() }),
    outputSchema: availabilitySchema,
  },
  async ({ sku }) => {
    const data = { sku, available: await inventory.count(sku) };
    return {
      content: [{ type: "text", text: JSON.stringify(data) }],
      structuredContent: data,
    };
  },
);
```

Prefer raw results:

| Need             | Return                                                     |
| ---------------- | ---------------------------------------------------------- |
| Text             | `{ content: [{ type: "text", text }] }`                    |
| Typed JSON       | `{ content, structuredContent: data }` with `outputSchema` |
| Expected failure | `{ isError: true, content: [{ type: "text", text }] }`     |
| Several blocks   | `{ content: [/* content blocks */] }`                      |

## Bind a View

Export the tool reference from the server entry so `mcp-env.d.ts` can expose
its input and output types to View code. Place the React entry at
`views/<name>/view.tsx`, set `view.name` to that directory name, and return its
data in `structuredContent`.

```typescript theme={null}
export const searchProducts = server.tool(
  {
    name: "search-products",
    inputSchema: z.object({ query: z.string() }),
    outputSchema: z.object({
      query: z.string(),
      results: z.array(z.object({ id: z.string(), name: z.string() })),
    }),
    view: { name: "product-search-result" },
  },
  async ({ query }) => {
    const data = { query, results: await products.search(query) };
    return {
      content: [
        { type: "text", text: `Found ${data.results.length} products.` },
      ],
      structuredContent: data,
    };
  },
);
```

A view-bound tool must declare `outputSchema`, and one View can bind to only
one tool. The view reads the structured data while the model reads `content`.

## Use request context

The second callback argument is scoped to the current request. It includes an
abort signal, client-reported capability metadata, progress and logging
methods, and the originating Hono request when HTTP context exists.

```typescript theme={null}
server.tool({ name: "request-info" }, async (_input, ctx) => {
  const data = {
    client: ctx.client.info().name ?? "unknown",
    supportsViews: ctx.client.supportsViews(),
    aborted: ctx.signal.aborted,
  };
  return {
    content: [{ type: "text", text: JSON.stringify(data) }],
    structuredContent: data,
  };
});
```

Client metadata is self-reported and must not be used for authorization.
`ctx.auth` is available only when the server has an OAuth provider; use its
verified provider user for access control.

## Notify tool-list listeners

Publish a tool-list invalidation when the tools clients can discover have
changed:

```typescript theme={null}
await server.notifyToolsChanged();
```

Clients with an active subscription listener can then request `tools/list`
again. This notification does not register or replace tools; register tools
while constructing the server, before it starts handling requests.

## Test tools

Run `mcp-use dev`, open the built-in inspector, and test valid inputs, schema
failures, error results, and structured output:

```bash theme={null}
npx mcp-use dev
```

For view-bound tools, also verify that the View renders the returned
`structuredContent`.
