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.
This guide walks you through creating a complete MCP server with interactive widget support.
What You’ll Build
By the end of this guide, you’ll have:- A fully functional MCP server
- Tools that return widgets (using the
widget()helper) - React widget components that receive props from tool handlers
- Production-ready configuration
Prerequisites
- Node.js 18+ installed
- Basic knowledge of TypeScript and React
- Familiarity with MCP concepts (see MCP 101)
Step 1: Create Your Project
The easiest way to start is using the mcp-apps template:Step 2: Understand the Tool That Returns a Widget
The template already has a widget-returning tool. Openindex.ts and find the search-tools tool. Here’s what each part does:
widget: { name, invoking, invoked }— Configures which widget to render and status messageswidget({ props, output })—propsgo to the widget viauseWidget().props;outputis shown to the model
ChatGPT and MCP catalogs: Many hosts require
annotations.readOnlyHint, annotations.openWorldHint, and annotations.destructiveHint (each an explicit boolean) on every tool, and recommend an outputSchema when the tool returns structured content—including widget tools, where widget() exposes props as structuredContent unless your output helper supplies its own.Step 3: Understand the Widget Component
The template already includesresources/product-search-result/widget.tsx. It receives props from the tool’s widget({ props }) return via useWidget():
Step 4: Add Traditional MCP Tools
You can mix widget-returning tools with traditional tools that return text or structured data. See Response Helpers fortext(), object(), and other utilities:
Step 5: Widgets Calling Other Tools (useCallTool)
Widgets can call other MCP tools. TheuseCallTool hook provides type-safe tool calling:
Type Safety:
mcp-use dev generates types from your tool definitions. The callTool function gets autocomplete for tool names and parameters.Step 6: Widget Metadata (Advanced)
Thewidget config on your tool handles metadata for Inspector and ChatGPT. For custom CSP, borders, or other options, see Content Security Policy, MCP Apps, and UI Widgets.
Step 7: Testing Your Server
Start the Development Server
- MCP server on port 3000
- Widget development server with Hot Module Replacement (HMR)
- Inspector UI at
http://localhost:3000/inspector
Test in Inspector
- Open
http://localhost:3000/inspector - Navigate to the Tools tab
- Find your
search-toolstool - Enter test parameters:
{ "query": "Widget" }or{} - Click Execute to see the widget render
Deploy on Manufact
To test in ChatGPT, deploy your server first. See the Deployment Guide for one-command deployment to Manufact cloud.Test in ChatGPT
- Configure your MCP server in ChatGPT settings (use your deployed URL)
- Ask: “Search for products” or “Show me product search results for Widget”
- ChatGPT will call
search-toolsand display the widget
Step 8: Advanced Widget Features
Accessing Tool Output
Widgets can access the output of their own tool execution:Calling Other Tools
Widgets can call other MCP tools:Persistent State
Widgets can maintain state across interactions:Step 9: Production Configuration
Environment Variables
Create a.env file:
Build for Production
- Compiles TypeScript
- Bundles React widgets for Apps SDK
- Optimizes assets
- Generates production-ready HTML templates
Content Security Policy
WhenbaseUrl is set, CSP is automatically configured so widget URLs use the correct domain and your server domain is whitelisted. See Content Security Policy for per-widget configuration, environment variables, and troubleshooting.
Step 10: Deployment
Deploy to Manufact
The easiest deployment option:Manual Deployment
- Build your server:
npm run build - Set environment variables
- Deploy to your hosting platform (Railway, Render, etc.)
- Update
MCP_URLto your production domain
Best Practices
1. Schema Design
Use descriptive Zod schemas on your tools to help LLMs understand parameters:2. Theme Support
Always support both light and dark themes:Troubleshooting
Widget Not Appearing
Problem: Tool runs but widget doesn’t render Solutions:- Ensure
widget.namein the tool config matches the folder name:resources/<widget.name>/widget.tsx - Ensure the tool has
widget: { name, invoking, invoked }config - Ensure the handler returns
widget({ props, output }), nottext()orobject()directly - Check server logs for errors
Props Not Received
Problem: Component receives empty props Solutions:- Check
isPendingfirst: Widgets render before the tool completes. Props are empty whenisPendingistrue - Ensure the handler passes data via
widget({ props: { ... } }) - Use
useWidget()hook (not React props)
CSP Errors
Problem: Widget loads but assets fail with CSP errors Solutions: SetbaseUrl in server config, add external domains to CSP (per-widget or via CSP_URLS), and use HTTPS for all resources. See Content Security Policy for details.
Next Steps
- MCP Apps - Learn about the standard MCP Apps protocol
- ChatGPT Apps SDK - Deep dive into ChatGPT-specific features
- Widget Components - Explore React hooks and components
- Debugging Widgets - Test with the Inspector
- Content Security Policy - CSP configuration for widgets
- Deployment Guide - Deploy your server to production
Example: Complete Server
Summary
You’ve learned how to build MCP servers with widgets:- ✅ Define tools with
annotations, optionaloutputSchema,widget: { name, invoking, invoked }, and returnwidget({ props, output }) - ✅ Create widget components in
resources/<widget.name>/widget.tsx - ✅ Use
useWidget()for props, theme, and loading state - ✅ Use
useCallTool()for widgets that call other tools