@muzikanto/nestjs-mcp 1.7.0 → 1.7.3

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +31 -11
  3. package/dist/index.d.ts +2 -8
  4. package/dist/index.js +2 -8
  5. package/dist/mcp-client/index.d.ts +3 -0
  6. package/dist/mcp-client/index.js +19 -0
  7. package/dist/mcp-client/mcp-client.module.d.ts +2 -6
  8. package/dist/mcp-client/mcp-client.module.js +5 -3
  9. package/dist/mcp-client/mcp-client.service.d.ts +2 -1
  10. package/dist/mcp-client/utils/openai.d.ts +34 -0
  11. package/dist/mcp-client/utils/openai.js +29 -0
  12. package/dist/mcp-server/config.d.ts +5 -0
  13. package/dist/mcp-server/controllers/mcp.controller.d.ts +2 -2
  14. package/dist/mcp-server/controllers/mcp.controller.js +5 -4
  15. package/dist/mcp-server/controllers/mcp.sse.controller.js +1 -0
  16. package/dist/mcp-server/decorators/mcp-resource.decorator.d.ts +7 -4
  17. package/dist/mcp-server/decorators/mcp-tool.decorator.d.ts +1 -1
  18. package/dist/mcp-server/dto/IMcpResourceResult.dto.d.ts +4 -0
  19. package/dist/mcp-server/dto/IMcpResourceResult.dto.js +26 -0
  20. package/dist/mcp-server/dto/McpResourceResult.dto.d.ts +4 -0
  21. package/dist/mcp-server/dto/McpResourceResult.dto.js +26 -0
  22. package/dist/mcp-server/dto/McpResourceResultItem.dto.d.ts +4 -0
  23. package/dist/mcp-server/dto/McpResourceResultItem.dto.js +30 -0
  24. package/dist/mcp-server/dto/McpToolResult.dto.d.ts +2 -2
  25. package/dist/mcp-server/dto/McpToolResultMessage.dto.d.ts +1 -1
  26. package/dist/mcp-server/index.d.ts +6 -0
  27. package/dist/mcp-server/index.js +22 -0
  28. package/dist/mcp-server/mcp.module.d.ts +13 -1
  29. package/dist/mcp-server/mcp.module.js +10 -2
  30. package/dist/mcp-server/services/mcp-dynamic.service.d.ts +5 -1
  31. package/dist/mcp-server/services/mcp-dynamic.service.js +12 -0
  32. package/dist/mcp-server/services/mcp.service.d.ts +1 -1
  33. package/dist/mcp-server/services/mcp.service.js +4 -1
  34. package/dist/mcp-server/services/mcp.sse.service.js +17 -2
  35. package/dist/mcp-server/utils/http-adapter.d.ts +1 -1
  36. package/dist/mcp-server/utils/openai.d.ts +34 -0
  37. package/dist/mcp-server/utils/openai.js +29 -0
  38. package/dist/mcp-server/utils/run-fillters.js +5 -2
  39. package/dist/mcp-server/utils/zod.js +4 -1
  40. package/package.json +18 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @muzikanto/nestjs-mcp
2
2
 
3
+ ## 1.7.3
4
+
5
+ ### Patch Changes
6
+
7
+ - fix dynamic tools filters
8
+
9
+ ## 1.7.2
10
+
11
+ ### Patch Changes
12
+
13
+ - add transports selection
14
+
15
+ ## 1.7.1
16
+
17
+ ### Patch Changes
18
+
19
+ - add exports for (client, server) and update example (add openai)
20
+
3
21
  ## 1.7.0
4
22
 
5
23
  ### Minor Changes
package/README.md CHANGED
@@ -50,6 +50,13 @@ NestJS MCP (Model Context Protocol) module — allows you to create “tools”,
50
50
  - Full TypeScript typing
51
51
  - Support `@UseGuards`, `@UseInterceptors`, `@UseFilters`
52
52
 
53
+ ## Examples
54
+
55
+ - [Example server](https://github.com/Muzikanto/nestjs-mcp/tree/main/example)
56
+ - [Example librechat](https://github.com/Muzikanto/nestjs-mcp/tree/main/example/librechat)
57
+ - [Example openai request](https://github.com/Muzikanto/nestjs-mcp/blob/main/example/src/openai/openai.service.ts)
58
+ - [Example mcp handlers](https://github.com/Muzikanto/nestjs-mcp/tree/main/example/src/mcp-server/handlers)
59
+
53
60
  ---
54
61
 
55
62
  ## Installation
@@ -74,6 +81,10 @@ import { TelegramAutoReplyPrompt } from "./prompts/telegram-auto-reply.prompt";
74
81
  imports: [
75
82
  McpModule.forRoot({
76
83
  providers: [TelegramSendMessageTool, TelegramAutoReplyPrompt],
84
+ transports: {
85
+ sse: true, // SSE endpoints for mcp
86
+ http: true, // HTTP endpoints for custom server
87
+ },
77
88
  }),
78
89
  ],
79
90
  })
@@ -542,7 +553,7 @@ class NotImplExceptionFilter implements ExceptionFilter {
542
553
  catch(exception: unknown, host: ArgumentsHost) {
543
554
  return {
544
555
  isError: true,
545
- text: (exception as Error).message,
556
+ messages: [{ type: "text", text: "Not implemented tool" }],
546
557
  };
547
558
  }
548
559
  }
@@ -552,7 +563,7 @@ class AuthExceptionFilter implements ExceptionFilter {
552
563
  catch(exception: unknown, host: ArgumentsHost) {
553
564
  return {
554
565
  isError: true,
555
- text: (exception as Error).message,
566
+ messages: [{ type: "text", text: "No access" }],
556
567
  };
557
568
  }
558
569
  }
@@ -574,6 +585,8 @@ export class TelegramSendMessageTool implements IMcpTool<
574
585
 
575
586
  ### Integration with OpenAI Function Calls
576
587
 
588
+ Example with `openai`: `6.25.0`
589
+
577
590
  ```ts
578
591
  import axios from "axios";
579
592
  import OpenAI from "openai";
@@ -583,17 +596,24 @@ const MCP_TELEGRAM_PROMPT_URL =
583
596
  "http://localhost:3000/mcp/prompts/telegram_auto_reply";
584
597
 
585
598
  // Create OpenAI client
586
- const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
599
+ const client = new OpenAI({
600
+ baseUrl: "https://openrouter.ai/api/v1",
601
+ apiKey: process.env.OPENROUTER_API_KEY,
602
+ });
587
603
 
588
604
  /**
589
605
  * Get all tools
590
606
  */
591
607
  async function getMcpTools() {
592
608
  const response = await axios.get(MCP_TOOLS_URL);
609
+
593
610
  return response.data.tools.map((el) => ({
594
- name: el.name,
595
- description: el.description,
596
- parameters: el.inputSchema,
611
+ type: "function",
612
+ function: {
613
+ name: el.name,
614
+ description: el.description,
615
+ parameters: el.inputSchema,
616
+ },
597
617
  }));
598
618
  }
599
619
 
@@ -623,16 +643,16 @@ async function callMcpTool(toolName: string, payload: Record<string, any>) {
623
643
  const promptResponse = await getMcpPrompt();
624
644
 
625
645
  const completion = await client.chat.completions.create({
626
- model: "gpt-4.1-mini",
646
+ model: "arcee-ai/trinity-large-preview:free",
627
647
  messages: promptResponse.messages,
628
- functions: toolsResponse.tools,
629
- function_call: "auto",
648
+ tools: toolsResponse,
649
+ tool_choice: "auto",
630
650
  });
631
651
 
632
652
  const message = completion.choices[0].message;
633
653
 
634
- if (message.function_call) {
635
- const { name, arguments: argsJson } = message.function_call;
654
+ if (message.tool_calls?.length) {
655
+ const { name, arguments: argsJson } = message.tool_calls[0].function;
636
656
  const args = JSON.parse(argsJson);
637
657
 
638
658
  const { messages, structuredContent } = await callMcpTool(name, args);
package/dist/index.d.ts CHANGED
@@ -1,8 +1,2 @@
1
- export * from "./mcp-server/mcp.module";
2
- export * from "./mcp-server/decorators/mcp-tool.decorator";
3
- export * from "./mcp-server/decorators/mcp-prompt.decorator";
4
- export * from "./mcp-server/decorators/mcp-resource.decorator";
5
- export * from "./mcp-client/mcp-client.module";
6
- export * from "./mcp-client/mcp-client.service";
7
- export * from "./mcp-server/services/mcp-dynamic.service";
8
- export * from "./mcp-server/exceptions";
1
+ export * from "./mcp-client";
2
+ export * from "./mcp-server";
package/dist/index.js CHANGED
@@ -14,11 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./mcp-server/mcp.module"), exports);
18
- __exportStar(require("./mcp-server/decorators/mcp-tool.decorator"), exports);
19
- __exportStar(require("./mcp-server/decorators/mcp-prompt.decorator"), exports);
20
- __exportStar(require("./mcp-server/decorators/mcp-resource.decorator"), exports);
21
- __exportStar(require("./mcp-client/mcp-client.module"), exports);
22
- __exportStar(require("./mcp-client/mcp-client.service"), exports);
23
- __exportStar(require("./mcp-server/services/mcp-dynamic.service"), exports);
24
- __exportStar(require("./mcp-server/exceptions"), exports);
17
+ __exportStar(require("./mcp-client"), exports);
18
+ __exportStar(require("./mcp-server"), exports);
@@ -0,0 +1,3 @@
1
+ export * from "./mcp-client.module";
2
+ export * from "./mcp-client.service";
3
+ export * from "./utils/openai";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./mcp-client.module"), exports);
18
+ __exportStar(require("./mcp-client.service"), exports);
19
+ __exportStar(require("./utils/openai"), exports);
@@ -1,4 +1,4 @@
1
- import { Provider, Type } from "@nestjs/common";
1
+ import { DynamicModule, Type } from "@nestjs/common";
2
2
  export interface IMcpClientConfig {
3
3
  url: string;
4
4
  }
@@ -7,9 +7,5 @@ export declare class McpClientModule {
7
7
  useValue?: IMcpClientConfig;
8
8
  useExisting?: Type<IMcpClientConfig>;
9
9
  useFactory?: (...args: any) => IMcpClientConfig | Promise<IMcpClientConfig>;
10
- }): {
11
- module: typeof McpClientModule;
12
- implements: import("@nestjs/common").DynamicModule[];
13
- providers: Provider<IMcpClientConfig>[];
14
- };
10
+ }): DynamicModule;
15
11
  }
@@ -24,15 +24,17 @@ let McpClientModule = McpClientModule_1 = class McpClientModule {
24
24
  };
25
25
  return {
26
26
  module: McpClientModule_1,
27
- implements: [
27
+ imports: [
28
28
  axios_1.HttpModule.registerAsync({
29
- inject: [inject_tokens_1.MCP_CLIENT_CONFIG],
30
29
  useFactory: (config) => {
31
- return { baseUrl: config.url };
30
+ return { baseURL: config.url };
32
31
  },
32
+ inject: [inject_tokens_1.MCP_CLIENT_CONFIG],
33
+ extraProviders: [configProvider],
33
34
  }),
34
35
  ],
35
36
  providers: [mcp_client_service_1.McpClientService, configProvider],
37
+ exports: [mcp_client_service_1.McpClientService],
36
38
  };
37
39
  }
38
40
  };
@@ -2,11 +2,12 @@ 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
4
  import { McpPromptResultDto } from "../mcp-server/dto/McpPrompResult.dto";
5
+ import { McpToolResultDto } from "../mcp-server/dto/McpToolResult.dto";
5
6
  export declare class McpClientService {
6
7
  private readonly httpService;
7
8
  constructor(httpService: HttpService);
8
9
  getAllTools(): Promise<McpToolsDto>;
9
10
  getAllPrompts(): Promise<McpPromptsDto>;
10
11
  getPromptByName<Payload = any>(promptName: string, params: Payload): Promise<McpPromptResultDto>;
11
- callMcpTool<Payload = any, Result = any>(toolName: string, payload: Payload): Promise<Result>;
12
+ callMcpTool<Payload = any, Result = any>(toolName: string, payload: Payload): Promise<McpToolResultDto<Result>>;
12
13
  }
@@ -0,0 +1,34 @@
1
+ import { McpToolDto } from "../../mcp-server/dto/McpTool.dto";
2
+ type OpenAiCall = {
3
+ function: {
4
+ name: string;
5
+ arguments: string;
6
+ };
7
+ };
8
+ export declare class McpOpenAiHelper {
9
+ static convertTools(tools: McpToolDto[]): {
10
+ type: "function";
11
+ function: {
12
+ name: string;
13
+ description: string | undefined;
14
+ parameters: any;
15
+ };
16
+ }[];
17
+ static convertTool(tool: McpToolDto): {
18
+ type: "function";
19
+ function: {
20
+ name: string;
21
+ description: string | undefined;
22
+ parameters: any;
23
+ };
24
+ };
25
+ static convertToolCalls(toolCalls: OpenAiCall[]): {
26
+ name: string;
27
+ payload: any;
28
+ }[];
29
+ static convertToolCall({ function: { name, arguments: args }, }: OpenAiCall): {
30
+ name: string;
31
+ payload: any;
32
+ };
33
+ }
34
+ export {};
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpOpenAiHelper = void 0;
4
+ class McpOpenAiHelper {
5
+ static convertTools(tools) {
6
+ return tools.map((tool) => McpOpenAiHelper.convertTool(tool));
7
+ }
8
+ static convertTool(tool) {
9
+ return {
10
+ type: "function",
11
+ function: {
12
+ name: tool.name,
13
+ description: tool.description,
14
+ parameters: tool.inputSchema,
15
+ },
16
+ };
17
+ }
18
+ static convertToolCalls(toolCalls) {
19
+ return toolCalls.map((toolCall) => McpOpenAiHelper.convertToolCall(toolCall));
20
+ }
21
+ static convertToolCall({ function: { name, arguments: args }, }) {
22
+ const argsJson = JSON.parse(args || "{}");
23
+ return {
24
+ name,
25
+ payload: argsJson,
26
+ };
27
+ }
28
+ }
29
+ exports.McpOpenAiHelper = McpOpenAiHelper;
@@ -3,6 +3,11 @@ export declare const MCP_CONFIG_TOKEN = "mcl:config-token";
3
3
  export type IMcpConfig = {
4
4
  name?: string;
5
5
  version?: string;
6
+ description?: string;
7
+ title?: string;
8
+ icons?: {
9
+ src: string;
10
+ }[];
6
11
  httpAdapter: IHttpAdapter;
7
12
  };
8
13
  export declare const InjectMcpConfig: () => PropertyDecorator & ParameterDecorator;
@@ -6,7 +6,7 @@ import { McpPromptsDto } from "../dto/McpPrompts.dto";
6
6
  import { McpPromptResultDto } from "../dto/McpPrompResult.dto";
7
7
  import { IMcpConfig } from "../config";
8
8
  import { McpResourcesDto } from "../dto/McpResources.dto";
9
- import { McpResourceItemsDto } from "../dto/McpResourceItems.dto";
9
+ import { McpResourceResultDto } from "../dto/McpResourceResult.dto";
10
10
  import { McpResourceRequestDto } from "../dto/McpResourceRequest.dto";
11
11
  import { McpToolResultDto } from "../dto/McpToolResult.dto";
12
12
  export declare class McpController {
@@ -19,6 +19,6 @@ export declare class McpController {
19
19
  getPrompts(context: ExecutionContext): Promise<McpPromptsDto>;
20
20
  getPrompt(name: string, body: object, context: ExecutionContext): Promise<McpPromptResultDto>;
21
21
  getResources(context: ExecutionContext): Promise<McpResourcesDto>;
22
- executeResource(name: string, body: McpResourceRequestDto, context: ExecutionContext): Promise<McpResourceItemsDto>;
22
+ executeResource(name: string, body: McpResourceRequestDto, context: ExecutionContext): Promise<McpResourceResultDto>;
23
23
  private checkGuard;
24
24
  }
@@ -25,7 +25,7 @@ const inject_tokens_1 = require("../utils/inject-tokens");
25
25
  const config_1 = require("../config");
26
26
  const rxjs_1 = require("rxjs");
27
27
  const McpResources_dto_1 = require("../dto/McpResources.dto");
28
- const McpResourceItems_dto_1 = require("../dto/McpResourceItems.dto");
28
+ const McpResourceResult_dto_1 = require("../dto/McpResourceResult.dto");
29
29
  const McpResourceRequest_dto_1 = require("../dto/McpResourceRequest.dto");
30
30
  const uri_1 = require("../utils/uri");
31
31
  const McpToolResult_dto_1 = require("../dto/McpToolResult.dto");
@@ -73,8 +73,8 @@ let McpController = class McpController {
73
73
  ? (0, uri_1.extractResourceParams)(resource.instance.uri, body.uri)
74
74
  : {};
75
75
  const observable = await this.service.executeResource(name, url, params, context);
76
- const contents = await (0, rxjs_1.firstValueFrom)(observable);
77
- return { contents };
76
+ const result = await (0, rxjs_1.firstValueFrom)(observable);
77
+ return result;
78
78
  }
79
79
  async checkGuard(context) {
80
80
  if (!(await this.guard.canActivate(context))) {
@@ -203,7 +203,7 @@ __decorate([
203
203
  (0, swagger_1.ApiResponse)({
204
204
  status: 200,
205
205
  description: "Resource template result",
206
- type: McpResourceItems_dto_1.McpResourceItemsDto,
206
+ type: McpResourceResult_dto_1.McpResourceResultDto,
207
207
  }),
208
208
  (0, swagger_1.ApiNotFoundResponse)({
209
209
  description: "Not found resource template",
@@ -219,6 +219,7 @@ __decorate([
219
219
  __metadata("design:returntype", Promise)
220
220
  ], McpController.prototype, "executeResource", null);
221
221
  exports.McpController = McpController = __decorate([
222
+ (0, swagger_1.ApiTags)("MCP server"),
222
223
  (0, common_1.Controller)("mcp"),
223
224
  __param(1, (0, common_1.Inject)(inject_tokens_1.MCP_GUARD)),
224
225
  __param(2, (0, config_1.InjectMcpConfig)()),
@@ -72,6 +72,7 @@ __decorate([
72
72
  __metadata("design:returntype", Promise)
73
73
  ], McpSseController.prototype, "handleSseMessages", null);
74
74
  exports.McpSseController = McpSseController = __decorate([
75
+ (0, swagger_1.ApiTags)("MCP server"),
75
76
  (0, common_1.Controller)("mcp"),
76
77
  __param(1, (0, common_1.Inject)(inject_tokens_1.MCP_GUARD)),
77
78
  __param(2, (0, config_1.InjectMcpConfig)()),
@@ -1,10 +1,13 @@
1
- import { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol";
2
- import { Resource, ServerNotification, ServerRequest } from "@modelcontextprotocol/sdk/types";
1
+ import { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
2
+ import { Resource, ServerNotification, ServerRequest } from "@modelcontextprotocol/sdk/types.js";
3
3
  import "reflect-metadata";
4
- export type IMcpResourceResult = {
4
+ export type IMcpResourceResultItem = {
5
5
  uri: string;
6
6
  text: string;
7
7
  };
8
+ export type IMcpResourceResult = {
9
+ contents: IMcpResourceResultItem[];
10
+ };
8
11
  export type IMcpResourceListItem = {
9
12
  name: string;
10
13
  uri: string;
@@ -18,7 +21,7 @@ export interface IMcpResource<Payload = any> {
18
21
  description?: string;
19
22
  annotations?: Resource["annotations"];
20
23
  _meta?: Resource["_meta"];
21
- execute(url: URL, input: Payload): Promise<IMcpResourceResult[]>;
24
+ execute(url: URL, input: Payload): Promise<IMcpResourceResult>;
22
25
  list?(extra: RequestHandlerExtra<ServerRequest, ServerNotification>): Promise<IMcpResourceListItem[]>;
23
26
  }
24
27
  export declare const MCP_RESOURCE_METADATA = "mcp:resource-class";
@@ -1,4 +1,4 @@
1
- import { ToolAnnotations } from "@modelcontextprotocol/sdk/types";
1
+ import { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
2
2
  import "reflect-metadata";
3
3
  import type * as z3 from "zod/v3";
4
4
  type AnySchema = z3.ZodTypeAny;
@@ -0,0 +1,4 @@
1
+ import { McpResourceItemDto } from "./McpResourceItem.dto";
2
+ export declare class McpResourceItemsDto {
3
+ contents: McpResourceItemDto[];
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.McpResourceItemsDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ const McpResourceItem_dto_1 = require("./McpResourceItem.dto");
15
+ class McpResourceItemsDto {
16
+ contents;
17
+ }
18
+ exports.McpResourceItemsDto = McpResourceItemsDto;
19
+ __decorate([
20
+ (0, swagger_1.ApiProperty)({
21
+ type: McpResourceItem_dto_1.McpResourceItemDto,
22
+ isArray: true,
23
+ description: "Resource result list",
24
+ }),
25
+ __metadata("design:type", Array)
26
+ ], McpResourceItemsDto.prototype, "contents", void 0);
@@ -0,0 +1,4 @@
1
+ import { McpResourceResultItemDto } from "./McpResourceResultItem.dto";
2
+ export declare class McpResourceResultDto {
3
+ contents: McpResourceResultItemDto[];
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.McpResourceResultDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ const McpResourceResultItem_dto_1 = require("./McpResourceResultItem.dto");
15
+ class McpResourceResultDto {
16
+ contents;
17
+ }
18
+ exports.McpResourceResultDto = McpResourceResultDto;
19
+ __decorate([
20
+ (0, swagger_1.ApiProperty)({
21
+ type: McpResourceResultItem_dto_1.McpResourceResultItemDto,
22
+ isArray: true,
23
+ description: "Resource result list",
24
+ }),
25
+ __metadata("design:type", Array)
26
+ ], McpResourceResultDto.prototype, "contents", void 0);
@@ -0,0 +1,4 @@
1
+ export declare class McpResourceResultItemDto {
2
+ uri: string;
3
+ text: string;
4
+ }
@@ -0,0 +1,30 @@
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.McpResourceResultItemDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ class McpResourceResultItemDto {
15
+ uri;
16
+ text;
17
+ }
18
+ exports.McpResourceResultItemDto = McpResourceResultItemDto;
19
+ __decorate([
20
+ (0, swagger_1.ApiProperty)({ type: "string", description: "Resource uri" }),
21
+ __metadata("design:type", String)
22
+ ], McpResourceResultItemDto.prototype, "uri", void 0);
23
+ __decorate([
24
+ (0, swagger_1.ApiProperty)({
25
+ type: "string",
26
+ description: "Resource text",
27
+ nullable: true,
28
+ }),
29
+ __metadata("design:type", String)
30
+ ], McpResourceResultItemDto.prototype, "text", void 0);
@@ -1,6 +1,6 @@
1
1
  import { McpToolResultMessageDto } from "./McpToolResultMessage.dto";
2
- export declare class McpToolResultDto {
3
- structuredContent?: any;
2
+ export declare class McpToolResultDto<Result = any> {
3
+ structuredContent?: Result;
4
4
  messages: McpToolResultMessageDto[];
5
5
  isError?: boolean;
6
6
  }
@@ -1,4 +1,4 @@
1
1
  export declare class McpToolResultMessageDto {
2
- type: string;
2
+ type: "text";
3
3
  text: string;
4
4
  }
@@ -0,0 +1,6 @@
1
+ export * from "./mcp.module";
2
+ export * from "./decorators/mcp-tool.decorator";
3
+ export * from "./decorators/mcp-prompt.decorator";
4
+ export * from "./decorators/mcp-resource.decorator";
5
+ export * from "./services/mcp-dynamic.service";
6
+ export * from "./exceptions";
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./mcp.module"), exports);
18
+ __exportStar(require("./decorators/mcp-tool.decorator"), exports);
19
+ __exportStar(require("./decorators/mcp-prompt.decorator"), exports);
20
+ __exportStar(require("./decorators/mcp-resource.decorator"), exports);
21
+ __exportStar(require("./services/mcp-dynamic.service"), exports);
22
+ __exportStar(require("./exceptions"), exports);
@@ -1,10 +1,22 @@
1
1
  import { CanActivate, DynamicModule, ModuleMetadata, Provider } from "@nestjs/common";
2
2
  import { IHttpAdapter } from "./utils/http-adapter";
3
3
  type Metadata = Pick<ModuleMetadata, "providers" | "imports" | "exports"> & {
4
- guard?: Provider<CanActivate>;
5
4
  name?: string;
5
+ description?: string;
6
+ title?: string;
7
+ icons?: {
8
+ src: string;
9
+ }[];
6
10
  version?: string;
11
+ /**
12
+ * @default { sse: true, http: true }
13
+ */
14
+ transports?: {
15
+ sse?: boolean;
16
+ http?: boolean;
17
+ };
7
18
  httpAdapter?: IHttpAdapter;
19
+ guard?: Provider<CanActivate>;
8
20
  };
9
21
  export declare class McpModule {
10
22
  static forRoot(metadata?: Metadata): DynamicModule;
@@ -22,11 +22,16 @@ const mcp_sse_service_1 = require("./services/mcp.sse.service");
22
22
  const publicGuard = { canActivate: () => Promise.resolve(true) };
23
23
  let McpModule = McpModule_1 = class McpModule {
24
24
  static forRoot(metadata = {}) {
25
+ // TODO remove defaut in next major version
26
+ const transports = metadata.transports || { sse: true, http: true };
25
27
  const configProviver = {
26
28
  provide: config_1.MCP_CONFIG_TOKEN,
27
29
  useValue: {
28
30
  name: metadata.name,
29
31
  version: metadata.version,
32
+ description: metadata.description,
33
+ title: metadata.title,
34
+ icons: metadata.icons,
30
35
  httpAdapter: metadata.httpAdapter || http_adapter_1.DEFAULT_FASTIFY_ADAPTER,
31
36
  },
32
37
  };
@@ -41,7 +46,7 @@ let McpModule = McpModule_1 = class McpModule {
41
46
  imports: [core_1.DiscoveryModule, ...(metadata.imports || [])],
42
47
  providers: [
43
48
  mcp_service_1.McpService,
44
- mcp_sse_service_1.McpSseService,
49
+ ...(transports.sse ? [mcp_sse_service_1.McpSseService] : []),
45
50
  mcp_explorer_1.McpExplorer,
46
51
  mcp_dynamic_service_1.McpDynamicService,
47
52
  configProviver,
@@ -50,7 +55,10 @@ let McpModule = McpModule_1 = class McpModule {
50
55
  ...(metadata.providers || []),
51
56
  ],
52
57
  exports: [mcp_dynamic_service_1.McpDynamicService, ...(metadata.exports || [])],
53
- controllers: [mcp_controller_1.McpController, mcp_sse_controller_1.McpSseController],
58
+ controllers: [
59
+ ...(transports.http ? [mcp_controller_1.McpController] : []),
60
+ ...(transports.sse ? [mcp_sse_controller_1.McpSseController] : []),
61
+ ],
54
62
  };
55
63
  }
56
64
  };
@@ -1,4 +1,4 @@
1
- import { CanActivate, NestInterceptor, Type } from "@nestjs/common";
1
+ import { CanActivate, ExceptionFilter, NestInterceptor, Type } from "@nestjs/common";
2
2
  import { ModuleRef } from "@nestjs/core";
3
3
  import { McpService } from "../services/mcp.service";
4
4
  import { IMcpTool } from "../decorators/mcp-tool.decorator";
@@ -7,14 +7,17 @@ import { IMcpPrompt } from "../decorators/mcp-prompt.decorator";
7
7
  export type IMcpDynamicTool<Input, Result extends Record<string, unknown>> = IMcpTool<Input, Result> & {
8
8
  guards?: Type<CanActivate>[];
9
9
  interceptors?: Type<NestInterceptor>[];
10
+ filters?: Type<ExceptionFilter>[];
10
11
  };
11
12
  export type IMcpDynamicPrompt<Input> = IMcpPrompt<Input> & {
12
13
  guards?: Type<CanActivate>[];
13
14
  interceptors?: Type<NestInterceptor>[];
15
+ filters?: Type<ExceptionFilter>[];
14
16
  };
15
17
  export type IMcpDynamicResource<Input> = IMcpResource<Input> & {
16
18
  guards?: Type<CanActivate>[];
17
19
  interceptors?: Type<NestInterceptor>[];
20
+ filters?: Type<ExceptionFilter>[];
18
21
  };
19
22
  export declare class McpDynamicService {
20
23
  private readonly moduleRef;
@@ -28,4 +31,5 @@ export declare class McpDynamicService {
28
31
  registerResource<Input>(resource: IMcpDynamicResource<Input>): Promise<void>;
29
32
  protected applyGuards(item: Function, guards: Type<CanActivate>[]): void;
30
33
  protected applyInterceptors(item: Function, interceptors: Type<NestInterceptor>[]): void;
34
+ protected applyFilters(item: Function, filters: Type<ExceptionFilter>[]): void;
31
35
  }
@@ -39,6 +39,9 @@ let McpDynamicService = class McpDynamicService {
39
39
  if (tool.interceptors) {
40
40
  this.applyInterceptors(DynamicToolClass, tool.interceptors);
41
41
  }
42
+ if (tool.filters) {
43
+ this.applyFilters(DynamicToolClass, tool.filters);
44
+ }
42
45
  const instance = await this.moduleRef.create(DynamicToolClass);
43
46
  this.mcpService.registerTool(instance.name, {
44
47
  instance,
@@ -60,6 +63,9 @@ let McpDynamicService = class McpDynamicService {
60
63
  if (prompt.interceptors) {
61
64
  this.applyInterceptors(DynamicPromptClass, prompt.interceptors);
62
65
  }
66
+ if (prompt.filters) {
67
+ this.applyFilters(DynamicPromptClass, prompt.filters);
68
+ }
63
69
  const instance = await this.moduleRef.create(DynamicPromptClass);
64
70
  this.mcpService.registerPrompt(instance.name, {
65
71
  instance,
@@ -84,6 +90,9 @@ let McpDynamicService = class McpDynamicService {
84
90
  if (resource.interceptors) {
85
91
  this.applyInterceptors(DynamicResourceClass, resource.interceptors);
86
92
  }
93
+ if (resource.filters) {
94
+ this.applyFilters(DynamicResourceClass, resource.filters);
95
+ }
87
96
  const instance = await this.moduleRef.create(DynamicResourceClass);
88
97
  this.mcpService.registerResource(instance.name, {
89
98
  instance,
@@ -96,6 +105,9 @@ let McpDynamicService = class McpDynamicService {
96
105
  applyInterceptors(item, interceptors) {
97
106
  Reflect.defineMetadata(constants_1.INTERCEPTORS_METADATA, interceptors, item);
98
107
  }
108
+ applyFilters(item, filters) {
109
+ Reflect.defineMetadata(constants_1.EXCEPTION_FILTERS_METADATA, filters, item);
110
+ }
99
111
  };
100
112
  exports.McpDynamicService = McpDynamicService;
101
113
  exports.McpDynamicService = McpDynamicService = __decorate([
@@ -74,5 +74,5 @@ export declare class McpService implements OnModuleInit {
74
74
  type: string;
75
75
  payload: any;
76
76
  }, context: ExecutionContext): Promise<Observable<IMcpToolResult<Record<string, unknown>>>>;
77
- executeResource(name: string, uri: URL, vars: Record<string, any>, context: ExecutionContext): Promise<Observable<IMcpResourceResult[]>>;
77
+ executeResource(name: string, uri: URL, vars: Record<string, any>, context: ExecutionContext): Promise<Observable<IMcpResourceResult>>;
78
78
  }
@@ -11,10 +11,13 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
14
17
  Object.defineProperty(exports, "__esModule", { value: true });
15
18
  exports.McpService = void 0;
16
19
  const common_1 = require("@nestjs/common");
17
- const ajv_1 = require("ajv");
20
+ const ajv_1 = __importDefault(require("ajv"));
18
21
  const zod_1 = require("../utils/zod");
19
22
  const run_guards_1 = require("../utils/run-guards");
20
23
  const core_1 = require("@nestjs/core");
@@ -63,7 +63,22 @@ let McpSseService = class McpSseService {
63
63
  const server = new mcp_js_1.McpServer({
64
64
  version: this.config.version || "1",
65
65
  name: this.config.name || "MCP server",
66
- }, {});
66
+ description: this.config.description,
67
+ title: this.config.title,
68
+ icons: this.config.icons,
69
+ }, {
70
+ capabilities: {
71
+ prompts: {
72
+ listChanged: true,
73
+ },
74
+ tools: {
75
+ listChanged: true,
76
+ },
77
+ resources: {
78
+ listChanged: true,
79
+ },
80
+ },
81
+ });
67
82
  this.registerTools(server, context);
68
83
  this.registerPrompts(server, context);
69
84
  this.registerResources(server, context);
@@ -150,7 +165,7 @@ let McpSseService = class McpSseService {
150
165
  // const resources = await resource.execute(url, variables);
151
166
  const observable = await this.service.executeResource(resource.name, url, variables, context);
152
167
  const result = await (0, rxjs_1.firstValueFrom)(observable);
153
- return { contents: result };
168
+ return result;
154
169
  }
155
170
  catch (e) {
156
171
  throw new exceptions_1.McpInternalServerErrorException(`Faild to execute tool ${prompt.name}`, {
@@ -1,4 +1,4 @@
1
- import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types";
1
+ import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
2
2
  import { IncomingMessage, ServerResponse } from "http";
3
3
  export type IRequest = {
4
4
  original: IncomingMessage & {
@@ -0,0 +1,34 @@
1
+ import { McpToolDto } from "../dto/McpTool.dto";
2
+ type OpenAiCall = {
3
+ function: {
4
+ name: string;
5
+ arguments: string;
6
+ };
7
+ };
8
+ export declare class McpOpenAiHelper {
9
+ static convertTools(tools: McpToolDto[]): {
10
+ type: "function";
11
+ function: {
12
+ name: string;
13
+ description: string | undefined;
14
+ parameters: any;
15
+ };
16
+ }[];
17
+ static convertTool(tool: McpToolDto): {
18
+ type: "function";
19
+ function: {
20
+ name: string;
21
+ description: string | undefined;
22
+ parameters: any;
23
+ };
24
+ };
25
+ static convertToolCalls(toolCalls: OpenAiCall[]): {
26
+ name: string;
27
+ payload: any;
28
+ }[];
29
+ static convertToolCall({ function: { name, arguments: args }, }: OpenAiCall): {
30
+ name: string;
31
+ payload: any;
32
+ };
33
+ }
34
+ export {};
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpOpenAiHelper = void 0;
4
+ class McpOpenAiHelper {
5
+ static convertTools(tools) {
6
+ return tools.map((tool) => McpOpenAiHelper.convertTool(tool));
7
+ }
8
+ static convertTool(tool) {
9
+ return {
10
+ type: "function",
11
+ function: {
12
+ name: tool.name,
13
+ description: tool.description,
14
+ parameters: tool.inputSchema,
15
+ },
16
+ };
17
+ }
18
+ static convertToolCalls(toolCalls) {
19
+ return toolCalls.map((toolCall) => McpOpenAiHelper.convertToolCall(toolCall));
20
+ }
21
+ static convertToolCall({ function: { name, arguments: args }, }) {
22
+ const argsJson = JSON.parse(args || "{}");
23
+ return {
24
+ name,
25
+ payload: argsJson,
26
+ };
27
+ }
28
+ }
29
+ exports.McpOpenAiHelper = McpOpenAiHelper;
@@ -22,8 +22,11 @@ async function runFilters(moduleRef, metatype, exception, host) {
22
22
  const filters = Reflect.getMetadata(constants_1.EXCEPTION_FILTERS_METADATA, metatype) || [];
23
23
  for (const Filter of filters) {
24
24
  const filterInstance = await resolveFilter(Filter);
25
- const filterExceptions = (Reflect.getMetadata(constants_1.FILTER_CATCH_EXCEPTIONS, Filter) || []);
26
- if (!filterExceptions ||
25
+ const filterExceptions = (Reflect.getMetadata(constants_1.FILTER_CATCH_EXCEPTIONS, Filter));
26
+ if (!filterExceptions) {
27
+ continue;
28
+ }
29
+ if (filterExceptions.length > 0 &&
27
30
  !filterExceptions.some((ex) => exception instanceof ex)) {
28
31
  continue;
29
32
  }
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.zodToJsonSchema = zodToJsonSchema;
4
7
  const v3_1 = require("zod/v3");
5
8
  const v4_1 = require("zod/v4");
6
- const zod_to_json_schema_1 = require("zod-to-json-schema");
9
+ const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema"));
7
10
  // Функция преобразования Zod в JSON Schema
8
11
  function zodToJsonSchema(schema, deep = 0) {
9
12
  if (schema && deep === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muzikanto/nestjs-mcp",
3
- "version": "1.7.0",
3
+ "version": "1.7.3",
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",
@@ -13,6 +13,23 @@
13
13
  ],
14
14
  "main": "dist/index.js",
15
15
  "types": "dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "require": "./dist/index.js",
20
+ "types": "./dist/index.d.ts"
21
+ },
22
+ "./client": {
23
+ "import": "./dist/mcp-client/index.js",
24
+ "require": "./dist/mcp-client/index.js",
25
+ "types": "./dist/mcp-client/index.d.ts"
26
+ },
27
+ "./server": {
28
+ "import": "./dist/mcp-server/index.js",
29
+ "require": "./dist/mcp-server/index.js",
30
+ "types": "./dist/mcp-server/index.d.ts"
31
+ }
32
+ },
16
33
  "files": [
17
34
  "dist"
18
35
  ],