JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 8320
  • Score
    100M100P100Q171340F
  • License Apache-2.0

FrontMCP SDK

Package Exports

  • @frontmcp/sdk
  • @frontmcp/sdk/package.json

Readme

FrontMCP 🚀

The TypeScript-first way to build production-grade MCP servers.

Made with ❤️ for TypeScript developers

NPM - @frontmcp/sdk Node License


FrontMCP is a TypeScript-first framework for the Model Context Protocol (MCP). You describe servers, apps, tools, resources, and prompts with decorators; FrontMCP handles protocol, transport, DI, session/auth, and execution flow.

// src/main.ts
import { FrontMcp, LogLevel } from '@frontmcp/sdk';
import HelloApp from './hello.app';

@FrontMcp({
  info: { name: 'Demo 🚀', version: '0.1.0' },
  apps: [HelloApp],
  http: { port: 3001 },
  logging: { level: LogLevel.Info },
})
export default class Server {}

Table of Contents


Why FrontMCP?

  • TypeScript-native DX — decorators, Zod validation, strong typing end-to-end
  • Spec-aligned transports — Streamable HTTP (GET/POST), streaming, sessions
  • Scoped invoker + DI — secure, composable execution with hooks
  • Adapters & Plugins — generate tools from OpenAPI; add cross-cutting behavior
  • Auth — remote OAuth (external IdP) or built-in local OAuth
  • Logging — pluggable log transports (console, JSONL, HTTP batch, …)

Installation

Choose your package manager:

# npm
npm install -S frontmcp @frontmcp/sdk zod reflect-metadata
npm install -D typescript tsx @types/node rimraf @modelcontextprotocol/inspector

Requires Node 20+.


Quickstart

Minimal Server & App

src/
  main.ts
  hello.app.ts
  tools/
    greet.tool.ts

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) || 3001 },
  logging: { level: LogLevel.Info },
})
export default class Server {}

src/hello.app.ts

import { App } from '@frontmcp/sdk';
import GreetTool from './tools/greet.tool';

@App({
  id: 'hello',
  name: 'Hello',
  tools: [GreetTool],
})
export default class HelloApp {}

Function and Class Tools

Function tool

import { tool } from '@frontmcp/sdk';
import { z } from 'zod';

export default tool({
  name: 'greet',
  description: 'Greets a user by name',
  inputSchema: z.object({ name: z.string() }),
})(({ name }) => `Hello, ${name}!`);

Class tool

import { Tool } from '@frontmcp/sdk';
import { z } from 'zod';

@Tool({
  name: 'add',
  description: 'Add two numbers',
  inputSchema: z.object({ a: z.number(), b: z.number() }),
})
export default class AddTool {
  execute({ a, b }: { a: number; b: number }) {
    return a + b;
  }
}

Scripts & tsconfig

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "lib": ["ES2020"],
    "rootDir": "src",
    "outDir": "dist",
    "moduleResolution": "Node",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "sourceMap": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["**/*.test.ts", "**/__tests__/**"]
}

tsconfig.build.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "declaration": true,
    "sourceMap": false
  },
  "exclude": ["**/*.test.ts", "**/__tests__/**", "src/**/*.dev.ts"]
}

package.json (scripts)

{
  "scripts": {
    "dev": "tsx watch src/main.ts",
    "start:dev": "tsx src/main.ts",
    "build": "tsc -p tsconfig.build.json",
    "start": "node dist/main.js",
    "typecheck": "tsc --noEmit -p tsconfig.json",
    "clean": "rimraf dist",
    "inspect:dev": "npx @modelcontextprotocol/inspector tsx src/main.ts",
    "inspect:dist": "npx @modelcontextprotocol/inspector node dist/main.js"
  }
}

Always import reflect-metadata first in your entry to enable decorator metadata.

MCP Inspector

Debug your server with a browser UI:

# Dev (runs TS)
npm run inspect:dev
# Dist (runs built JS)
npm run inspect:dist

Core Concepts

Servers

The decorated entry (@FrontMcp) defines server info, apps, http, logging, session, optional **auth **, and shared providers.

Apps

Use @App to group tools, resources, prompts, providers, adapters, and plugins. With splitByApp: true, each app has its own scope/base path and (optionally) its own auth.

Tools

Active actions with input/output schemas. Use class tools (@Tool) or function tools (tool({...})(handler)).

Resources

Expose read-only data by URI. Define with @Resource or resource(...) (see docs).

Prompts

Reusable prompt templates (@Prompt / prompt(...)) supplying arguments for LLM interactions.

Providers

Dependency-injected singletons for config/DB/Redis/KMS/etc., with scopes: GLOBAL, SESSION, REQUEST.

Adapters

Generate tools/resources/prompts from external definitions (e.g., OpenAPI).

Plugins

Cross-cutting behavior (caching, tracing, policy). Plugins can contribute providers/adapters/tools/resources/prompts.


Authentication

You can configure auth on the server (multi-app shared) or per app (isolated scopes).

Remote OAuth

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
}

Local OAuth

{
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
}

With splitByApp: true, define auth per @App (server-level auth is disallowed).


Sessions & Transport

session: {
  sessionMode ? : 'stateful' | 'stateless' | ((issuer) =>
...), // default 'stateless'
  transportIdMode ? : 'uuid' | 'jwt' | ((issuer) =>
...),       // default 'uuid'
}
  • Stateful: server-side store for tokens; enables refresh; recommended for short-lived upstream tokens.
  • Stateless: tokens embedded in JWT; simpler but no silent refresh.
  • Transport IDs: uuid (per node) or jwt (signed; distributed setups).

Logging Transports

Add custom log sinks via @LogTransport:

import { LogTransport, LogTransportInterface, LogRecord } from '@frontmcp/sdk';

@LogTransport({ name: 'StructuredJson', description: 'JSONL to stdout' })
export class StructuredJsonTransport extends LogTransportInterface {
  log(rec: LogRecord): void {
    try {
      process.stdout.write(
        JSON.stringify({
          ts: rec.timestamp.toISOString(),
          level: rec.levelName,
          msg: String(rec.message),
          prefix: rec.prefix || undefined,
          args: (rec.args || []).map(String),
        }) + '\n',
      );
    } catch {}
  }
}

Register:

logging: {
  level: LogLevel.Info,
  enableConsole: false,
  transports : [StructuredJsonTransport],
}

Deployment

Local Dev

# npm
npm run dev
# yarn
yarn dev
# pnpm
pnpm dev
  • HTTP default: http.port (e.g., 3001)
  • http.entryPath defaults to '' (set to /mcp if you prefer)

Version Alignment

If versions drift, the runtime may throw a "version mismatch" error at boot. Keep @frontmcp/* on the same version across your workspace.


Contributing

PRs welcome! Please:

  • Keep changes focused and tested
  • Run typecheck, build, and try MCP Inspector locally
  • Align @frontmcp/* versions in examples

License

See LICENSE.