---
title: Quickstart
slug: getting-started/quickstart
icon: rocket-launch
description: Build your first MCP server with FrontMCP in under 5 minutes
keywords: ['frontmcp', 'mcp', 'model context protocol', 'getting started', 'setup', 'install', 'quickstart', 'typescript']
---

Build and run your first MCP server with FrontMCP. This quickstart gets you from zero to a working server in under 5 minutes.

## Prerequisites

- **Node.js**: Version 24+ (LTS)
  - _The `engines` field in `@frontmcp/sdk` and `frontmcp` requires Node 24+. FrontMCP is developed and tested on Node 24._
- **npm ≥ 10** (or pnpm/yarn)

---

<Tabs>
  <Tab title="Standard">

## Create a new project

<CodeGroup>

```bash npm
npx frontmcp create my-mcp-server
cd my-mcp-server
npm run dev
```

```bash pnpm
pnpm dlx frontmcp create my-mcp-server
cd my-mcp-server
pnpm dev
```

```bash yarn
npx frontmcp create my-mcp-server
cd my-mcp-server
yarn dev
```

</CodeGroup>

<Info>
The `create` command is **interactive** by default. It will ask you about:
- **Deployment target**: Node.js (Docker), Vercel, AWS Lambda, or Cloudflare Workers
- **Redis setup**: Docker Compose, existing Redis, or none (Docker target only)
- **GitHub Actions**: Enable CI/CD workflows

Use `--yes` (or `-y`) to skip prompts and use defaults.

</Info>

The CLI creates a complete project structure with:

- ✅ TypeScript configured
- ✅ Sample server, app, and tool
- ✅ Development scripts ready
- ✅ Hot-reload enabled
- ✅ Deployment configuration for your target platform
- ✅ GitHub Actions CI/CD (optional)
- ✅ Git repository initialized with initial commit

<Check>Your server is now running at `http://localhost:3000`!</Check>

---

## Add to Existing Project

If you already have a Node.js project, install FrontMCP:

<CodeGroup>

```bash npm
npm install @frontmcp/sdk reflect-metadata
npm install -D frontmcp @types/node@^24
npx frontmcp init
```

```bash pnpm
pnpm add @frontmcp/sdk reflect-metadata
pnpm add -D frontmcp @types/node@^24
pnpm dlx frontmcp init
```

```bash yarn
yarn add @frontmcp/sdk reflect-metadata
yarn add -D frontmcp @types/node@^24
npx frontmcp init
```

</CodeGroup>

The `init` command:

- Creates or updates `tsconfig.json` with the required decorator settings

---

## Project Structure

After creating your project, you'll have:

<Tabs>
  <Tab title="Docker (default)">
    ```
    my-mcp-server/
    ├── ci/
    │   ├── Dockerfile
    │   ├── docker-compose.yml
    │   └── .env.docker
    ├── .github/workflows/    # If CI/CD enabled
    │   ├── ci.yml
    │   ├── e2e.yml
    │   └── deploy.yml
    ├── src/
    │   ├── main.ts
    │   ├── calc.app.ts
    │   └── tools/
    │       └── add.tool.ts
    ├── package.json
    └── tsconfig.json
    ```
  </Tab>
  <Tab title="Vercel">
    ```
    my-mcp-server/
    ├── vercel.json
    ├── src/
    │   ├── main.ts
    │   ├── calc.app.ts
    │   └── tools/
    │       └── add.tool.ts
    ├── package.json
    └── tsconfig.json
    ```
  </Tab>
  <Tab title="Lambda">
    ```
    my-mcp-server/
    ├── ci/
    │   └── template.yaml    # AWS SAM template
    ├── src/
    │   ├── main.ts
    │   ├── calc.app.ts
    │   └── tools/
    │       └── add.tool.ts
    ├── package.json
    └── tsconfig.json
    ```
  </Tab>
  <Tab title="Cloudflare">
    ```
    my-mcp-server/
    ├── wrangler.toml
    ├── src/
    │   ├── main.ts
    │   ├── calc.app.ts
    │   └── tools/
    │       └── add.tool.ts
    ├── package.json
    └── tsconfig.json
    ```
  </Tab>
</Tabs>

---

## Available Commands

Your project includes these scripts:

<CodeGroup>

```bash Development
npm run dev
# Starts server with hot-reload and type-checking
```

```bash Build
npm run build
# Compiles TypeScript to ./dist
```

```bash Production
./dist/<app-name>
# Runs the compiled server via the bash runner produced by `npm run build`
```

```bash Inspector
npm run inspect
# Opens the MCP Inspector UI
```

```bash Doctor
npm run doctor
# Verifies Node/npm versions and config
```

</CodeGroup>

  </Tab>
  <Tab title="Nx Monorepo">

## Create the workspace

<CodeGroup>

```bash npm
npx frontmcp create my-platform --nx
cd my-platform
```

```bash pnpm
pnpm dlx frontmcp create my-platform --nx --pm pnpm
cd my-platform
```

```bash yarn
npx frontmcp create my-platform --nx --pm yarn
cd my-platform
```

</CodeGroup>

This scaffolds the full monorepo structure with a sample app, including `apps/`, `libs/`, and `servers/` directories.

---

## Build your first app

<Steps>
  <Step title="Generate an app">
    ```bash
    nx g @frontmcp/nx:app crm
    ```

    Creates `apps/crm/` with a main entry point, app class, and sample tool.

  </Step>

  <Step title="Add a tool">
    ```bash
    nx g @frontmcp/nx:tool fetch-contacts --project crm
    ```

    Creates `apps/crm/src/tools/fetch-contacts.tool.ts` — edit the `execute()` method to add your logic.

  </Step>

  <Step title="Generate a shared library">
    ```bash
    nx g @frontmcp/nx:lib shared-utils
    ```

    Creates `libs/shared-utils/` — use it for code shared across apps.

  </Step>

  <Step title="Generate a server">
    ```bash
    nx g @frontmcp/nx:server production --apps crm --deploymentTarget node
    ```

    Creates `servers/production/` with a Dockerfile, docker-compose.yml, and an entry point that composes the CRM app.

  </Step>

  <Step title="Start development">
    ```bash
    nx dev crm
    ```

    Starts the CRM app in development mode with hot-reload.

  </Step>

  <Step title="Build and test">
    ```bash
    nx build production
    nx test crm
    ```

    Compiles the production server and runs tests.

  </Step>
</Steps>

<Check>Your monorepo is ready! Add more apps, tools, and libraries as your platform grows.</Check>

---

## Project Structure

After completing the steps above, your workspace looks like this:

```
my-platform/
├── apps/
│   └── crm/
│       ├── src/
│       │   ├── main.ts
│       │   ├── crm.app.ts
│       │   └── tools/
│       │       ├── hello.tool.ts
│       │       └── fetch-contacts.tool.ts
│       ├── project.json
│       └── tsconfig.json
├── libs/
│   └── shared-utils/
│       ├── src/
│       │   ├── shared-utils.ts
│       │   └── index.ts
│       └── project.json
├── servers/
│   └── production/
│       ├── src/main.ts
│       ├── Dockerfile
│       ├── docker-compose.yml
│       └── project.json
├── nx.json
├── tsconfig.base.json
└── package.json
```

---

## Common Commands

| Command                | Description                  |
| ---------------------- | ---------------------------- |
| `nx dev <app>`         | Start an app with hot-reload |
| `nx build <project>`   | Build an app or server       |
| `nx test <project>`    | Run tests                    |
| `nx inspector <app>`   | Launch MCP Inspector         |
| `nx graph`             | Visualize dependency graph   |
| `nx affected -t test`  | Test only affected projects  |
| `nx run-many -t build` | Build all projects           |

  </Tab>
</Tabs>

---

## Server Configuration

```ts src/main.ts
import 'reflect-metadata';
import { FrontMcp, LogLevel } from '@frontmcp/sdk';
import { CalcApp } from './calc.app';

@FrontMcp({
  info: { name: 'Hello MCP', version: '0.1.0' },
  apps: [CalcApp],
  http: { port: 3000 },
  logging: { level: LogLevel.Info },
})
export default class Server {}
```

<Info>
  The `@FrontMcp` decorator configures your server. It requires `info`, `apps`, and optional `http` and `logging`
  settings.
</Info>

### App Definition

```ts src/calc.app.ts
import { App } from '@frontmcp/sdk';
import AddTool from './tools/add.tool';

@App({
  id: 'calc',
  name: 'Calculator',
  tools: [AddTool],
})
export class CalcApp {}
```

<Info>
  Apps organize related tools, plugins, and providers. Each app can have its own authentication and configuration.
</Info>

### Your First Tool

<Tabs>
  <Tab title="Class-based (Recommended)">
    ```ts src/tools/add.tool.ts
    import { Tool, ToolContext } from '@frontmcp/sdk';
    import { z } from '@frontmcp/sdk';

    @Tool({
      name: 'add',
      description: 'Adds two numbers together',
      inputSchema: { a: z.number(), b: z.number() },
    })
    export default class AddTool extends ToolContext {
      async execute(input: { a: number; b: number }) {
        return input.a + input.b;
      }
    }
    ```

  </Tab>

  <Tab title="Function-based">
    ```ts src/tools/add.tool.ts
    import { tool } from '@frontmcp/sdk';
    import { z } from '@frontmcp/sdk';

    export default tool({
      name: 'add',
      description: 'Adds two numbers together',
      inputSchema: { a: z.number(), b: z.number() },
    })(async (input) => {
      return input.a + input.b;
    });
    ```

  </Tab>
</Tabs>

<Tip>
  Use class-based tools when you need access to providers, logging, or auth context. Use function-based tools for simple
  stateless operations.
</Tip>

---

## Test Your Server

<Steps>
  <Step stepNumber={1} title="Start the server">
    ```bash
    npm run dev
    ```

    You should see:
    ```
    [INFO] Server listening on http://localhost:3000
    [INFO] Registered 1 tool: add
    ```

  </Step>

  <Step stepNumber={2} title="Launch the Inspector">
    Open a new terminal and run:

    ```bash
    npm run inspect
    ```

    This opens the MCP Inspector at `http://localhost:6274`

  </Step>

<Step stepNumber={3} title="Connect to your server">
  In the Inspector: 1. Enter server URL: `http://localhost:3000` 2. Click "Connect" 3. You should see your `add` tool
  listed
</Step>

  <Step title="Call your tool">
    1. Select the `add` tool
    2. Enter input: `{ "a": 2, "b": 3 }`
    3. Click "Call Tool"
    4. You should see: `5`
  </Step>
</Steps>

<Check>Congratulations! You've built and tested your first MCP server!</Check>

---

## What's Next?

<Info>
**Choosing how to run FrontMCP?** See [Runtime Modes](/frontmcp/deployment/runtime-modes) for a comparison of SDK, Server, and Serverless options.
</Info>

<CardGroup cols={2}>
  <Card title="Add Tools" icon="wrench" href="/frontmcp/servers/tools">
    Learn how to create more powerful tools with validation, providers, and context
  </Card>

<Card title="OpenAPI Adapter" icon="file-code" href="/frontmcp/guides/add-openapi-adapter">
  Auto-generate tools from your REST API's OpenAPI spec
</Card>

<Card title="Add Caching" icon="database" href="/frontmcp/guides/caching-and-cache-miss">
  Improve performance with transparent caching
</Card>

<Card title="Authentication" icon="lock" href="/frontmcp/authentication/overview">
  Secure your server with OAuth (local or remote)
</Card>

<Card title="Plugins" icon="puzzle-piece" href="/frontmcp/extensibility/plugins">
  Add cross-cutting features like logging, metrics, and rate limiting
</Card>

  <Card title="Deploy" icon="cloud-arrow-up" href="/frontmcp/deployment/production-build">
    Build and deploy your server to production
  </Card>
</CardGroup>

---

## Common Commands Reference

| Command                            | Description                                 |
| ---------------------------------- | ------------------------------------------- |
| `npx frontmcp create <name>`       | Create a new FrontMCP project (interactive) |
| `npx frontmcp create <name> --yes` | Create with defaults (non-interactive)      |
| `npx frontmcp create <name> --nx`  | Create an Nx monorepo                       |
| `npx frontmcp init`                | Add FrontMCP to existing project            |
| `npm run dev`                      | Start with hot-reload                       |
| `npm run build`                    | Compile to production                       |
| `npm run inspect`                  | Open MCP Inspector                          |
| `npm run doctor`                   | Verify setup                                |

### Create Command Flags

| Flag                 | Description                                                 |
| -------------------- | ----------------------------------------------------------- |
| `--yes, -y`          | Use defaults (non-interactive mode)                         |
| `--target <type>`    | Deployment target: `node`, `vercel`, `lambda`, `cloudflare` |
| `--redis <setup>`    | Redis setup: `docker`, `existing`, `none`                   |
| `--cicd / --no-cicd` | Enable/disable GitHub Actions CI/CD                         |
| `--pm <manager>`     | Package manager: `npm`, `yarn`, `pnpm`                      |
| `--nx`               | Scaffold an Nx monorepo instead of standalone project       |

---

## Troubleshooting

<AccordionGroup>
  <Accordion title="Server won't start">
    **Check:**
    1. Node.js version 24+: `node --version`
    2. Port 3000 is available
    3. No TypeScript errors: Check console output

    **Fix:**
    ```bash
    npm run doctor  # Verify configuration
    ```

  </Accordion>

  <Accordion title="Tools not appearing">
    **Possible causes:**
    - Tool not imported in app
    - Decorator metadata not enabled

    **Fix:**
    1. Verify `import AddTool from './tools/add.tool'`
    2. Check `tsconfig.json` has:
       ```json
       {
         "experimentalDecorators": true,
         "emitDecoratorMetadata": true
       }
       ```
    3. Ensure `import 'reflect-metadata'` at top of `main.ts`

  </Accordion>

  <Accordion title="Type errors in development">
    **Solution:**
    The `dev` command performs async type-checks. Fix TypeScript errors shown in the console.

    ```bash
    # Manual type check
    npx tsc --noEmit
    ```

  </Accordion>

  <Accordion title="Inspector can't connect">
    **Check:**
    1. Server is running: `http://localhost:3000` should be accessible
    2. Correct URL in Inspector: `http://localhost:3000` (not `https`)
    3. No CORS issues: Both server and inspector on localhost

    **Debug:**
    ```bash
    # Test server directly
    curl http://localhost:3000/health
    ```

  </Accordion>
</AccordionGroup>

---

## Example: Greeting Tool

A separate example showing more advanced features (auth context, optional fields, structured output):

```ts
import { Tool, ToolContext } from '@frontmcp/sdk';
import { z } from '@frontmcp/sdk';

@Tool({
  name: 'greet',
  description: 'Greets a user with optional formality level',
  inputSchema: {
    name: z.string().min(1, 'Name is required'),
    formality: z.enum(['casual', 'formal', 'enthusiastic']).default('casual'),
    timeOfDay: z.enum(['morning', 'afternoon', 'evening']).optional(),
  },
})
export default class GreetTool extends ToolContext {
  async execute(input: {
    name: string;
    formality: 'casual' | 'formal' | 'enthusiastic';
    timeOfDay?: 'morning' | 'afternoon' | 'evening';
  }) {
    // Access auth info (token, clientId, scopes — see MCP AuthInfo)
    const clientId = this.context.authInfo.clientId;

    // Build greeting based on formality
    let greeting = '';
    switch (input.formality) {
      case 'formal':
        greeting = `Good ${input.timeOfDay || 'day'}, ${input.name}.`;
        break;
      case 'enthusiastic':
        greeting = `Hey ${input.name}! Great to see you!`;
        break;
      case 'casual':
      default:
        greeting = `Hello, ${input.name}!`;
    }

    return {
      message: greeting,
      timestamp: new Date().toISOString(),
      clientId,
    };
  }
}
```

This example demonstrates:

- Input validation with Zod
- Default values
- Optional fields
- Accessing auth context
- Structured output

---

<Tip>
  FrontMCP speaks **MCP Streamable HTTP**. Any MCP-capable client (Claude Desktop, custom agents, etc.) can connect and
  call your tools!
</Tip>
