@muzikanto/nestjs-mcp 1.6.0 → 1.7.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 +6 -0
- package/README.md +64 -42
- package/dist/mcp-client/mcp-client.service.d.ts +2 -2
- package/dist/mcp-server/controllers/mcp.controller.d.ts +4 -3
- package/dist/mcp-server/controllers/mcp.controller.js +6 -6
- package/dist/mcp-server/decorators/mcp-prompt.decorator.d.ts +7 -3
- package/dist/mcp-server/decorators/mcp-resource.decorator.d.ts +3 -1
- package/dist/mcp-server/decorators/mcp-tool.decorator.d.ts +14 -2
- package/dist/mcp-server/dto/McpPrompResult.dto.d.ts +5 -0
- package/dist/mcp-server/dto/McpPrompResult.dto.js +31 -0
- package/dist/mcp-server/dto/McpPromptMessage.dto.d.ts +5 -0
- package/dist/mcp-server/dto/McpPromptMessage.dto.js +40 -0
- package/dist/mcp-server/dto/McpTool.dto.d.ts +1 -0
- package/dist/mcp-server/dto/McpTool.dto.js +10 -0
- package/dist/mcp-server/dto/McpToolResult.dto.d.ts +6 -0
- package/dist/mcp-server/dto/McpToolResult.dto.js +32 -0
- package/dist/mcp-server/dto/McpToolResultMessage.dto.d.ts +4 -0
- package/dist/mcp-server/dto/McpToolResultMessage.dto.js +26 -0
- package/dist/mcp-server/exceptions/index.d.ts +3 -1
- package/dist/mcp-server/exceptions/index.js +3 -1
- package/dist/mcp-server/services/mcp-dynamic.service.d.ts +2 -2
- package/dist/mcp-server/services/mcp-dynamic.service.js +5 -0
- package/dist/mcp-server/services/mcp.service.d.ts +8 -6
- package/dist/mcp-server/services/mcp.service.js +5 -2
- package/dist/mcp-server/services/mcp.sse.service.d.ts +3 -0
- package/dist/mcp-server/services/mcp.sse.service.js +20 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ export class AppModule {}
|
|
|
85
85
|
```ts
|
|
86
86
|
import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
|
|
87
87
|
import { Telegraf } from "telegraf";
|
|
88
|
-
import z from "zod";
|
|
88
|
+
import z from "zod/v3";
|
|
89
89
|
|
|
90
90
|
const schema = {
|
|
91
91
|
chatId: z.number().describe("Telegram chat id"), // строка с описанием
|
|
@@ -98,14 +98,16 @@ export class TelegramSendMessageTool implements IMcpTool<
|
|
|
98
98
|
{ success: boolean }
|
|
99
99
|
> {
|
|
100
100
|
name = "telegram.sendMessage";
|
|
101
|
-
|
|
102
101
|
inputSchema = schema;
|
|
103
102
|
|
|
104
103
|
constructor(private readonly bot: Telegraf) {}
|
|
105
104
|
|
|
106
105
|
async execute(input: { chatId: string; text: string }) {
|
|
107
106
|
await this.bot.telegram.sendMessage(input.chatId, input.text);
|
|
108
|
-
return {
|
|
107
|
+
return {
|
|
108
|
+
structuredContent: { success: true },
|
|
109
|
+
messages: [{ type: "text", text: "Success sent to user" }],
|
|
110
|
+
};
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
```
|
|
@@ -128,9 +130,10 @@ POST /mcp/tools
|
|
|
128
130
|
|
|
129
131
|
```json
|
|
130
132
|
{
|
|
131
|
-
"
|
|
133
|
+
"structuredContent": {
|
|
132
134
|
"success": true
|
|
133
|
-
}
|
|
135
|
+
},
|
|
136
|
+
"messages": [{ "type": "text", "text": "Success sent to user" }]"
|
|
134
137
|
}
|
|
135
138
|
```
|
|
136
139
|
|
|
@@ -167,7 +170,7 @@ GET /mcp/tools
|
|
|
167
170
|
|
|
168
171
|
```ts
|
|
169
172
|
import { IMcpPrompt, McpPrompt } from "@muzikanto/nestjs-mcp";
|
|
170
|
-
import z from "zod";
|
|
173
|
+
import z from "zod/v3";
|
|
171
174
|
|
|
172
175
|
const schema = {
|
|
173
176
|
chatId: z.number().describe("Telegram chat id"), // строка с описанием
|
|
@@ -185,26 +188,28 @@ export class TelegramAutoReplyPrompt implements IMcpPrompt<{
|
|
|
185
188
|
schema = schema;
|
|
186
189
|
|
|
187
190
|
async execute({ text, chatId }: { text: string; chatId: number }) {
|
|
188
|
-
return
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
191
|
+
return {
|
|
192
|
+
messages: [
|
|
193
|
+
{
|
|
194
|
+
role: "system",
|
|
195
|
+
content: `You are a friendly Telegram bot. Reply briefly and to the point.`,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
role: "user",
|
|
199
|
+
content: text,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
role: "assistant",
|
|
203
|
+
tool_call: {
|
|
204
|
+
name: "telegram.sendMessage",
|
|
205
|
+
arguments: {
|
|
206
|
+
chatId,
|
|
207
|
+
text: "{{model_output}}",
|
|
208
|
+
},
|
|
204
209
|
},
|
|
205
210
|
},
|
|
206
|
-
|
|
207
|
-
|
|
211
|
+
],
|
|
212
|
+
};
|
|
208
213
|
}
|
|
209
214
|
}
|
|
210
215
|
```
|
|
@@ -349,7 +354,11 @@ export class McpDynamic {
|
|
|
349
354
|
this.mcpDynamicService.registerTool({
|
|
350
355
|
name: "dynamic_tool",
|
|
351
356
|
title: "Dynamic tool",
|
|
352
|
-
execute: () =>
|
|
357
|
+
execute: () =>
|
|
358
|
+
Promise.resolve({
|
|
359
|
+
structuredContent: { text: "test" },
|
|
360
|
+
messages: [{ type: "text" as const, text: "test" }],
|
|
361
|
+
}),
|
|
353
362
|
guards: [ExampleGuard],
|
|
354
363
|
interceptors: [ExampleInterceptor],
|
|
355
364
|
});
|
|
@@ -357,7 +366,8 @@ export class McpDynamic {
|
|
|
357
366
|
this.mcpDynamicService.registerPrompt({
|
|
358
367
|
name: "dynamic_prompt",
|
|
359
368
|
title: "Dynamic prompt",
|
|
360
|
-
execute: () =>
|
|
369
|
+
execute: () =>
|
|
370
|
+
Promise.resolve({ messages: [{ role: "assistant", content: "test" }] }),
|
|
361
371
|
guards: [ExampleGuard],
|
|
362
372
|
interceptors: [ExampleInterceptor],
|
|
363
373
|
});
|
|
@@ -370,6 +380,11 @@ export class McpDynamic {
|
|
|
370
380
|
Promise.resolve([{ uri: uri.href, text: `ID: ${input.testId}` }]),
|
|
371
381
|
guards: [ExampleGuard],
|
|
372
382
|
interceptors: [ExampleInterceptor],
|
|
383
|
+
list: async () => {
|
|
384
|
+
return [
|
|
385
|
+
{ uri: "dynamic://test/1", name: "dynamice_1", title: "Dynamic 1" },
|
|
386
|
+
];
|
|
387
|
+
},
|
|
373
388
|
});
|
|
374
389
|
}
|
|
375
390
|
}
|
|
@@ -405,7 +420,10 @@ export class TelegramSendMessageTool implements IMcpTool<
|
|
|
405
420
|
|
|
406
421
|
async execute() {
|
|
407
422
|
// await this.bot.telegram.sendMessage(input.chatId, input.text);
|
|
408
|
-
return {
|
|
423
|
+
return {
|
|
424
|
+
structuredContent: { success: true },
|
|
425
|
+
messages: { type: "text", text: "Success sent" },
|
|
426
|
+
};
|
|
409
427
|
}
|
|
410
428
|
}
|
|
411
429
|
```
|
|
@@ -473,7 +491,10 @@ export class TelegramSendMessageTool implements IMcpTool<
|
|
|
473
491
|
|
|
474
492
|
async execute() {
|
|
475
493
|
// await this.bot.telegram.sendMessage(input.chatId, input.text);
|
|
476
|
-
return {
|
|
494
|
+
return {
|
|
495
|
+
success: true,
|
|
496
|
+
messagse: [{ type: "text", text: "Success sent" }],
|
|
497
|
+
};
|
|
477
498
|
}
|
|
478
499
|
}
|
|
479
500
|
```
|
|
@@ -554,11 +575,12 @@ export class TelegramSendMessageTool implements IMcpTool<
|
|
|
554
575
|
### Integration with OpenAI Function Calls
|
|
555
576
|
|
|
556
577
|
```ts
|
|
557
|
-
import axios from
|
|
558
|
-
import OpenAI from
|
|
578
|
+
import axios from "axios";
|
|
579
|
+
import OpenAI from "openai";
|
|
559
580
|
|
|
560
|
-
const MCP_TOOLS_URL =
|
|
561
|
-
const MCP_TELEGRAM_PROMPT_URL =
|
|
581
|
+
const MCP_TOOLS_URL = "http://localhost:3000/mcp/tools";
|
|
582
|
+
const MCP_TELEGRAM_PROMPT_URL =
|
|
583
|
+
"http://localhost:3000/mcp/prompts/telegram_auto_reply";
|
|
562
584
|
|
|
563
585
|
// Create OpenAI client
|
|
564
586
|
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
@@ -568,7 +590,7 @@ const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
|
568
590
|
*/
|
|
569
591
|
async function getMcpTools() {
|
|
570
592
|
const response = await axios.get(MCP_TOOLS_URL);
|
|
571
|
-
return response.data.tools.map(el => ({
|
|
593
|
+
return response.data.tools.map((el) => ({
|
|
572
594
|
name: el.name,
|
|
573
595
|
description: el.description,
|
|
574
596
|
parameters: el.inputSchema,
|
|
@@ -579,17 +601,17 @@ async function getMcpTools() {
|
|
|
579
601
|
* Get all prompts
|
|
580
602
|
*/
|
|
581
603
|
async function getMcpPrompt() {
|
|
582
|
-
const response = await axios.post(MCP_TELEGRAM_PROMPT_URL, {
|
|
604
|
+
const response = await axios.post(MCP_TELEGRAM_PROMPT_URL, {
|
|
605
|
+
/* prompt generation arguments */
|
|
606
|
+
});
|
|
583
607
|
return response.data;
|
|
608
|
+
}
|
|
584
609
|
|
|
585
610
|
/**
|
|
586
611
|
* Request mcp tool
|
|
587
612
|
*/
|
|
588
613
|
async function callMcpTool(toolName: string, payload: Record<string, any>) {
|
|
589
|
-
const response = await axios.post(
|
|
590
|
-
MCP_TOOLS_URL,
|
|
591
|
-
{ type: toolName, payload },
|
|
592
|
-
);
|
|
614
|
+
const response = await axios.post(MCP_TOOLS_URL, { type: toolName, payload });
|
|
593
615
|
return response.data;
|
|
594
616
|
}
|
|
595
617
|
|
|
@@ -601,10 +623,10 @@ async function callMcpTool(toolName: string, payload: Record<string, any>) {
|
|
|
601
623
|
const promptResponse = await getMcpPrompt();
|
|
602
624
|
|
|
603
625
|
const completion = await client.chat.completions.create({
|
|
604
|
-
model:
|
|
626
|
+
model: "gpt-4.1-mini",
|
|
605
627
|
messages: promptResponse.messages,
|
|
606
628
|
functions: toolsResponse.tools,
|
|
607
|
-
function_call:
|
|
629
|
+
function_call: "auto",
|
|
608
630
|
});
|
|
609
631
|
|
|
610
632
|
const message = completion.choices[0].message;
|
|
@@ -613,8 +635,8 @@ async function callMcpTool(toolName: string, payload: Record<string, any>) {
|
|
|
613
635
|
const { name, arguments: argsJson } = message.function_call;
|
|
614
636
|
const args = JSON.parse(argsJson);
|
|
615
637
|
|
|
616
|
-
const
|
|
617
|
-
console.log(
|
|
638
|
+
const { messages, structuredContent } = await callMcpTool(name, args);
|
|
639
|
+
console.log("Result from MCP tool:", messages, structuredContent);
|
|
618
640
|
}
|
|
619
641
|
})();
|
|
620
642
|
```
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { HttpService } from "@nestjs/axios";
|
|
2
2
|
import { McpToolsDto } from "../mcp-server/dto/McpTools.dto";
|
|
3
3
|
import { McpPromptsDto } from "../mcp-server/dto/McpPrompts.dto";
|
|
4
|
-
import {
|
|
4
|
+
import { McpPromptResultDto } from "../mcp-server/dto/McpPrompResult.dto";
|
|
5
5
|
export declare class McpClientService {
|
|
6
6
|
private readonly httpService;
|
|
7
7
|
constructor(httpService: HttpService);
|
|
8
8
|
getAllTools(): Promise<McpToolsDto>;
|
|
9
9
|
getAllPrompts(): Promise<McpPromptsDto>;
|
|
10
|
-
getPromptByName<Payload = any>(promptName: string, params: Payload): Promise<
|
|
10
|
+
getPromptByName<Payload = any>(promptName: string, params: Payload): Promise<McpPromptResultDto>;
|
|
11
11
|
callMcpTool<Payload = any, Result = any>(toolName: string, payload: Payload): Promise<Result>;
|
|
12
12
|
}
|
|
@@ -3,20 +3,21 @@ import { McpService } from "../services/mcp.service";
|
|
|
3
3
|
import { McpMessageDto } from "../dto/McpMessage.dto";
|
|
4
4
|
import { McpToolsDto } from "../dto/McpTools.dto";
|
|
5
5
|
import { McpPromptsDto } from "../dto/McpPrompts.dto";
|
|
6
|
-
import {
|
|
6
|
+
import { McpPromptResultDto } from "../dto/McpPrompResult.dto";
|
|
7
7
|
import { IMcpConfig } from "../config";
|
|
8
8
|
import { McpResourcesDto } from "../dto/McpResources.dto";
|
|
9
9
|
import { McpResourceItemsDto } from "../dto/McpResourceItems.dto";
|
|
10
10
|
import { McpResourceRequestDto } from "../dto/McpResourceRequest.dto";
|
|
11
|
+
import { McpToolResultDto } from "../dto/McpToolResult.dto";
|
|
11
12
|
export declare class McpController {
|
|
12
13
|
private readonly service;
|
|
13
14
|
private readonly guard;
|
|
14
15
|
private readonly config;
|
|
15
16
|
constructor(service: McpService, guard: CanActivate, config: IMcpConfig);
|
|
16
|
-
handleTool(body: McpMessageDto, request: any, context: ExecutionContext): Promise<
|
|
17
|
+
handleTool(body: McpMessageDto, request: any, context: ExecutionContext): Promise<McpToolResultDto>;
|
|
17
18
|
getTools(context: ExecutionContext): Promise<McpToolsDto>;
|
|
18
19
|
getPrompts(context: ExecutionContext): Promise<McpPromptsDto>;
|
|
19
|
-
getPrompt(name: string, body: object, context: ExecutionContext): Promise<
|
|
20
|
+
getPrompt(name: string, body: object, context: ExecutionContext): Promise<McpPromptResultDto>;
|
|
20
21
|
getResources(context: ExecutionContext): Promise<McpResourcesDto>;
|
|
21
22
|
executeResource(name: string, body: McpResourceRequestDto, context: ExecutionContext): Promise<McpResourceItemsDto>;
|
|
22
23
|
private checkGuard;
|
|
@@ -19,7 +19,7 @@ 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
21
|
const McpPrompts_dto_1 = require("../dto/McpPrompts.dto");
|
|
22
|
-
const
|
|
22
|
+
const McpPrompResult_dto_1 = require("../dto/McpPrompResult.dto");
|
|
23
23
|
const context_decorator_1 = require("../utils/context.decorator");
|
|
24
24
|
const inject_tokens_1 = require("../utils/inject-tokens");
|
|
25
25
|
const config_1 = require("../config");
|
|
@@ -28,6 +28,7 @@ const McpResources_dto_1 = require("../dto/McpResources.dto");
|
|
|
28
28
|
const McpResourceItems_dto_1 = require("../dto/McpResourceItems.dto");
|
|
29
29
|
const McpResourceRequest_dto_1 = require("../dto/McpResourceRequest.dto");
|
|
30
30
|
const uri_1 = require("../utils/uri");
|
|
31
|
+
const McpToolResult_dto_1 = require("../dto/McpToolResult.dto");
|
|
31
32
|
let McpController = class McpController {
|
|
32
33
|
service;
|
|
33
34
|
guard;
|
|
@@ -56,10 +57,8 @@ let McpController = class McpController {
|
|
|
56
57
|
async getPrompt(name, body, context) {
|
|
57
58
|
await this.checkGuard(context);
|
|
58
59
|
const observable = await this.service.executePrompt(name, body, context);
|
|
59
|
-
const
|
|
60
|
-
return
|
|
61
|
-
messages,
|
|
62
|
-
};
|
|
60
|
+
const result = await (0, rxjs_1.firstValueFrom)(observable);
|
|
61
|
+
return result;
|
|
63
62
|
}
|
|
64
63
|
async getResources(context) {
|
|
65
64
|
await this.checkGuard(context);
|
|
@@ -91,6 +90,7 @@ __decorate([
|
|
|
91
90
|
summary: "Request tool",
|
|
92
91
|
}),
|
|
93
92
|
(0, swagger_1.ApiResponse)({
|
|
93
|
+
type: McpToolResult_dto_1.McpToolResultDto,
|
|
94
94
|
status: 200,
|
|
95
95
|
description: "Tool execution result",
|
|
96
96
|
}),
|
|
@@ -155,7 +155,7 @@ __decorate([
|
|
|
155
155
|
(0, swagger_1.ApiResponse)({
|
|
156
156
|
status: 200,
|
|
157
157
|
description: "Prompt messages",
|
|
158
|
-
type:
|
|
158
|
+
type: McpPrompResult_dto_1.McpPromptResultDto,
|
|
159
159
|
}),
|
|
160
160
|
(0, swagger_1.ApiNotFoundResponse)({
|
|
161
161
|
description: "Not found prompt",
|
|
@@ -2,7 +2,11 @@ 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
|
|
5
|
+
export type IMcpPromptResult = {
|
|
6
|
+
messages: IMcpPromptResultMessage[];
|
|
7
|
+
description?: string;
|
|
8
|
+
};
|
|
9
|
+
export type IMcpPromptResultMessage = {
|
|
6
10
|
role: "user" | "assistant" | "system";
|
|
7
11
|
content?: string;
|
|
8
12
|
tool_call?: {
|
|
@@ -10,12 +14,12 @@ export type IMcpPromptMessage = {
|
|
|
10
14
|
arguments: object;
|
|
11
15
|
};
|
|
12
16
|
};
|
|
13
|
-
export interface IMcpPrompt<Payload = any
|
|
17
|
+
export interface IMcpPrompt<Payload = any> {
|
|
14
18
|
name: string;
|
|
15
19
|
title?: string;
|
|
16
20
|
description?: string;
|
|
17
21
|
inputSchema?: ZodRawShapeCompat;
|
|
18
|
-
execute(input: Payload): Promise<
|
|
22
|
+
execute(input: Payload): Promise<IMcpPromptResult>;
|
|
19
23
|
}
|
|
20
24
|
export declare const MCP_PROMPT_METADATA = "mcp:prompt-class";
|
|
21
25
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol";
|
|
2
|
-
import { ServerNotification, ServerRequest } from "@modelcontextprotocol/sdk/types";
|
|
2
|
+
import { Resource, ServerNotification, ServerRequest } from "@modelcontextprotocol/sdk/types";
|
|
3
3
|
import "reflect-metadata";
|
|
4
4
|
export type IMcpResourceResult = {
|
|
5
5
|
uri: string;
|
|
@@ -16,6 +16,8 @@ export interface IMcpResource<Payload = any> {
|
|
|
16
16
|
uri: string;
|
|
17
17
|
title?: string;
|
|
18
18
|
description?: string;
|
|
19
|
+
annotations?: Resource["annotations"];
|
|
20
|
+
_meta?: Resource["_meta"];
|
|
19
21
|
execute(url: URL, input: Payload): Promise<IMcpResourceResult[]>;
|
|
20
22
|
list?(extra: RequestHandlerExtra<ServerRequest, ServerNotification>): Promise<IMcpResourceListItem[]>;
|
|
21
23
|
}
|
|
@@ -1,13 +1,25 @@
|
|
|
1
|
+
import { ToolAnnotations } from "@modelcontextprotocol/sdk/types";
|
|
1
2
|
import "reflect-metadata";
|
|
2
3
|
import type * as z3 from "zod/v3";
|
|
3
4
|
type AnySchema = z3.ZodTypeAny;
|
|
4
5
|
type ZodRawShapeCompat = Record<string, AnySchema>;
|
|
5
|
-
export
|
|
6
|
+
export type IMcpToolResult<Result extends Record<string, unknown>> = {
|
|
7
|
+
structuredContent?: Result;
|
|
8
|
+
messages: Array<{
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
}>;
|
|
12
|
+
isError?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export interface IMcpTool<Payload = any, Result extends Record<string, unknown> = Record<string, unknown>> {
|
|
6
15
|
name: string;
|
|
7
16
|
title?: string;
|
|
8
17
|
description?: string;
|
|
9
18
|
inputSchema?: ZodRawShapeCompat;
|
|
10
|
-
|
|
19
|
+
outputSchema?: ZodRawShapeCompat;
|
|
20
|
+
annotations?: ToolAnnotations;
|
|
21
|
+
_meta?: Record<string, unknown>;
|
|
22
|
+
execute(input: Payload): Promise<IMcpToolResult<Result>>;
|
|
11
23
|
}
|
|
12
24
|
export declare const MCP_TOOL_METADATA = "mcp:tool-class";
|
|
13
25
|
/**
|
|
@@ -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.McpPromptResultDto = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const McpPromptMessage_dto_1 = require("./McpPromptMessage.dto");
|
|
15
|
+
class McpPromptResultDto {
|
|
16
|
+
messages;
|
|
17
|
+
description;
|
|
18
|
+
}
|
|
19
|
+
exports.McpPromptResultDto = McpPromptResultDto;
|
|
20
|
+
__decorate([
|
|
21
|
+
(0, swagger_1.ApiProperty)({
|
|
22
|
+
type: McpPromptMessage_dto_1.McpPromptMessageDto,
|
|
23
|
+
isArray: true,
|
|
24
|
+
description: "Messages list",
|
|
25
|
+
}),
|
|
26
|
+
__metadata("design:type", Array)
|
|
27
|
+
], McpPromptResultDto.prototype, "messages", void 0);
|
|
28
|
+
__decorate([
|
|
29
|
+
(0, swagger_1.ApiProperty)({ type: "string", nullable: true }),
|
|
30
|
+
__metadata("design:type", String)
|
|
31
|
+
], McpPromptResultDto.prototype, "description", void 0);
|
|
@@ -0,0 +1,40 @@
|
|
|
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)({
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Request ai message",
|
|
28
|
+
nullable: true,
|
|
29
|
+
}),
|
|
30
|
+
__metadata("design:type", String)
|
|
31
|
+
], McpPromptMessageDto.prototype, "content", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
(0, swagger_1.ApiProperty)({
|
|
34
|
+
type: "object",
|
|
35
|
+
description: "Tool call context",
|
|
36
|
+
nullable: true,
|
|
37
|
+
additionalProperties: false,
|
|
38
|
+
}),
|
|
39
|
+
__metadata("design:type", Object)
|
|
40
|
+
], McpPromptMessageDto.prototype, "tool_call", void 0);
|
|
@@ -16,6 +16,7 @@ class McpToolDto {
|
|
|
16
16
|
title;
|
|
17
17
|
description;
|
|
18
18
|
inputSchema;
|
|
19
|
+
outputSchema;
|
|
19
20
|
}
|
|
20
21
|
exports.McpToolDto = McpToolDto;
|
|
21
22
|
__decorate([
|
|
@@ -47,3 +48,12 @@ __decorate([
|
|
|
47
48
|
}),
|
|
48
49
|
__metadata("design:type", Object)
|
|
49
50
|
], McpToolDto.prototype, "inputSchema", void 0);
|
|
51
|
+
__decorate([
|
|
52
|
+
(0, swagger_1.ApiProperty)({
|
|
53
|
+
type: "object",
|
|
54
|
+
description: "Tool result schema",
|
|
55
|
+
nullable: true,
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
}),
|
|
58
|
+
__metadata("design:type", Object)
|
|
59
|
+
], McpToolDto.prototype, "outputSchema", void 0);
|
|
@@ -0,0 +1,32 @@
|
|
|
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.McpToolResultDto = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const McpToolResultMessage_dto_1 = require("./McpToolResultMessage.dto");
|
|
15
|
+
class McpToolResultDto {
|
|
16
|
+
structuredContent;
|
|
17
|
+
messages;
|
|
18
|
+
isError;
|
|
19
|
+
}
|
|
20
|
+
exports.McpToolResultDto = McpToolResultDto;
|
|
21
|
+
__decorate([
|
|
22
|
+
(0, swagger_1.ApiProperty)({ description: "Tool result", nullable: true }),
|
|
23
|
+
__metadata("design:type", Object)
|
|
24
|
+
], McpToolResultDto.prototype, "structuredContent", void 0);
|
|
25
|
+
__decorate([
|
|
26
|
+
(0, swagger_1.ApiProperty)({ type: McpToolResultMessage_dto_1.McpToolResultMessageDto, isArray: true }),
|
|
27
|
+
__metadata("design:type", Array)
|
|
28
|
+
], McpToolResultDto.prototype, "messages", void 0);
|
|
29
|
+
__decorate([
|
|
30
|
+
(0, swagger_1.ApiProperty)({ type: "boolean", nullable: true }),
|
|
31
|
+
__metadata("design:type", Boolean)
|
|
32
|
+
], McpToolResultDto.prototype, "isError", void 0);
|
|
@@ -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.McpToolResultMessageDto = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
class McpToolResultMessageDto {
|
|
15
|
+
type;
|
|
16
|
+
text;
|
|
17
|
+
}
|
|
18
|
+
exports.McpToolResultMessageDto = McpToolResultMessageDto;
|
|
19
|
+
__decorate([
|
|
20
|
+
(0, swagger_1.ApiProperty)({ type: "string", description: "Message type" }),
|
|
21
|
+
__metadata("design:type", String)
|
|
22
|
+
], McpToolResultMessageDto.prototype, "type", void 0);
|
|
23
|
+
__decorate([
|
|
24
|
+
(0, swagger_1.ApiProperty)({ type: "string", description: "Message text" }),
|
|
25
|
+
__metadata("design:type", String)
|
|
26
|
+
], McpToolResultMessageDto.prototype, "text", void 0);
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { HttpException, HttpStatus } from "@nestjs/common";
|
|
2
|
+
import { ErrorObject } from "ajv";
|
|
2
3
|
export declare class McpException extends HttpException {
|
|
3
4
|
constructor(message: string, status?: HttpStatus, options?: {
|
|
4
5
|
cause?: unknown;
|
|
5
6
|
});
|
|
6
7
|
}
|
|
7
8
|
export declare class McpBadRequestException extends McpException {
|
|
8
|
-
|
|
9
|
+
errors?: ErrorObject[];
|
|
10
|
+
constructor(message: string, errors: ErrorObject[] | undefined, options?: {
|
|
9
11
|
cause?: unknown;
|
|
10
12
|
});
|
|
11
13
|
}
|
|
@@ -9,8 +9,10 @@ class McpException extends common_1.HttpException {
|
|
|
9
9
|
}
|
|
10
10
|
exports.McpException = McpException;
|
|
11
11
|
class McpBadRequestException extends McpException {
|
|
12
|
-
|
|
12
|
+
errors;
|
|
13
|
+
constructor(message, errors, options) {
|
|
13
14
|
super(message, common_1.HttpStatus.BAD_REQUEST, options);
|
|
15
|
+
this.errors = errors;
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
exports.McpBadRequestException = McpBadRequestException;
|
|
@@ -4,7 +4,7 @@ import { McpService } from "../services/mcp.service";
|
|
|
4
4
|
import { IMcpTool } from "../decorators/mcp-tool.decorator";
|
|
5
5
|
import { IMcpResource } from "../decorators/mcp-resource.decorator";
|
|
6
6
|
import { IMcpPrompt } from "../decorators/mcp-prompt.decorator";
|
|
7
|
-
export type IMcpDynamicTool<Input, Result
|
|
7
|
+
export type IMcpDynamicTool<Input, Result extends Record<string, unknown>> = IMcpTool<Input, Result> & {
|
|
8
8
|
guards?: Type<CanActivate>[];
|
|
9
9
|
interceptors?: Type<NestInterceptor>[];
|
|
10
10
|
};
|
|
@@ -21,7 +21,7 @@ export declare class McpDynamicService {
|
|
|
21
21
|
private readonly mcpService;
|
|
22
22
|
constructor(moduleRef: ModuleRef, mcpService: McpService);
|
|
23
23
|
/** Динамически регистрирует MCP tools */
|
|
24
|
-
registerTool<Input, Result
|
|
24
|
+
registerTool<Input, Result extends Record<string, unknown>>(tool: IMcpDynamicTool<Input, Result>): Promise<void>;
|
|
25
25
|
/** Динамически регистрирует MCP prompts */
|
|
26
26
|
registerPrompt<Input>(prompt: IMcpDynamicPrompt<Input>): Promise<void>;
|
|
27
27
|
/** Динамически регистрирует MCP resources */
|
|
@@ -29,6 +29,9 @@ let McpDynamicService = class McpDynamicService {
|
|
|
29
29
|
description = tool.description;
|
|
30
30
|
execute = tool.execute;
|
|
31
31
|
inputSchema = tool.inputSchema;
|
|
32
|
+
outputSchema = tool.outputSchema;
|
|
33
|
+
annotations = tool.annotations;
|
|
34
|
+
_meta = tool._meta;
|
|
32
35
|
};
|
|
33
36
|
if (tool.guards) {
|
|
34
37
|
this.applyGuards(DynamicToolClass, tool.guards);
|
|
@@ -72,6 +75,8 @@ let McpDynamicService = class McpDynamicService {
|
|
|
72
75
|
description = resource.description;
|
|
73
76
|
execute = resource.execute;
|
|
74
77
|
list = resource.list;
|
|
78
|
+
annotations = resource.annotations;
|
|
79
|
+
_meta = resource._meta;
|
|
75
80
|
};
|
|
76
81
|
if (resource.guards) {
|
|
77
82
|
this.applyGuards(DynamicResourceClass, resource.guards);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ExecutionContext, OnModuleInit } from "@nestjs/common";
|
|
2
|
-
import { IMcpTool } from "../decorators/mcp-tool.decorator";
|
|
3
|
-
import { IMcpPrompt } from "../decorators/mcp-prompt.decorator";
|
|
4
|
-
import { IMcpResource } from "../decorators/mcp-resource.decorator";
|
|
2
|
+
import { IMcpTool, IMcpToolResult } from "../decorators/mcp-tool.decorator";
|
|
3
|
+
import { IMcpPrompt, IMcpPromptResult } from "../decorators/mcp-prompt.decorator";
|
|
4
|
+
import { IMcpResource, IMcpResourceResult } from "../decorators/mcp-resource.decorator";
|
|
5
5
|
import { ModuleRef } from "@nestjs/core";
|
|
6
|
+
import { Observable } from "rxjs";
|
|
6
7
|
import { IMcpConfig } from "../config";
|
|
7
8
|
export interface McpMessage {
|
|
8
9
|
type: string;
|
|
@@ -39,6 +40,7 @@ export declare class McpService implements OnModuleInit {
|
|
|
39
40
|
title: string | undefined;
|
|
40
41
|
description: string | undefined;
|
|
41
42
|
inputSchema: any;
|
|
43
|
+
outputSchema: any;
|
|
42
44
|
}[];
|
|
43
45
|
listPrompts(): {
|
|
44
46
|
name: string;
|
|
@@ -64,13 +66,13 @@ export declare class McpService implements OnModuleInit {
|
|
|
64
66
|
instance: IMcpResource;
|
|
65
67
|
metatype: Function;
|
|
66
68
|
}): void;
|
|
67
|
-
executePrompt(name: string, payload: object, context: ExecutionContext): Promise<
|
|
69
|
+
executePrompt(name: string, payload: object, context: ExecutionContext): Promise<Observable<IMcpPromptResult>>;
|
|
68
70
|
/**
|
|
69
71
|
* Отправить сообщение в MCP "сервер"
|
|
70
72
|
*/
|
|
71
73
|
executeTool(msg: {
|
|
72
74
|
type: string;
|
|
73
75
|
payload: any;
|
|
74
|
-
}, context: ExecutionContext): Promise<
|
|
75
|
-
executeResource(name: string, uri: URL, vars: Record<string, any>, context: ExecutionContext): Promise<
|
|
76
|
+
}, context: ExecutionContext): Promise<Observable<IMcpToolResult<Record<string, unknown>>>>;
|
|
77
|
+
executeResource(name: string, uri: URL, vars: Record<string, any>, context: ExecutionContext): Promise<Observable<IMcpResourceResult[]>>;
|
|
76
78
|
}
|
|
@@ -46,6 +46,9 @@ let McpService = class McpService {
|
|
|
46
46
|
title: t.title,
|
|
47
47
|
description: t.description,
|
|
48
48
|
inputSchema: t.inputSchema ? (0, zod_1.zodToJsonSchema)(t.inputSchema) : undefined,
|
|
49
|
+
outputSchema: t.outputSchema
|
|
50
|
+
? (0, zod_1.zodToJsonSchema)(t.outputSchema)
|
|
51
|
+
: undefined,
|
|
49
52
|
}));
|
|
50
53
|
}
|
|
51
54
|
listPrompts() {
|
|
@@ -86,7 +89,7 @@ let McpService = class McpService {
|
|
|
86
89
|
const validate = this.ajv.compile(zodSchema);
|
|
87
90
|
const valid = validate(payload);
|
|
88
91
|
if (!valid) {
|
|
89
|
-
throw new exceptions_1.McpBadRequestException("Invalid prompt arguments");
|
|
92
|
+
throw new exceptions_1.McpBadRequestException("Invalid prompt arguments", validate.errors || []);
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
// const result = await prompt.execute(payload);
|
|
@@ -120,7 +123,7 @@ let McpService = class McpService {
|
|
|
120
123
|
const validate = this.ajv.compile(zodSchema);
|
|
121
124
|
const valid = validate(msg.payload);
|
|
122
125
|
if (!valid) {
|
|
123
|
-
throw new exceptions_1.McpBadRequestException(
|
|
126
|
+
throw new exceptions_1.McpBadRequestException("Invalid tool arguments", validate.errors || []);
|
|
124
127
|
}
|
|
125
128
|
}
|
|
126
129
|
// const result = await tool.execute(msg.payload);
|
|
@@ -22,4 +22,7 @@ export declare class McpSseService implements OnModuleInit {
|
|
|
22
22
|
handleSse(_: IRequest, res: IResponse, context: ExecutionContext): Promise<void>;
|
|
23
23
|
handleSseMessage(req: IRequest, res: IResponse): Promise<void>;
|
|
24
24
|
private createServer;
|
|
25
|
+
private registerTools;
|
|
26
|
+
private registerPrompts;
|
|
27
|
+
private registerResources;
|
|
25
28
|
}
|
|
@@ -64,11 +64,20 @@ let McpSseService = class McpSseService {
|
|
|
64
64
|
version: this.config.version || "1",
|
|
65
65
|
name: this.config.name || "MCP server",
|
|
66
66
|
}, {});
|
|
67
|
+
this.registerTools(server, context);
|
|
68
|
+
this.registerPrompts(server, context);
|
|
69
|
+
this.registerResources(server, context);
|
|
70
|
+
return server;
|
|
71
|
+
}
|
|
72
|
+
registerTools(server, context) {
|
|
67
73
|
for (const [toolName, { instance: tool }] of this.service.tools.entries()) {
|
|
68
74
|
server.registerTool(tool.name, {
|
|
69
75
|
title: tool.title,
|
|
70
76
|
description: tool.description,
|
|
71
77
|
inputSchema: tool.inputSchema,
|
|
78
|
+
outputSchema: tool.outputSchema,
|
|
79
|
+
annotations: tool.annotations,
|
|
80
|
+
_meta: tool._meta,
|
|
72
81
|
}, async (payload) => {
|
|
73
82
|
try {
|
|
74
83
|
// const result = await tool.execute(
|
|
@@ -77,9 +86,9 @@ let McpSseService = class McpSseService {
|
|
|
77
86
|
const observable = await this.service.executeTool({ type: tool.name, payload }, context);
|
|
78
87
|
const result = await (0, rxjs_1.firstValueFrom)(observable);
|
|
79
88
|
return {
|
|
80
|
-
content:
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
content: result.messages,
|
|
90
|
+
structuredContent: result.structuredContent,
|
|
91
|
+
isError: result.isError,
|
|
83
92
|
};
|
|
84
93
|
}
|
|
85
94
|
catch (e) {
|
|
@@ -89,6 +98,8 @@ let McpSseService = class McpSseService {
|
|
|
89
98
|
}
|
|
90
99
|
});
|
|
91
100
|
}
|
|
101
|
+
}
|
|
102
|
+
registerPrompts(server, context) {
|
|
92
103
|
for (const [promptName, { instance: prompt },] of this.service.prompts.entries()) {
|
|
93
104
|
server.registerPrompt(prompt.name, {
|
|
94
105
|
title: prompt.title,
|
|
@@ -99,7 +110,7 @@ let McpSseService = class McpSseService {
|
|
|
99
110
|
// const result = await prompt.execute({ ...params });
|
|
100
111
|
const observable = await this.service.executePrompt(prompt.name, payload, context);
|
|
101
112
|
const result = await (0, rxjs_1.firstValueFrom)(observable);
|
|
102
|
-
const messages = result.map((el) => ({
|
|
113
|
+
const messages = result.messages.map((el) => ({
|
|
103
114
|
role: (el.role === "system" ? "assistant" : el.role),
|
|
104
115
|
content: el.tool_call
|
|
105
116
|
? {
|
|
@@ -108,7 +119,7 @@ let McpSseService = class McpSseService {
|
|
|
108
119
|
}
|
|
109
120
|
: { type: "text", text: el.content },
|
|
110
121
|
}));
|
|
111
|
-
return { messages: messages };
|
|
122
|
+
return { messages: messages, description: result.description };
|
|
112
123
|
}
|
|
113
124
|
catch (e) {
|
|
114
125
|
throw new exceptions_1.McpInternalServerErrorException(`Faild to execute tool ${prompt.name}`, {
|
|
@@ -117,6 +128,8 @@ let McpSseService = class McpSseService {
|
|
|
117
128
|
}
|
|
118
129
|
});
|
|
119
130
|
}
|
|
131
|
+
}
|
|
132
|
+
registerResources(server, context) {
|
|
120
133
|
for (const [_, { instance: resource },] of this.service.resources.entries()) {
|
|
121
134
|
const resourceList = resource.list;
|
|
122
135
|
server.registerResource(resource.name, new mcp_js_1.ResourceTemplate(resource.uri, {
|
|
@@ -130,6 +143,8 @@ let McpSseService = class McpSseService {
|
|
|
130
143
|
}), {
|
|
131
144
|
title: resource.title,
|
|
132
145
|
description: resource.description,
|
|
146
|
+
annotations: resource.annotations,
|
|
147
|
+
_meta: resource._meta,
|
|
133
148
|
}, async (url, variables) => {
|
|
134
149
|
try {
|
|
135
150
|
// const resources = await resource.execute(url, variables);
|
|
@@ -144,7 +159,6 @@ let McpSseService = class McpSseService {
|
|
|
144
159
|
}
|
|
145
160
|
});
|
|
146
161
|
}
|
|
147
|
-
return server;
|
|
148
162
|
}
|
|
149
163
|
};
|
|
150
164
|
exports.McpSseService = McpSseService;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muzikanto/nestjs-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
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",
|