@muzikanto/nestjs-mcp 1.5.0 → 1.5.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.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - custom mcp errors for filters
8
+
3
9
  ## 1.5.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -456,23 +456,23 @@ import { APP_INTERCEPTOR } from "@nestjs/core";
456
456
  export class TestModule {}
457
457
  ```
458
458
 
459
- ### Fitlers
459
+ ### Filters
460
460
 
461
461
  ```ts
462
- import { IMcpTool, McpTool } from "@muzikanto/nestjs-mcp";
462
+ import { IMcpTool, McpTool, McpUnauthorizedException } from "@muzikanto/nestjs-mcp";
463
463
  import {
464
464
  ExceptionFilter,
465
465
  Catch,
466
466
  ArgumentsHost,
467
- NotImplementedException,
468
467
  UseFilters,
469
468
  } from "@nestjs/common";
470
469
 
471
- @Catch(NotImplementedException)
470
+ @Catch(McpUnauthorizedException)
472
471
  class ExampleFilter implements ExceptionFilter {
473
472
  catch(exception: unknown, host: ArgumentsHost) {
474
473
  return {
475
- message: (exception as Error).message,
474
+ isError: true,
475
+ text: (exception as Error).message,
476
476
  };
477
477
  }
478
478
  }
package/dist/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export * from "./mcp-server/decorators/mcp-resource.decorator";
5
5
  export * from "./mcp-client/mcp-client.module";
6
6
  export * from "./mcp-client/mcp-client.service";
7
7
  export * from "./mcp-server/mcp-dynamic.service";
8
+ export * from "./mcp-server/exceptions";
package/dist/index.js CHANGED
@@ -21,3 +21,4 @@ __exportStar(require("./mcp-server/decorators/mcp-resource.decorator"), exports)
21
21
  __exportStar(require("./mcp-client/mcp-client.module"), exports);
22
22
  __exportStar(require("./mcp-client/mcp-client.service"), exports);
23
23
  __exportStar(require("./mcp-server/mcp-dynamic.service"), exports);
24
+ __exportStar(require("./mcp-server/exceptions"), exports);
@@ -0,0 +1,31 @@
1
+ import { HttpException, HttpStatus } from "@nestjs/common";
2
+ export declare class McpException extends HttpException {
3
+ constructor(message: string, status?: HttpStatus, options?: {
4
+ cause?: unknown;
5
+ });
6
+ }
7
+ export declare class McpBadRequestException extends McpException {
8
+ constructor(message: string, options?: {
9
+ cause?: unknown;
10
+ });
11
+ }
12
+ export declare class McpNotFoundException extends McpException {
13
+ constructor(message: string, options?: {
14
+ cause?: unknown;
15
+ });
16
+ }
17
+ export declare class McpInternalServerErrorException extends McpException {
18
+ constructor(message: string, options?: {
19
+ cause?: unknown;
20
+ });
21
+ }
22
+ export declare class McpUnauthorizedException extends McpException {
23
+ constructor(message: string, options?: {
24
+ cause?: unknown;
25
+ });
26
+ }
27
+ export declare class McpNotImplementedException extends McpException {
28
+ constructor(message: string, options?: {
29
+ cause?: unknown;
30
+ });
31
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpNotImplementedException = exports.McpUnauthorizedException = exports.McpInternalServerErrorException = exports.McpNotFoundException = exports.McpBadRequestException = exports.McpException = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ class McpException extends common_1.HttpException {
6
+ constructor(message, status = common_1.HttpStatus.INTERNAL_SERVER_ERROR, options) {
7
+ super({ message, ...(options?.cause ? { cause: options.cause } : {}) }, status);
8
+ }
9
+ }
10
+ exports.McpException = McpException;
11
+ class McpBadRequestException extends McpException {
12
+ constructor(message, options) {
13
+ super(message, common_1.HttpStatus.BAD_REQUEST, options);
14
+ }
15
+ }
16
+ exports.McpBadRequestException = McpBadRequestException;
17
+ class McpNotFoundException extends McpException {
18
+ constructor(message, options) {
19
+ super(message, common_1.HttpStatus.NOT_FOUND, options);
20
+ }
21
+ }
22
+ exports.McpNotFoundException = McpNotFoundException;
23
+ class McpInternalServerErrorException extends McpException {
24
+ constructor(message, options) {
25
+ super(message, common_1.HttpStatus.INTERNAL_SERVER_ERROR, options);
26
+ }
27
+ }
28
+ exports.McpInternalServerErrorException = McpInternalServerErrorException;
29
+ class McpUnauthorizedException extends McpException {
30
+ constructor(message, options) {
31
+ super(message, common_1.HttpStatus.UNAUTHORIZED, options);
32
+ }
33
+ }
34
+ exports.McpUnauthorizedException = McpUnauthorizedException;
35
+ class McpNotImplementedException extends McpException {
36
+ constructor(message, options) {
37
+ super(message, common_1.HttpStatus.NOT_IMPLEMENTED, options);
38
+ }
39
+ }
40
+ exports.McpNotImplementedException = McpNotImplementedException;
@@ -20,6 +20,7 @@ const core_1 = require("@nestjs/core");
20
20
  const run_interceptors_1 = require("./utils/run-interceptors");
21
21
  const rxjs_1 = require("rxjs");
22
22
  const run_fillters_1 = require("./utils/run-fillters");
23
+ const exceptions_1 = require("./exceptions");
23
24
  let McpService = class McpService {
24
25
  moduleRef;
25
26
  tools = new Map();
@@ -88,23 +89,20 @@ let McpService = class McpService {
88
89
  }
89
90
  async executePrompt(name, payload, context) {
90
91
  if (!this.prompts.has(name)) {
91
- throw new common_1.NotFoundException("Not found prompt");
92
- }
93
- const { instance: prompt, metatype } = this.prompts.get(name) || {};
94
- if (!prompt || !metatype) {
95
- throw new common_1.NotFoundException(`Unknown prompt: "${name}"`);
96
- }
97
- await (0, run_guards_1.runGuards)(this.moduleRef, metatype, context);
98
- // Валидация через AJV, если есть inputSchema
99
- if (prompt.inputSchema) {
100
- const zodSchema = (0, zod_1.zodToJsonSchema)(prompt.inputSchema);
101
- const validate = this.ajv.compile(zodSchema);
102
- const valid = validate(payload);
103
- if (!valid) {
104
- throw new common_1.NotFoundException("Invalid prompt arguments");
105
- }
92
+ throw new exceptions_1.McpNotFoundException("Not found prompt");
106
93
  }
94
+ const { instance: prompt, metatype } = this.prompts.get(name);
107
95
  try {
96
+ await (0, run_guards_1.runGuards)(this.moduleRef, metatype, context);
97
+ // Валидация через AJV, если есть inputSchema
98
+ if (prompt.inputSchema) {
99
+ const zodSchema = (0, zod_1.zodToJsonSchema)(prompt.inputSchema);
100
+ const validate = this.ajv.compile(zodSchema);
101
+ const valid = validate(payload);
102
+ if (!valid) {
103
+ throw new exceptions_1.McpBadRequestException("Invalid prompt arguments");
104
+ }
105
+ }
108
106
  // const result = await prompt.execute(payload);
109
107
  const stream = await (0, run_interceptors_1.runInterceptors)(this.moduleRef, metatype, context, () => {
110
108
  return (0, rxjs_1.from)(prompt.execute(payload));
@@ -112,28 +110,33 @@ let McpService = class McpService {
112
110
  return stream.pipe((0, rxjs_1.catchError)((err) => (0, rxjs_1.from)((0, run_fillters_1.runFilters)(this.moduleRef, metatype, err, context))));
113
111
  }
114
112
  catch (err) {
115
- throw new common_1.InternalServerErrorException("Failed to execute prompt");
113
+ const result = await (0, run_fillters_1.runFilters)(this.moduleRef, metatype, err, context);
114
+ if (result) {
115
+ return (0, rxjs_1.of)(result);
116
+ }
117
+ // Пробрасываем дальше, чтобы Observable корректно завершился
118
+ return (0, rxjs_1.throwError)(() => err);
116
119
  }
117
120
  }
118
121
  /**
119
122
  * Отправить сообщение в MCP "сервер"
120
123
  */
121
124
  async executeTool(msg, context) {
122
- const { instance: tool, metatype } = this.tools.get(msg.type) || {};
123
- if (!tool || !metatype) {
124
- throw new common_1.NotFoundException(`Unknown tool: "${msg.type}"`);
125
- }
126
- await (0, run_guards_1.runGuards)(this.moduleRef, metatype, context);
127
- // Валидация через AJV, если есть inputSchema
128
- if (tool.inputSchema) {
129
- const zodSchema = (0, zod_1.zodToJsonSchema)(tool.inputSchema);
130
- const validate = this.ajv.compile(zodSchema);
131
- const valid = validate(msg.payload);
132
- if (!valid) {
133
- throw new common_1.BadRequestException(this.ajv.errorsText(validate.errors));
134
- }
125
+ if (!this.tools.has(msg.type)) {
126
+ throw new exceptions_1.McpNotFoundException("Not found tool");
135
127
  }
128
+ const { instance: tool, metatype } = this.tools.get(msg.type);
136
129
  try {
130
+ await (0, run_guards_1.runGuards)(this.moduleRef, metatype, context);
131
+ // Валидация через AJV, если есть inputSchema
132
+ if (tool.inputSchema) {
133
+ const zodSchema = (0, zod_1.zodToJsonSchema)(tool.inputSchema);
134
+ const validate = this.ajv.compile(zodSchema);
135
+ const valid = validate(msg.payload);
136
+ if (!valid) {
137
+ throw new exceptions_1.McpBadRequestException(this.ajv.errorsText(validate.errors));
138
+ }
139
+ }
137
140
  // const result = await tool.execute(msg.payload);
138
141
  const stream = await (0, run_interceptors_1.runInterceptors)(this.moduleRef, metatype, context, () => {
139
142
  return (0, rxjs_1.from)(tool.execute(msg.payload));
@@ -141,16 +144,21 @@ let McpService = class McpService {
141
144
  return stream.pipe((0, rxjs_1.catchError)((err) => (0, rxjs_1.from)((0, run_fillters_1.runFilters)(this.moduleRef, metatype, err, context))));
142
145
  }
143
146
  catch (err) {
144
- throw new common_1.InternalServerErrorException("Failed to execute tool");
147
+ const result = await (0, run_fillters_1.runFilters)(this.moduleRef, metatype, err, context);
148
+ if (result) {
149
+ return (0, rxjs_1.of)(result);
150
+ }
151
+ // Пробрасываем дальше, чтобы Observable корректно завершился
152
+ return (0, rxjs_1.throwError)(() => err);
145
153
  }
146
154
  }
147
155
  async executeResource(name, uri, vars, context) {
148
- const { instance: resource, metatype } = this.resources.get(name) || {};
149
- if (!resource || !metatype) {
150
- throw new common_1.NotFoundException(`Unknown resource: "${name}"`);
156
+ if (!this.resources.has(name)) {
157
+ throw new exceptions_1.McpNotFoundException("Not found prompt");
151
158
  }
152
- await (0, run_guards_1.runGuards)(this.moduleRef, metatype, context);
159
+ const { instance: resource, metatype } = this.resources.get(name);
153
160
  try {
161
+ await (0, run_guards_1.runGuards)(this.moduleRef, metatype, context);
154
162
  // const result = await resource.execute(uri, vars);
155
163
  const stream = await (0, run_interceptors_1.runInterceptors)(this.moduleRef, metatype, context, () => {
156
164
  return (0, rxjs_1.from)(resource.execute(uri, vars));
@@ -158,7 +166,12 @@ let McpService = class McpService {
158
166
  return stream.pipe((0, rxjs_1.catchError)((err) => (0, rxjs_1.from)((0, run_fillters_1.runFilters)(this.moduleRef, metatype, err, context))));
159
167
  }
160
168
  catch (err) {
161
- throw new common_1.InternalServerErrorException("Failed to execute tool");
169
+ const result = await (0, run_fillters_1.runFilters)(this.moduleRef, metatype, err, context);
170
+ if (result) {
171
+ return (0, rxjs_1.of)(result);
172
+ }
173
+ // Пробрасываем дальше, чтобы Observable корректно завершился
174
+ return (0, rxjs_1.throwError)(() => err);
162
175
  }
163
176
  }
164
177
  createServer(context) {
@@ -182,8 +195,9 @@ let McpService = class McpService {
182
195
  };
183
196
  }
184
197
  catch (e) {
185
- console.error(e);
186
- throw new Error(`Faild to execute tool ${tool.name}`);
198
+ throw new exceptions_1.McpInternalServerErrorException(`Faild to execute tool ${tool.name}`, {
199
+ cause: e,
200
+ });
187
201
  }
188
202
  });
189
203
  }
@@ -209,7 +223,9 @@ let McpService = class McpService {
209
223
  return { messages: messages };
210
224
  }
211
225
  catch (e) {
212
- throw new Error(`Faild to execute tool ${prompt.name}`);
226
+ throw new exceptions_1.McpInternalServerErrorException(`Faild to execute tool ${prompt.name}`, {
227
+ cause: e,
228
+ });
213
229
  }
214
230
  });
215
231
  }
@@ -234,7 +250,9 @@ let McpService = class McpService {
234
250
  return { contents: result };
235
251
  }
236
252
  catch (e) {
237
- throw new Error(`Faild to execute tool ${prompt.name}`);
253
+ throw new exceptions_1.McpInternalServerErrorException(`Faild to execute tool ${prompt.name}`, {
254
+ cause: e,
255
+ });
238
256
  }
239
257
  });
240
258
  }
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runGuards = runGuards;
4
- const common_1 = require("@nestjs/common");
5
4
  const constants_1 = require("@nestjs/common/constants");
5
+ const exceptions_1 = require("../exceptions");
6
6
  /**
7
7
  * Универсальный helper для проверки массивов NestJS Guards
8
8
  */
@@ -28,7 +28,7 @@ async function runGuards(moduleRef, metatype, context) {
28
28
  const guardInstance = await resolveGuard(Guard);
29
29
  const can = await guardInstance.canActivate(context);
30
30
  if (!can) {
31
- throw new common_1.UnauthorizedException("Guard blocked execution");
31
+ throw new exceptions_1.McpUnauthorizedException("Guard blocked execution");
32
32
  }
33
33
  }
34
34
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muzikanto/nestjs-mcp",
3
- "version": "1.5.0",
3
+ "version": "1.5.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",