loading…
Search for a command to run...
loading…
A NestJS module for building Model Context Protocol (MCP) servers using decorators to expose services as tools, resources, and prompts. It features auto-discove
A NestJS module for building Model Context Protocol (MCP) servers using decorators to expose services as tools, resources, and prompts. It features auto-discovery, a built-in playground UI, and support for multiple transports including SSE and Stdio.
NestJS module for building Model Context Protocol (MCP) servers. Expose your NestJS services as MCP tools, resources, and prompts using decorators — with auto-discovery, multiple transports, and a built-in playground UI.
@McpTool(), @McpResource(), @McpPrompt(), @McpGuard(), @McpToolGroup()/mcp-playground to browse and test toolsnpm install mcp-nestjs
npm install @nestjs/common @nestjs/core reflect-metadata rxjs
npm install zod # for Zod schemas
npm install joi # for Joi schemas
npm install class-validator class-transformer # for DTO schemas
// app.module.ts
import { Module } from '@nestjs/common';
import { McpModule } from 'mcp-nestjs';
import { GreetingService } from './greeting.service';
@Module({
imports: [
McpModule.forRoot({
name: 'my-mcp-server',
version: '1.0.0',
transports: { sse: { enabled: true } },
playground: true,
}),
],
providers: [GreetingService],
})
export class AppModule {}
// greeting.service.ts
import { Injectable } from '@nestjs/common';
import { McpTool } from 'mcp-nestjs';
@Injectable()
export class GreetingService {
@McpTool({
description: 'Say hello to someone',
schema: {
name: { type: 'string', description: 'Name to greet' },
},
})
async greet(args: { name: string }) {
return { message: `Hello, ${args.name}!` };
}
}
Start your app and visit http://localhost:3000/mcp-playground.
McpModule.forRoot(options)McpModule.forRoot({
name: 'my-server', // Server name (required)
version: '1.0.0', // Server version (required)
transports: {
sse: { enabled: true, path: '/sse' }, // SSE transport
http: { enabled: true, path: '/mcp' }, // Streamable HTTP transport
stdio: { enabled: false }, // Stdio transport
},
session: {
timeout: 30 * 60 * 1000, // Session timeout (default: 30min)
cleanupInterval: 5 * 60 * 1000, // Cleanup interval (default: 5min)
maxSessions: 1000, // Max concurrent sessions
},
playground: true, // Enable playground UI
tools: [], // Manual tool registrations
guards: [], // Global guards
})
McpModule.forRootAsync(options)McpModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
name: config.get('MCP_SERVER_NAME'),
version: config.get('MCP_VERSION'),
transports: { sse: { enabled: true } },
playground: true,
}),
inject: [ConfigService],
})
McpModule.forFeature(providers)Register additional providers in feature modules:
McpModule.forFeature([MyFeatureService])
@McpTool(options) — Method DecoratorMarks a method as an MCP tool.
@McpTool({
name?: string, // Override tool name (default: [group_]methodName)
description: string, // Required description
schema?: ZodType | JoiSchema | Record<string, InlinePropertyDef>, // Input schema
transform?: 'auto' | 'raw' | ((result) => ToolResult), // Response mode
excludeProperties?: string[], // Hide fields from schema
requiredProperties?: string[], // Override required fields
})
Schema options:
// Inline (always available)
@McpTool({
description: 'Search users',
schema: {
query: { type: 'string', description: 'Search term' },
limit: { type: 'number', default: 10, required: false },
role: { type: 'string', enum: ['admin', 'user'] },
tags: { type: 'array', items: { type: 'string' }, required: false },
},
})
// Zod (if installed)
import { z } from 'zod';
@McpTool({
description: 'Create user',
schema: z.object({
name: z.string(),
email: z.string(),
role: z.enum(['admin', 'user']).optional(),
}),
})
// Joi (if installed)
import Joi from 'joi';
@McpTool({
description: 'Create user',
schema: Joi.object({
name: Joi.string().required(),
email: Joi.string().required(),
}),
})
Transform modes:
// 'auto' (default) — return value auto-wrapped in ToolResult
@McpTool({ description: 'Get data' })
async getData() {
return { key: 'value' }; // → { content: [{ type: 'text', text: '{"key":"value"}' }] }
}
// 'raw' — you return a ToolResult directly
@McpTool({ description: 'Get data', transform: 'raw' })
async getData(): Promise<ToolResult> {
return { content: [{ type: 'text', text: 'hello' }] };
}
// Custom function
@McpTool({
description: 'Get user',
transform: (user) => ({
content: [{ type: 'text', text: `User: ${user.name}` }],
}),
})
@McpToolGroup(prefix?) — Class DecoratorPrefixes all tool names in a class:
@McpToolGroup('files') // tools: files_list, files_read, files_write
@Injectable()
export class FilesService {
@McpTool({ description: 'List files' })
async list() { ... }
@McpTool({ description: 'Read file' })
async read(args: { path: string }) { ... }
}
@McpToolGroup() // Auto-derive from @Controller path
@McpResource(options) — Method DecoratorExposes data as MCP resources:
// Static resource
@McpResource({
uri: 'config://app',
name: 'app_config',
description: 'Application config',
mimeType: 'application/json',
})
async getConfig() {
return {
contents: [{
uri: 'config://app',
mimeType: 'application/json',
text: JSON.stringify({ debug: true }),
}],
};
}
// Parameterized resource (URI template)
@McpResource({
uriTemplate: 'users://{userId}',
name: 'user_detail',
mimeType: 'application/json',
})
async getUser(uri: string) {
const id = uri.match(/users:\/\/(.+)/)?.[1];
return { contents: [{ uri, text: JSON.stringify(user) }] };
}
@McpPrompt(options) — Method DecoratorReusable prompt templates:
@McpPrompt({
name: 'code_review',
description: 'Generate a code review prompt',
schema: {
code: { type: 'string', description: 'Code to review' },
language: { type: 'string', description: 'Programming language' },
},
})
async codeReview(args: { code: string; language: string }) {
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: `Review this ${args.language} code:\n\`\`\`\n${args.code}\n\`\`\``,
},
}],
};
}
@McpGuard(...guards) — Class or Method DecoratorPer-tool or per-class authorization:
import { IMcpGuard, McpExecutionContext } from 'mcp-nestjs';
export class ApiKeyGuard implements IMcpGuard {
canActivate(context: McpExecutionContext): boolean {
const args = context.getArgs();
return args.apiKey === 'secret';
}
}
// Class-level: all tools require auth
@McpGuard(ApiKeyGuard)
@Injectable()
export class AdminService { ... }
// Method-level: only this tool requires auth
@McpGuard(RateLimitGuard)
@McpTool({ description: 'Sensitive operation' })
async sensitiveOp() { ... }
McpExecutionContext provides:
getSessionId() — current session IDgetArgs() — tool/prompt argumentsgetRequest() — raw transport requestgetToolName() — tool/resource/prompt namegetType() — 'tool' | 'resource' | 'prompt'// Via forRoot options
McpModule.forRoot({
...config,
tools: [{
definition: {
name: 'echo',
description: 'Echo input',
inputSchema: {
type: 'object',
properties: { message: { type: 'string' } },
required: ['message'],
},
},
handler: async (args) => ({
content: [{ type: 'text', text: args.message }],
}),
}],
})
// Via ToolRegistryService at runtime
@Injectable()
export class DynamicTools implements OnModuleInit {
constructor(private registry: ToolRegistryService) {}
onModuleInit() {
this.registry.registerTool({ definition: {...}, handler: async (args) => {...} });
}
}
GET /sse → Opens SSE stream, returns session endpoint
POST /messages?sessionId=X → Send JSON-RPC requests
POST /mcp → Single JSON-RPC request/response
Session via `mcp-session-id` header
Reads JSON-RPC from stdin, writes responses to stdout. For CLI subprocess spawning.
Enable with playground: true in module options. Visit /mcp-playground to:
See the examples/ directory for complete working examples:
| Example | What it shows |
|---|---|
01-basic |
Minimal setup — one service, two tools |
02-inline-schema |
All inline schema options — enums, arrays, defaults, optionals |
03-zod-schema |
Zod schema integration |
04-tool-groups |
@McpToolGroup prefix namespacing |
05-resources |
Static URIs and URI templates |
06-prompts |
Reusable prompt templates |
07-guards |
API key auth, rate limiting, logging guards |
08-manual-tools |
forRoot({ tools }) + runtime ToolRegistryService |
09-multiple-transports |
SSE + HTTP + Stdio with session config |
10-async-config |
forRootAsync() with injected ConfigService |
11-full-app |
Everything combined |
Run any example:
npx ts-node -r reflect-metadata examples/01-basic/main.ts
MIT
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"mcp-nestjs": {
"command": "npx",
"args": []
}
}
}Extract design specs and assets
An Open-Sourced UI to install and manage MCP servers for Windows, Linux and macOS.
Build, validate, and deploy multi-agent AI solutions on the ADAS platform. Design skills with tools, manage solution lifecycle, and connect from any AI environm
MCP Bundles: Create custom bundles of tools and connect providers with OAuth or API keys. Use one MCP server across thousands of integrations, with programmatic