Build MCP Apps with mcp-use v2
Treat the installed mcp-use package, its generated types, and the project's existing exports as the source of truth. Check the installed version before changing code; do not assume APIs from mcp-use v1.
Workflow
- Inspect
package.json, the server entry, exported tool refs, views/, and the installed mcp-use version.
- Scaffold a new project with
npx create-mcp-use-app@latest; do not hand-build framework boilerplate.
- Read only the references needed for the task:
- Server primitives for tools, resources, prompts, middleware, and result envelopes.
- Views for interactive MCP Apps and React hooks.
- Authentication for OAuth providers and authenticated tool handlers.
- Migration when converting v1 code or reviewing package boundaries.
- Verification before reporting completion.
- Implement against the package types. Export every statically declared tool ref that a View calls.
- Validate through the real lifecycle: build/typecheck, run the server, connect a client, call the tool, and render the View when one exists.
Native v2 invariants
- Import server APIs from
mcp-use; provider adapters come from mcp-use/oauth/*; React APIs come from mcp-use/react.
- Define tools with
inputSchema; add outputSchema when returning structured data or binding a View.
- Return MCP result envelopes with
content, structuredContent, and optionally _meta or isError.
- Put each View at
views/<name>/view.tsx and bind it with view: { name: "<name>" }.
- Read the rendering call with
useToolContext; use focused hooks such as useCallTool, useViewState, useHostContext, and useDisplayMode for additional behavior.
- Export the server as the default export. Let
mcp-use dev, build, and start own framework lifecycle and View compilation.
- Keep request state in the request context or an external store. Do not rely on module globals for cross-request identity or elicitation continuity.
Minimal server and View
import { MCPServer } from "mcp-use";
import { z } from "zod";
const server = new MCPServer({ name: "catalog", version: "1.0.0" });
export const showProduct = server.tool(
{
name: "show-product",
description: "Show one catalog product",
inputSchema: z.object({ id: z.string() }),
outputSchema: z.object({ id: z.string(), name: z.string() }),
view: { name: "product" },
},
async ({ id }) => {
const product = { id, name: "Example product" };
return {
content: [{ type: "text", text: JSON.stringify(product) }],
structuredContent: product,
};
},
);
export default server;
// views/product/view.tsx
import { ThemeProvider, useToolContext } from "mcp-use/react";
export default function ProductView() {
const view = useToolContext<"show-product">();
if (view.status === "pending") return <p>Loading…</p>;
if (view.status === "error") return <p>{view.error.message}</p>;
return <ThemeProvider>{view.toolOutput.name}</ThemeProvider>;
}
Guardrails
- Do not copy examples from v1 docs or historical changelogs.
- Do not invent exports or configuration fields; confirm them in installed declarations or source.
- Do not return a plain domain object from a tool callback.
- Do not bind a View without an
outputSchema and matching structuredContent.
- Do not claim success from a source build alone when package exports or interactive behavior changed.
- Do not deploy or mutate external systems unless the user explicitly requests it.
Run node <skill-dir>/scripts/check-v2.mjs <project-root> during migrations and reviews, then complete the focused checks in Verification.
1---2name: mcp-apps-builder3description: Build, modify, debug, migrate, or review TypeScript MCP servers and interactive MCP Apps using mcp-use v2. Use for tools, resources, prompts, Views, React host interactions, OAuth, middleware, Inspector workflows, package-boundary migrations, and release-ready verification in an mcp-use project.4---56# Build MCP Apps with mcp-use v278Treat the installed `mcp-use` package, its generated types, and the project's existing exports as the source of truth. Check the installed version before changing code; do not assume APIs from mcp-use v1.910## Workflow11121. Inspect `package.json`, the server entry, exported tool refs, `views/`, and the installed `mcp-use` version.132. Scaffold a new project with `npx create-mcp-use-app@latest`; do not hand-build framework boilerplate.143. Read only the references needed for the task:15 - [Server primitives](references/server.md) for tools, resources, prompts, middleware, and result envelopes.16 - [Views](references/views.md) for interactive MCP Apps and React hooks.17 - [Authentication](references/auth.md) for OAuth providers and authenticated tool handlers.18 - [Migration](references/migration.md) when converting v1 code or reviewing package boundaries.19 - [Verification](references/verification.md) before reporting completion.204. Implement against the package types. Export every statically declared tool ref that a View calls.215. Validate through the real lifecycle: build/typecheck, run the server, connect a client, call the tool, and render the View when one exists.2223## Native v2 invariants2425- Import server APIs from `mcp-use`; provider adapters come from `mcp-use/oauth/*`; React APIs come from `mcp-use/react`.26- Define tools with `inputSchema`; add `outputSchema` when returning structured data or binding a View.27- Return MCP result envelopes with `content`, `structuredContent`, and optionally `_meta` or `isError`.28- Put each View at `views/<name>/view.tsx` and bind it with `view: { name: "<name>" }`.29- Read the rendering call with `useToolContext`; use focused hooks such as `useCallTool`, `useViewState`, `useHostContext`, and `useDisplayMode` for additional behavior.30- Export the server as the default export. Let `mcp-use dev`, `build`, and `start` own framework lifecycle and View compilation.31- Keep request state in the request context or an external store. Do not rely on module globals for cross-request identity or elicitation continuity.3233## Minimal server and View3435```ts36import { MCPServer } from "mcp-use";37import { z } from "zod";3839const server = new MCPServer({ name: "catalog", version: "1.0.0" });4041export const showProduct = server.tool(42 {43 name: "show-product",44 description: "Show one catalog product",45 inputSchema: z.object({ id: z.string() }),46 outputSchema: z.object({ id: z.string(), name: z.string() }),47 view: { name: "product" },48 },49 async ({ id }) => {50 const product = { id, name: "Example product" };51 return {52 content: [{ type: "text", text: JSON.stringify(product) }],53 structuredContent: product,54 };55 },56);5758export default server;59```6061```tsx62// views/product/view.tsx63import { ThemeProvider, useToolContext } from "mcp-use/react";6465export default function ProductView() {66 const view = useToolContext<"show-product">();67 if (view.status === "pending") return <p>Loading…</p>;68 if (view.status === "error") return <p>{view.error.message}</p>;69 return <ThemeProvider>{view.toolOutput.name}</ThemeProvider>;70}71```7273## Guardrails7475- Do not copy examples from v1 docs or historical changelogs.76- Do not invent exports or configuration fields; confirm them in installed declarations or source.77- Do not return a plain domain object from a tool callback.78- Do not bind a View without an `outputSchema` and matching `structuredContent`.79- Do not claim success from a source build alone when package exports or interactive behavior changed.80- Do not deploy or mutate external systems unless the user explicitly requests it.8182Run `node <skill-dir>/scripts/check-v2.mjs <project-root>` during migrations and reviews, then complete the focused checks in [Verification](references/verification.md).