Getting Started
Create and run your first MCP server in 5 minutes.
Prerequisites
- Node.js 18 or higher (
node -vto check) - npm, pnpm, or yarn
Step 1: Create a project (~1 min)
npx @airmcp-dev/cli create my-serverA language selection prompt appears:
Select language / 언어를 선택하세요:
1) English
2) 한국어
> 1Skip the interactive prompt with --template and --lang:
npx @airmcp-dev/cli create my-server --template basic --lang enAvailable templates: basic (default), api, crud, agent. See Templates for details.
Install dependencies:
cd my-server
npm installGenerated structure:
my-server/
├── src/
│ └── index.ts # Server definition
├── package.json # Includes @airmcp-dev/core dependency
└── tsconfig.json # TypeScript ESM configpackage.json contents:
{
"name": "my-server",
"version": "0.1.0",
"type": "module",
"scripts": {
"build": "tsc",
"dev": "npx @airmcp-dev/cli dev"
},
"dependencies": {
"@airmcp-dev/core": "^0.1.3"
},
"devDependencies": {
"typescript": "^5.5.0",
"@types/node": "^20.0.0"
}
}Step 2: Write server code (~1 min)
Open src/index.ts (basic template):
import { defineServer, defineTool } from '@airmcp-dev/core';
const server = defineServer({
name: 'my-server',
version: '0.1.0',
transport: { type: 'sse', port: 3510 },
tools: [
defineTool('greet', {
description: 'Say hello to someone',
params: {
name: { type: 'string', description: 'Person to greet' },
},
handler: async ({ name }) => `Hello, ${name}!`,
}),
],
});
server.start();Key structure:
defineServer— defines the server. Takes name, version, transport, and tool listdefineTool— defines a single tool. Takes name, description, params, handlerserver.start()— starts the server
Step 3: Start dev mode (~30 sec)
npx @airmcp-dev/cli dev --console -p 3510Terminal output:
[air] Starting dev mode...
[air] Transport: sse (port 3510)
[air] Tools: greet
[air] Test console: http://localhost:3510
[air] Watching for file changes...Features:
- Hot reload — auto-restart on
src/file changes - Test console — test tools in the browser at
http://localhost:3510
TIP
Omit -p to use the default port 3100 (dev.port default in air.config.ts).
Step 4: Test your tool (~1 min)
Browser test console
Open http://localhost:3510:
- Select the
greettool - Enter a value for
name(e.g.,World) - Click Run
- Result:
Hello, World!
Programmatic testing
const result = await server.callTool('greet', { name: 'World' });
console.log(result); // "Hello, World!"callTool goes through the full middleware chain (validation, error handling, plugins). Test code runs the exact same path as production.
Step 5: Connect to Claude Desktop (~30 sec)
npx @airmcp-dev/cli connect claude-desktopThis adds the server to Claude Desktop's MCP config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Restart Claude Desktop and the greet tool appears in the tool list.
INFO
With stdio transport, Claude Desktop launches the server as a child process. With sse or http, you need to run the server separately.
Add more tools
Register multiple tools in the same server:
const server = defineServer({
name: 'my-server',
version: '0.1.0',
tools: [
defineTool('greet', {
description: 'Say hello',
params: { name: 'string' },
handler: async ({ name }) => `Hello, ${name}!`,
}),
defineTool('add', {
description: 'Add two numbers',
params: { a: 'number', b: 'number' },
handler: async ({ a, b }) => a + b,
}),
defineTool('now', {
description: 'Return current time',
handler: async () => new Date().toISOString(),
}),
],
});Tools without params are also valid (see now).
Add plugins
Add plugins to the use array. They execute in array order.
import {
defineServer, defineTool,
cachePlugin, retryPlugin, timeoutPlugin,
} from '@airmcp-dev/core';
const server = defineServer({
name: 'my-server',
version: '0.1.0',
use: [
timeoutPlugin(10_000), // Abort after 10s
retryPlugin({ maxRetries: 2 }), // Retry 2x on failure (200ms → 400ms backoff)
cachePlugin({ ttlMs: 30_000 }), // Cache identical calls for 30s
],
tools: [
defineTool('search', {
description: 'Search documents',
params: {
query: { type: 'string', description: 'Search query' },
limit: { type: 'number', description: 'Max results', optional: true },
},
handler: async ({ query, limit }) => {
return { results: [], total: 0 };
},
}),
],
});
server.start();Execution order: timeout → retry → cache → handler. See Plugins for all 19 built-in plugins.
Production build
# Compile TypeScript
npx tsc
# Run production
node dist/index.jsNext steps
- Configuration — separate settings with air.config.ts
- Define a Server — full defineServer options and AirServer interface
- Tools — 3 parameter formats (shorthand, object, Zod), handler context, response types
- Plugins — 19 built-in plugins and execution order
- Transport — stdio vs SSE vs HTTP and when to use each
- CLI Commands — all 12 CLI commands
- Writing Tests — test tools with vitest