@muzikanto/nestjs-mcp 1.1.0 → 1.1.1

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @muzikanto/nestjs-mcp
2
2
 
3
+ ## 1.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - add guard authorization check
8
+
3
9
  ## 1.1.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -18,6 +18,9 @@ NestJS MCP (Model Context Protocol) module — allows you to create “tools”
18
18
  - [Create MCP prompt](#create-mcp-prompt)
19
19
  - [Calling MCP tools via HTTP](#calling-mcp-tools-via-http)
20
20
  - [Obtaining all tools](#obtaining-all-tools)
21
+ - [Obtaining all prompts](#obtaining-all-prompts)
22
+ - [Obtain prompt](#obtain-prompt)
23
+ - [Auth guard](#auth-guard)
21
24
  - [Integration with OpenAI Function Calls](#integration-with-openai-function-calls)
22
25
 
23
26
  ## Features
@@ -231,6 +234,31 @@ Response
231
234
  }
232
235
  ```
233
236
 
237
+ ### Auth guard
238
+ ```ts
239
+ import { McpModule } from '@muzikanto/nestjs-mcp';
240
+ import { Module, CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
241
+
242
+ @Injectable()
243
+ export class TestGuard implements CanActivate {
244
+ canActivate(context: ExecutionContext): Promise<boolean> {
245
+ const request = context.switchToHttp().getRequest();
246
+ const authHeader = request.headers['authorization'];
247
+
248
+ return true;
249
+ }
250
+ }
251
+
252
+ @Module({
253
+ imports: [
254
+ McpModule.forRoot({
255
+ guard: TestGuard
256
+ }),
257
+ ],
258
+ })
259
+ export class AppModule {}
260
+ ```
261
+
234
262
  ### Integration with OpenAI Function Calls
235
263
 
236
264
  ```ts
@@ -1,9 +1,12 @@
1
1
  import "reflect-metadata";
2
+ export type IMcpToolContext = {
3
+ request: any;
4
+ };
2
5
  export interface IMcpTool<Payload = any, Result = any> {
3
6
  name: string;
4
7
  description?: string;
5
8
  inputSchema?: object | object[];
6
- execute(input: Payload): Promise<Result>;
9
+ execute(input: Payload, context: IMcpToolContext): Promise<Result>;
7
10
  }
8
11
  export declare const MCP_TOOL_METADATA = "mcp:tool-class";
9
12
  /**
@@ -17,10 +17,10 @@ class McpMessageDto {
17
17
  }
18
18
  exports.McpMessageDto = McpMessageDto;
19
19
  __decorate([
20
- (0, swagger_1.ApiProperty)({ type: 'string', description: 'Tool name' }),
20
+ (0, swagger_1.ApiProperty)({ type: "string", description: "Tool name" }),
21
21
  __metadata("design:type", String)
22
22
  ], McpMessageDto.prototype, "type", void 0);
23
23
  __decorate([
24
- (0, swagger_1.ApiProperty)({ description: 'Tool handler payload' }),
24
+ (0, swagger_1.ApiProperty)({ description: "Tool handler payload" }),
25
25
  __metadata("design:type", Object)
26
26
  ], McpMessageDto.prototype, "payload", void 0);
@@ -17,10 +17,14 @@ class McpPromptDto {
17
17
  }
18
18
  exports.McpPromptDto = McpPromptDto;
19
19
  __decorate([
20
- (0, swagger_1.ApiProperty)({ type: 'string', description: 'Propmt name' }),
20
+ (0, swagger_1.ApiProperty)({ type: "string", description: "Propmt name" }),
21
21
  __metadata("design:type", String)
22
22
  ], McpPromptDto.prototype, "name", void 0);
23
23
  __decorate([
24
- (0, swagger_1.ApiProperty)({ type: 'string', description: 'Propmt description', nullable: true }),
24
+ (0, swagger_1.ApiProperty)({
25
+ type: "string",
26
+ description: "Propmt description",
27
+ nullable: true,
28
+ }),
25
29
  __metadata("design:type", String)
26
30
  ], McpPromptDto.prototype, "description", void 0);
@@ -18,14 +18,23 @@ class McpPromptMessageDto {
18
18
  }
19
19
  exports.McpPromptMessageDto = McpPromptMessageDto;
20
20
  __decorate([
21
- (0, swagger_1.ApiProperty)({ type: 'string', description: 'AI role' }),
21
+ (0, swagger_1.ApiProperty)({ type: "string", description: "AI role" }),
22
22
  __metadata("design:type", String)
23
23
  ], McpPromptMessageDto.prototype, "role", void 0);
24
24
  __decorate([
25
- (0, swagger_1.ApiProperty)({ type: 'string', description: 'Request ai message', nullable: true }),
25
+ (0, swagger_1.ApiProperty)({
26
+ type: "string",
27
+ description: "Request ai message",
28
+ nullable: true,
29
+ }),
26
30
  __metadata("design:type", String)
27
31
  ], McpPromptMessageDto.prototype, "content", void 0);
28
32
  __decorate([
29
- (0, swagger_1.ApiProperty)({ type: 'object', description: 'Tool call context', nullable: true, additionalProperties: false }),
33
+ (0, swagger_1.ApiProperty)({
34
+ type: "object",
35
+ description: "Tool call context",
36
+ nullable: true,
37
+ additionalProperties: false,
38
+ }),
30
39
  __metadata("design:type", Object)
31
40
  ], McpPromptMessageDto.prototype, "tool_call", void 0);
@@ -17,6 +17,10 @@ class McpPromptMessagesDto {
17
17
  }
18
18
  exports.McpPromptMessagesDto = McpPromptMessagesDto;
19
19
  __decorate([
20
- (0, swagger_1.ApiProperty)({ type: McpPromptMessage_1.McpPromptMessageDto, isArray: true, description: 'Messages list' }),
20
+ (0, swagger_1.ApiProperty)({
21
+ type: McpPromptMessage_1.McpPromptMessageDto,
22
+ isArray: true,
23
+ description: "Messages list",
24
+ }),
21
25
  __metadata("design:type", Array)
22
26
  ], McpPromptMessagesDto.prototype, "messages", void 0);
@@ -17,6 +17,10 @@ class McpPromptsDto {
17
17
  }
18
18
  exports.McpPromptsDto = McpPromptsDto;
19
19
  __decorate([
20
- (0, swagger_1.ApiProperty)({ type: McpPrompt_dto_1.McpPromptDto, isArray: true, description: 'Prompts list' }),
20
+ (0, swagger_1.ApiProperty)({
21
+ type: McpPrompt_dto_1.McpPromptDto,
22
+ isArray: true,
23
+ description: "Prompts list",
24
+ }),
21
25
  __metadata("design:type", Array)
22
26
  ], McpPromptsDto.prototype, "prompts", void 0);
@@ -18,14 +18,23 @@ class McpToolDto {
18
18
  }
19
19
  exports.McpToolDto = McpToolDto;
20
20
  __decorate([
21
- (0, swagger_1.ApiProperty)({ type: 'string', description: 'Tool name' }),
21
+ (0, swagger_1.ApiProperty)({ type: "string", description: "Tool name" }),
22
22
  __metadata("design:type", String)
23
23
  ], McpToolDto.prototype, "name", void 0);
24
24
  __decorate([
25
- (0, swagger_1.ApiProperty)({ type: 'string', description: 'Tool description', nullable: true }),
25
+ (0, swagger_1.ApiProperty)({
26
+ type: "string",
27
+ description: "Tool description",
28
+ nullable: true,
29
+ }),
26
30
  __metadata("design:type", String)
27
31
  ], McpToolDto.prototype, "description", void 0);
28
32
  __decorate([
29
- (0, swagger_1.ApiProperty)({ type: 'object', description: 'Tool validation schema', nullable: true, additionalProperties: false }),
33
+ (0, swagger_1.ApiProperty)({
34
+ type: "object",
35
+ description: "Tool validation schema",
36
+ nullable: true,
37
+ additionalProperties: false,
38
+ }),
30
39
  __metadata("design:type", Object)
31
40
  ], McpToolDto.prototype, "parameters", void 0);
@@ -17,6 +17,6 @@ class McpToolsDto {
17
17
  }
18
18
  exports.McpToolsDto = McpToolsDto;
19
19
  __decorate([
20
- (0, swagger_1.ApiProperty)({ type: McpTool_dto_1.McpToolDto, isArray: true, description: 'Tools list' }),
20
+ (0, swagger_1.ApiProperty)({ type: McpTool_dto_1.McpToolDto, isArray: true, description: "Tools list" }),
21
21
  __metadata("design:type", Array)
22
22
  ], McpToolsDto.prototype, "tools", void 0);
@@ -1,3 +1,4 @@
1
+ import { ExecutionContext, CanActivate } from "@nestjs/common";
1
2
  import { McpService } from "./mcp.service";
2
3
  import { McpMessageDto } from "./dto/McpMessage.dto";
3
4
  import { McpToolsDto } from "./dto/McpTools.dto";
@@ -5,8 +6,9 @@ import { McpPromptsDto } from "./dto/McpPrompts.dto";
5
6
  import { McpPromptMessagesDto } from "./dto/McpPromptMessages.dto";
6
7
  export declare class McpController {
7
8
  private readonly service;
8
- constructor(service: McpService);
9
- handle(body: McpMessageDto): Promise<{
9
+ private readonly guard;
10
+ constructor(service: McpService, guard: CanActivate);
11
+ handle(body: McpMessageDto, request: any, context: ExecutionContext): Promise<{
10
12
  success: boolean;
11
13
  data: any;
12
14
  error?: undefined;
@@ -15,7 +17,8 @@ export declare class McpController {
15
17
  error: any;
16
18
  data?: undefined;
17
19
  }>;
18
- getTools(): Promise<McpToolsDto>;
19
- getPrompts(): Promise<McpPromptsDto>;
20
- getPrompt(name: string, body: object): Promise<McpPromptMessagesDto>;
20
+ getTools(context: ExecutionContext): Promise<McpToolsDto>;
21
+ getPrompts(context: ExecutionContext): Promise<McpPromptsDto>;
22
+ getPrompt(name: string, body: object, context: ExecutionContext): Promise<McpPromptMessagesDto>;
23
+ private checkGuard;
21
24
  }
@@ -20,103 +20,134 @@ 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
22
  const McpPromptMessages_dto_1 = require("./dto/McpPromptMessages.dto");
23
+ const context_decorator_1 = require("./utils/context.decorator");
24
+ const inject_tokens_1 = require("./utils/inject-tokens");
23
25
  let McpController = class McpController {
24
26
  service;
25
- constructor(service) {
27
+ guard;
28
+ constructor(service, guard) {
26
29
  this.service = service;
30
+ this.guard = guard;
27
31
  }
28
- async handle(body) {
29
- return this.service.sendMessage(body);
32
+ async handle(body, request, context) {
33
+ await this.checkGuard(context);
34
+ return this.service.sendMessage(body, { request });
30
35
  }
31
- async getTools() {
36
+ async getTools(context) {
37
+ await this.checkGuard(context);
32
38
  const tools = this.service.listTools();
33
39
  return { tools };
34
40
  }
35
- async getPrompts() {
41
+ async getPrompts(context) {
42
+ await this.checkGuard(context);
36
43
  const prompts = this.service.listPrompts();
37
44
  return { prompts };
38
45
  }
39
- async getPrompt(name, body) {
46
+ async getPrompt(name, body, context) {
47
+ await this.checkGuard(context);
40
48
  const messages = await this.service.getPrompt(name, body);
41
49
  return {
42
50
  messages,
43
51
  };
44
52
  }
53
+ async checkGuard(context) {
54
+ if (!(await this.guard.canActivate(context))) {
55
+ throw new common_1.ForbiddenException();
56
+ }
57
+ }
45
58
  };
46
59
  exports.McpController = McpController;
47
60
  __decorate([
48
61
  (0, common_1.Post)(),
49
62
  (0, common_1.Header)("Content-Type", "application/json"),
50
63
  (0, swagger_1.ApiOperation)({
51
- summary: 'Request tool',
64
+ summary: "Request tool",
52
65
  }),
53
66
  (0, swagger_1.ApiResponse)({
54
67
  status: 200,
55
- description: 'Tool execution result',
68
+ description: "Tool execution result",
56
69
  }),
57
70
  (0, swagger_1.ApiBadRequestResponse)({
58
- description: 'Invalid request body',
71
+ description: "Invalid request body",
72
+ }),
73
+ (0, swagger_1.ApiForbiddenResponse)({
74
+ description: "No access to method",
59
75
  }),
60
76
  __param(0, (0, common_1.Body)()),
77
+ __param(1, (0, common_1.Request)()),
78
+ __param(2, (0, context_decorator_1.Context)()),
61
79
  __metadata("design:type", Function),
62
- __metadata("design:paramtypes", [McpMessage_dto_1.McpMessageDto]),
80
+ __metadata("design:paramtypes", [McpMessage_dto_1.McpMessageDto, Object, Object]),
63
81
  __metadata("design:returntype", Promise)
64
82
  ], McpController.prototype, "handle", null);
65
83
  __decorate([
66
84
  (0, common_1.Get)("tools"),
67
85
  (0, swagger_1.ApiOperation)({
68
- summary: 'Get tool list',
86
+ summary: "Get tool list",
69
87
  }),
70
88
  (0, swagger_1.ApiResponse)({
71
89
  status: 200,
72
- description: 'Tools list',
90
+ description: "Tools list",
73
91
  type: McpTools_dto_1.McpToolsDto,
74
92
  }),
93
+ (0, swagger_1.ApiForbiddenResponse)({
94
+ description: "No access to method",
95
+ }),
96
+ __param(0, (0, context_decorator_1.Context)()),
75
97
  __metadata("design:type", Function),
76
- __metadata("design:paramtypes", []),
98
+ __metadata("design:paramtypes", [Object]),
77
99
  __metadata("design:returntype", Promise)
78
100
  ], McpController.prototype, "getTools", null);
79
101
  __decorate([
80
102
  (0, common_1.Get)("prompts"),
81
103
  (0, swagger_1.ApiOperation)({
82
- summary: 'Get prompt list',
104
+ summary: "Get prompt list",
83
105
  }),
84
106
  (0, swagger_1.ApiResponse)({
85
107
  status: 200,
86
- description: 'Prompts list',
108
+ description: "Prompts list",
87
109
  type: McpPrompts_dto_1.McpPromptsDto,
88
110
  }),
111
+ (0, swagger_1.ApiForbiddenResponse)({
112
+ description: "No access to method",
113
+ }),
114
+ __param(0, (0, context_decorator_1.Context)()),
89
115
  __metadata("design:type", Function),
90
- __metadata("design:paramtypes", []),
116
+ __metadata("design:paramtypes", [Object]),
91
117
  __metadata("design:returntype", Promise)
92
118
  ], McpController.prototype, "getPrompts", null);
93
119
  __decorate([
94
120
  (0, common_1.Post)("prompts/:name"),
95
121
  (0, swagger_1.ApiOperation)({
96
- summary: 'Generate messages by prompt name',
122
+ summary: "Generate messages by prompt name",
97
123
  }),
98
124
  (0, swagger_1.ApiBody)({
99
- description: 'Any body structure',
125
+ description: "Any body structure",
100
126
  type: Object, // Указываем, что тело может быть любым объектом
101
127
  }),
102
128
  (0, swagger_1.ApiResponse)({
103
129
  status: 200,
104
- description: 'Prompt messages',
130
+ description: "Prompt messages",
105
131
  type: McpPromptMessages_dto_1.McpPromptMessagesDto,
106
132
  }),
107
133
  (0, swagger_1.ApiNotFoundResponse)({
108
- description: 'Not found prompt',
134
+ description: "Not found prompt",
109
135
  }),
110
136
  (0, swagger_1.ApiBadRequestResponse)({
111
- description: 'Invalid prompt arguments',
137
+ description: "Invalid prompt arguments",
138
+ }),
139
+ (0, swagger_1.ApiForbiddenResponse)({
140
+ description: "No access to method",
112
141
  }),
113
- __param(0, (0, common_1.Param)('name')),
142
+ __param(0, (0, common_1.Param)("name")),
114
143
  __param(1, (0, common_1.Body)()),
144
+ __param(2, (0, context_decorator_1.Context)()),
115
145
  __metadata("design:type", Function),
116
- __metadata("design:paramtypes", [String, Object]),
146
+ __metadata("design:paramtypes", [String, Object, Object]),
117
147
  __metadata("design:returntype", Promise)
118
148
  ], McpController.prototype, "getPrompt", null);
119
149
  exports.McpController = McpController = __decorate([
120
150
  (0, common_1.Controller)("mcp"),
121
- __metadata("design:paramtypes", [mcp_service_1.McpService])
151
+ __param(1, (0, common_1.Inject)(inject_tokens_1.MCP_GUARD)),
152
+ __metadata("design:paramtypes", [mcp_service_1.McpService, Object])
122
153
  ], McpController);
@@ -1,5 +1,7 @@
1
- import { DynamicModule, ModuleMetadata } from "@nestjs/common";
2
- type Metadata = Pick<ModuleMetadata, 'providers' | 'imports' | 'exports'>;
1
+ import { CanActivate, DynamicModule, ModuleMetadata, Provider } from "@nestjs/common";
2
+ type Metadata = Pick<ModuleMetadata, "providers" | "imports" | "exports"> & {
3
+ guard?: Provider<CanActivate>;
4
+ };
3
5
  export declare class McpModule {
4
6
  static forRoot(metadata?: Metadata): DynamicModule;
5
7
  }
@@ -13,13 +13,27 @@ const core_1 = require("@nestjs/core");
13
13
  const mcp_service_1 = require("./mcp.service");
14
14
  const mcp_explorer_1 = require("./mcp.explorer");
15
15
  const mcp_controller_1 = require("./mcp.controller");
16
+ const inject_tokens_1 = require("./utils/inject-tokens");
17
+ const publicGuard = { canActivate: () => Promise.resolve(true) };
16
18
  let McpModule = McpModule_1 = class McpModule {
17
19
  static forRoot(metadata = {}) {
20
+ const guardProvider = metadata.guard
21
+ ? { provide: inject_tokens_1.MCP_GUARD, useExisting: metadata.guard }
22
+ : {
23
+ provide: inject_tokens_1.MCP_GUARD,
24
+ useValue: publicGuard,
25
+ };
18
26
  return {
19
27
  module: McpModule_1,
20
28
  imports: [core_1.DiscoveryModule, ...(metadata.imports || [])],
21
- providers: [mcp_service_1.McpService, mcp_explorer_1.McpExplorer, ...(metadata.providers || [])],
22
- exports: [mcp_service_1.McpService, ...(metadata.providers || [])],
29
+ providers: [
30
+ mcp_service_1.McpService,
31
+ mcp_explorer_1.McpExplorer,
32
+ guardProvider,
33
+ ...(metadata.guard ? [metadata.guard] : []),
34
+ ...(metadata.providers || []),
35
+ ],
36
+ exports: [mcp_service_1.McpService, ...(metadata.exports || [])],
23
37
  controllers: [mcp_controller_1.McpController],
24
38
  };
25
39
  }
@@ -1,5 +1,5 @@
1
1
  import { OnModuleInit } from "@nestjs/common";
2
- import { IMcpTool } from "./decorators/mcp-tool.decorator";
2
+ import { IMcpTool, IMcpToolContext } from "./decorators/mcp-tool.decorator";
3
3
  import { IMcpPrompt } from "./decorators/mcp-prompt.decorator";
4
4
  export interface McpMessage {
5
5
  type: string;
@@ -36,7 +36,7 @@ export declare class McpService implements OnModuleInit {
36
36
  sendMessage(msg: {
37
37
  type: string;
38
38
  payload: any;
39
- }): Promise<{
39
+ }, context: IMcpToolContext): Promise<{
40
40
  success: boolean;
41
41
  data: any;
42
42
  error?: undefined;
@@ -40,7 +40,7 @@ let McpService = class McpService {
40
40
  }
41
41
  getPrompt(name, payload) {
42
42
  if (!this.prompts.has(name)) {
43
- throw new common_1.NotFoundException('Not found prompt');
43
+ throw new common_1.NotFoundException("Not found prompt");
44
44
  }
45
45
  const prompt = this.prompts.get(name);
46
46
  // Валидация через AJV, если есть inputSchema
@@ -48,7 +48,7 @@ let McpService = class McpService {
48
48
  const validate = this.ajv.compile(prompt.inputSchema);
49
49
  const valid = validate(payload);
50
50
  if (!valid) {
51
- throw new common_1.NotFoundException('Invalid prompt arguments');
51
+ throw new common_1.NotFoundException("Invalid prompt arguments");
52
52
  }
53
53
  }
54
54
  return prompt.execute(payload);
@@ -56,7 +56,7 @@ let McpService = class McpService {
56
56
  /**
57
57
  * Отправить сообщение в MCP "сервер"
58
58
  */
59
- async sendMessage(msg) {
59
+ async sendMessage(msg, context) {
60
60
  const tool = this.tools.get(msg.type);
61
61
  if (!tool) {
62
62
  return { success: false, error: `Unknown tool: "${msg.type}"` };
@@ -70,7 +70,7 @@ let McpService = class McpService {
70
70
  }
71
71
  }
72
72
  try {
73
- const result = await tool.execute(msg.payload);
73
+ const result = await tool.execute(msg.payload, context);
74
74
  return { success: true, data: result };
75
75
  }
76
76
  catch (err) {
@@ -0,0 +1 @@
1
+ export declare const Context: (...dataOrPipes: unknown[]) => ParameterDecorator;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Context = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ exports.Context = (0, common_1.createParamDecorator)((data, context) => context);
@@ -0,0 +1 @@
1
+ export declare const MCP_GUARD = "MCP:guard";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MCP_GUARD = void 0;
4
+ exports.MCP_GUARD = "MCP:guard";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muzikanto/nestjs-mcp",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
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",