> ## 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.

# Overview

> Understand how MCP tools render interactive UI with mcp-use.

An MCP App combines an `MCPServer`, a React component under `views/`, and a tool bound to that View. The `mcp-use` framework includes a Vite-based build system that discovers, builds, and serves your Views in development and production.

MCP Apps let your tools render interactive UI inside AI conversations. Build a View when users need to explore data, complete a form, review a preview, or act on a tool result.

<video
  alt="Interactive MCP App View"
  style={{
maxWidth: "600px",
borderRadius: "8px",
marginBottom: "1.5rem",
boxShadow: "0 2px 12px rgba(0,0,0,0.08)",
}}
  muted
  autoPlay
  loop
>
  <source src="https://mintcdn.com/mcpuse/aBF0-m9bcdsFAIVU/images/view.mp4?fit=max&auto=format&n=aBF0-m9bcdsFAIVU&q=85&s=2a5db3aa23adb78a9b14b302169f082d" type="video/mp4" data-path="images/view.mp4" />
</video>

## How a tool renders a View

Add `view: { name }` to a tool definition. The name must match a directory under `views/`.

```text theme={null}
product-search/
├── index.ts
├── views/
│   └── product-results/
│       └── view.tsx
├── public/
├── mcp-env.d.ts
└── package.json
```

The View-bound tool must declare an `outputSchema`. Its handler returns a normal MCP tool result with matching `structuredContent`.

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

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

export const searchProducts = server.tool(
  {
    name: "search-products",
    inputSchema: z.object({
      query: z.string(),
    }),
    outputSchema: z.object({
      results: z.array(
        z.object({
          id: z.string(),
          name: z.string(),
        }),
      ),
    }),
    view: {
      name: "product-results",
    },
  },
  async ({ query }) => {
    const results = [
      { id: "starter-kit", name: `${query} starter kit` },
      { id: "travel-kit", name: `${query} travel kit` },
    ];

    return {
      content: [
        {
          type: "text",
          text: `Found ${results.length} products matching "${query}".`,
        },
      ],
      structuredContent: {
        results,
      },
    };
  },
);

export default server;
```

Each View can be bound to at most one tool. Export the tool reference so mcp-use can infer its input and output types inside the View.

## Read the tool result in the View

A View default-exports a React component. The component receives no React props. Read the tool lifecycle and result with `useToolContext()`.

```tsx theme={null}
import { useToolContext } from "mcp-use/react";

export default function ProductResults() {
  const { status, toolInput, toolOutput, error } =
    useToolContext<"search-products">();

  if (status === "error") {
    return <p>{error.message}</p>;
  }

  if (status === "pending") {
    return <p>Searching for {toolInput?.query ?? "products"}…</p>;
  }

  return (
    <main>
      <h2>Product results</h2>
      <ul>
        {toolOutput.results.map(({ id, name }) => (
          <li key={id}>{name}</li>
        ))}
      </ul>
    </main>
  );
}
```

## Choose what the model and View receive

MCP tool results provide separate channels for conversation output, structured data, and View-only metadata.

| Channel             | Model receives it? | View receives it?    | Use it for                                                        |
| ------------------- | ------------------ | -------------------- | ----------------------------------------------------------------- |
| `content`           | Yes                | Yes, as `content`    | A concise result for the conversation and text-only clients       |
| `structuredContent` | Yes                | Yes, as `toolOutput` | Typed data that the model can reason over and the View can render |
| `_meta`             | No                 | Yes, as `meta`       | Data that is not visible to the model                             |

Do not place secrets in any result channel. A View runs on the client and can read its result data.

## Continue building

<CardGroup cols={2}>
  <Card title="Build your first MCP App" icon="rocket" href="/v2/typescript/mcp-apps/quickstart">
    Create a project, run it locally, and render its View in the Inspector.
  </Card>

  <Card title="Interactivity" icon="mouse-pointer-click" href="/v2/typescript/mcp-apps/interactivity">
    Call tools, open links, send follow-up messages, and change display modes.
  </Card>

  <Card title="Model context" icon="brain" href="/v2/typescript/mcp-apps/model-context">
    Expose View state and visible UI information to future model turns.
  </Card>

  <Card title="Content Security Policy" icon="shield" href="/v2/typescript/mcp-apps/content-security-policy">
    Allow the external APIs, assets, and embedded content your View needs.
  </Card>
</CardGroup>
