Build with mcp-use & ChatGPT Apps
Treat the installed mcp-use package, its exported types, generated declarations (mcp-env.d.ts), and official documentation at docs.mcp-use.com as the authoritative sources of truth.
This skill grounds on the official MCPServer API surface, applies the lean architecture of the official mcp-use skills, and ensures that every ChatGPT app built with mcp-use is compliant with the OpenAI Apps SDK UI (@openai/apps-sdk-ui) by default.
Workflow
- Inspect Project: Check
package.json, server entry, exported tool refs, views/, skills/, and the installed mcp-use version (Node.js >= 22.22.2 required).
- Scaffold or Initialize: For greenfield projects, scaffold with the official CLI:
npx create-mcp-use-app@latest my-app --template mcp-apps
(Use --template mcp-server for headless tool servers).
- Read Focused References:
- Server: Tools, resources, prompts, middleware, request context, result envelopes, and
ServerConfig.
- Views: MCP Apps, React hooks, interaction channels, host capabilities, and CSP.
- OpenAI Apps SDK UI Guide: Full 29 components, hooks, Tailwind 4 setup, design tokens, and theme sync.
- ChatGPT Plugin Extensions: Launch entrypoints (
global, thread, file), native server.settings(), tool icons, useDeepLink(), and useModelContext().
- Authentication: OAuth provider adapters,
mixedAuth: true, tool-level securitySchemes, and verified identity on ctx.auth.
- Skills over MCP: Reusable agent workflows and conventions under
skills/.
- Advanced Features: OpenAPI (
fromOpenAPI), proxying, notifications, subscriptions, and interactive elicitation (inputRequired).
- Multi-Host & Archestra: Deploying to ChatGPT, Claude Desktop, and Archestra (installed-server route vs owned apps).
- Migration: Upgrading legacy v1 patterns, deprecated imports, and obsolete helpers to v2.
- Verification: Verification loop with
mcp-use typecheck, mcp-use dev, mcp-use client, and mcp-use screenshot.
- Implement Against Installed Types: Always export static tool references and default-export the server instance.
- Verify Deterministically: Drive real tool calls through
mcp-use client and capture view screenshots with mcp-use screenshot.
Core Invariants
- Root Server Import: Always import
MCPServer and server primitives from "mcp-use" (the legacy "mcp-use/server" subpath is obsolete).
- Export Static Tool Refs: Always export every tool reference (
export const myTool = server.tool(...)). The TypeScript compiler derives view and client contracts in mcp-env.d.ts from exported tool names.
- Default Server Export: Always default-export the server instance (
export default server;). The CLI runner (mcp-use dev, build, start) owns the HTTP listener and Vite view pipeline.
- Definition-First Tools & Standard Schema: Define tools with
server.tool(definition, callback). Tool arguments use inputSchema; model prompts use schema. Always describe model-filled schema fields.
- Raw Result Envelopes: Tool callbacks must return raw
CallToolResult envelopes ({ content: [...], structuredContent?: ... }). Do not use deprecated v1 helpers (text(), object(), widget()). Expected failures return { isError: true, content: [...] }; unexpected failures throw.
- Views Architecture: Put each view at
views/<name>/view.tsx. Each view must have exactly one owning tool with matching view: { name: "<name>" } and a mandatory outputSchema. Return matching structuredContent.
- OpenAI Apps SDK UI Compliance: Every ChatGPT app must install
@openai/apps-sdk-ui, import @openai/apps-sdk-ui/css, configure Tailwind 4 with @source, and wrap interactive components with <AppsSDKUIProvider linkComponent="a">.
- Stateless Request Model: Server instances are request-scoped. Never use module globals or in-memory session registries for multi-request state or authentication. Use
ctx.requestState or an external database.
- Strict CLI Flag Syntax: Boolean CLI flags reject inline values in v2.7.2+ (
--tunnel=false fails; use --tunnel or omit).
Guardrails & Common Anti-Patterns
- Never import non-existent
@openai/apps-sdk-ui components:
Card does not exist in @openai/apps-sdk-ui. Surface cards are standard <div> elements styled with Tailwind utility classes (rounded-2xl border border-default bg-surface p-4 shadow-sm).
AvatarGroup and CopyTooltip are official @openai/apps-sdk-ui components (from @openai/apps-sdk-ui/components/Avatar and @openai/apps-sdk-ui/components/Tooltip).
Cart and Checkmark do not exist in @openai/apps-sdk-ui/components/Icon. Use Check, CheckCircle, Search, Plus, Settings, etc.
- Never omit
linkComponent on <AppsSDKUIProvider>: The TypeScript contract requires linkComponent (e.g. <AppsSDKUIProvider linkComponent="a">).
- Never read
useToolContext().toolOutput un-narrowed: useToolContext() is a discriminated union. When status === "pending", toolOutput is undefined. Always handle status === "pending" and status === "error" before accessing toolOutput. Narrow error instanceof ToolCancelledError for cancelled actions.
- Configure
websiteUrl, icons, and logging at the top level of MCPServer:
icons?: Icon[], websiteUrl?: string, and logging?: LoggingOptions are top-level properties on ServerConfig. Do not nest them in a fictitious branding: { ... } object (server.branding is a read-only getter).
- Server logging level is configured via
logging: { enabled: true, level: "info" } or overridden by the MCP_USE_LOG_LEVEL environment variable.
- Never use legacy v1
ctx.elicit(): Removed in v2.0.0 during the transition to the stateless request model. Use official protocol primitives: inputRequired, inputRequired.elicit, inputRequired.elicitUrl, inputResponse, and acceptedContent.
- Never use wrong CLI commands:
- Client connect syntax:
mcp-use client connect <name> <url> [options] (e.g. npx mcp-use client connect dev http://localhost:3000/mcp).
- Screenshot syntax:
mcp-use screenshot (--server <name> | --mcp <url>) --tool <name> [args...] [options].
Base MCPServer Architecture
Ground on MCPServer and Server Documentation:
import { MCPServer } from "mcp-use";
const server = new MCPServer({
name: "catalog-server",
version: "1.0.0",
title: "Inventory & Catalog Manager",
description: "Manage product catalog, stock levels, and search items.",
instructions: "Use lookup-item before creating an order. Confirm stock availability.",
basePath: "/mcp", // default route
host: "127.0.0.1", // "0.0.0.0" for public hosting
port: 3000,
legacy: "stateless", // "stateless" (default) or "reject"
websiteUrl: "https://example.com",
icons: [
{ src: "icons/logo.svg", mimeType: "image/svg+xml", sizes: ["20x20"] }
],
logging: { enabled: true, level: "info" }, // Overridden by MCP_USE_LOG_LEVEL env var
skills: true, // Auto-discover conventional skills/ directory
cors: {
origin: "*",
credentials: true,
},
});
export default server;
Tool Definitions & Result Envelopes
Documentation: Server Tools
import { MCPServer } from "mcp-use";
import { z } from "zod";
const server = new MCPServer({ name: "catalog", version: "1.0.0" });
export const getProduct = server.tool(
{
name: "get-product",
title: "Get Product Details",
description: "Fetch product metadata, pricing, and live inventory by SKU.",
icons: [
{ src: "icons/product.svg", mimeType: "image/svg+xml", sizes: ["20x20"] }
],
inputSchema: z.object({
sku: z.string().describe("Stock Keeping Unit identifier (e.g. 'PROD-100')"),
}),
outputSchema: z.object({
sku: z.string(),
title: z.string(),
price: z.number(),
inStock: z.boolean(),
}),
annotations: {
readOnlyHint: true,
openWorldHint: false,
},
visibility: "model", // "model" (default) or "app" (hidden from LLM, visible to UI views)
view: {
name: "product-card", // binds to views/product-card/view.tsx
description: "Interactive product display card",
},
},
async ({ sku }, ctx) => {
// Expected operational failure
if (!sku.startsWith("PROD-")) {
return {
isError: true,
content: [{ type: "text", text: `Invalid SKU format: ${sku}` }],
};
}
const data = { sku, title: "Precision Screwdriver", price: 29.99, inStock: true };
return {
content: [{ type: "text", text: `Product ${data.title} (${sku}) is in stock at $${data.price}` }],
structuredContent: data,
_meta: { internalId: "db_98213" }, // Private to view, hidden from LLM
};
}
);
export default server;
ChatGPT Apps & OpenAI Apps SDK UI Compliance
Documentation:
1. Installation & Styles Setup
npm install @openai/apps-sdk-ui tailwindcss @tailwindcss/vite
In views/main.css (or view-specific CSS):
@import "tailwindcss";
@import "@openai/apps-sdk-ui/css";
@source "../node_modules/@openai/apps-sdk-ui";
2. View Component with Apps SDK UI & Theme Sync
Create views/product-card/view.tsx:
import "./main.css";
import React, { useEffect } from "react";
import { useToolContext, useModelContext, useViewTheme, ToolCancelledError, type ViewConfig } from "mcp-use/react";
import { AppsSDKUIProvider } from "@openai/apps-sdk-ui/components/AppsSDKUIProvider";
import { Button } from "@openai/apps-sdk-ui/components/Button";
import { Badge } from "@openai/apps-sdk-ui/components/Badge";
import { applyDocumentTheme } from "@openai/apps-sdk-ui/theme";
import { Check, Plus } from "@openai/apps-sdk-ui/components/Icon";
export const viewConfig = {
autoResize: true,
displayModes: ["inline", "fullscreen"],
preferredDisplayMode: "inline",
} satisfies ViewConfig;
export default function ProductCardView() {
const { status, toolInput, toolOutput, error } = useToolContext<"get-product">();
const theme = useViewTheme();
const { add } = useModelContext();
// Synchronize host theme with Apps SDK UI data-theme attribute
useEffect(() => {
if (theme) applyDocumentTheme(theme);
}, [theme]);
if (status === "pending") {
return <div className="p-4 text-secondary text-sm">Loading SKU {toolInput?.sku}…</div>;
}
if (status === "error") {
if (error instanceof ToolCancelledError) {
return <div className="p-4 text-secondary text-sm">Action cancelled: {error.reason}</div>;
}
return <div className="p-4 text-danger text-sm">Error: {error.message}</div>;
}
return (
<AppsSDKUIProvider linkComponent="a">
{/* Standard surface card styled with semantic tokens */}
<div className="w-full max-w-md rounded-2xl border border-default bg-surface p-4 shadow-sm">
<div className="flex items-start justify-between">
<div>
<h2 className="heading-md">{toolOutput.title}</h2>
<p className="text-secondary text-sm">SKU: {toolOutput.sku}</p>
</div>
<Badge color={toolOutput.inStock ? "success" : "warning"}>
{toolOutput.inStock ? "In Stock" : "Backorder"}
</Badge>
</div>
<div className="mt-4 flex items-center justify-between border-t border-subtle pt-3">
<span className="text-lg font-semibold">${toolOutput.price.toFixed(2)}</span>
<Button
color="primary"
=> {
// Attach verified evidence to next ChatGPT model turn (synchronous void)
add("selected:product", {
type: "text",
text: `Selected SKU ${toolOutput.sku}: $${toolOutput.price}`,
});
}}
>
<Plus className="size-4" />
Add to Chat
</Button>
</div>
</div>
</AppsSDKUIProvider>
);
}
3. Complete Apps SDK UI Component Inventory (29 Components)
All imported from @openai/apps-sdk-ui/components/<Component>:
| Category |
Components |
Purpose |
| Feedback & Status |
Alert, Badge, Indicator, EmptyMessage, ShimmerText |
Status banners, live badges, empty states, and loading shimmers. |
| Identity & Icons |
Avatar, Image, Icon |
User profiles, image fallbacks, and 700+ monochrome SVGs. |
| Actions |
Button, ButtonLink (plus CopyButton) |
Primary, secondary, soft, outline action buttons and copy controls. |
| Form Inputs |
Input, Textarea, Checkbox, Switch, RadioGroup, Slider, SegmentedControl, Select, SelectControl, TagInput |
Accessible, validated inputs and grouped controls. |
| Date Pickers |
DatePicker, DateRangePicker |
Calendar popups and date range selectors. |
| Overlays |
Menu, Popover, Tooltip |
Dropdown menus, anchored popovers, and contextual tooltips. |
| Typography & Content |
Markdown, CodeBlock, TextLink |
Styled markdown renderer, syntax-highlighted code blocks, and themed hyperlinks. |
| Motion & Transitions |
Transition (Animate, AnimateLayout, SlotTransitionGroup, TransitionGroup) |
Smooth height, fade, and layout morph transitions for iframes. |
| Providers |
AppsSDKUIProvider |
Root context providing router linkComponent configuration. |
4. Official Hooks Suite (@openai/apps-sdk-ui/hooks)
useBreakpoint(size: BreakpointName): Responsive breakpoint match boolean (e.g. useBreakpoint("md")).
useAutoGrowTextarea(): Dynamic auto-growing textarea heights.
useAnimatedScrollTo(): Smooth programmatic scrolling with cancellation.
useDocumentVisible(): Tracks iframe visibility.
useIsMounted(), useLatestValue(), usePrevious(), useScrollable(), useSimulatedProgress(), useStableCallback(), useTextSelection(), useTrailingValue().
ChatGPT Plugin Extensions
Documentation: ChatGPT Plugin Extensions | Extensions Reference
1. Typed Launch Entrypoints
Declare launch surfaces on tool.view.entrypoints:
global: Launches app from ChatGPT top-level launcher (input schema must accept {}).
thread: Launches app within conversation tab (input schema must accept {}).
file: Launches app as file viewer for matching extensions (input schema must receive { file: { name: string, resourceUri: string } }).
export const openCsvViewer = server.tool(
{
name: "open-csv",
title: "CSV Table Viewer",
inputSchema: z.object({
file: z.object({ name: z.string(), resourceUri: z.string() }),
}),
outputSchema: z.object({ file: z.object({ name: z.string(), resourceUri: z.string() }) }),
view: {
name: "csv-viewer",
entrypoints: [{ type: "file", extensions: [".csv", ".tsv"] }],
},
},
async ({ file }) => ({ content: [], structuredContent: { file } })
);
2. Native Plugin Settings (server.settings)
Register native ChatGPT plugin settings with typed fields and layout sections:
server.settings({
fields: {
theme: { type: "string", label: "Theme", default: "system" },
autoSync: { type: "boolean", label: "Automatic Sync", default: true },
},
layout: [
{
title: "Preferences",
fields: ["theme", "autoSync"],
},
],
read: async (ctx) => ({ theme: "system", autoSync: true }),
update: async (patch, ctx) => ({ theme: "system", autoSync: true, ...patch }),
});
3. Incoming Deep Links (useDeepLink)
Read incoming URLs sent to global entrypoints:
import { useDeepLink } from "mcp-use/react";
export function AppRouter() {
const { url } = useDeepLink(); // e.g. "/items?tag=hardware"
}
4. Selected Model Context (useModelContext)
Manage evidence attachments sent with the next user model turn (attachments is Record<string, ModelContextBlock>, add is synchronous void):
import { useModelContext } from "mcp-use/react";
const { attachments, add, remove, clearAttachments } = useModelContext();
// Attach text summary (synchronous void, no title)
add("summary", { type: "text", text: "Order Summary: Total $120.00" });
// Attach image with Base64 data (PNG/JPEG/GIF/WebP, max 10MB)
add("receipt", { type: "image", data: receiptBase64, mimeType: "image/png" });
// Enumerate attached blocks
Object.entries(attachments).map(([key, block]) => (
<span key={key}>{key}: {block.type}</span>
));
Authentication & Mixed Auth
Documentation: Authentication | Mixed Auth | Auth Reference
Configure mixedAuth: true on MCPServer to serve public discovery, optional auth, and protected tools from one endpoint:
import { MCPServer } from "mcp-use";
import { oauthAuth0Provider } from "mcp-use/oauth/auth0";
import { z } from "zod";
const server = new MCPServer({
name: "store",
version: "1.0.0",
oauth: oauthAuth0Provider({ domain: process.env.AUTH0_DOMAIN! }),
mixedAuth: true, // Enables unauthenticated tools/list discovery
});
// Public tool: Anyone may call without token
export const searchCatalog = server.tool(
{
name: "search-catalog",
inputSchema: z.object({ query: z.string() }),
securitySchemes: [{ type: "noauth" }],
},
async ({ query }, ctx) => {
return { content: [{ type: "text", text: `Results for ${query}` }] };
}
);
// Protected tool: Requires sign-in with specific scopes
export const checkout = server.tool(
{
name: "checkout",
inputSchema: z.object({ cartId: z.string() }),
securitySchemes: [{ type: "oauth2", scopes: ["orders:write"] }],
},
async ({ cartId }, ctx) => {
const userId = ctx.auth.user.id;
return { content: [{ type: "text", text: `Order placed for user ${userId}` }] };
}
);
Supported Providers: Clerk (mcp-use/oauth/clerk), Auth0 (mcp-use/oauth/auth0), WorkOS (mcp-use/oauth/workos), Supabase (mcp-use/oauth/supabase), Keycloak (mcp-use/oauth/keycloak), Better Auth (mcp-use/oauth/better-auth), Scalekit (mcp-use/oauth/scalekit), Convex (mcp-use/oauth/convex), and Custom (oauthCustomProvider).
Interactive Elicitation
Documentation: Elicitation | Advanced Features
ctx.elicit() was removed in v2.0.0 during the transition to the stateless request model. Use official protocol primitives:
import { MCPServer, inputRequired, inputResponse, acceptedContent } from "mcp-use";
import { z } from "zod";
const confirmSchema = z.object({ approve: z.boolean().describe("Confirm action") });
server.tool(
{
name: "delete-resource",
inputSchema: z.object({ id: z.string() }),
},
async ({ id }, ctx) => {
const response = inputResponse(ctx.inputResponses, "delete-approval");
if (response.kind === "elicit" && response.action !== "accept") {
return { isError: true, content: [{ type: "text", text: "Action cancelled" }] };
}
const confirmation = acceptedContent(ctx.inputResponses, "delete-approval", confirmSchema);
if (!confirmation) {
return inputRequired({
inputRequests: {
"delete-approval": inputRequired.elicit({
message: `Permanently delete resource ${id}?`,
requestedSchema: confirmSchema,
}),
},
});
}
if (!confirmation.approve) {
return { isError: true, content: [{ type: "text", text: "Action rejected" }] };
}
// Side-effects execute only after confirmed, validated input
await db.delete(id);
return { content: [{ type: "text", text: `Deleted ${id}` }] };
}
);
For external authorization: inputRequired.elicitUrl({ message: "...", url: authUrl }).
Skills over MCP (SEP-2640)
Documentation: Skills over MCP | Skills Reference
Serve reusable instruction workflows alongside tools:
- Place skills under
skills/<skill-name>/SKILL.md.
- Automatic discovery is enabled by default. Require with
skills: true or disable with skills: false on MCPServer.
- Hosts retrieve skill metadata via
skills/list and skills/get.
CLI & Tooling Reference
Documentation: CLI Reference | Client CLI | Verification
# Scaffold new v2 project
npx create-mcp-use-app@latest my-server --template mcp-apps
# Start development with hot reload, Vite views pipeline, and Inspector
mcp-use dev
# Start development with authenticated public tunnel for live ChatGPT testing
mcp-use dev --tunnel
# Typecheck server and views
mcp-use typecheck
# Build for production
mcp-use build
# Start production server
mcp-use start
# Connect live client session straight from terminal
mcp-use client connect dev http://localhost:3000/mcp
# List tools and call with arguments
mcp-use client dev tools list
mcp-use client dev tools call get-product sku=PROD-100
# Capture automated screenshot of view preview
mcp-use screenshot --server dev --tool get-product sku=PROD-100
# Deploy to mcp-use cloud (requires GitHub repo)
mcp-use deploy
Canonical Documentation Links
1---2name: build-mcp-use-server3description: Use if building, modifying, debugging, or verifying TypeScript MCP servers and ChatGPT Apps with mcp-use v2, MCPServer, Apps SDK UI, Views, and Plugin Extensions.4disable-model-invocation: true5metadata:6 source: https://skillmd.com/skills/yigitkonur/build-mcp-use-server7---89# Build with mcp-use & ChatGPT Apps1011Treat the installed `mcp-use` package, its exported types, generated declarations (`mcp-env.d.ts`), and official documentation at [docs.mcp-use.com](https://docs.mcp-use.com) as the authoritative sources of truth.1213This skill grounds on the official [`MCPServer`](https://api-reference.mcp-use.com/classes/mcp-use.index.MCPServer.html) API surface, applies the lean architecture of the official `mcp-use` skills, and ensures that every ChatGPT app built with `mcp-use` is compliant with the **OpenAI Apps SDK UI** (`@openai/apps-sdk-ui`) by default.1415---1617## Workflow18191. **Inspect Project**: Check `package.json`, server entry, exported tool refs, `views/`, `skills/`, and the installed `mcp-use` version (Node.js >= 22.22.2 required).202. **Scaffold or Initialize**: For greenfield projects, scaffold with the official CLI:21 ```bash22 npx create-mcp-use-app@latest my-app --template mcp-apps23 ```24 (Use `--template mcp-server` for headless tool servers).253. **Read Focused References**:26 - [Server](references/server.md): Tools, resources, prompts, middleware, request context, result envelopes, and `ServerConfig`.27 - [Views](references/views.md): MCP Apps, React hooks, interaction channels, host capabilities, and CSP.28 - [OpenAI Apps SDK UI Guide](references/chatgpt-apps-ui.md): Full 29 components, hooks, Tailwind 4 setup, design tokens, and theme sync.29 - [ChatGPT Plugin Extensions](references/chatgpt-extensions.md): Launch entrypoints (`global`, `thread`, `file`), native `server.settings()`, tool icons, `useDeepLink()`, and `useModelContext()`.30 - [Authentication](references/auth.md): OAuth provider adapters, `mixedAuth: true`, tool-level `securitySchemes`, and verified identity on `ctx.auth`.31 - [Skills over MCP](references/skills-over-mcp.md): Reusable agent workflows and conventions under `skills/`.32 - [Advanced Features](references/advanced-features.md): OpenAPI (`fromOpenAPI`), proxying, notifications, subscriptions, and interactive elicitation (`inputRequired`).33 - [Multi-Host & Archestra](references/archestra-and-multi-host.md): Deploying to ChatGPT, Claude Desktop, and Archestra (installed-server route vs owned apps).34 - [Migration](references/migration.md): Upgrading legacy v1 patterns, deprecated imports, and obsolete helpers to v2.35 - [Verification](references/verification.md): Verification loop with `mcp-use typecheck`, `mcp-use dev`, `mcp-use client`, and `mcp-use screenshot`.364. **Implement Against Installed Types**: Always export static tool references and default-export the server instance.375. **Verify Deterministically**: Drive real tool calls through `mcp-use client` and capture view screenshots with `mcp-use screenshot`.3839---4041## Core Invariants42431. **Root Server Import**: Always import `MCPServer` and server primitives from `"mcp-use"` (the legacy `"mcp-use/server"` subpath is obsolete).442. **Export Static Tool Refs**: Always export every tool reference (`export const myTool = server.tool(...)`). The TypeScript compiler derives view and client contracts in `mcp-env.d.ts` from exported tool names.453. **Default Server Export**: Always default-export the server instance (`export default server;`). The CLI runner (`mcp-use dev`, `build`, `start`) owns the HTTP listener and Vite view pipeline.464. **Definition-First Tools & Standard Schema**: Define tools with `server.tool(definition, callback)`. Tool arguments use `inputSchema`; model prompts use `schema`. Always describe model-filled schema fields.475. **Raw Result Envelopes**: Tool callbacks must return raw `CallToolResult` envelopes (`{ content: [...], structuredContent?: ... }`). Do not use deprecated v1 helpers (`text()`, `object()`, `widget()`). Expected failures return `{ isError: true, content: [...] }`; unexpected failures throw.486. **Views Architecture**: Put each view at `views/<name>/view.tsx`. Each view must have exactly one owning tool with matching `view: { name: "<name>" }` and a mandatory `outputSchema`. Return matching `structuredContent`.497. **OpenAI Apps SDK UI Compliance**: Every ChatGPT app must install `@openai/apps-sdk-ui`, import `@openai/apps-sdk-ui/css`, configure Tailwind 4 with `@source`, and wrap interactive components with `<AppsSDKUIProvider linkComponent="a">`.508. **Stateless Request Model**: Server instances are request-scoped. Never use module globals or in-memory session registries for multi-request state or authentication. Use `ctx.requestState` or an external database.519. **Strict CLI Flag Syntax**: Boolean CLI flags reject inline values in v2.7.2+ (`--tunnel=false` fails; use `--tunnel` or omit).5253---5455## Guardrails & Common Anti-Patterns5657- **Never import non-existent `@openai/apps-sdk-ui` components**:58 - `Card` does **not** exist in `@openai/apps-sdk-ui`. Surface cards are standard `<div>` elements styled with Tailwind utility classes (`rounded-2xl border border-default bg-surface p-4 shadow-sm`).59 - `AvatarGroup` and `CopyTooltip` **are** official `@openai/apps-sdk-ui` components (from `@openai/apps-sdk-ui/components/Avatar` and `@openai/apps-sdk-ui/components/Tooltip`).60 - `Cart` and `Checkmark` do **not** exist in `@openai/apps-sdk-ui/components/Icon`. Use `Check`, `CheckCircle`, `Search`, `Plus`, `Settings`, etc.61- **Never omit `linkComponent` on `<AppsSDKUIProvider>`**: The TypeScript contract requires `linkComponent` (e.g. `<AppsSDKUIProvider linkComponent="a">`).62- **Never read `useToolContext().toolOutput` un-narrowed**: `useToolContext()` is a discriminated union. When `status === "pending"`, `toolOutput` is `undefined`. Always handle `status === "pending"` and `status === "error"` before accessing `toolOutput`. Narrow `error instanceof ToolCancelledError` for cancelled actions.63- **Configure `websiteUrl`, `icons`, and `logging` at the top level of `MCPServer`**:64 - `icons?: Icon[]`, `websiteUrl?: string`, and `logging?: LoggingOptions` are top-level properties on `ServerConfig`. Do not nest them in a fictitious `branding: { ... }` object (`server.branding` is a read-only getter).65 - Server logging level is configured via `logging: { enabled: true, level: "info" }` or overridden by the `MCP_USE_LOG_LEVEL` environment variable.66- **Never use legacy v1 `ctx.elicit()`**: Removed in v2.0.0 during the transition to the stateless request model. Use official protocol primitives: `inputRequired`, `inputRequired.elicit`, `inputRequired.elicitUrl`, `inputResponse`, and `acceptedContent`.67- **Never use wrong CLI commands**:68 - Client connect syntax: `mcp-use client connect <name> <url> [options]` (e.g. `npx mcp-use client connect dev http://localhost:3000/mcp`).69 - Screenshot syntax: `mcp-use screenshot (--server <name> | --mcp <url>) --tool <name> [args...] [options]`.7071---7273## Base MCPServer Architecture7475Ground on [`MCPServer`](https://api-reference.mcp-use.com/classes/mcp-use.index.MCPServer.html) and [Server Documentation](https://docs.mcp-use.com/v2/typescript/server):7677```typescript78import { MCPServer } from "mcp-use";7980const server = new MCPServer({81 name: "catalog-server",82 version: "1.0.0",83 title: "Inventory & Catalog Manager",84 description: "Manage product catalog, stock levels, and search items.",85 instructions: "Use lookup-item before creating an order. Confirm stock availability.",86 basePath: "/mcp", // default route87 host: "127.0.0.1", // "0.0.0.0" for public hosting88 port: 3000,89 legacy: "stateless", // "stateless" (default) or "reject"90 websiteUrl: "https://example.com",91 icons: [92 { src: "icons/logo.svg", mimeType: "image/svg+xml", sizes: ["20x20"] }93 ],94 logging: { enabled: true, level: "info" }, // Overridden by MCP_USE_LOG_LEVEL env var95 skills: true, // Auto-discover conventional skills/ directory96 cors: {97 origin: "*",98 credentials: true,99 },100});101102export default server;103```104105---106107## Tool Definitions & Result Envelopes108109Documentation: [Server Tools](https://docs.mcp-use.com/v2/typescript/server/tools)110111```typescript112import { MCPServer } from "mcp-use";113import { z } from "zod";114115const server = new MCPServer({ name: "catalog", version: "1.0.0" });116117export const getProduct = server.tool(118 {119 name: "get-product",120 title: "Get Product Details",121 description: "Fetch product metadata, pricing, and live inventory by SKU.",122 icons: [123 { src: "icons/product.svg", mimeType: "image/svg+xml", sizes: ["20x20"] }124 ],125 inputSchema: z.object({126 sku: z.string().describe("Stock Keeping Unit identifier (e.g. 'PROD-100')"),127 }),128 outputSchema: z.object({129 sku: z.string(),130 title: z.string(),131 price: z.number(),132 inStock: z.boolean(),133 }),134 annotations: {135 readOnlyHint: true,136 openWorldHint: false,137 },138 visibility: "model", // "model" (default) or "app" (hidden from LLM, visible to UI views)139 view: {140 name: "product-card", // binds to views/product-card/view.tsx141 description: "Interactive product display card",142 },143 },144 async ({ sku }, ctx) => {145 // Expected operational failure146 if (!sku.startsWith("PROD-")) {147 return {148 isError: true,149 content: [{ type: "text", text: `Invalid SKU format: ${sku}` }],150 };151 }152153 const data = { sku, title: "Precision Screwdriver", price: 29.99, inStock: true };154 return {155 content: [{ type: "text", text: `Product ${data.title} (${sku}) is in stock at $${data.price}` }],156 structuredContent: data,157 _meta: { internalId: "db_98213" }, // Private to view, hidden from LLM158 };159 }160);161162export default server;163```164165---166167## ChatGPT Apps & OpenAI Apps SDK UI Compliance168169Documentation:170- [ChatGPT Plugin Extensions](https://docs.mcp-use.com/v2/typescript/mcp-apps/chatgpt-extensions)171- [OpenAI Apps SDK UI Repository](https://github.com/openai/apps-sdk-ui)172- [Apps SDK UI Storybook Docs](https://openai.github.io/apps-sdk-ui/?path=/docs/overview-introduction--docs)173- [ChatGPT Apps UI Reference](references/chatgpt-apps-ui.md)174175### 1. Installation & Styles Setup176```bash177npm install @openai/apps-sdk-ui tailwindcss @tailwindcss/vite178```179180In `views/main.css` (or view-specific CSS):181```css182@import "tailwindcss";183@import "@openai/apps-sdk-ui/css";184@source "../node_modules/@openai/apps-sdk-ui";185```186187### 2. View Component with Apps SDK UI & Theme Sync188Create `views/product-card/view.tsx`:189190```tsx191import "./main.css";192import React, { useEffect } from "react";193import { useToolContext, useModelContext, useViewTheme, ToolCancelledError, type ViewConfig } from "mcp-use/react";194import { AppsSDKUIProvider } from "@openai/apps-sdk-ui/components/AppsSDKUIProvider";195import { Button } from "@openai/apps-sdk-ui/components/Button";196import { Badge } from "@openai/apps-sdk-ui/components/Badge";197import { applyDocumentTheme } from "@openai/apps-sdk-ui/theme";198import { Check, Plus } from "@openai/apps-sdk-ui/components/Icon";199200export const viewConfig = {201 autoResize: true,202 displayModes: ["inline", "fullscreen"],203 preferredDisplayMode: "inline",204} satisfies ViewConfig;205206export default function ProductCardView() {207 const { status, toolInput, toolOutput, error } = useToolContext<"get-product">();208 const theme = useViewTheme();209 const { add } = useModelContext();210211 // Synchronize host theme with Apps SDK UI data-theme attribute212 useEffect(() => {213 if (theme) applyDocumentTheme(theme);214 }, [theme]);215216 if (status === "pending") {217 return <div className="p-4 text-secondary text-sm">Loading SKU {toolInput?.sku}…</div>;218 }219220 if (status === "error") {221 if (error instanceof ToolCancelledError) {222 return <div className="p-4 text-secondary text-sm">Action cancelled: {error.reason}</div>;223 }224 return <div className="p-4 text-danger text-sm">Error: {error.message}</div>;225 }226227 return (228 <AppsSDKUIProvider linkComponent="a">229 {/* Standard surface card styled with semantic tokens */}230 <div className="w-full max-w-md rounded-2xl border border-default bg-surface p-4 shadow-sm">231 <div className="flex items-start justify-between">232 <div>233 <h2 className="heading-md">{toolOutput.title}</h2>234 <p className="text-secondary text-sm">SKU: {toolOutput.sku}</p>235 </div>236 <Badge color={toolOutput.inStock ? "success" : "warning"}>237 {toolOutput.inStock ? "In Stock" : "Backorder"}238 </Badge>239 </div>240241 <div className="mt-4 flex items-center justify-between border-t border-subtle pt-3">242 <span className="text-lg font-semibold">${toolOutput.price.toFixed(2)}</span>243 <Button244 color="primary"245 onClick={() => {246 // Attach verified evidence to next ChatGPT model turn (synchronous void)247 add("selected:product", {248 type: "text",249 text: `Selected SKU ${toolOutput.sku}: $${toolOutput.price}`,250 });251 }}252 >253 <Plus className="size-4" />254 Add to Chat255 </Button>256 </div>257 </div>258 </AppsSDKUIProvider>259 );260}261```262263### 3. Complete Apps SDK UI Component Inventory (29 Components)264265All imported from `@openai/apps-sdk-ui/components/<Component>`:266267| Category | Components | Purpose |268|---|---|---|269| **Feedback & Status** | `Alert`, `Badge`, `Indicator`, `EmptyMessage`, `ShimmerText` | Status banners, live badges, empty states, and loading shimmers. |270| **Identity & Icons** | `Avatar`, `Image`, `Icon` | User profiles, image fallbacks, and 700+ monochrome SVGs. |271| **Actions** | `Button`, `ButtonLink` (plus `CopyButton`) | Primary, secondary, soft, outline action buttons and copy controls. |272| **Form Inputs** | `Input`, `Textarea`, `Checkbox`, `Switch`, `RadioGroup`, `Slider`, `SegmentedControl`, `Select`, `SelectControl`, `TagInput` | Accessible, validated inputs and grouped controls. |273| **Date Pickers** | `DatePicker`, `DateRangePicker` | Calendar popups and date range selectors. |274| **Overlays** | `Menu`, `Popover`, `Tooltip` | Dropdown menus, anchored popovers, and contextual tooltips. |275| **Typography & Content** | `Markdown`, `CodeBlock`, `TextLink` | Styled markdown renderer, syntax-highlighted code blocks, and themed hyperlinks. |276| **Motion & Transitions** | `Transition` (`Animate`, `AnimateLayout`, `SlotTransitionGroup`, `TransitionGroup`) | Smooth height, fade, and layout morph transitions for iframes. |277| **Providers** | `AppsSDKUIProvider` | Root context providing router `linkComponent` configuration. |278279### 4. Official Hooks Suite (`@openai/apps-sdk-ui/hooks`)280- `useBreakpoint(size: BreakpointName)`: Responsive breakpoint match boolean (e.g. `useBreakpoint("md")`).281- `useAutoGrowTextarea()`: Dynamic auto-growing textarea heights.282- `useAnimatedScrollTo()`: Smooth programmatic scrolling with cancellation.283- `useDocumentVisible()`: Tracks iframe visibility.284- `useIsMounted()`, `useLatestValue()`, `usePrevious()`, `useScrollable()`, `useSimulatedProgress()`, `useStableCallback()`, `useTextSelection()`, `useTrailingValue()`.285286---287288## ChatGPT Plugin Extensions289290Documentation: [ChatGPT Plugin Extensions](https://docs.mcp-use.com/v2/typescript/mcp-apps/chatgpt-extensions) | [Extensions Reference](references/chatgpt-extensions.md)291292### 1. Typed Launch Entrypoints293Declare launch surfaces on `tool.view.entrypoints`:294- `global`: Launches app from ChatGPT top-level launcher (input schema must accept `{}`).295- `thread`: Launches app within conversation tab (input schema must accept `{}`).296- `file`: Launches app as file viewer for matching extensions (input schema must receive `{ file: { name: string, resourceUri: string } }`).297298```typescript299export const openCsvViewer = server.tool(300 {301 name: "open-csv",302 title: "CSV Table Viewer",303 inputSchema: z.object({304 file: z.object({ name: z.string(), resourceUri: z.string() }),305 }),306 outputSchema: z.object({ file: z.object({ name: z.string(), resourceUri: z.string() }) }),307 view: {308 name: "csv-viewer",309 entrypoints: [{ type: "file", extensions: [".csv", ".tsv"] }],310 },311 },312 async ({ file }) => ({ content: [], structuredContent: { file } })313);314```315316### 2. Native Plugin Settings (`server.settings`)317Register native ChatGPT plugin settings with typed fields and layout sections:318319```typescript320server.settings({321 fields: {322 theme: { type: "string", label: "Theme", default: "system" },323 autoSync: { type: "boolean", label: "Automatic Sync", default: true },324 },325 layout: [326 {327 title: "Preferences",328 fields: ["theme", "autoSync"],329 },330 ],331 read: async (ctx) => ({ theme: "system", autoSync: true }),332 update: async (patch, ctx) => ({ theme: "system", autoSync: true, ...patch }),333});334```335336### 3. Incoming Deep Links (`useDeepLink`)337Read incoming URLs sent to global entrypoints:338```tsx339import { useDeepLink } from "mcp-use/react";340341export function AppRouter() {342 const { url } = useDeepLink(); // e.g. "/items?tag=hardware"343}344```345346### 4. Selected Model Context (`useModelContext`)347Manage evidence attachments sent with the next user model turn (`attachments` is `Record<string, ModelContextBlock>`, `add` is synchronous void):348```tsx349import { useModelContext } from "mcp-use/react";350351const { attachments, add, remove, clearAttachments } = useModelContext();352353// Attach text summary (synchronous void, no title)354add("summary", { type: "text", text: "Order Summary: Total $120.00" });355356// Attach image with Base64 data (PNG/JPEG/GIF/WebP, max 10MB)357add("receipt", { type: "image", data: receiptBase64, mimeType: "image/png" });358359// Enumerate attached blocks360Object.entries(attachments).map(([key, block]) => (361 <span key={key}>{key}: {block.type}</span>362));363```364365---366367## Authentication & Mixed Auth368369Documentation: [Authentication](https://docs.mcp-use.com/v2/typescript/server/authentication) | [Mixed Auth](https://docs.mcp-use.com/v2/typescript/server/authentication/mixed-auth) | [Auth Reference](references/auth.md)370371Configure `mixedAuth: true` on `MCPServer` to serve public discovery, optional auth, and protected tools from one endpoint:372373```typescript374import { MCPServer } from "mcp-use";375import { oauthAuth0Provider } from "mcp-use/oauth/auth0";376import { z } from "zod";377378const server = new MCPServer({379 name: "store",380 version: "1.0.0",381 oauth: oauthAuth0Provider({ domain: process.env.AUTH0_DOMAIN! }),382 mixedAuth: true, // Enables unauthenticated tools/list discovery383});384385// Public tool: Anyone may call without token386export const searchCatalog = server.tool(387 {388 name: "search-catalog",389 inputSchema: z.object({ query: z.string() }),390 securitySchemes: [{ type: "noauth" }],391 },392 async ({ query }, ctx) => {393 return { content: [{ type: "text", text: `Results for ${query}` }] };394 }395);396397// Protected tool: Requires sign-in with specific scopes398export const checkout = server.tool(399 {400 name: "checkout",401 inputSchema: z.object({ cartId: z.string() }),402 securitySchemes: [{ type: "oauth2", scopes: ["orders:write"] }],403 },404 async ({ cartId }, ctx) => {405 const userId = ctx.auth.user.id;406 return { content: [{ type: "text", text: `Order placed for user ${userId}` }] };407 }408);409```410411Supported Providers: Clerk (`mcp-use/oauth/clerk`), Auth0 (`mcp-use/oauth/auth0`), WorkOS (`mcp-use/oauth/workos`), Supabase (`mcp-use/oauth/supabase`), Keycloak (`mcp-use/oauth/keycloak`), Better Auth (`mcp-use/oauth/better-auth`), Scalekit (`mcp-use/oauth/scalekit`), Convex (`mcp-use/oauth/convex`), and Custom (`oauthCustomProvider`).412413---414415## Interactive Elicitation416417Documentation: [Elicitation](https://docs.mcp-use.com/v2/typescript/server/elicitation) | [Advanced Features](references/advanced-features.md)418419`ctx.elicit()` was removed in v2.0.0 during the transition to the stateless request model. Use official protocol primitives:420421```typescript422import { MCPServer, inputRequired, inputResponse, acceptedContent } from "mcp-use";423import { z } from "zod";424425const confirmSchema = z.object({ approve: z.boolean().describe("Confirm action") });426427server.tool(428 {429 name: "delete-resource",430 inputSchema: z.object({ id: z.string() }),431 },432 async ({ id }, ctx) => {433 const response = inputResponse(ctx.inputResponses, "delete-approval");434 if (response.kind === "elicit" && response.action !== "accept") {435 return { isError: true, content: [{ type: "text", text: "Action cancelled" }] };436 }437438 const confirmation = acceptedContent(ctx.inputResponses, "delete-approval", confirmSchema);439 if (!confirmation) {440 return inputRequired({441 inputRequests: {442 "delete-approval": inputRequired.elicit({443 message: `Permanently delete resource ${id}?`,444 requestedSchema: confirmSchema,445 }),446 },447 });448 }449450 if (!confirmation.approve) {451 return { isError: true, content: [{ type: "text", text: "Action rejected" }] };452 }453454 // Side-effects execute only after confirmed, validated input455 await db.delete(id);456 return { content: [{ type: "text", text: `Deleted ${id}` }] };457 }458);459```460461For external authorization: `inputRequired.elicitUrl({ message: "...", url: authUrl })`.462463---464465## Skills over MCP (SEP-2640)466467Documentation: [Skills over MCP](https://docs.mcp-use.com/v2/typescript/server/skills) | [Skills Reference](references/skills-over-mcp.md)468469Serve reusable instruction workflows alongside tools:4701. Place skills under `skills/<skill-name>/SKILL.md`.4712. Automatic discovery is enabled by default. Require with `skills: true` or disable with `skills: false` on `MCPServer`.4723. Hosts retrieve skill metadata via `skills/list` and `skills/get`.473474---475476## CLI & Tooling Reference477478Documentation: [CLI Reference](https://docs.mcp-use.com/v2/typescript/api-reference/cli-reference) | [Client CLI](https://docs.mcp-use.com/v2/typescript/tooling/client-cli) | [Verification](references/verification.md)479480```bash481# Scaffold new v2 project482npx create-mcp-use-app@latest my-server --template mcp-apps483484# Start development with hot reload, Vite views pipeline, and Inspector485mcp-use dev486487# Start development with authenticated public tunnel for live ChatGPT testing488mcp-use dev --tunnel489490# Typecheck server and views491mcp-use typecheck492493# Build for production494mcp-use build495496# Start production server497mcp-use start498499# Connect live client session straight from terminal500mcp-use client connect dev http://localhost:3000/mcp501502# List tools and call with arguments503mcp-use client dev tools list504mcp-use client dev tools call get-product sku=PROD-100505506# Capture automated screenshot of view preview507mcp-use screenshot --server dev --tool get-product sku=PROD-100508509# Deploy to mcp-use cloud (requires GitHub repo)510mcp-use deploy511```512513---514515## Canonical Documentation Links516517- **API Base**: [MCPServer Class Reference](https://api-reference.mcp-use.com/classes/mcp-use.index.MCPServer.html)518- **Official Docs**: [docs.mcp-use.com](https://docs.mcp-use.com)519 - [Server Quickstart & Core](https://docs.mcp-use.com/v2/typescript/server)520 - [Server Migration Guide](https://docs.mcp-use.com/v2/typescript/server/migration)521 - [Server Tools](https://docs.mcp-use.com/v2/typescript/server/tools)522 - [Server Examples](https://docs.mcp-use.com/v2/typescript/server/examples)523 - [MCP Apps Quickstart](https://docs.mcp-use.com/v2/typescript/mcp-apps/quickstart)524 - [ChatGPT Plugin Extensions](https://docs.mcp-use.com/v2/typescript/mcp-apps/chatgpt-extensions)525 - [MCP Apps Interactivity](https://docs.mcp-use.com/v2/typescript/mcp-apps/interactivity)526 - [Model Context Attachments](https://docs.mcp-use.com/v2/typescript/mcp-apps/model-context)527 - [Content Security Policy](https://docs.mcp-use.com/v2/typescript/mcp-apps/content-security-policy)528 - [Authentication & Mixed Auth](https://docs.mcp-use.com/v2/typescript/server/authentication/mixed-auth)529 - [Interactive Elicitation](https://docs.mcp-use.com/v2/typescript/server/elicitation)530 - [Skills over MCP](https://docs.mcp-use.com/v2/typescript/server/skills)531 - [CLI Reference](https://docs.mcp-use.com/v2/typescript/api-reference/cli-reference)532 - [Client CLI Guide](https://docs.mcp-use.com/v2/typescript/tooling/client-cli)533 - [Changelog & Breaking Changes](https://docs.mcp-use.com/typescript/changelog/changelog)534- **OpenAI Apps SDK UI**:535 - [Apps SDK UI GitHub](https://github.com/openai/apps-sdk-ui)536 - [Apps SDK UI Storybook Docs](https://openai.github.io/apps-sdk-ui/?path=/docs/overview-introduction--docs)