Skip to main content
Run your FrontMCP server locally with hot-reload and verify it with the FrontMCP Inspector (zero setup).

Prerequisites

  • Node.js:
    • Minimum: Version 22 (LTS Maintenance)
    • Recommended: Version 24 (Active LTS)
    • FrontMCP is developed and tested on Node.js 24
  • npm ≥ 10 (pnpm/yarn also supported)

Quick start

Option A — New project

Creates a folder and scaffolds everything for you.
npx frontmcp create my-app
The create command is interactive by default. Use --yes for non-interactive mode with defaults (Docker target, Redis via Docker Compose, GitHub Actions enabled).

Option B — Existing project

Install and initialize in your current repo:
bash universal npm i -D frontmcp @types/node@^24 npx frontmcp init
init adds the required scripts and updates tsconfig.json automatically.

Package scripts

After create or init, your package.json will include:
{
  "scripts": {
    "dev": "frontmcp dev",
    "build": "frontmcp build",
    "inspect": "frontmcp inspector",
    "doctor": "frontmcp doctor"
  }
}
  • frontmcp dev — run in watch mode with type-checks
  • frontmcp build — compile to ./dist (override with --out-dir)
  • frontmcp inspector — launches @modelcontextprotocol/inspector with zero setup
  • frontmcp doctor — verifies Node/npm versions and project configuration

Docker scripts (Docker target only)

If you created your project with the Docker target (--target node), you’ll also have:
{
  "scripts": {
    "docker:up": "docker compose -f ci/docker-compose.yml up",
    "docker:down": "docker compose -f ci/docker-compose.yml down",
    "docker:build": "docker compose -f ci/docker-compose.yml build"
  }
}
# Start the full stack (app + Redis if configured)
npm run docker:up

# Stop containers
npm run docker:down

# Rebuild the Docker image
npm run docker:build

# Rebuild only the app service (selective rebuild — skips Redis)
docker compose -f ci/docker-compose.yml up --build app

init writes this for you, but if you prefer to manage it manually:
tsconfig.json
{
  "compilerOptions": {
    "target": "es2021",
    "module": "esnext",
    "lib": ["es2021"],
    "moduleResolution": "bundler",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "sourceMap": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["**/*.spec.ts", "**/__tests__/**"]
}

Minimal app

You can import from @frontmcp/sdk directly; no extra install needed.
src/main.ts
import 'reflect-metadata';
import { FrontMcp, LogLevel } from '@frontmcp/sdk';
import HelloApp from './hello.app';

@FrontMcp({
  info: { name: 'Hello MCP', version: '0.1.0' },
  apps: [HelloApp],
  http: { port: Number(process.env.PORT) || 3000 },
  logging: { level: LogLevel.Info },
})
export default class Server {}
src/hello.app.ts
import { App } from '@frontmcp/sdk';
import Greet from './tools/greet.tool';

@App({ id: 'hello', name: 'Hello', tools: [Greet] })
export default class HelloApp {}
src/tools/greet.tool.ts
import { Tool, ToolContext, z } from '@frontmcp/sdk';

@Tool({
  name: 'greet',
  description: 'Greets a user by name',
  inputSchema: { name: z.string() },
})
export default class Greet extends ToolContext {
  async execute({ name }: { name: string }) {
    return `Hello, ${name}!`;
  }
}

Run the dev server

bash universal npm run dev
Your server will start (default http://localhost:3000). The console will print the MCP endpoint.

Port conflict handling

frontmcp dev performs a pre-flight TCP probe before spawning tsx --watch. If the port is already in use the command exits with a one-line message instead of a raw EADDRINUSE stack trace:
[dev] Port 3000 is already in use — refusing to start.
      Retry with one of:
        • frontmcp dev --port <other-port>
        • frontmcp dev --auto-port     (pick the next free port automatically)
        • PORT=<other-port> frontmcp dev
FlagBehaviour
--port <n>Bind the dev server to TCP port <n> (sets PORT=<n> in the child’s env).
--auto-portIf the requested port is busy, walk forward to the next free port.
--show-conflictOn EADDRINUSE, run lsof (POSIX) to print which process is holding the port.
The PORT env var only takes effect when your @FrontMcp metadata reads it — the canonical http: { port: Number(process.env.PORT) || 3000 } pattern shown above. If you hard-code http.port: 4000 in metadata, your server will bind to 4000 regardless of --port or PORT, and the pre-flight probe is advisory only.

MCP endpoint path

By default the MCP endpoint is served at the root path (/). Set transport.http.path in frontmcp.config.ts to mount it elsewhere — frontmcp dev honors it, so the endpoint matches the URL emitted in your generated client config (clients.*.url) and an HTTP client pointed at that path no longer 404s:
// frontmcp.config.ts
export default {
  // ...
  transport: { default: 'http', http: { port: 3000, path: '/mcp' } },
};
[dev] listening on port: 3000
[dev] MCP endpoint path: /mcp        # POST http://localhost:3000/mcp
Under the hood dev passes the configured path to the spawned server via the FRONTMCP_HTTP_ENTRY_PATH env var, which the SDK’s http.entryPath default reads — the same pattern as PORT.
As with PORT, an explicit @FrontMcp({ http: { entryPath } }) in your metadata wins over transport.http.path / the env var. Keep the two in sync, or omit entryPath from metadata and let transport.http.path drive the mount.

Inspect locally (zero setup)

Launch the FrontMCP Inspector to exercise tools and messages in a friendly UI:
bash universal npm run inspect
  • This runs npx @modelcontextprotocol/inspector behind the scenes.
  • Point it at your local server URL printed by dev (e.g., http://localhost:3000).
  • Try calling greet and watch responses stream back in real time.

Troubleshooting

  • Check configuration
npm run doctor
Ensures Node/npm versions, entry detection, and tsconfig.json are correct.
  • Entry detection The CLI looks for package.json.main; if missing, it falls back to src/main.ts. If no entry is found, it will tell you how to create one.
  • Type errors in dev The dev command performs async type-checks while watching your files, so you’ll see issues immediately without stopping the server.