@muzikanto/nestjs-mcp 1.2.0 → 1.5.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 +18 -0
- package/README.md +267 -77
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp-server/config.d.ts +6 -0
- package/dist/mcp-server/config.js +7 -0
- package/dist/mcp-server/decorators/mcp-tool.decorator.d.ts +2 -5
- package/dist/mcp-server/mcp-dynamic.service.d.ts +31 -0
- package/dist/mcp-server/mcp-dynamic.service.js +100 -0
- package/dist/mcp-server/mcp.controller.d.ts +6 -13
- package/dist/mcp-server/mcp.controller.js +26 -10
- package/dist/mcp-server/mcp.explorer.js +3 -3
- package/dist/mcp-server/mcp.module.d.ts +4 -0
- package/dist/mcp-server/mcp.module.js +12 -1
- package/dist/mcp-server/mcp.service.d.ts +23 -18
- package/dist/mcp-server/mcp.service.js +87 -32
- package/dist/mcp-server/utils/http-adapter.d.ts +18 -0
- package/dist/mcp-server/utils/http-adapter.js +18 -0
- package/dist/mcp-server/utils/ref.d.ts +1 -0
- package/dist/mcp-server/utils/ref.js +4 -0
- package/dist/mcp-server/utils/run-fillters.d.ts +3 -0
- package/dist/mcp-server/utils/run-fillters.js +37 -0
- package/dist/mcp-server/utils/run-guards.d.ts +6 -0
- package/dist/mcp-server/utils/run-guards.js +34 -0
- package/dist/mcp-server/utils/run-interceprots.d.ts +11 -0
- package/dist/mcp-server/utils/run-interceprots.js +43 -0
- package/dist/mcp-server/utils/run-interceptors.d.ts +7 -0
- package/dist/mcp-server/utils/run-interceptors.js +40 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @muzikanto/nestjs-mcp
|
|
2
2
|
|
|
3
|
+
## 1.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- add UseFilters support
|
|
8
|
+
|
|
9
|
+
## 1.4.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- Dynamic tools, prompts, resources initialization
|
|
14
|
+
|
|
15
|
+
## 1.3.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- a5c79ec: add guards and interceptors
|
|
20
|
+
|
|
3
21
|
## 1.2.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @muzikanto/nestjs-mcp
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@muzikanto/nestjs-mcp)
|
|
4
|
-
[]((https://www.npmjs.com/package/@muzikanto/nestjs-mcp))
|
|
4
|
+
[](<(https://www.npmjs.com/package/@muzikanto/nestjs-mcp)>)
|
|
5
5
|
[](https://github.com/Muzikanto/nestjs-mcp)
|
|
6
6
|
[](https://github.com/Muzikanto/nestjs-mcp/blob/main/LICENSE)
|
|
7
7
|
|
|
@@ -10,6 +10,7 @@ NestJS MCP (Model Context Protocol) module — allows you to create “tools”,
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Contents
|
|
13
|
+
|
|
13
14
|
- [Features](#features)
|
|
14
15
|
- [Installation](#installation)
|
|
15
16
|
- [Usage](#usage)
|
|
@@ -17,11 +18,18 @@ NestJS MCP (Model Context Protocol) module — allows you to create “tools”,
|
|
|
17
18
|
- [Create MCP tool](#create-mcp-tool)
|
|
18
19
|
- [Create MCP prompt](#create-mcp-prompt)
|
|
19
20
|
- [Create MCP resource](#create-mcp-resource)
|
|
21
|
+
- [Dynamic creation](#dynamic-creation)
|
|
20
22
|
- [Calling MCP tools via HTTP](#calling-mcp-tools-via-http)
|
|
21
23
|
- [Calling MCP prompt via HTTP](#obtain-prompt)
|
|
22
24
|
- [Obtaining all tools](#obtaining-all-tools)
|
|
23
25
|
- [Obtaining all prompts](#obtaining-all-prompts)
|
|
24
|
-
- [
|
|
26
|
+
- [Guards](#guards)
|
|
27
|
+
- [For one](#for-one)
|
|
28
|
+
- [For all](#for-all)
|
|
29
|
+
- [Interceptors](#interceptors)
|
|
30
|
+
- [For one](#for-one-1)
|
|
31
|
+
- [For all](#for-all-1)
|
|
32
|
+
- [Filters](#filters)
|
|
25
33
|
- [Integration with OpenAI Function Calls](#integration-with-openai-function-calls)
|
|
26
34
|
|
|
27
35
|
## Features
|
|
@@ -30,13 +38,15 @@ NestJS MCP (Model Context Protocol) module — allows you to create “tools”,
|
|
|
30
38
|
- Register MCP prompts using the `@McpPrompt()` decorator
|
|
31
39
|
- Automatic detection of all providers (tools) in the module
|
|
32
40
|
- Input data validation
|
|
33
|
-
- SSE endpoints for MCP
|
|
34
|
-
- Endpoint for calling tool (`POST /mcp/toos`)
|
|
35
|
-
- Endpoint for a list of all tools (`GET /mcp/tools`)
|
|
41
|
+
- SSE endpoints for MCP (`GET /mcp/sse, POST /mcp/messages`)
|
|
42
|
+
- Endpoint for calling tool (`POST /mcp/toos`)
|
|
43
|
+
- Endpoint for a list of all tools (`GET /mcp/tools`)
|
|
36
44
|
- Endpoint for calling prompt (`POST /mcp/prompts/:name`)
|
|
37
|
-
- Endpoint for a list of all prompts (`GET /mcp/prompts`)
|
|
38
|
-
- Easy integration with LLM (OpenAI Function Calls)
|
|
39
|
-
-
|
|
45
|
+
- Endpoint for a list of all prompts (`GET /mcp/prompts`)
|
|
46
|
+
- Easy integration with LLM (OpenAI Function Calls)
|
|
47
|
+
- Support http adapters (default fastify)
|
|
48
|
+
- Full TypeScript typing
|
|
49
|
+
- Support `@UseGuards`, `@UseInterceptors`, `@UseFilters`
|
|
40
50
|
|
|
41
51
|
---
|
|
42
52
|
|
|
@@ -46,17 +56,17 @@ NestJS MCP (Model Context Protocol) module — allows you to create “tools”,
|
|
|
46
56
|
yarn add @muzikanto/nestjs-mcp
|
|
47
57
|
```
|
|
48
58
|
|
|
49
|
-
Peer dependencies: `@nestjs/common, @nestjs/core, reflect-metadata`
|
|
59
|
+
Peer dependencies: `@nestjs/common, @nestjs/core, @nestjs/swagger, reflect-metadata`
|
|
50
60
|
|
|
51
61
|
## Usage
|
|
52
62
|
|
|
53
63
|
### Connecting the MCP module
|
|
54
64
|
|
|
55
65
|
```ts
|
|
56
|
-
import { Module } from
|
|
57
|
-
import { McpModule } from
|
|
58
|
-
import { TelegramSendMessageTool } from
|
|
59
|
-
import { TelegramAutoReplyPrompt } from
|
|
66
|
+
import { Module } from "@nestjs/common";
|
|
67
|
+
import { McpModule } from "@muzikanto/nestjs-mcp";
|
|
68
|
+
import { TelegramSendMessageTool } from "./tools/telegram-send-message.tool";
|
|
69
|
+
import { TelegramAutoReplyPrompt } from "./prompts/telegram-auto-reply.prompt";
|
|
60
70
|
|
|
61
71
|
@Module({
|
|
62
72
|
imports: [
|
|
@@ -71,13 +81,13 @@ export class AppModule {}
|
|
|
71
81
|
### Create MCP tool
|
|
72
82
|
|
|
73
83
|
```ts
|
|
74
|
-
import { IMcpTool, McpTool } from
|
|
75
|
-
import { Telegraf } from
|
|
76
|
-
import z from
|
|
84
|
+
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
|
|
85
|
+
import { Telegraf } from "telegraf";
|
|
86
|
+
import z from "zod";
|
|
77
87
|
|
|
78
88
|
const schema = {
|
|
79
|
-
chatId: z.string().describe(
|
|
80
|
-
text: z.string().describe(
|
|
89
|
+
chatId: z.string().describe("Telegram chat id"), // строка с описанием
|
|
90
|
+
text: z.string().describe("Message text"), // строка с описанием
|
|
81
91
|
};
|
|
82
92
|
|
|
83
93
|
@McpTool()
|
|
@@ -85,7 +95,7 @@ export class TelegramSendMessageTool implements IMcpTool<
|
|
|
85
95
|
{ chatId: string; text: string },
|
|
86
96
|
{ success: boolean }
|
|
87
97
|
> {
|
|
88
|
-
name =
|
|
98
|
+
name = "telegram.sendMessage";
|
|
89
99
|
|
|
90
100
|
inputSchema = schema;
|
|
91
101
|
|
|
@@ -112,7 +122,8 @@ POST /mcp
|
|
|
112
122
|
}
|
|
113
123
|
```
|
|
114
124
|
|
|
115
|
-
Ответ
|
|
125
|
+
Ответ
|
|
126
|
+
|
|
116
127
|
```json
|
|
117
128
|
{
|
|
118
129
|
"data": {
|
|
@@ -133,7 +144,7 @@ GET /mcp/tool
|
|
|
133
144
|
"inputSchema": {
|
|
134
145
|
"type": "object",
|
|
135
146
|
"properties": {
|
|
136
|
-
|
|
147
|
+
"chatId": {
|
|
137
148
|
"type": "number",
|
|
138
149
|
"description": "Telegram chat ID"
|
|
139
150
|
},
|
|
@@ -142,10 +153,7 @@ GET /mcp/tool
|
|
|
142
153
|
"description": "Message text"
|
|
143
154
|
}
|
|
144
155
|
},
|
|
145
|
-
"required": [
|
|
146
|
-
"chatId",
|
|
147
|
-
"text"
|
|
148
|
-
]
|
|
156
|
+
"required": ["chatId", "text"]
|
|
149
157
|
}
|
|
150
158
|
}
|
|
151
159
|
]
|
|
@@ -154,29 +162,33 @@ GET /mcp/tool
|
|
|
154
162
|
### Create MCP prompt
|
|
155
163
|
|
|
156
164
|
```ts
|
|
157
|
-
import { IMcpPrompt, McpPrompt } from
|
|
158
|
-
import z from
|
|
165
|
+
import { IMcpPrompt, McpPrompt } from "@muzikanto/nestjs-mcp";
|
|
166
|
+
import z from "zod";
|
|
159
167
|
|
|
160
168
|
const schema = {
|
|
161
|
-
chatId: z.string().describe(
|
|
162
|
-
text: z.string().describe(
|
|
169
|
+
chatId: z.string().describe("Telegram chat id"), // строка с описанием
|
|
170
|
+
text: z.string().describe("Message text"), // строка с описанием
|
|
163
171
|
};
|
|
164
172
|
|
|
165
173
|
@McpPrompt()
|
|
166
|
-
export class TelegramAutoReplyPrompt implements IMcpPrompt<{
|
|
167
|
-
|
|
168
|
-
|
|
174
|
+
export class TelegramAutoReplyPrompt implements IMcpPrompt<{
|
|
175
|
+
text: string;
|
|
176
|
+
chatId: number;
|
|
177
|
+
}> {
|
|
178
|
+
name = "telegram_auto_reply";
|
|
179
|
+
description =
|
|
180
|
+
"Generate a short, fiendly reply to an incoming Telegram message and send it back to the same chat using teegram.sendMessage tool";
|
|
169
181
|
schema = schema;
|
|
170
182
|
|
|
171
183
|
async execute({ text, chatId }: { text: string; chatId: number }) {
|
|
172
184
|
return [
|
|
173
185
|
{
|
|
174
186
|
role: "system",
|
|
175
|
-
content: `You are a friendly Telegram bot. Reply briefly and to the point
|
|
187
|
+
content: `You are a friendly Telegram bot. Reply briefly and to the point.`,
|
|
176
188
|
},
|
|
177
189
|
{
|
|
178
190
|
role: "user",
|
|
179
|
-
content: text
|
|
191
|
+
content: text,
|
|
180
192
|
},
|
|
181
193
|
{
|
|
182
194
|
role: "assistant",
|
|
@@ -184,10 +196,10 @@ export class TelegramAutoReplyPrompt implements IMcpPrompt<{ text: string; chatI
|
|
|
184
196
|
name: "telegram.sendMessage",
|
|
185
197
|
arguments: {
|
|
186
198
|
chatId,
|
|
187
|
-
text: "{{model_output}}"
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
199
|
+
text: "{{model_output}}",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
191
203
|
];
|
|
192
204
|
}
|
|
193
205
|
}
|
|
@@ -205,7 +217,7 @@ GET /mcp/prompts
|
|
|
205
217
|
"inputSchema": {
|
|
206
218
|
"type": "object",
|
|
207
219
|
"properties": {
|
|
208
|
-
|
|
220
|
+
"chatId": {
|
|
209
221
|
"type": "number",
|
|
210
222
|
"description": "Telegram chat ID"
|
|
211
223
|
},
|
|
@@ -214,10 +226,7 @@ GET /mcp/prompts
|
|
|
214
226
|
"description": "Message text"
|
|
215
227
|
}
|
|
216
228
|
},
|
|
217
|
-
"required": [
|
|
218
|
-
"chatId",
|
|
219
|
-
"text"
|
|
220
|
-
]
|
|
229
|
+
"required": ["chatId", "text"]
|
|
221
230
|
}
|
|
222
231
|
}
|
|
223
232
|
]
|
|
@@ -235,42 +244,43 @@ POST /mcp/prompts/telegram_auto_reply
|
|
|
235
244
|
```
|
|
236
245
|
|
|
237
246
|
Response
|
|
247
|
+
|
|
238
248
|
```json
|
|
239
249
|
{
|
|
240
250
|
"messages": [
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
251
|
+
{
|
|
252
|
+
"role": "system",
|
|
253
|
+
"content": "You are a friendly Telegram bot. Reply briefly and to the point."
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"role": "user",
|
|
257
|
+
"content": "Hi. How are you ?"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"role": "assistant",
|
|
261
|
+
"tool_call": {
|
|
262
|
+
"name": "telegram.sendMessage",
|
|
263
|
+
"arguments": {
|
|
264
|
+
"chatId": 100000000,
|
|
265
|
+
"text": "{{model_output}}"
|
|
257
266
|
}
|
|
258
267
|
}
|
|
259
|
-
|
|
268
|
+
}
|
|
269
|
+
]
|
|
260
270
|
}
|
|
261
271
|
```
|
|
262
272
|
|
|
263
273
|
### Create MCP resource
|
|
264
274
|
|
|
265
275
|
```ts
|
|
266
|
-
import { IMcpResource, McpResource } from
|
|
276
|
+
import { IMcpResource, McpResource } from "@muzikanto/nestjs-mcp";
|
|
267
277
|
|
|
268
278
|
@McpResource()
|
|
269
279
|
export class TestResource implements IMcpResource<{ userId: string }> {
|
|
270
|
-
name =
|
|
271
|
-
uri =
|
|
272
|
-
title =
|
|
273
|
-
description =
|
|
280
|
+
name = "users.get";
|
|
281
|
+
uri = "users://{userId}";
|
|
282
|
+
title = "Get test user";
|
|
283
|
+
description = "Get user by id";
|
|
274
284
|
|
|
275
285
|
async execute(url: URL, vars: { userId: string }) {
|
|
276
286
|
return [{ uri: url.href, text: `Hello ${vars.userId}` }];
|
|
@@ -278,29 +288,207 @@ export class TestResource implements IMcpResource<{ userId: string }> {
|
|
|
278
288
|
}
|
|
279
289
|
```
|
|
280
290
|
|
|
281
|
-
###
|
|
291
|
+
### Dynamic creation
|
|
292
|
+
|
|
282
293
|
```ts
|
|
283
|
-
import {
|
|
284
|
-
import {
|
|
294
|
+
import { McpDynamicService } from "@muzikanto/nestjs-mcp";
|
|
295
|
+
import { Injectable } from "@nestjs/common";
|
|
296
|
+
import { ExampleInterceptor } from "./example.interceptor";
|
|
297
|
+
import { ExampleGuard } from "./example.guard";
|
|
285
298
|
|
|
286
299
|
@Injectable()
|
|
287
|
-
export class
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
300
|
+
export class McpDynamic {
|
|
301
|
+
constructor(protected readonly mcpDynamicService: McpDynamicService) {}
|
|
302
|
+
|
|
303
|
+
onModuleInit() {
|
|
304
|
+
this.mcpDynamicService.registerTool({
|
|
305
|
+
name: "dynamic_tool",
|
|
306
|
+
title: "Dynamic tool",
|
|
307
|
+
execute: () => Promise.resolve("test"),
|
|
308
|
+
guards: [ExampleGuard],
|
|
309
|
+
interceptors: [ExampleInterceptor],
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
this.mcpDynamicService.registerPrompt({
|
|
313
|
+
name: "dynamic_prompt",
|
|
314
|
+
title: "Dynamic prompt",
|
|
315
|
+
execute: () => Promise.resolve([{ role: "assistant", content: "test" }]),
|
|
316
|
+
guards: [ExampleGuard],
|
|
317
|
+
interceptors: [ExampleInterceptor],
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
this.mcpDynamicService.registerResource<{ testId: string }>({
|
|
321
|
+
name: "dynamic_resource",
|
|
322
|
+
title: "Dynamic resource",
|
|
323
|
+
uri: "dynamic://test/{testId}",
|
|
324
|
+
execute: (uri, input) =>
|
|
325
|
+
Promise.resolve([{ uri: uri.href, text: `ID: ${input.testId}` }]),
|
|
326
|
+
guards: [ExampleGuard],
|
|
327
|
+
interceptors: [ExampleInterceptor],
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Guards
|
|
334
|
+
|
|
335
|
+
### For one
|
|
336
|
+
|
|
337
|
+
```ts
|
|
338
|
+
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
|
|
339
|
+
import { UseGuards } from "@nestjs/common";
|
|
340
|
+
import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
|
|
341
|
+
import { Observable } from "rxjs";
|
|
342
|
+
|
|
343
|
+
@Injectable()
|
|
344
|
+
class TestGuard implements CanActivate {
|
|
345
|
+
canActivate(
|
|
346
|
+
context: ExecutionContext,
|
|
347
|
+
): boolean | Promise<boolean> | Observable<boolean> {
|
|
348
|
+
console.log("TestGuard called");
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
294
351
|
}
|
|
295
352
|
|
|
353
|
+
@UseGuard(TestGuard)
|
|
354
|
+
@McpTool()
|
|
355
|
+
export class TelegramSendMessageTool implements IMcpTool<
|
|
356
|
+
{ chatId: string; text: string },
|
|
357
|
+
{ success: boolean }
|
|
358
|
+
> {
|
|
359
|
+
name = "telegram.sendMessage";
|
|
360
|
+
|
|
361
|
+
async execute() {
|
|
362
|
+
await this.bot.telegram.sendMessage(input.chatId, input.text);
|
|
363
|
+
return { success: true };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
#### For all
|
|
369
|
+
|
|
370
|
+
```ts
|
|
371
|
+
import { McpModule } from "@muzikanto/nestjs-mcp";
|
|
372
|
+
import { Module } from "@nestjs/common";
|
|
373
|
+
import { TestGuard } from "./other/test.guard";
|
|
374
|
+
import { ToolWithoutGuards } from "./test.tool";
|
|
375
|
+
import { APP_GUARD } from "@nestjs/core";
|
|
376
|
+
|
|
296
377
|
@Module({
|
|
297
378
|
imports: [
|
|
298
379
|
McpModule.forRoot({
|
|
299
|
-
|
|
380
|
+
providers: [
|
|
381
|
+
ToolWithoutGuards,
|
|
382
|
+
TestGuard,
|
|
383
|
+
{ provide: APP_GUARD, useExisting: TestGuard },
|
|
384
|
+
],
|
|
300
385
|
}),
|
|
301
386
|
],
|
|
302
387
|
})
|
|
303
|
-
export class
|
|
388
|
+
export class TestModule {}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Interceptors
|
|
392
|
+
|
|
393
|
+
#### For one
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
|
|
397
|
+
import {
|
|
398
|
+
ExecutionContext,
|
|
399
|
+
NestInterceptor,
|
|
400
|
+
CallHandler,
|
|
401
|
+
Injectable,
|
|
402
|
+
UseInterceptors,
|
|
403
|
+
} from "@nestjs/common";
|
|
404
|
+
import { map } from "rxjs";
|
|
405
|
+
|
|
406
|
+
@Injectable()
|
|
407
|
+
export class ExampleInterceptor implements NestInterceptor {
|
|
408
|
+
intercept(context: ExecutionContext, next: CallHandler) {
|
|
409
|
+
console.log("Before execute");
|
|
410
|
+
|
|
411
|
+
return next.handle().pipe(
|
|
412
|
+
map((data: unknown) => {
|
|
413
|
+
console.log("After execute", data);
|
|
414
|
+
|
|
415
|
+
return data;
|
|
416
|
+
}),
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
@UseInterceptors(TestInterceptor)
|
|
422
|
+
@McpTool()
|
|
423
|
+
export class TelegramSendMessageTool implements IMcpTool<
|
|
424
|
+
{ chatId: string; text: string },
|
|
425
|
+
{ success: boolean }
|
|
426
|
+
> {
|
|
427
|
+
name = "telegram.sendMessage";
|
|
428
|
+
|
|
429
|
+
async execute() {
|
|
430
|
+
await this.bot.telegram.sendMessage(input.chatId, input.text);
|
|
431
|
+
return { success: true };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
#### For all
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
import { McpModule } from "@muzikanto/nestjs-mcp";
|
|
440
|
+
import { Module } from "@nestjs/common";
|
|
441
|
+
import { TestInterceptor } from "./other/test.interceptor";
|
|
442
|
+
import { ToolWithoutInterceptors } from "./test.tool";
|
|
443
|
+
import { APP_INTERCEPTOR } from "@nestjs/core";
|
|
444
|
+
|
|
445
|
+
@Module({
|
|
446
|
+
imports: [
|
|
447
|
+
McpModule.forRoot({
|
|
448
|
+
providers: [
|
|
449
|
+
ToolWithoutInterceptors,
|
|
450
|
+
TestGuard,
|
|
451
|
+
{ provide: APP_INTERCEPTOR, useExisting: TestInterceptor },
|
|
452
|
+
],
|
|
453
|
+
}),
|
|
454
|
+
],
|
|
455
|
+
})
|
|
456
|
+
export class TestModule {}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Fitlers
|
|
460
|
+
|
|
461
|
+
```ts
|
|
462
|
+
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
|
|
463
|
+
import {
|
|
464
|
+
ExceptionFilter,
|
|
465
|
+
Catch,
|
|
466
|
+
ArgumentsHost,
|
|
467
|
+
NotImplementedException,
|
|
468
|
+
UseFilters,
|
|
469
|
+
} from "@nestjs/common";
|
|
470
|
+
|
|
471
|
+
@Catch(NotImplementedException)
|
|
472
|
+
class ExampleFilter implements ExceptionFilter {
|
|
473
|
+
catch(exception: unknown, host: ArgumentsHost) {
|
|
474
|
+
return {
|
|
475
|
+
message: (exception as Error).message,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
@UseFilters(ExampleFilter)
|
|
481
|
+
@McpTool()
|
|
482
|
+
export class TelegramSendMessageTool implements IMcpTool<
|
|
483
|
+
{ chatId: string; text: string },
|
|
484
|
+
{ success: boolean }
|
|
485
|
+
> {
|
|
486
|
+
name = "telegram.sendMessage";
|
|
487
|
+
|
|
488
|
+
async execute() {
|
|
489
|
+
throw new NotImplementedException();
|
|
490
|
+
}
|
|
491
|
+
}
|
|
304
492
|
```
|
|
305
493
|
|
|
306
494
|
### Integration with OpenAI Function Calls
|
|
@@ -368,7 +556,9 @@ async function callMcpTool(toolName: string, payload: Record<string, any>) {
|
|
|
368
556
|
```
|
|
369
557
|
|
|
370
558
|
## Contributing
|
|
559
|
+
|
|
371
560
|
Contributions are welcome! Please open issues or submit PRs.
|
|
372
561
|
|
|
373
562
|
## Changelog
|
|
563
|
+
|
|
374
564
|
See [CHANGELOG](https://github.com/Muzikanto/nestjs-mcp/blob/main/CHANGELOG.md) for detailed version history and updates.
|
package/dist/index.d.ts
CHANGED
|
@@ -4,3 +4,4 @@ export * from "./mcp-server/decorators/mcp-prompt.decorator";
|
|
|
4
4
|
export * from "./mcp-server/decorators/mcp-resource.decorator";
|
|
5
5
|
export * from "./mcp-client/mcp-client.module";
|
|
6
6
|
export * from "./mcp-client/mcp-client.service";
|
|
7
|
+
export * from "./mcp-server/mcp-dynamic.service";
|
package/dist/index.js
CHANGED
|
@@ -20,3 +20,4 @@ __exportStar(require("./mcp-server/decorators/mcp-prompt.decorator"), exports);
|
|
|
20
20
|
__exportStar(require("./mcp-server/decorators/mcp-resource.decorator"), exports);
|
|
21
21
|
__exportStar(require("./mcp-client/mcp-client.module"), exports);
|
|
22
22
|
__exportStar(require("./mcp-client/mcp-client.service"), exports);
|
|
23
|
+
__exportStar(require("./mcp-server/mcp-dynamic.service"), exports);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InjectMcpConfig = exports.MCP_CONFIG_TOKEN = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
exports.MCP_CONFIG_TOKEN = "mcl:config-token";
|
|
6
|
+
const InjectMcpConfig = () => (0, common_1.Inject)(exports.MCP_CONFIG_TOKEN);
|
|
7
|
+
exports.InjectMcpConfig = InjectMcpConfig;
|
|
@@ -2,19 +2,16 @@ import "reflect-metadata";
|
|
|
2
2
|
import type * as z3 from "zod/v3";
|
|
3
3
|
type AnySchema = z3.ZodTypeAny;
|
|
4
4
|
type ZodRawShapeCompat = Record<string, AnySchema>;
|
|
5
|
-
export type IMcpToolContext = {
|
|
6
|
-
request: any;
|
|
7
|
-
};
|
|
8
5
|
export interface IMcpTool<Payload = any, Result = any> {
|
|
9
6
|
name: string;
|
|
10
7
|
title?: string;
|
|
11
8
|
description?: string;
|
|
12
9
|
inputSchema?: ZodRawShapeCompat;
|
|
13
|
-
execute(input: Payload
|
|
10
|
+
execute(input: Payload): Promise<Result>;
|
|
14
11
|
}
|
|
15
12
|
export declare const MCP_TOOL_METADATA = "mcp:tool-class";
|
|
16
13
|
/**
|
|
17
14
|
* Декоратор класса для MCP тулзы
|
|
18
15
|
*/
|
|
19
|
-
export declare const McpTool: () =>
|
|
16
|
+
export declare const McpTool: () => ClassDecorator;
|
|
20
17
|
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CanActivate, NestInterceptor, Type } from "@nestjs/common";
|
|
2
|
+
import { ModuleRef } from "@nestjs/core";
|
|
3
|
+
import { McpService } from "./mcp.service";
|
|
4
|
+
import { IMcpTool } from "./decorators/mcp-tool.decorator";
|
|
5
|
+
import { IMcpResource } from "./decorators/mcp-resource.decorator";
|
|
6
|
+
import { IMcpPrompt } from "./decorators/mcp-prompt.decorator";
|
|
7
|
+
export type IMcpDynamicTool<Input, Result> = IMcpTool<Input, Result> & {
|
|
8
|
+
guards?: Type<CanActivate>[];
|
|
9
|
+
interceptors?: Type<NestInterceptor>[];
|
|
10
|
+
};
|
|
11
|
+
export type IMcpDynamicPrompt<Input> = IMcpPrompt<Input> & {
|
|
12
|
+
guards?: Type<CanActivate>[];
|
|
13
|
+
interceptors?: Type<NestInterceptor>[];
|
|
14
|
+
};
|
|
15
|
+
export type IMcpDynamicResource<Input> = IMcpResource<Input> & {
|
|
16
|
+
guards?: Type<CanActivate>[];
|
|
17
|
+
interceptors?: Type<NestInterceptor>[];
|
|
18
|
+
};
|
|
19
|
+
export declare class McpDynamicService {
|
|
20
|
+
private readonly moduleRef;
|
|
21
|
+
private readonly mcpService;
|
|
22
|
+
constructor(moduleRef: ModuleRef, mcpService: McpService);
|
|
23
|
+
/** Динамически регистрирует MCP tools */
|
|
24
|
+
registerTool<Input, Result>(tool: IMcpDynamicTool<Input, Result>): Promise<void>;
|
|
25
|
+
/** Динамически регистрирует MCP prompts */
|
|
26
|
+
registerPrompt<Input>(prompt: IMcpDynamicPrompt<Input>): Promise<void>;
|
|
27
|
+
/** Динамически регистрирует MCP resources */
|
|
28
|
+
registerResource<Input>(resource: IMcpDynamicResource<Input>): Promise<void>;
|
|
29
|
+
protected applyGuards(item: Function, guards: Type<CanActivate>[]): void;
|
|
30
|
+
protected applyInterceptors(item: Function, interceptors: Type<NestInterceptor>[]): void;
|
|
31
|
+
}
|