@muzikanto/nestjs-mcp 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # @muzikanto/nestjs-mcp
2
+
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add prompt decorators and routes
8
+
9
+ ## 1.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated README for better readability and clearer usage examples
package/README.md CHANGED
@@ -1,16 +1,35 @@
1
1
  # @muzikanto/nestjs-mcp
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@muzikanto/nestjs-mcp)](https://www.npmjs.com/package/@muzikanto/nestjs-mcp)
4
+ [![downloads](https://img.shields.io/npm/dt/@muzikanto/nestjs-mcp)]((https://www.npmjs.com/package/@muzikanto/nestjs-mcp))
5
+ [![GitHub stars](https://img.shields.io/github/stars/Muzikanto/nestjs-mcp?style=social)](https://github.com/Muzikanto/nestjs-mcp)
6
+ [![License](https://img.shields.io/npm/l/@muzikanto/nestjs-mcp)](https://github.com/Muzikanto/nestjs-mcp/blob/main/LICENSE)
7
+
3
8
  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.
4
9
 
5
10
  ---
6
11
 
12
+ ## Contents
13
+ - [Features](#features)
14
+ - [Installation](#installation)
15
+ - [Usage](#usage)
16
+ - [Connecting the MCP module](#connecting-the-mcp-module)
17
+ - [Create MCP tool](#create-mcp-tool)
18
+ - [Create MCP prompt](#create-mcp-prompt)
19
+ - [Calling MCP tools via HTTP](#calling-mcp-tools-via-http)
20
+ - [Obtaining all tools](#obtaining-all-tools)
21
+ - [Integration with OpenAI Function Calls](#integration-with-openai-function-calls)
22
+
7
23
  ## Features
8
24
 
9
25
  - Register MCP tools using the `@McpTool()` decorator
26
+ - Register MCP prompts using the `@McpPrompt()` decorator
10
27
  - Automatic detection of all providers (tools) in the module
11
28
  - Input data validation
12
29
  - HTTP endpoint for calling tools (`POST /mcp`)
13
30
  - Endpoint for a list of all tools (`GET /mcp/tools`)
31
+ - Endpoint for a list of all prompts (`GET /mcp/prompts`)
32
+ - Endpoint for prompt (`GET /mcp/prompts/:name`)
14
33
  - Easy integration with LLM (OpenAI Function Calls)
15
34
  - Full TypeScript typing
16
35
 
@@ -31,14 +50,14 @@ Peer dependencies: `@nestjs/common, @nestjs/core, reflect-metadata`
31
50
  ```ts
32
51
  import { Module } from '@nestjs/common';
33
52
  import { McpModule } from '@muzikanto/nestjs-mcp';
34
- import { GetCurrentDateTool } from './tools/payment.tool';
53
+ import { TelegramSendMessageTool } from './tools/telegram-send-message.tool';
54
+ import { TelegramAutoReplyPrompt } from './prompts/telegram-auto-reply.prompt';
35
55
 
36
56
  @Module({
37
57
  imports: [
38
- McpModule.forRoot(),
39
- ],
40
- providers: [
41
- GetCurrentDateTool,
58
+ McpModule.forRoot({
59
+ providers: [TelegramSendMessageTool, TelegramAutoReplyPrompt],
60
+ }),
42
61
  ],
43
62
  })
44
63
  export class AppModule {}
@@ -48,21 +67,35 @@ export class AppModule {}
48
67
 
49
68
  ```ts
50
69
  import { IMcpTool, McpTool } from '@muzikanto/nestjs-mcp';
70
+ import { Telegraf } from 'telegraf';
51
71
 
52
72
  @McpTool()
53
- export class GetCurrentDateTool implements IMcpTool<{ country: string; }, { date: string }> {
54
- name = 'get-date';
73
+ export class TelegramSendMessageTool implements IMcpTool<
74
+ { chatId: string; text: string },
75
+ { success: boolean }
76
+ > {
77
+ name = 'telegram.sendMessage';
55
78
 
56
79
  inputSchema = {
57
- "type": "object",
58
- "properties": {
59
- "country": { "type": "string", "description": "Country" }
80
+ type: "object",
81
+ properties: {
82
+ chatId: {
83
+ type: "string",
84
+ description: "Telegram chat id"
85
+ },
86
+ text: {
87
+ type: "string",
88
+ description: "Message text"
89
+ }
60
90
  },
61
- "required": ["country"]
91
+ required: ["chatId", "text"]
62
92
  };
63
93
 
64
- async execute(input: { country: string }) {
65
- return { date: new Date().toLocaleString() };
94
+ constructor(private readonly bot: Telegraf) {}
95
+
96
+ async execute(input: { chatId: string; text: string }) {
97
+ await this.bot.telegram.sendMessage(input.chatId, input.text);
98
+ return { success: true };
66
99
  }
67
100
  }
68
101
  ```
@@ -73,9 +106,10 @@ POST /mcp
73
106
 
74
107
  ```json
75
108
  {
76
- "type": "get-date",
109
+ "type": "telegram.sendMessage",
77
110
  "payload": {
78
- "country": "ru"
111
+ "chatId": "...",
112
+ "text": "Hi, how are you ?"
79
113
  }
80
114
  }
81
115
  ```
@@ -84,7 +118,7 @@ POST /mcp
84
118
  ```json
85
119
  {
86
120
  "data": {
87
- "date": "21/02/2026, 16:17:00"
121
+ "success": true
88
122
  }
89
123
  }
90
124
  ```
@@ -96,15 +130,107 @@ GET /mcp/tool
96
130
  ```json
97
131
  [
98
132
  {
99
- "name": "get-date",
100
- "description": "",
133
+ "name": "telegram.sendMessage",
134
+ "description": "Sent message via Telegram",
101
135
  "inputSchema": {
102
- "country": { "type": "string", "description": "Страна" },
136
+ "chatId": {
137
+ "type": "string",
138
+ "description": "Telegram chat ID"
139
+ },
140
+ "text": {
141
+ "type": "string",
142
+ "description": "Message text"
143
+ }
103
144
  }
104
145
  }
105
146
  ]
106
147
  ```
107
148
 
149
+ ### Create MCP prompt
150
+
151
+ ```ts
152
+ import { IMcpPrompt, McpPrompt } from '@muzikanto/nestjs-mcp';
153
+
154
+ @McpPrompt()
155
+ export class TelegramAutoReplyPrompt implements IMcpPrompt<{ text: string; chatId: number; }> {
156
+ name = 'telegram_auto_reply';
157
+ description = 'Generate a short, fiendly reply to an incoming Telegram message and send it back to the same chat using teegram.sendMessage tool';
158
+
159
+ async execute({ text, chatId }: { text: string; chatId: number }) {
160
+ return [
161
+ {
162
+ role: "system",
163
+ content: `You are a friendly Telegram bot. Reply briefly and to the point.`
164
+ },
165
+ {
166
+ role: "user",
167
+ content: text
168
+ },
169
+ {
170
+ role: "assistant",
171
+ tool_call: {
172
+ name: "telegram.sendMessage",
173
+ arguments: {
174
+ chatId,
175
+ text: "{{model_output}}"
176
+ }
177
+ }
178
+ }
179
+ ];
180
+ }
181
+ }
182
+ ```
183
+
184
+ ### Obtaining all prompts
185
+
186
+ GET /mcp/prompts
187
+
188
+ ```json
189
+ [
190
+ {
191
+ "name": "telegram_auto_reply",
192
+ "description": "Generate a short, fiendly reply to an incoming Telegram message and send it back to the same chat using teegram.sendMessage tool"
193
+ }
194
+ ]
195
+ ```
196
+
197
+ ### Obtainin prompt
198
+
199
+ POST /mcp/prompts/telegram_auto_reply
200
+
201
+ ```json
202
+ {
203
+ "text": "Hi. How are you ?",
204
+ "chatId": 100000000
205
+ }
206
+ ```
207
+
208
+ Response
209
+ ```json
210
+ {
211
+ "messages": [
212
+ {
213
+ "role": "system",
214
+ "content": "You are a friendly Telegram bot. Reply briefly and to the point."
215
+ },
216
+ {
217
+ "role": "user",
218
+ "content": "Hi. How are you ?"
219
+ },
220
+ {
221
+ "role": "assistant",
222
+ "tool_call": {
223
+ "name": "telegram.sendMessage",
224
+ "arguments": {
225
+ "chatId": 100000000,
226
+ "text": "{{model_output}}"
227
+ }
228
+ }
229
+ }
230
+ ]
231
+ }
232
+ ```
233
+
108
234
  ### Integration with OpenAI Function Calls
109
235
 
110
236
  ```ts
@@ -113,6 +239,7 @@ import OpenAI from 'openai';
113
239
 
114
240
  const MCP_URL = 'http://localhost:3000/mcp';
115
241
  const MCP_TOOLS_URL = 'http://localhost:3000/mcp/tools';
242
+ const MCP_TELEGRAM_PROMPT_URL = 'http://localhost:3000/mcp/prompts/telegram_auto_reply';
116
243
 
117
244
  // Create OpenAI client
118
245
  const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
@@ -120,11 +247,19 @@ const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
120
247
  /**
121
248
  * Get all tools
122
249
  */
123
- async function listMcpTools() {
250
+ async function getMcpTools() {
124
251
  const response = await axios.get(MCP_TOOLS_URL);
125
252
  return response.data;
126
253
  }
127
254
 
255
+ /**
256
+ * Get all prompts
257
+ */
258
+ async function getMcpPrompt() {
259
+ const response = await axios.post(MCP_TELEGRAM_PROMPT_URL, {/* propmpt generation arguments */});
260
+ return response.data;
261
+ }
262
+
128
263
  /**
129
264
  * Request mcp tool
130
265
  */
@@ -141,12 +276,13 @@ async function callMcpTool(toolName: string, payload: Record<string, any>) {
141
276
  * Example
142
277
  */
143
278
  (async () => {
144
- const functions = await listMcpTools();
279
+ const toolsResponse = await getMcpTools();
280
+ const promptResponse = await getMcpPrompt();
145
281
 
146
282
  const completion = await client.chat.completions.create({
147
283
  model: 'gpt-4.1-mini',
148
- messages: [{ role: 'user', content: 'Confirm cart abc123' }],
149
- functions,
284
+ messages: promptResponse.messages,
285
+ functions: toolsResponse.tools,
150
286
  function_call: 'auto',
151
287
  });
152
288
 
@@ -161,3 +297,9 @@ async function callMcpTool(toolName: string, payload: Record<string, any>) {
161
297
  }
162
298
  })();
163
299
  ```
300
+
301
+ ## Contributing
302
+ Contributions are welcome! Please open issues or submit PRs.
303
+
304
+ ## Changelog
305
+ See [CHANGELOG](https://github.com/Muzikanto/nestjs-mcp/blob/main/CHANGELOG.md) for detailed version history and updates.
@@ -0,0 +1,20 @@
1
+ import "reflect-metadata";
2
+ export type IMcpPromptMessage = {
3
+ role: string;
4
+ content?: string;
5
+ tool_call?: {
6
+ name: string;
7
+ arguments: object;
8
+ };
9
+ };
10
+ export interface IMcpPrompt<Payload = any, Result extends IMcpPromptMessage[] = IMcpPromptMessage[]> {
11
+ name: string;
12
+ description?: string;
13
+ inputSchema?: object | object[];
14
+ execute(input: Payload): Promise<Result>;
15
+ }
16
+ export declare const MCP_PROMPT_METADATA = "mcp:prompt-class";
17
+ /**
18
+ * Декоратор класса для MCP prompt
19
+ */
20
+ export declare const McpPrompt: () => (target: any) => void;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpPrompt = exports.MCP_PROMPT_METADATA = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ require("reflect-metadata");
6
+ exports.MCP_PROMPT_METADATA = "mcp:prompt-class";
7
+ /**
8
+ * Декоратор класса для MCP prompt
9
+ */
10
+ const McpPrompt = () => {
11
+ return (target) => {
12
+ (0, common_1.Injectable)()(target);
13
+ Reflect.defineMetadata(exports.MCP_PROMPT_METADATA, {}, target);
14
+ };
15
+ };
16
+ exports.McpPrompt = McpPrompt;
@@ -0,0 +1,4 @@
1
+ export declare class McpPromptDto {
2
+ name: string;
3
+ description?: string;
4
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.McpPromptDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ class McpPromptDto {
15
+ name;
16
+ description;
17
+ }
18
+ exports.McpPromptDto = McpPromptDto;
19
+ __decorate([
20
+ (0, swagger_1.ApiProperty)({ type: 'string', description: 'Propmt name' }),
21
+ __metadata("design:type", String)
22
+ ], McpPromptDto.prototype, "name", void 0);
23
+ __decorate([
24
+ (0, swagger_1.ApiProperty)({ type: 'string', description: 'Propmt description', nullable: true }),
25
+ __metadata("design:type", String)
26
+ ], McpPromptDto.prototype, "description", void 0);
@@ -0,0 +1,5 @@
1
+ export declare class McpPromptMessageDto {
2
+ role: string;
3
+ content?: string;
4
+ tool_call?: object;
5
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.McpPromptMessageDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ class McpPromptMessageDto {
15
+ role;
16
+ content;
17
+ tool_call;
18
+ }
19
+ exports.McpPromptMessageDto = McpPromptMessageDto;
20
+ __decorate([
21
+ (0, swagger_1.ApiProperty)({ type: 'string', description: 'AI role' }),
22
+ __metadata("design:type", String)
23
+ ], McpPromptMessageDto.prototype, "role", void 0);
24
+ __decorate([
25
+ (0, swagger_1.ApiProperty)({ type: 'string', description: 'Request ai message', nullable: true }),
26
+ __metadata("design:type", String)
27
+ ], McpPromptMessageDto.prototype, "content", void 0);
28
+ __decorate([
29
+ (0, swagger_1.ApiProperty)({ type: 'object', description: 'Tool call context', nullable: true, additionalProperties: false }),
30
+ __metadata("design:type", Object)
31
+ ], McpPromptMessageDto.prototype, "tool_call", void 0);
@@ -0,0 +1,4 @@
1
+ import { McpPromptMessageDto } from "./McpPromptMessage";
2
+ export declare class McpPromptMessagesDto {
3
+ messages: McpPromptMessageDto[];
4
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.McpPromptMessagesDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ const McpPromptMessage_1 = require("./McpPromptMessage");
15
+ class McpPromptMessagesDto {
16
+ messages;
17
+ }
18
+ exports.McpPromptMessagesDto = McpPromptMessagesDto;
19
+ __decorate([
20
+ (0, swagger_1.ApiProperty)({ type: McpPromptMessage_1.McpPromptMessageDto, isArray: true, description: 'Messages list' }),
21
+ __metadata("design:type", Array)
22
+ ], McpPromptMessagesDto.prototype, "messages", void 0);
@@ -0,0 +1,4 @@
1
+ import { McpPromptDto } from "./McpPrompt.dto";
2
+ export declare class McpPromptsDto {
3
+ prompts: McpPromptDto[];
4
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.McpPromptsDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ const McpPrompt_dto_1 = require("./McpPrompt.dto");
15
+ class McpPromptsDto {
16
+ prompts;
17
+ }
18
+ exports.McpPromptsDto = McpPromptsDto;
19
+ __decorate([
20
+ (0, swagger_1.ApiProperty)({ type: McpPrompt_dto_1.McpPromptDto, isArray: true, description: 'Prompts list' }),
21
+ __metadata("design:type", Array)
22
+ ], McpPromptsDto.prototype, "prompts", void 0);
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./mcp.module";
2
2
  export * from "./decorators/mcp-tool.decorator";
3
+ export * from "./decorators/mcp-prompt.decorator";
package/dist/index.js CHANGED
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./mcp.module"), exports);
18
18
  __exportStar(require("./decorators/mcp-tool.decorator"), exports);
19
+ __exportStar(require("./decorators/mcp-prompt.decorator"), exports);
@@ -1,6 +1,8 @@
1
1
  import { McpService } from "./mcp.service";
2
2
  import { McpMessageDto } from "./dto/McpMessage.dto";
3
3
  import { McpToolsDto } from "./dto/McpTools.dto";
4
+ import { McpPromptsDto } from "./dto/McpPrompts.dto";
5
+ import { McpPromptMessagesDto } from "./dto/McpPromptMessages.dto";
4
6
  export declare class McpController {
5
7
  private readonly service;
6
8
  constructor(service: McpService);
@@ -14,4 +16,6 @@ export declare class McpController {
14
16
  data?: undefined;
15
17
  }>;
16
18
  getTools(): Promise<McpToolsDto>;
19
+ getPrompts(): Promise<McpPromptsDto>;
20
+ getPrompt(name: string, body: object): Promise<McpPromptMessagesDto>;
17
21
  }
@@ -18,6 +18,8 @@ const mcp_service_1 = require("./mcp.service");
18
18
  const McpMessage_dto_1 = require("./dto/McpMessage.dto");
19
19
  const swagger_1 = require("@nestjs/swagger");
20
20
  const McpTools_dto_1 = require("./dto/McpTools.dto");
21
+ const McpPrompts_dto_1 = require("./dto/McpPrompts.dto");
22
+ const McpPromptMessages_dto_1 = require("./dto/McpPromptMessages.dto");
21
23
  let McpController = class McpController {
22
24
  service;
23
25
  constructor(service) {
@@ -30,6 +32,16 @@ let McpController = class McpController {
30
32
  const tools = this.service.listTools();
31
33
  return { tools };
32
34
  }
35
+ async getPrompts() {
36
+ const prompts = this.service.listPrompts();
37
+ return { prompts };
38
+ }
39
+ async getPrompt(name, body) {
40
+ const messages = await this.service.getPrompt(name, body);
41
+ return {
42
+ messages,
43
+ };
44
+ }
33
45
  };
34
46
  exports.McpController = McpController;
35
47
  __decorate([
@@ -64,6 +76,46 @@ __decorate([
64
76
  __metadata("design:paramtypes", []),
65
77
  __metadata("design:returntype", Promise)
66
78
  ], McpController.prototype, "getTools", null);
79
+ __decorate([
80
+ (0, common_1.Get)("prompts"),
81
+ (0, swagger_1.ApiOperation)({
82
+ summary: 'Get prompt list',
83
+ }),
84
+ (0, swagger_1.ApiResponse)({
85
+ status: 200,
86
+ description: 'Prompts list',
87
+ type: McpPrompts_dto_1.McpPromptsDto,
88
+ }),
89
+ __metadata("design:type", Function),
90
+ __metadata("design:paramtypes", []),
91
+ __metadata("design:returntype", Promise)
92
+ ], McpController.prototype, "getPrompts", null);
93
+ __decorate([
94
+ (0, common_1.Post)("prompts/:name"),
95
+ (0, swagger_1.ApiOperation)({
96
+ summary: 'Generate messages by prompt name',
97
+ }),
98
+ (0, swagger_1.ApiBody)({
99
+ description: 'Any body structure',
100
+ type: Object, // Указываем, что тело может быть любым объектом
101
+ }),
102
+ (0, swagger_1.ApiResponse)({
103
+ status: 200,
104
+ description: 'Prompt messages',
105
+ type: McpPromptMessages_dto_1.McpPromptMessagesDto,
106
+ }),
107
+ (0, swagger_1.ApiNotFoundResponse)({
108
+ description: 'Not found prompt',
109
+ }),
110
+ (0, swagger_1.ApiBadRequestResponse)({
111
+ description: 'Invalid prompt arguments',
112
+ }),
113
+ __param(0, (0, common_1.Param)('name')),
114
+ __param(1, (0, common_1.Body)()),
115
+ __metadata("design:type", Function),
116
+ __metadata("design:paramtypes", [String, Object]),
117
+ __metadata("design:returntype", Promise)
118
+ ], McpController.prototype, "getPrompt", null);
67
119
  exports.McpController = McpController = __decorate([
68
120
  (0, common_1.Controller)("mcp"),
69
121
  __metadata("design:paramtypes", [mcp_service_1.McpService])
@@ -14,6 +14,7 @@ const core_1 = require("@nestjs/core");
14
14
  const common_1 = require("@nestjs/common");
15
15
  const mcp_service_1 = require("./mcp.service");
16
16
  const mcp_tool_decorator_1 = require("./decorators/mcp-tool.decorator");
17
+ const mcp_prompt_decorator_1 = require("./decorators/mcp-prompt.decorator");
17
18
  let McpExplorer = class McpExplorer {
18
19
  discovery;
19
20
  mcpService;
@@ -35,6 +36,18 @@ let McpExplorer = class McpExplorer {
35
36
  }
36
37
  this.mcpService.registerTool(instance.name, instance);
37
38
  });
39
+ providers.forEach(({ instance, metatype }) => {
40
+ if (!instance || !metatype)
41
+ return;
42
+ const metadata = Reflect.getMetadata(mcp_prompt_decorator_1.MCP_PROMPT_METADATA, metatype);
43
+ if (!metadata)
44
+ return;
45
+ // Проверка интерфейса
46
+ if (typeof instance.execute !== "function") {
47
+ throw new Error(`MCP Prompt ${instance.name} must implement IMcpPrompt with execute() method`);
48
+ }
49
+ this.mcpService.registerPrompt(instance.name, instance);
50
+ });
38
51
  }
39
52
  };
40
53
  exports.McpExplorer = McpExplorer;
@@ -26,5 +26,6 @@ let McpModule = McpModule_1 = class McpModule {
26
26
  };
27
27
  exports.McpModule = McpModule;
28
28
  exports.McpModule = McpModule = McpModule_1 = __decorate([
29
+ (0, common_1.Global)(),
29
30
  (0, common_1.Module)({})
30
31
  ], McpModule);
@@ -1,5 +1,6 @@
1
1
  import { OnModuleInit } from "@nestjs/common";
2
2
  import { IMcpTool } from "./decorators/mcp-tool.decorator";
3
+ import { IMcpPrompt } from "./decorators/mcp-prompt.decorator";
3
4
  export interface McpMessage {
4
5
  type: string;
5
6
  payload: any;
@@ -11,6 +12,7 @@ export interface McpResponse {
11
12
  }
12
13
  export declare class McpService implements OnModuleInit {
13
14
  private tools;
15
+ private prompts;
14
16
  private ajv;
15
17
  onModuleInit(): void;
16
18
  /**
@@ -21,7 +23,13 @@ export declare class McpService implements OnModuleInit {
21
23
  description: string;
22
24
  parameters: object;
23
25
  }[];
26
+ listPrompts(): {
27
+ name: string;
28
+ description: string;
29
+ }[];
24
30
  registerTool(name: string, handler: IMcpTool): void;
31
+ registerPrompt(name: string, handler: IMcpPrompt): void;
32
+ getPrompt(name: string, payload: object): Promise<import("./decorators/mcp-prompt.decorator").IMcpPromptMessage[]>;
25
33
  /**
26
34
  * Отправить сообщение в MCP "сервер"
27
35
  */
@@ -11,6 +11,7 @@ const common_1 = require("@nestjs/common");
11
11
  const ajv_1 = require("ajv");
12
12
  let McpService = class McpService {
13
13
  tools = new Map();
14
+ prompts = new Map();
14
15
  ajv = new ajv_1.default();
15
16
  onModuleInit() {
16
17
  // console.log('MCP Service initialized');
@@ -25,9 +26,33 @@ let McpService = class McpService {
25
26
  parameters: t.inputSchema || {},
26
27
  }));
27
28
  }
29
+ listPrompts() {
30
+ return Array.from(this.prompts.values()).map((t) => ({
31
+ name: t.name,
32
+ description: t.description || "",
33
+ }));
34
+ }
28
35
  registerTool(name, handler) {
29
36
  this.tools.set(name, handler);
30
37
  }
38
+ registerPrompt(name, handler) {
39
+ this.prompts.set(name, handler);
40
+ }
41
+ getPrompt(name, payload) {
42
+ if (!this.prompts.has(name)) {
43
+ throw new common_1.NotFoundException('Not found prompt');
44
+ }
45
+ const prompt = this.prompts.get(name);
46
+ // Валидация через AJV, если есть inputSchema
47
+ if (prompt.inputSchema) {
48
+ const validate = this.ajv.compile(prompt.inputSchema);
49
+ const valid = validate(payload);
50
+ if (!valid) {
51
+ throw new common_1.NotFoundException('Invalid prompt arguments');
52
+ }
53
+ }
54
+ return prompt.execute(payload);
55
+ }
31
56
  /**
32
57
  * Отправить сообщение в MCP "сервер"
33
58
  */
package/package.json CHANGED
@@ -1,18 +1,15 @@
1
1
  {
2
2
  "name": "@muzikanto/nestjs-mcp",
3
- "version": "1.0.0",
4
- "description": "Model Context Protocol integration for NestJS",
3
+ "version": "1.1.0",
4
+ "description": "NestJS MCP (Model Context Protocol) module for creating tools for LLM or HTTP with validation, decorators, and OpenAI Function Calls integration.",
5
5
  "keywords": [
6
6
  "nestjs",
7
+ "nestjs module",
7
8
  "mcp",
8
- "ai",
9
- "model-context-protocol"
10
- ],
11
- "license": "MIT",
12
- "maintainers": [
13
- {
14
- "name": "Maxim Schiriy"
15
- }
9
+ "openai",
10
+ "llm",
11
+ "tools",
12
+ "typescript"
16
13
  ],
17
14
  "main": "dist/index.js",
18
15
  "types": "dist/index.d.ts",
@@ -21,7 +18,12 @@
21
18
  ],
22
19
  "scripts": {
23
20
  "build": "tsc",
24
- "prepublishOnly": "npm run build"
21
+ "prepublishOnly": "npm run build",
22
+ "lint": "prettier --check 'src/**/*.ts'",
23
+ "format": "prettier --write 'src/**/*.ts'",
24
+ "ch": "changeset",
25
+ "vers": "changeset version",
26
+ "pub": "changeset publish"
25
27
  },
26
28
  "peerDependencies": {
27
29
  "@nestjs/common": "^10 || ^11",
@@ -34,6 +36,7 @@
34
36
  "ajv": "^8.18.0"
35
37
  },
36
38
  "devDependencies": {
39
+ "@changesets/cli": "^2.29.8",
37
40
  "@nestjs/common": "^10 || ^11",
38
41
  "@nestjs/core": "^10 || ^11",
39
42
  "@nestjs/swagger": "^10 || ^11",
@@ -41,5 +44,22 @@
41
44
  "prettier": "^3.8.1",
42
45
  "reflect-metadata": "^0.1.13",
43
46
  "typescript": "^5.0.0"
47
+ },
48
+ "license": "MIT",
49
+ "maintainers": [
50
+ {
51
+ "name": "Maxim Schiriy"
52
+ }
53
+ ],
54
+ "homepage": "https://github.com/Muzikanto/nestjs-mcp#readme",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/Muzikanto/nestjs-mcp"
58
+ },
59
+ "bugs": {
60
+ "url": "https://github.com/Muzikanto/nestjs-mcp/issues"
61
+ },
62
+ "engines": {
63
+ "node": ">=18.0.0"
44
64
  }
45
65
  }