Quick Start
Build your first MCP server tool in 5 minutes.
Setup
Scaffolding a New Project
npx create-mcp-use-app my-server
cd my-server
npm run devThis installs dependencies, starts the server on port 3000, and opens the inspector at http://localhost:3000/inspector.
Choosing a Template
Pick the template that matches what the user is building:
| Template | Command | Use When |
|---|---|---|
| starter (default) | npx create-mcp-use-app my-server | Full-featured server with tools, resources, prompts, and widget examples |
| mcp-apps | npx create-mcp-use-app my-server --template mcp-apps | Widget-focused for ChatGPT, Claude, and other MCP Apps-compatible clients |
| blank | npx create-mcp-use-app my-server --template blank | Clean slate — bare server with commented-out examples |
| GitHub repo | npx create-mcp-use-app my-server --template owner/repo | Custom or community templates from any GitHub repository |
When unsure, use mcp-apps. It's the recommended default with widget support for ChatGPT, Claude, and other MCP Apps-compatible clients.
Common Flags
# Choose package manager
npx create-mcp-use-app my-server --npm
npx create-mcp-use-app my-server --pnpm
# Skip interactive prompts
npx create-mcp-use-app my-server --install --skills
# List all available templates
npx create-mcp-use-app --list-templatesWhat Each Template Produces
starter:
my-server/
├── index.ts # Server with example tool, resource, and prompt
├── resources/ # Widget directory (display-weather.tsx example)
├── public/ # Static assets (favicon, icon)
├── package.json # Pre-configured scripts: dev, build, start, deploy
└── tsconfig.jsonmcp-apps:
my-server/
├── index.ts # Server with widget-returning tools
├── resources/ # Widget directory (product-search-result/ example)
│ └── product-search-result/
│ ├── widget.tsx # React widget with carousel UI
│ └── components/ # Reusable widget components
├── public/
├── package.json
└── tsconfig.jsonblank:
my-server/
├── index.ts # Bare MCPServer with commented-out examples
├── public/
├── package.json
└── tsconfig.jsonDevelopment Workflow
After scaffolding:
npm run dev— starts server with hot reload + inspector- Edit
index.tsto add tools, resources, prompts - Add widgets as
.tsxfiles inresources/ - Test everything at
http://localhost:3000/inspector npm run build— production buildnpm run deploy— deploy to production
Your First Tool
Open index.ts and you'll see a basic server. Let's add a simple tool:
import { MCPServer, text } from "mcp-use/server";
import { z } from "zod";
const server = new MCPServer({
name: "my-server",
title: "My Server",
version: "1.0.0",
baseUrl: process.env.MCP_URL || "http://localhost:3000"
});
// Add this tool
server.tool(
{
name: "greet",
description: "Greet a user by name",
schema: z.object({
name: z.string().describe("User's name")
})
},
async ({ name }) => {
return text(`Hello, ${name}! Welcome to MCP.`);
}
);
server.listen();Save the file - the server auto-reloads!
Test it:
- Open inspector (
http://localhost:3000/inspector) - Click "List Tools"
- Find "greet" tool
- Click "Call Tool"
- Enter
{"name": "Alice"} - See response: "Hello, Alice! Welcome to MCP."
Add Mock Data
Let's build a weather tool with mock data:
// Mock weather data
const mockWeather: Record<string, { temp: number; conditions: string }> = {
"New York": { temp: 22, conditions: "Partly Cloudy" },
"London": { temp: 15, conditions: "Rainy" },
"Tokyo": { temp: 28, conditions: "Sunny" },
"Paris": { temp: 18, conditions: "Overcast" }
};
server.tool(
{
name: "get-weather",
description: "Get current weather for a city",
schema: z.object({
city: z.string().describe("City name")
})
},
async ({ city }) => {
const weather = mockWeather[city];
if (!weather) {
return text(`No weather data for ${city}`);
}
return text(
`Weather in ${city}: ${weather.temp}°C, ${weather.conditions}`
);
}
);Test it:
- Call tool with
{"city": "Tokyo"} - Response: "Weather in Tokyo: 28°C, Sunny"
Add Structure
Return structured data with object():
import { MCPServer, text, object } from "mcp-use/server";
server.tool(
{
name: "get-weather-detailed",
description: "Get detailed weather information",
schema: z.object({
city: z.string().describe("City name")
})
},
async ({ city }) => {
const weather = mockWeather[city];
if (!weather) {
return object({ error: `No data for ${city}` });
}
return object({
city,
temperature: weather.temp,
conditions: weather.conditions,
unit: "celsius",
timestamp: new Date().toISOString()
});
}
);Add a Resource
Resources provide read-only data:
server.resource(
{
name: "available_cities",
uri: "weather://available-cities",
title: "Available Cities",
description: "List of cities with weather data"
},
async () => object({
cities: Object.keys(mockWeather)
})
);Test it:
- Inspector → "List Resources"
- Find "Available Cities"
- Click "Read Resource"
- See:
{"cities": ["New York", "London", "Tokyo", "Paris"]}
Next Steps
Now that you have the basics:
- Learn response helpers → ../server/response-helpers.md
- Build your first widget → ../widgets/basics.md
- See complete examples → ../patterns/common-patterns.md
Want to add visual UI? Continue to widgets:
- Widget Basics - Create your first interactive widget