About nestjs
nestjs is an MCP server published by Muzikanto in the AI category: nestJS MCP (Model Context Protocol) module — allows you to create “tools” (functions) for LLM or HTTP, with automatic detection via decorators, validation, and integration with OpenAI Function Calls.
The repository has 1 stars and 0 forks, with the last commit 7 months ago. Six months or more without a commit doesn't mean the server is broken, but check the open issues before depending on it in production.
Install
npx @muzikanto/nestjs-mcpclaude mcp add nestjs-mcp-muzikant -- npx -y @muzikanto/nestjs-mcpnpx -y @muzikanto/nestjs-mcpThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about nestjs
Powered by Claude · Grounded in docs
Security checks
- ✓README presentThe repository ships documentation.
- ✓License declaredUsable under a stated license.
- !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.
3 checks have not been run yet.
Releases
README
@muzikanto/nestjs-mcp
NestJS MCP (Model Context Protocol) module — allows you to create “tools”, “prompts”, “resources” for LLM or HTTP, with automatic detection via decorators, validation, and integration with OpenAI Function Calls.
Contents
- Features
- Installation
- Usage
- Connecting the MCP module
- Create MCP tool
- Create MCP prompt
- Create MCP resource
- Dynamic creation
- Calling MCP tools via HTTP
- Calling MCP prompt via HTTP
- Calling MCP resource via HTTP
- Obtaining all tools
- Obtaining all prompts
- Obtaining all resources
- Guards
- Interceptors
- Filters
- Integration with OpenAI Function Calls
Features
- Register MCP tools using the
@McpTool()decorator - Register MCP prompts using the
@McpPrompt()decorator - Automatic detection of all providers (tools) in the module
- Input data validation
- SSE endpoints for MCP (
GET /mcp/sse, POST /mcp/messages) - Endpoint for calling a tool (
POST /mcp/tools) - Endpoint for a list of all tools (
GET /mcp/tools) - Endpoint for calling a prompt (
POST /mcp/prompts/:name) - Endpoint for a list of all prompts (
GET /mcp/prompts) - Easy integration with LLM (OpenAI Function Calls)
- Support http adapters (default fastify)
- Full TypeScript typing
- Support
@UseGuards,@UseInterceptors,@UseFilters
Examples
Installation
yarn add @muzikanto/nestjs-mcp
Peer dependencies: @nestjs/common, @nestjs/core, @nestjs/swagger, @nestjs/axios, reflect-metadata
Usage
Connecting the MCP module
import { Module } from "@nestjs/common";
import { McpModule } from "@muzikanto/nestjs-mcp";
import { TelegramSendMessageTool } from "./tools/telegram-send-message.tool";
import { TelegramAutoReplyPrompt } from "./prompts/telegram-auto-reply.prompt";
@Module({
imports: [
McpModule.forRoot({
providers: [TelegramSendMessageTool, TelegramAutoReplyPrompt],
transports: {
sse: true, // SSE endpoints for mcp
http: true, // HTTP endpoints for custom server
},
}),
],
})
export class AppModule {}
Create MCP tool
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
import { Telegraf } from "telegraf";
import z from "zod/v3";
const schema = {
chatId: z.number().describe("Telegram chat id"), // строка с описанием
text: z.string().describe("Message text"), // строка с описанием
};
@McpTool()
export class TelegramSendMessageTool implements IMcpTool<
{ chatId: string; text: string },
{ success: boolean }
> {
name = "telegram.sendMessage";
inputSchema = schema;
constructor(private readonly bot: Telegraf) {}
async execute(input: { chatId: string; text: string }) {
await this.bot.telegram.sendMessage(input.chatId, input.text);
return {
structuredContent: { success: true },
messages: [{ type: "text", text: "Success sent to user" }],
};
}
}
Calling MCP tools via HTTP
POST /mcp/tools
{
"type": "telegram.sendMessage",
"payload": {
"chatId": "...",
"text": "Hi, how are you ?"
}
}
Ответ
{
"structuredContent": {
"success": true
},
"messages": [{ "type": "text", "text": "Success sent to user" }]"
}
Obtaining all tools
GET /mcp/tools
{
"tools": [
{
"name": "telegram.sendMessage",
"description": "Sent message via Telegram",
"inputSchema": {
"type": "object",
"properties": {
"chatId": {
"type": "number",
"description": "Telegram chat ID"
},
"text": {
"type": "string",
"description": "Message text"
}
},
"required": ["chatId", "text"]
}
}
]
}
Create MCP prompt
import { IMcpPrompt, McpPrompt } from "@muzikanto/nestjs-mcp";
import z from "zod/v3";
const schema = {
chatId: z.number().describe("Telegram chat id"), // строка с описанием
text: z.string().describe("Message text"), // строка с описанием
};
@McpPrompt()
export class TelegramAutoReplyPrompt implements IMcpPrompt<{
text: string;
chatId: number;
}> {
name = "telegram_auto_reply";
description =
"Generate a short, friendly reply to an incoming Telegram message and send it back to the same chat using telegram.sendMessage tool";
schema = schema;
async execute({ text, chatId }: { text: string; chatId: number }) {
return {
messages: [
{
role: "system",
content: `You are a friendly Telegram bot. Reply briefly and to the point.`,
},
{
role: "user",
content: text,
},
{
role: "assistant",
tool_call: {
name: "telegram.sendMessage",
arguments: {
chatId,
text: "{{model_output}}",
},
},
},
],
};
}
}
Obtaining all prompts
GET /mcp/prompts
{
"prompts": [
{
"name": "telegram_auto_reply",
"description": "Generate a short, friendly reply to an incoming Telegram message and send it back to the same chat using telegram.sendMessage tool",
"inputSchema": {
"type": "object",
"properties": {
"chatId": {
"type": "number",
"description": "Telegram chat ID"
},
"text": {
"type": "string",
"description": "Message text"
}
},
"required": ["chatId", "text"]
}
}
]
}
Calling MCP prompt via HTTP
POST /mcp/prompts/telegram_auto_reply
{
"text": "Hi. How are you ?",
"chatId": 100000000
}
Response
{
"messages": [
{
"role": "system",
"content": "You are a friendly Telegram bot. Reply briefly and to the point."
},
{
"role": "user",
"content": "Hi. How are you ?"
},
{
"role": "assistant",
"tool_call": {
"name": "telegram.sendMessage",
"arguments": {
"chatId": 100000000,
"text": "{{model_output}}"
}
}
}
]
}
Create MCP resource
import { IMcpResource, McpResource } from "@muzikanto/nestjs-mcp";
@McpResource()
export class TestResource implements IMcpResource<{ userId: string }> {
name = "users.get";
uri = "users://{userId}";
title = "Get test user";
description = "Get user by id";
async execute(uri: string, vars: { userId: string }) {
return [{ uri, text: `Hello ${vars.userId}` }];
}
}
Calling MCP resource via HTTP
POST /mcp/resources/users.get
{
"uri": "users://user/1"
}
Response
{
"contents": [
{
"uri": "users://user/1",
"content": "Hello 1"
}
]
}
Obtaining all resources
GET /mcp/resources
{
"resources": [
{
"name": "users.get",
"title": "Get user by id",
"uri": "users://user/{userId}"
}
]
}
Dynamic creation
import { McpDynamicService } from "@muzikanto/nestjs-mcp";
import { Injectable } from "@nestjs/common";
import { ExampleInterceptor } from "./example.interceptor";
import { ExampleGuard } from "./example.guard";
@Injectable()
export class McpDynamic {
constructor(protected readonly mcpDynamicService: McpDynamicService) {}
onModuleInit() {
this.mcpDynamicService.registerTool({
name: "dynamic_tool",
title: "Dynamic tool",
execute: () =>
Promise.resolve({
structuredContent: { text: "test" },
messages: [{ type: "text" as const, text: "test" }],
}),
guards: [ExampleGuard],
interceptors: [ExampleInterceptor],
});
this.mcpDynamicService.registerPrompt({
name: "dynamic_prompt",
title: "Dynamic prompt",
execute: () =>
Promise.resolve({ messages: [{ role: "assistant", content: "test" }] }),
guards: [ExampleGuard],
interceptors: [ExampleInterceptor],
});
this.mcpDynamicService.registerResource<{ testId: string }>({
name: "dynamic_resource",
title: "Dynamic resource",
uri: "dynamic://test/{testId}",
execute: (uri, input) =>
Promise.resolve([{ uri: uri.href, text: `ID: ${input.testId}` }]),
guards: [ExampleGuard],
interceptors: [ExampleInterceptor],
list: async () => {
return [
{ uri: "dynamic://test/1", name: "dynamice_1", title: "Dynamic 1" },
];
},
});
}
}
Guards
For one
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
import { UseGuards } from "@nestjs/common";
import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
import { Observable } from "rxjs";
@Injectable()
class TestGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
console.log("TestGuard called");
return true;
}
}
@UseGuards(TestGuard)
@McpTool()
export class TelegramSendMessageTool implements IMcpTool<
{ chatId: string; text: string },
{ success: boolean }
> {
name = "telegram.sendMessage";
async execute() {
// await this.bot.telegram.sendMessage(input.chatId, input.text);
return {
structuredContent: { success: true },
messages: { type: "text", text: "Success sent" },
};
}
}
For all
import { McpModule } from "@muzikanto/nestjs-mcp";
import { Module } from "@nestjs/common";
import { TestGuard } from "./other/test.guard";
import { ToolWithoutGuards } from "./test.tool";
import { APP_GUARD } from "@nestjs/core";
@Module({
imports: [
McpModule.forRoot({
providers: [
ToolWithoutGuards,
TestGuard,
{ provide: APP_GUARD, useExisting: TestGuard },
],
}),
],
})
export class TestModule {}
Interceptors
For one
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
import {
ExecutionContext,
NestInterceptor,
CallHandler,
Injectable,
UseInterceptors,
} from "@nestjs/common";
import { map } from "rxjs";
@Injectable()
export class ExampleInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
console.log("Before execute");
return next.handle().pipe(
map((data: unknown) => {
console.log("After execute", data);
return data;
}),
);
}
}
@UseInterceptors(ExampleInterceptor)
@McpTool()
export class TelegramSendMessageTool implements IMcpTool<
{ chatId: string; text: string },
{ success: boolean }
> {
name = "telegram.sendMessage";
async execute() {
// await this.bot.telegram.sendMessage(input.chatId, input.text);
return {
success: true,
messagse: [{ type: "text", text: "Success sent" }],
};
}
}
For all
import { McpModule } from "@muzikanto/nestjs-mcp";
import { Module } from "@nestjs/common";
import { TestInterceptor } from "./other/test.interceptor";
import { ToolWithoutInterceptors } from "./test.tool";
import { APP_INTERCEPTOR } from "@nestjs/core";
@Module({
imports: [
McpModule.forRoot({
providers: [
ToolWithoutInterceptors,
TestInterceptor,
{ provide: APP_INTERCEPTOR, useExisting: TestInterceptor },
],
}),
],
})
export class TestModule {}
Filters
import {
IMcpTool,
McpTool,
McpUnauthorizedException,
} from "@muzikanto/nestjs-mcp";
import {
ExceptionFilter,
Catch,
ArgumentsHost,
UseFilters,
} from "@nestjs/common";
@Catch(NotImplementedException)
class NotImplExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
return {
isError: true,
messages: [{ type: "text", text: "Not implemented tool" }],
};
}
}
@Catch(McpUnauthorizedException)
class AuthExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
return {
isError: true,
messages: [{ type: "text", text: "No access" }],
};
}
}
@UseGuards(AuthGuard)
@UseFilters(AuthExceptionFilter, NotImplExceptionFilter)
@McpTool()
export class TelegramSendMessageTool implements IMcpTool<
{ chatId: string; text: string },
{ success: boolean }
> {
name = "telegram.sendMessage";
async execute() {
throw new NotImplementedException();
}
}
Integration with OpenAI Function Calls
Example with openai: 6.25.0
import axios from "axios";
import OpenAI from "openai";
const MCP_TOOLS_URL = "http://localhost:3000/mcp/tools";
const MCP_TELEGRAM_PROMPT_URL =
"http://localhost:3000/mcp/prompts/telegram_auto_reply";
// Create OpenAI client
const client = new OpenAI({
baseUrl: "https://openrouter.ai/api/v1",
apiKey: process.env.OPENROUTER_API_KEY,
});
/**
* Get all tools
*/
async function getMcpTools() {
const response = await axios.get(MCP_TOOLS_URL);
return response.data.tools.map((el) => ({
type: "function",
function: {
name: el.name,
description: el.description,
parameters: el.inputSchema,
},
}));
}
/**
* Get all prompts
*/
async function getMcpPrompt() {
const response = await axios.post(MCP_TELEGRAM_PROMPT_URL, {
/* prompt generation arguments */
});
return response.data;
}
/**
* Request mcp tool
*/
async function callMcpTool(toolName: string, payload: Record<string, any>) {
const response = await axios.post(MCP_TOOLS_URL, { type: toolName, payload });
return response.data;
}
/**
* Example
*/
(async () => {
const toolsResponse = await getMcpTools();
const promptResponse = await getMcpPrompt();
const completion = await client.chat.completions.create({
model: "arcee-ai/trinity-large-preview:free",
messages: promptResponse.messages,
tools: toolsResponse,
tool_choice: "auto",
});
const message = completion.choices[0].message;
if (message.tool_calls?.length) {
const { name, arguments: argsJson } = message.tool_calls[0].function;
const args = JSON.parse(argsJson);
const { messages, structuredContent } = await callMcpTool(name, args);
console.log("Result from MCP tool:", messages, structuredContent);
}
})();
Contributing
Contributions are welcome! Please open issues or submit PRs.
Changelog
See CHANGELOG for detailed version history and updates.
README copy captured when this server was indexed; it may lag the repository. The original is authoritative.