The TypeScript way to build MCP servers with decorators, DI, and Streamable HTTP.
Made with ❤️ for TypeScript developers
FrontMCP is a TypeScript-first framework for the Model Context Protocol (MCP). You write clean, typed code; FrontMCP handles the protocol, transport, DI, session/auth, and execution flow.
// src/main.ts
import 'reflect-metadata';
import { FrontMcp, LogLevel } from '@frontmcp/sdk';
import HelloApp from './hello.app';
@FrontMcp({
info: { name: 'Demo 🚀', version: '0.1.0' },
apps: [HelloApp],
http: { port: 3000 },
logging: { level: LogLevel.Info },
})
export default class Server {}- Why FrontMCP?
- Installation
- Quickstart
- Core Concepts
- Authentication
- Sessions & Transport
- Deployment
- Version Alignment
- Contributing
- License
- TypeScript-native DX — decorators, Zod, and strong typing end-to-end
- Scoped invoker + DI — secure, composable execution with hooks
- Adapters & Plugins — extend your server without boilerplate
- Spec-aligned transport — Streamable HTTP for modern MCP clients
Prerequisites:
- Node.js: Minimum version 22 (LTS) | Recommended version 24 (Active LTS)
- This framework is developed and tested on Node.js 24
- npm: ≥ 10 (or pnpm/yarn equivalent)
For detailed setup instructions, see the Installation Guide.
npx frontmcp create my-appThis scaffolds a FrontMCP project, writes a modern ESM tsconfig.json for decorators, adds helpful package scripts, and
installs required dev deps. (Installation - FrontMCP)
npm i -D frontmcp @types/node@^22
npx frontmcp initinit adds scripts, verifies your tsconfig.json, and checks layout. No need to install @frontmcp/sdk directly—the
CLI bundles a compatible SDK for you. (Installation - FrontMCP)
If you haven’t installed FrontMCP yet, follow the installation guide first.
// src/main.ts
import { FrontMcp, LogLevel } from '@frontmcp/sdk';
import HelloApp from './hello.app';
@FrontMcp({
info: { name: 'Hello MCP', version: '0.1.0' },
apps: [HelloApp],
http: { port: 3000 },
logging: { level: LogLevel.INFO },
})
export default class HelloServer {}// src/hello.app.ts
import { App } from '@frontmcp/sdk';
import GreetTool from './tools/greet.tool';
@App({
id: 'hello',
name: 'Hello App',
tools: [GreetTool],
})
export default class HelloApp {}// src/tools/greet.tool.ts
import { Tool } from '@frontmcp/sdk';
import { z } from 'zod';
@Tool({
name: 'greet',
description: 'Greets a user by name',
inputSchema: { name: z.string() },
})
export default class GreetTool {
async execute({ name }: { name: string }) {
return `Hello, ${name}!`;
}
}Add scripts (if you didn't use frontmcp create):
{
"scripts": {
"dev": "frontmcp dev",
"build": "frontmcp build",
"start": "node dist/main.js"
}
}Then:
npm run dev
# Server listening on http://localhost:3000Tip: FrontMCP speaks MCP Streamable HTTP. Connect any MCP-capable client and call
greetwith{"name": "Ada"}. (Quickstart - FrontMCP)
Tools are typed actions with Zod schemas. Implement them as classes with @Tool({...}) or inline via tool(). Pass
Zod fields directly (no z.object({...})). (Tools - FrontMCP)
Function tool
import { tool } from '@frontmcp/sdk';
import { z } from 'zod';
export default tool({
name: 'greet',
description: 'Greets a user by name',
inputSchema: { name: z.string() }, // shape, not z.object
})(({ name }) => `Hello, ${name}!`);Class tool
import { Tool } from '@frontmcp/sdk';
import { z } from 'zod';
@Tool({
name: 'add',
description: 'Add two numbers',
inputSchema: { a: z.number(), b: z.number() },
})
export default class AddTool {
async execute({ a, b }: { a: number; b: number }) {
return a + b;
}
}After create or init, you’ll have:
{
"scripts": {
"dev": "frontmcp dev",
"build": "frontmcp build",
"inspect": "frontmcp inspector",
"doctor": "frontmcp doctor"
}
}These map to dev watch, production build, zero‑setup Inspector launch, and environment checks. (Installation - FrontMCP)
Recommended tsconfig.json (ESM + decorators)
{
"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": ["**/*.test.ts", "**/__tests__/**"]
}This mirrors what init writes for you. (Local Dev Server - FrontMCP)
Optional tsconfig.build.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true,
"sourceMap": false
},
"exclude": ["**/*.test.ts", "**/__tests__/**", "src/**/*.dev.ts"]
}Run a browser UI to exercise tools and messages:
npm run inspectThis launches the MCP Inspector; point it at your local server (e.g., http://localhost:3000). (Local Dev Server -
FrontMCP)
The FrontMCP server is defined with a single decorator: @FrontMcp({...}). It configures info, apps, http,
logging, session, and optional auth. Start minimal and scale up with providers and plugins.
(The FrontMCP Server - FrontMCP)
Apps are the organizational units for capabilities. Each app groups related tools, resources, and prompts
into a cohesive domain, along with providers, adapters, and plugins. With splitByApp: true, apps get
isolated scopes and auth surfaces. (Apps - FrontMCP)
Tools are typed actions that execute operations with side effects. They're the primary way to enable an AI model to
interact with external systems—calling APIs, modifying data, performing calculations, or triggering workflows. Use the
class @Tool decorator or inline tool({...})(handler) with Zod schemas. (Tools - FrontMCP)
Resources expose readable data to an AI model's context. Unlike tools that execute actions with side effects, resources are designed for read-only data retrieval—configuration files, user profiles, documents, or any content the model needs to reference. (Resources - FrontMCP)
Prompts provide reusable message templates for AI interactions. They return MCP GetPromptResult with typed
arguments, enabling consistent conversation patterns. (Prompts - FrontMCP)
Inject shared services, generate tools from OpenAPI specs, and add cross‑cutting behavior like caching and hooks. (Add OpenAPI Adapter - FrontMCP)
Configure auth at the server (shared) or per app (isolated). With splitByApp: true, define auth per app
(server‑level auth is disallowed). (Authentication - FrontMCP)
auth: {
type: 'remote',
name: 'frontegg',
baseUrl: 'https://idp.example.com',
dcrEnabled?: boolean,
clientId?: string | ((info: { clientId: string }) => string),
mode?: 'orchestrated' | 'transparent',
allowAnonymous?: boolean,
consent?: boolean,
scopes?: string[],
grantTypes?: ('authorization_code' | 'refresh_token')[],
authEndpoint?: string,
tokenEndpoint?: string,
registrationEndpoint?: string,
userInfoEndpoint?: string,
jwks?: JSONWebKeySet,
jwksUri?: string
}See Authentication → Remote OAuth for full details and DCR vs non‑DCR. (Remote OAuth - FrontMCP)
auth: {
type: 'local',
id: 'local',
name: 'Local Auth',
scopes?: string[],
grantTypes?: ('authorization_code' | 'refresh_token')[],
allowAnonymous?: boolean, // default true
consent?: boolean,
jwks?: JSONWebKeySet,
signKey?: JWK | Uint8Array
}Use per‑app when isolating scopes. (Local OAuth - FrontMCP)
session: {
sessionMode?: 'stateful' | 'stateless' | ((issuer) => ...), // default 'stateless'
transportIdMode?: 'uuid' | 'jwt' | ((issuer) => ...), // default 'uuid'
}- Stateful: server‑side store (e.g., Redis); supports refresh; best for short‑lived upstream tokens.
- Stateless: embeds session in JWT; simpler but no silent refresh.
- Transport IDs:
uuid(per node) orjwt(signed; distributed setups). (The FrontMCP Server - FrontMCP)
npm run dev- Default HTTP port:
3000unless configured npm run doctorchecks Node/npm versions,tsconfig, and scripts. (Local Dev Server - FrontMCP)
npm run build
NODE_ENV=production PORT=8080 npm startBuilds to dist/ (uses tsconfig.build.json). Consider a process manager and reverse proxy; align all @frontmcp/*
versions. (Production Build - FrontMCP)
If versions drift, the runtime will throw a clear “version mismatch” at boot. Keep @frontmcp/* versions aligned.
(Production Build - FrontMCP)
- PRs welcome! Read the full CONTRIBUTING.md for workflow details, coding standards, and the PR checklist.
- Keep changes focused, add/adjust Jest specs, and update docs/snippets when behavior changes.
- Before opening a PR run
yarn nx run-many -t lint,test,build,npx frontmcp doctor, and verify the demo/Inspector flows relevant to your change. - Align
@frontmcp/*versions in examples to avoid runtime version mismatches.
See LICENSE.