@rekog/mcp-nest 1.9.0-alpha.0 → 1.9.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.
Files changed (72) hide show
  1. package/README.md +2 -2
  2. package/dist/authz/guards/jwt-auth.guard.d.ts +3 -1
  3. package/dist/authz/guards/jwt-auth.guard.d.ts.map +1 -1
  4. package/dist/authz/guards/jwt-auth.guard.js +26 -3
  5. package/dist/authz/guards/jwt-auth.guard.js.map +1 -1
  6. package/dist/mcp/decorators/index.d.ts +3 -0
  7. package/dist/mcp/decorators/index.d.ts.map +1 -1
  8. package/dist/mcp/decorators/index.js +3 -0
  9. package/dist/mcp/decorators/index.js.map +1 -1
  10. package/dist/mcp/decorators/prompt.decorator.d.ts +2 -2
  11. package/dist/mcp/decorators/prompt.decorator.d.ts.map +1 -1
  12. package/dist/mcp/decorators/prompt.decorator.js.map +1 -1
  13. package/dist/mcp/decorators/public.decorator.d.ts +3 -0
  14. package/dist/mcp/decorators/public.decorator.d.ts.map +1 -0
  15. package/dist/mcp/decorators/public.decorator.js +8 -0
  16. package/dist/mcp/decorators/public.decorator.js.map +1 -0
  17. package/dist/mcp/decorators/require-roles.decorator.d.ts +3 -0
  18. package/dist/mcp/decorators/require-roles.decorator.d.ts.map +1 -0
  19. package/dist/mcp/decorators/require-roles.decorator.js +13 -0
  20. package/dist/mcp/decorators/require-roles.decorator.js.map +1 -0
  21. package/dist/mcp/decorators/require-scopes.decorator.d.ts +3 -0
  22. package/dist/mcp/decorators/require-scopes.decorator.d.ts.map +1 -0
  23. package/dist/mcp/decorators/require-scopes.decorator.js +13 -0
  24. package/dist/mcp/decorators/require-scopes.decorator.js.map +1 -0
  25. package/dist/mcp/decorators/tool-roles.decorator.d.ts +3 -0
  26. package/dist/mcp/decorators/tool-roles.decorator.d.ts.map +1 -0
  27. package/dist/mcp/decorators/tool-roles.decorator.js +13 -0
  28. package/dist/mcp/decorators/tool-roles.decorator.js.map +1 -0
  29. package/dist/mcp/decorators/tool-scopes.decorator.d.ts +3 -0
  30. package/dist/mcp/decorators/tool-scopes.decorator.d.ts.map +1 -0
  31. package/dist/mcp/decorators/tool-scopes.decorator.js +13 -0
  32. package/dist/mcp/decorators/tool-scopes.decorator.js.map +1 -0
  33. package/dist/mcp/decorators/tool.decorator.d.ts +10 -0
  34. package/dist/mcp/decorators/tool.decorator.d.ts.map +1 -1
  35. package/dist/mcp/decorators/tool.decorator.js.map +1 -1
  36. package/dist/mcp/interfaces/mcp-options.interface.d.ts +1 -0
  37. package/dist/mcp/interfaces/mcp-options.interface.d.ts.map +1 -1
  38. package/dist/mcp/interfaces/mcp-options.interface.js.map +1 -1
  39. package/dist/mcp/mcp.module.d.ts.map +1 -1
  40. package/dist/mcp/mcp.module.js +4 -1
  41. package/dist/mcp/mcp.module.js.map +1 -1
  42. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts +6 -2
  43. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts.map +1 -1
  44. package/dist/mcp/services/handlers/mcp-tools.handler.js +33 -7
  45. package/dist/mcp/services/handlers/mcp-tools.handler.js.map +1 -1
  46. package/dist/mcp/services/mcp-executor.service.d.ts +3 -2
  47. package/dist/mcp/services/mcp-executor.service.d.ts.map +1 -1
  48. package/dist/mcp/services/mcp-executor.service.js +4 -4
  49. package/dist/mcp/services/mcp-executor.service.js.map +1 -1
  50. package/dist/mcp/services/mcp-registry.service.d.ts.map +1 -1
  51. package/dist/mcp/services/mcp-registry.service.js +25 -1
  52. package/dist/mcp/services/mcp-registry.service.js.map +1 -1
  53. package/dist/mcp/services/tool-authorization.service.d.ts +11 -0
  54. package/dist/mcp/services/tool-authorization.service.d.ts.map +1 -0
  55. package/dist/mcp/services/tool-authorization.service.js +109 -0
  56. package/dist/mcp/services/tool-authorization.service.js.map +1 -0
  57. package/package.json +3 -4
  58. package/src/authz/guards/jwt-auth.guard.ts +33 -1
  59. package/src/mcp/decorators/index.ts +3 -0
  60. package/src/mcp/decorators/prompt.decorator.ts +2 -4
  61. package/src/mcp/decorators/public.decorator.ts +29 -0
  62. package/src/mcp/decorators/require-roles.decorator.ts +44 -0
  63. package/src/mcp/decorators/require-scopes.decorator.ts +51 -0
  64. package/src/mcp/decorators/tool-roles.decorator.ts +45 -0
  65. package/src/mcp/decorators/tool-scopes.decorator.ts +52 -0
  66. package/src/mcp/decorators/tool.decorator.ts +12 -0
  67. package/src/mcp/interfaces/mcp-options.interface.ts +16 -0
  68. package/src/mcp/mcp.module.ts +4 -1
  69. package/src/mcp/services/handlers/mcp-tools.handler.ts +61 -8
  70. package/src/mcp/services/mcp-executor.service.ts +11 -3
  71. package/src/mcp/services/mcp-registry.service.ts +43 -5
  72. package/src/mcp/services/tool-authorization.service.ts +211 -0
package/README.md CHANGED
@@ -31,13 +31,13 @@ With `@rekog/mcp-nest` you define tools, resources, and prompts in a way that's
31
31
  - 💉 **[Dependency Injection](docs/dependency-injection.md)**: Leverage NestJS DI system throughout MCP components
32
32
  - 📝 **[Logging Configuration](docs/server-examples.md#logging-configuration)**: Fine-grained control over MCP module logging levels
33
33
 
34
- **Are you interested to build ChatGPT widgets (with the OpenAI SDK)?**
34
+ **Are you interested to build ChatGPT widgets (with the OpenAI SDK)?**
35
35
  Find out how to do that with `@rekog/MCP-Nest` in this repository [MCP-Nest-Samples/pizzaz-openai-apps-sdk](https://github.com/rinormaloku/MCP-Nest-Samples/tree/main/pizzaz-openai-apps-sdk)
36
36
 
37
37
  ## Installation
38
38
 
39
39
  ```bash
40
- npm install @rekog/mcp-nest @modelcontextprotocol/sdk zod@^3
40
+ npm install @rekog/mcp-nest @modelcontextprotocol/sdk zod@^4
41
41
  ```
42
42
 
43
43
  ### Optional dependencies
@@ -3,6 +3,7 @@ import { ModuleRef } from '@nestjs/core';
3
3
  import { Request } from 'express';
4
4
  import { JwtPayload, JwtTokenService } from '../services/jwt-token.service';
5
5
  import { IOAuthStore } from '../stores/oauth-store.interface';
6
+ import { McpOptions } from '../../mcp';
6
7
  export interface AuthenticatedRequest extends Request {
7
8
  user: JwtPayload;
8
9
  }
@@ -10,7 +11,8 @@ export declare class McpAuthJwtGuard implements CanActivate {
10
11
  private readonly jwtTokenService;
11
12
  private readonly store;
12
13
  private readonly moduleRef;
13
- constructor(jwtTokenService: JwtTokenService | null, store: IOAuthStore | null, moduleRef: ModuleRef);
14
+ private readonly options?;
15
+ constructor(jwtTokenService: JwtTokenService | null, store: IOAuthStore | null, moduleRef: ModuleRef, options?: McpOptions | undefined);
14
16
  canActivate(context: ExecutionContext): Promise<boolean>;
15
17
  private extractTokenFromHeader;
16
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-auth.guard.d.ts","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,gBAAgB,EAIjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,qBACa,eAAgB,YAAW,WAAW;IAEnC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAG5C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAJG,eAAe,EAAE,eAAe,GAAG,IAAI,EAGnD,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,SAAS,EAAE,SAAS;IAGjC,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0D9D,OAAO,CAAC,sBAAsB;CAS/B"}
1
+ {"version":3,"file":"jwt-auth.guard.d.ts","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,gBAAgB,EAIjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,qBACa,eAAgB,YAAW,WAAW;IAEnC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAG5C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAG1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAPI,eAAe,EAAE,eAAe,GAAG,IAAI,EAGnD,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,SAAS,EAAE,SAAS,EAGpB,OAAO,CAAC,EAAE,UAAU,YAAA;IAGjC,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAsF9D,OAAO,CAAC,sBAAsB;CAS/B"}
@@ -17,16 +17,23 @@ const common_1 = require("@nestjs/common");
17
17
  const core_1 = require("@nestjs/core");
18
18
  const jwt_token_service_1 = require("../services/jwt-token.service");
19
19
  let McpAuthJwtGuard = class McpAuthJwtGuard {
20
- constructor(jwtTokenService, store, moduleRef) {
20
+ constructor(jwtTokenService, store, moduleRef, options) {
21
21
  this.jwtTokenService = jwtTokenService;
22
22
  this.store = store;
23
23
  this.moduleRef = moduleRef;
24
+ this.options = options;
24
25
  }
25
26
  async canActivate(context) {
26
27
  const request = context.switchToHttp().getRequest();
27
28
  const token = this.extractTokenFromHeader(request);
29
+ const allowUnauthenticated = this.options?.allowUnauthenticatedAccess ?? false;
28
30
  if (!token) {
29
- throw new common_1.UnauthorizedException('Access token required');
31
+ if (allowUnauthenticated) {
32
+ return true;
33
+ }
34
+ else {
35
+ throw new common_1.UnauthorizedException('Access token required');
36
+ }
30
37
  }
31
38
  const jwtTokenService = this.jwtTokenService ||
32
39
  this.moduleRef.get(jwt_token_service_1.JwtTokenService, { strict: false });
@@ -59,6 +66,20 @@ let McpAuthJwtGuard = class McpAuthJwtGuard {
59
66
  ud.username ||
60
67
  ud.email ||
61
68
  enriched.sub;
69
+ if (enriched.scope && typeof enriched.scope === 'string') {
70
+ enriched.scopes = enriched.scope
71
+ .split(' ')
72
+ .filter((s) => s.length > 0);
73
+ }
74
+ else if (!enriched.scopes) {
75
+ enriched.scopes = [];
76
+ }
77
+ if (!enriched.roles && ud.roles && Array.isArray(ud.roles)) {
78
+ enriched.roles = ud.roles;
79
+ }
80
+ else if (!enriched.roles) {
81
+ enriched.roles = [];
82
+ }
62
83
  }
63
84
  catch {
64
85
  }
@@ -80,6 +101,8 @@ exports.McpAuthJwtGuard = McpAuthJwtGuard = __decorate([
80
101
  __param(0, (0, common_1.Optional)()),
81
102
  __param(1, (0, common_1.Optional)()),
82
103
  __param(1, (0, common_1.Inject)('IOAuthStore')),
83
- __metadata("design:paramtypes", [Object, Object, core_1.ModuleRef])
104
+ __param(3, (0, common_1.Optional)()),
105
+ __param(3, (0, common_1.Inject)('MCP_OPTIONS')),
106
+ __metadata("design:paramtypes", [Object, Object, core_1.ModuleRef, Object])
84
107
  ], McpAuthJwtGuard);
85
108
  //# sourceMappingURL=jwt-auth.guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n CanActivate,\n ExecutionContext,\n UnauthorizedException,\n Inject,\n Optional,\n} from '@nestjs/common';\nimport { ModuleRef } from '@nestjs/core';\nimport { Request } from 'express';\nimport { JwtPayload, JwtTokenService } from '../services/jwt-token.service';\nimport { IOAuthStore } from '../stores/oauth-store.interface';\n\nexport interface AuthenticatedRequest extends Request {\n user: JwtPayload;\n}\n\n@Injectable()\nexport class McpAuthJwtGuard implements CanActivate {\n constructor(\n @Optional() private readonly jwtTokenService: JwtTokenService | null,\n @Optional()\n @Inject('IOAuthStore')\n private readonly store: IOAuthStore | null,\n private readonly moduleRef: ModuleRef,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<AuthenticatedRequest>();\n const token = this.extractTokenFromHeader(request);\n\n if (!token) {\n throw new UnauthorizedException('Access token required');\n }\n\n // Resolve services dynamically if not injected directly\n const jwtTokenService =\n this.jwtTokenService ||\n this.moduleRef.get(JwtTokenService, { strict: false });\n const store =\n this.store ||\n this.moduleRef.get<IOAuthStore>('IOAuthStore', { strict: false });\n\n if (!jwtTokenService || !store) {\n throw new UnauthorizedException('Authentication service not available');\n }\n\n const payload = jwtTokenService.validateToken(token);\n\n if (!payload) {\n throw new UnauthorizedException('Invalid or expired access token');\n }\n\n // Enrich request.user with friendly fields for tools\n const enriched: any = { ...payload };\n try {\n if (!enriched.user_data && enriched.user_profile_id) {\n const profile = await store.getUserProfileById(\n enriched.user_profile_id,\n );\n if (profile) {\n enriched.user_data = profile;\n }\n }\n const ud = enriched.user_data || {};\n // Provide convenient top-level fields commonly used by tools\n enriched.username =\n enriched.username || ud.username || ud.id || enriched.sub;\n enriched.email = enriched.email || ud.email;\n enriched.displayName = enriched.displayName || ud.displayName;\n enriched.avatarUrl = enriched.avatarUrl || ud.avatarUrl;\n enriched.name =\n enriched.name ||\n ud.displayName ||\n ud.username ||\n ud.email ||\n enriched.sub;\n } catch {\n // Non-fatal; proceed with raw payload\n }\n\n request.user = enriched as JwtPayload;\n return true;\n }\n\n private extractTokenFromHeader(request: Request): string | undefined {\n const authHeader = request.headers.authorization;\n if (!authHeader) {\n return undefined;\n }\n\n const [type, token] = authHeader.split(' ');\n return type === 'Bearer' ? token : undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n CanActivate,\n ExecutionContext,\n UnauthorizedException,\n Inject,\n Optional,\n} from '@nestjs/common';\nimport { ModuleRef } from '@nestjs/core';\nimport { Request } from 'express';\nimport { JwtPayload, JwtTokenService } from '../services/jwt-token.service';\nimport { IOAuthStore } from '../stores/oauth-store.interface';\nimport { McpOptions } from '../../mcp';\n\nexport interface AuthenticatedRequest extends Request {\n user: JwtPayload;\n}\n\n@Injectable()\nexport class McpAuthJwtGuard implements CanActivate {\n constructor(\n @Optional() private readonly jwtTokenService: JwtTokenService | null,\n @Optional()\n @Inject('IOAuthStore')\n private readonly store: IOAuthStore | null,\n private readonly moduleRef: ModuleRef,\n @Optional()\n @Inject('MCP_OPTIONS')\n private readonly options?: McpOptions,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<AuthenticatedRequest>();\n const token = this.extractTokenFromHeader(request);\n\n // Check if unauthenticated access is allowed\n const allowUnauthenticated =\n this.options?.allowUnauthenticatedAccess ?? false;\n\n if (!token) {\n if (allowUnauthenticated) {\n // Allow unauthenticated sessions\n // Per-tool authorization will decide what's accessible (@PublicTool() tools only)\n return true;\n } else {\n // Standard OAuth flow: Reject and trigger authorization\n throw new UnauthorizedException('Access token required');\n }\n }\n\n // Resolve services dynamically if not injected directly\n const jwtTokenService =\n this.jwtTokenService ||\n this.moduleRef.get(JwtTokenService, { strict: false });\n const store =\n this.store ||\n this.moduleRef.get<IOAuthStore>('IOAuthStore', { strict: false });\n\n if (!jwtTokenService || !store) {\n throw new UnauthorizedException('Authentication service not available');\n }\n\n // If a token is provided, it must be valid\n const payload = jwtTokenService.validateToken(token);\n\n if (!payload) {\n throw new UnauthorizedException('Invalid or expired access token');\n }\n\n // Enrich request.user with friendly fields for tools\n const enriched: any = { ...payload };\n try {\n if (!enriched.user_data && enriched.user_profile_id) {\n const profile = await store.getUserProfileById(\n enriched.user_profile_id,\n );\n if (profile) {\n enriched.user_data = profile;\n }\n }\n const ud = enriched.user_data || {};\n // Provide convenient top-level fields commonly used by tools\n enriched.username =\n enriched.username || ud.username || ud.id || enriched.sub;\n enriched.email = enriched.email || ud.email;\n enriched.displayName = enriched.displayName || ud.displayName;\n enriched.avatarUrl = enriched.avatarUrl || ud.avatarUrl;\n enriched.name =\n enriched.name ||\n ud.displayName ||\n ud.username ||\n ud.email ||\n enriched.sub;\n\n // Parse scopes: OAuth 2.0 standard is space-delimited string in 'scope' field\n if (enriched.scope && typeof enriched.scope === 'string') {\n enriched.scopes = enriched.scope\n .split(' ')\n .filter((s: string) => s.length > 0);\n } else if (!enriched.scopes) {\n enriched.scopes = [];\n }\n\n // Extract roles from user_data if present\n if (!enriched.roles && ud.roles && Array.isArray(ud.roles)) {\n enriched.roles = ud.roles;\n } else if (!enriched.roles) {\n enriched.roles = [];\n }\n } catch {\n // Non-fatal; proceed with raw payload\n }\n\n request.user = enriched as JwtPayload;\n return true;\n }\n\n private extractTokenFromHeader(request: Request): string | undefined {\n const authHeader = request.headers.authorization;\n if (!authHeader) {\n return undefined;\n }\n\n const [type, token] = authHeader.split(' ');\n return type === 'Bearer' ? token : undefined;\n }\n}\n"]}
@@ -3,4 +3,7 @@ export * from './constants';
3
3
  export * from './resource.decorator';
4
4
  export * from './resource-template.decorator';
5
5
  export * from './prompt.decorator';
6
+ export * from './public.decorator';
7
+ export * from './tool-scopes.decorator';
8
+ export * from './tool-roles.decorator';
6
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC"}
@@ -19,4 +19,7 @@ __exportStar(require("./constants"), exports);
19
19
  __exportStar(require("./resource.decorator"), exports);
20
20
  __exportStar(require("./resource-template.decorator"), exports);
21
21
  __exportStar(require("./prompt.decorator"), exports);
22
+ __exportStar(require("./public.decorator"), exports);
23
+ __exportStar(require("./tool-scopes.decorator"), exports);
24
+ __exportStar(require("./tool-roles.decorator"), exports);
22
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/decorators/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,8CAA4B;AAC5B,uDAAqC;AACrC,gEAA8C;AAC9C,qDAAmC","sourcesContent":["export * from './tool.decorator';\nexport * from './constants';\nexport * from './resource.decorator';\nexport * from './resource-template.decorator';\nexport * from './prompt.decorator';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/decorators/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,8CAA4B;AAC5B,uDAAqC;AACrC,gEAA8C;AAC9C,qDAAmC;AACnC,qDAAmC;AACnC,0DAAwC;AACxC,yDAAuC","sourcesContent":["export * from './tool.decorator';\nexport * from './constants';\nexport * from './resource.decorator';\nexport * from './resource-template.decorator';\nexport * from './prompt.decorator';\nexport * from './public.decorator';\nexport * from './tool-scopes.decorator';\nexport * from './tool-roles.decorator';\n"]}
@@ -1,6 +1,6 @@
1
- import { ZodType, ZodTypeDef, ZodOptional, ZodObject } from 'zod';
1
+ import { ZodObject, ZodTypeAny } from 'zod';
2
2
  type PromptArgsRawShape = {
3
- [k: string]: ZodType<string, ZodTypeDef, string> | ZodOptional<ZodType<string, ZodTypeDef, string>>;
3
+ [k: string]: ZodTypeAny;
4
4
  };
5
5
  export interface PromptMetadata {
6
6
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/prompt.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAElE,KAAK,kBAAkB,GAAG;IACxB,CAAC,CAAC,EAAE,MAAM,GACN,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,GACnC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,CAAC,kBAAkB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,CAAC,kBAAkB,CAAC,CAAC;CAC5C;AAED,eAAO,MAAM,MAAM,GAAI,SAAS,aAAa,qDAE5C,CAAC"}
1
+ {"version":3,"file":"prompt.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/prompt.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAE5C,KAAK,kBAAkB,GAAG;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,CAAC,kBAAkB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,CAAC,kBAAkB,CAAC,CAAC;CAC5C;AAED,eAAO,MAAM,MAAM,GAAI,SAAS,aAAa,qDAE5C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/prompt.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAC7C,2CAAsD;AAqB/C,MAAM,MAAM,GAAG,CAAC,OAAsB,EAAE,EAAE;IAC/C,OAAO,IAAA,oBAAW,EAAC,mCAAuB,EAAE,OAAO,CAAC,CAAC;AACvD,CAAC,CAAC;AAFW,QAAA,MAAM,UAEjB","sourcesContent":["import { SetMetadata } from '@nestjs/common';\nimport { MCP_PROMPT_METADATA_KEY } from './constants';\nimport { ZodType, ZodTypeDef, ZodOptional, ZodObject } from 'zod';\n\ntype PromptArgsRawShape = {\n [k: string]:\n | ZodType<string, ZodTypeDef, string>\n | ZodOptional<ZodType<string, ZodTypeDef, string>>;\n};\n\nexport interface PromptMetadata {\n name: string;\n description: string;\n parameters?: ZodObject<PromptArgsRawShape>;\n}\n\nexport interface PromptOptions {\n name?: string;\n description: string;\n parameters?: ZodObject<PromptArgsRawShape>;\n}\n\nexport const Prompt = (options: PromptOptions) => {\n return SetMetadata(MCP_PROMPT_METADATA_KEY, options);\n};\n"]}
1
+ {"version":3,"file":"prompt.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/prompt.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAC7C,2CAAsD;AAmB/C,MAAM,MAAM,GAAG,CAAC,OAAsB,EAAE,EAAE;IAC/C,OAAO,IAAA,oBAAW,EAAC,mCAAuB,EAAE,OAAO,CAAC,CAAC;AACvD,CAAC,CAAC;AAFW,QAAA,MAAM,UAEjB","sourcesContent":["import { SetMetadata } from '@nestjs/common';\nimport { MCP_PROMPT_METADATA_KEY } from './constants';\nimport { ZodObject, ZodTypeAny } from 'zod';\n\ntype PromptArgsRawShape = {\n [k: string]: ZodTypeAny;\n};\n\nexport interface PromptMetadata {\n name: string;\n description: string;\n parameters?: ZodObject<PromptArgsRawShape>;\n}\n\nexport interface PromptOptions {\n name?: string;\n description: string;\n parameters?: ZodObject<PromptArgsRawShape>;\n}\n\nexport const Prompt = (options: PromptOptions) => {\n return SetMetadata(MCP_PROMPT_METADATA_KEY, options);\n};\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const MCP_PUBLIC_METADATA_KEY = "mcp:public-tool";
2
+ export declare const PublicTool: () => import("@nestjs/common").CustomDecorator<string>;
3
+ //# sourceMappingURL=public.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/public.decorator.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,uBAAuB,oBAAoB,CAAC;AAuBzD,eAAO,MAAM,UAAU,wDAAmD,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PublicTool = exports.MCP_PUBLIC_METADATA_KEY = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ exports.MCP_PUBLIC_METADATA_KEY = 'mcp:public-tool';
6
+ const PublicTool = () => (0, common_1.SetMetadata)(exports.MCP_PUBLIC_METADATA_KEY, true);
7
+ exports.PublicTool = PublicTool;
8
+ //# sourceMappingURL=public.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/public.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAKhC,QAAA,uBAAuB,GAAG,iBAAiB,CAAC;AAuBlD,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAA,oBAAW,EAAC,+BAAuB,EAAE,IAAI,CAAC,CAAC;AAA9D,QAAA,UAAU,cAAoD","sourcesContent":["import { SetMetadata } from '@nestjs/common';\n\n/**\n * Metadata key for marking a tool as publicly accessible\n */\nexport const MCP_PUBLIC_METADATA_KEY = 'mcp:public-tool';\n\n/**\n * Decorator to mark a tool as publicly accessible, bypassing authentication requirements.\n *\n * Use this when you want a tool to be available even to unauthenticated users\n * when `allowUnauthenticatedAccess` is enabled in McpModule options.\n *\n * When applied to a tool method, it allows the tool to be called without authentication,\n * even if the module has guards configured.\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class MyTools {\n * @Tool({ name: 'public-search', description: 'Search publicly' })\n * @PublicTool()\n * async search() {\n * return { content: [{ type: 'text', text: 'Public results' }] };\n * }\n * }\n * ```\n */\nexport const PublicTool = () => SetMetadata(MCP_PUBLIC_METADATA_KEY, true);\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const MCP_ROLES_METADATA_KEY = "mcp:roles";
2
+ export declare const ToolRoles: (roles: string[]) => import("@nestjs/common").CustomDecorator<string>;
3
+ //# sourceMappingURL=require-roles.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-roles.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/require-roles.decorator.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,sBAAsB,cAAc,CAAC;AAiClD,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,EAAE,qDAKxC,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolRoles = exports.MCP_ROLES_METADATA_KEY = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ exports.MCP_ROLES_METADATA_KEY = 'mcp:roles';
6
+ const ToolRoles = (roles) => {
7
+ if (!Array.isArray(roles) || roles.length === 0) {
8
+ throw new Error('@ToolRoles() requires a non-empty array of role strings');
9
+ }
10
+ return (0, common_1.SetMetadata)(exports.MCP_ROLES_METADATA_KEY, roles);
11
+ };
12
+ exports.ToolRoles = ToolRoles;
13
+ //# sourceMappingURL=require-roles.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-roles.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/require-roles.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAKhC,QAAA,sBAAsB,GAAG,WAAW,CAAC;AAiC3C,MAAM,SAAS,GAAG,CAAC,KAAe,EAAE,EAAE;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,IAAA,oBAAW,EAAC,8BAAsB,EAAE,KAAK,CAAC,CAAC;AACpD,CAAC,CAAC;AALW,QAAA,SAAS,aAKpB","sourcesContent":["import { SetMetadata } from '@nestjs/common';\n\n/**\n * Metadata key for storing required roles\n */\nexport const MCP_ROLES_METADATA_KEY = 'mcp:roles';\n\n/**\n * Decorator to specify roles required to access a tool.\n *\n * When applied to a tool method, it requires the authenticated user to have\n * ALL specified roles in their JWT token or user profile.\n *\n * Can be combined with @ToolScopes() for fine-grained access control.\n *\n * @param roles - Array of required role strings\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class MyTools {\n * // Requires 'admin' role\n * @Tool({ name: 'system-config', description: 'Configure system' })\n * @ToolRoles(['admin'])\n * async configureSystem(args, ctx, req: McpRequestWithUser) {\n * return { content: [{ type: 'text', text: 'System configured' }] };\n * }\n *\n * // Requires both role and scope\n * @Tool({ name: 'audit-log', description: 'View audit logs' })\n * @ToolRoles(['auditor'])\n * @ToolScopes(['logs.read'])\n * async viewAuditLog(args, ctx, req: McpRequestWithUser) {\n * return { content: [{ type: 'text', text: 'Audit log data...' }] };\n * }\n * }\n * ```\n */\nexport const ToolRoles = (roles: string[]) => {\n if (!Array.isArray(roles) || roles.length === 0) {\n throw new Error('@ToolRoles() requires a non-empty array of role strings');\n }\n return SetMetadata(MCP_ROLES_METADATA_KEY, roles);\n};\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const MCP_SCOPES_METADATA_KEY = "mcp:scopes";
2
+ export declare const ToolScopes: (scopes: string[]) => import("@nestjs/common").CustomDecorator<string>;
3
+ //# sourceMappingURL=require-scopes.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-scopes.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/require-scopes.decorator.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,uBAAuB,eAAe,CAAC;AAsCpD,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,qDAO1C,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolScopes = exports.MCP_SCOPES_METADATA_KEY = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ exports.MCP_SCOPES_METADATA_KEY = 'mcp:scopes';
6
+ const ToolScopes = (scopes) => {
7
+ if (!Array.isArray(scopes) || scopes.length === 0) {
8
+ throw new Error('@ToolScopes() requires a non-empty array of scope strings');
9
+ }
10
+ return (0, common_1.SetMetadata)(exports.MCP_SCOPES_METADATA_KEY, scopes);
11
+ };
12
+ exports.ToolScopes = ToolScopes;
13
+ //# sourceMappingURL=require-scopes.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-scopes.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/require-scopes.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAKhC,QAAA,uBAAuB,GAAG,YAAY,CAAC;AAsC7C,MAAM,UAAU,GAAG,CAAC,MAAgB,EAAE,EAAE;IAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IACD,OAAO,IAAA,oBAAW,EAAC,+BAAuB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC,CAAC;AAPW,QAAA,UAAU,cAOrB","sourcesContent":["import { SetMetadata } from '@nestjs/common';\n\n/**\n * Metadata key for storing required OAuth scopes\n */\nexport const MCP_SCOPES_METADATA_KEY = 'mcp:scopes';\n\n/**\n * Decorator to specify OAuth scopes required to access a tool.\n *\n * When applied to a tool method, it requires the authenticated user to have\n * ALL specified scopes in their JWT token.\n *\n * Can be combined with @PublicTool() to create tools that work better with authentication\n * but are also accessible anonymously.\n *\n * @param scopes - Array of required OAuth scope strings\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class MyTools {\n * // Requires 'admin' and 'write' scopes\n * @Tool({ name: 'delete-user', description: 'Delete a user' })\n * @ToolScopes(['admin', 'write'])\n * async deleteUser(args, ctx, req: McpRequestWithUser) {\n * // Only users with both 'admin' AND 'write' scopes can call this\n * return { content: [{ type: 'text', text: 'User deleted' }] };\n * }\n *\n * // Optional auth - works better with 'premium' scope\n * @Tool({ name: 'search', description: 'Search content' })\n * @PublicTool()\n * @ToolScopes(['premium'])\n * async search(args, ctx, req: McpRequestWithUser) {\n * if (req.user?.scopes?.includes('premium')) {\n * return { content: [{ type: 'text', text: 'AI-powered results' }] };\n * }\n * return { content: [{ type: 'text', text: 'Basic results' }] };\n * }\n * }\n * ```\n */\nexport const ToolScopes = (scopes: string[]) => {\n if (!Array.isArray(scopes) || scopes.length === 0) {\n throw new Error(\n '@ToolScopes() requires a non-empty array of scope strings',\n );\n }\n return SetMetadata(MCP_SCOPES_METADATA_KEY, scopes);\n};\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const MCP_ROLES_METADATA_KEY = "mcp:roles";
2
+ export declare const ToolRoles: (roles: string[]) => import("@nestjs/common").CustomDecorator<string>;
3
+ //# sourceMappingURL=tool-roles.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-roles.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-roles.decorator.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,sBAAsB,cAAc,CAAC;AAkClD,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,EAAE,qDAKxC,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolRoles = exports.MCP_ROLES_METADATA_KEY = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ exports.MCP_ROLES_METADATA_KEY = 'mcp:roles';
6
+ const ToolRoles = (roles) => {
7
+ if (!Array.isArray(roles) || roles.length === 0) {
8
+ throw new Error('@ToolRoles() requires a non-empty array of role strings');
9
+ }
10
+ return (0, common_1.SetMetadata)(exports.MCP_ROLES_METADATA_KEY, roles);
11
+ };
12
+ exports.ToolRoles = ToolRoles;
13
+ //# sourceMappingURL=tool-roles.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-roles.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-roles.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAKhC,QAAA,sBAAsB,GAAG,WAAW,CAAC;AAkC3C,MAAM,SAAS,GAAG,CAAC,KAAe,EAAE,EAAE;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,IAAA,oBAAW,EAAC,8BAAsB,EAAE,KAAK,CAAC,CAAC;AACpD,CAAC,CAAC;AALW,QAAA,SAAS,aAKpB","sourcesContent":["import { SetMetadata } from '@nestjs/common';\n\n/**\n * Metadata key for storing required roles\n */\nexport const MCP_ROLES_METADATA_KEY = 'mcp:roles';\n\n/**\n * Decorator to specify roles required to access a tool.\n *\n * Use this to restrict tool access based on user roles (RBAC).\n * When applied, it requires the authenticated user to have\n * ALL specified roles in their JWT token or user profile.\n *\n * Can be combined with @ToolScopes() for fine-grained access control.\n *\n * @param roles - Array of required role strings\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class MyTools {\n * // Requires 'admin' role\n * @Tool({ name: 'system-config', description: 'Configure system' })\n * @ToolRoles(['admin'])\n * async configureSystem(args, ctx, req: McpRequestWithUser) {\n * return { content: [{ type: 'text', text: 'System configured' }] };\n * }\n *\n * // Requires both role and scope\n * @Tool({ name: 'audit-log', description: 'View audit logs' })\n * @ToolRoles(['auditor'])\n * @ToolScopes(['logs.read'])\n * async viewAuditLog(args, ctx, req: McpRequestWithUser) {\n * return { content: [{ type: 'text', text: 'Audit log data...' }] };\n * }\n * }\n * ```\n */\nexport const ToolRoles = (roles: string[]) => {\n if (!Array.isArray(roles) || roles.length === 0) {\n throw new Error('@ToolRoles() requires a non-empty array of role strings');\n }\n return SetMetadata(MCP_ROLES_METADATA_KEY, roles);\n};\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const MCP_SCOPES_METADATA_KEY = "mcp:scopes";
2
+ export declare const ToolScopes: (scopes: string[]) => import("@nestjs/common").CustomDecorator<string>;
3
+ //# sourceMappingURL=tool-scopes.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-scopes.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-scopes.decorator.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,uBAAuB,eAAe,CAAC;AAuCpD,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,qDAO1C,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolScopes = exports.MCP_SCOPES_METADATA_KEY = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ exports.MCP_SCOPES_METADATA_KEY = 'mcp:scopes';
6
+ const ToolScopes = (scopes) => {
7
+ if (!Array.isArray(scopes) || scopes.length === 0) {
8
+ throw new Error('@ToolScopes() requires a non-empty array of scope strings');
9
+ }
10
+ return (0, common_1.SetMetadata)(exports.MCP_SCOPES_METADATA_KEY, scopes);
11
+ };
12
+ exports.ToolScopes = ToolScopes;
13
+ //# sourceMappingURL=tool-scopes.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-scopes.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-scopes.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAKhC,QAAA,uBAAuB,GAAG,YAAY,CAAC;AAuC7C,MAAM,UAAU,GAAG,CAAC,MAAgB,EAAE,EAAE;IAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IACD,OAAO,IAAA,oBAAW,EAAC,+BAAuB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC,CAAC;AAPW,QAAA,UAAU,cAOrB","sourcesContent":["import { SetMetadata } from '@nestjs/common';\n\n/**\n * Metadata key for storing required OAuth scopes\n */\nexport const MCP_SCOPES_METADATA_KEY = 'mcp:scopes';\n\n/**\n * Decorator to specify OAuth scopes required to access a tool.\n *\n * Use this to restrict tool access based on OAuth permissions (Scopes).\n * When applied, it requires the authenticated user to have\n * ALL specified scopes in their JWT token.\n *\n * Can be combined with @PublicTool() to create tools that work better with authentication\n * but are also accessible anonymously.\n *\n * @param scopes - Array of required OAuth scope strings\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class MyTools {\n * // Requires 'admin' and 'write' scopes\n * @Tool({ name: 'delete-user', description: 'Delete a user' })\n * @ToolScopes(['admin', 'write'])\n * async deleteUser(args, ctx, req: McpRequestWithUser) {\n * // Only users with both 'admin' AND 'write' scopes can call this\n * return { content: [{ type: 'text', text: 'User deleted' }] };\n * }\n *\n * // Optional auth - works better with 'premium' scope\n * @Tool({ name: 'search', description: 'Search content' })\n * @PublicTool()\n * @ToolScopes(['premium'])\n * async search(args, ctx, req: McpRequestWithUser) {\n * if (req.user?.scopes?.includes('premium')) {\n * return { content: [{ type: 'text', text: 'AI-powered results' }] };\n * }\n * return { content: [{ type: 'text', text: 'Basic results' }] };\n * }\n * }\n * ```\n */\nexport const ToolScopes = (scopes: string[]) => {\n if (!Array.isArray(scopes) || scopes.length === 0) {\n throw new Error(\n '@ToolScopes() requires a non-empty array of scope strings',\n );\n }\n return SetMetadata(MCP_SCOPES_METADATA_KEY, scopes);\n};\n"]}
@@ -1,5 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  import { ToolAnnotations as SdkToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
3
+ export type SecurityScheme = {
4
+ type: 'noauth';
5
+ } | {
6
+ type: 'oauth2';
7
+ scopes?: string[];
8
+ };
3
9
  export interface ToolMetadata {
4
10
  name: string;
5
11
  description: string;
@@ -7,6 +13,10 @@ export interface ToolMetadata {
7
13
  outputSchema?: z.ZodTypeAny;
8
14
  annotations?: SdkToolAnnotations;
9
15
  _meta?: Record<string, any>;
16
+ securitySchemes?: SecurityScheme[];
17
+ isPublic?: boolean;
18
+ requiredScopes?: string[];
19
+ requiredRoles?: string[];
10
20
  }
11
21
  export interface ToolAnnotations extends SdkToolAnnotations {
12
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/tool.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,IAAI,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE3F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC5B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC7B;AAGD,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;CAAG;AAE9D,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC5B,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC7B;AAWD,eAAO,MAAM,IAAI,GAAI,SAAS,WAAW,qDAMxC,CAAC"}
1
+ {"version":3,"file":"tool.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/tool.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,IAAI,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAK3F,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC5B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE5B,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAGD,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;CAAG;AAE9D,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;IAC5B,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC7B;AAWD,eAAO,MAAM,IAAI,GAAI,SAAS,WAAW,qDAMxC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/tool.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAC7C,2CAAoD;AACpD,6BAAwB;AAiCjB,MAAM,IAAI,GAAG,CAAC,OAAoB,EAAE,EAAE;IAC3C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO,CAAC,UAAU,GAAG,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,IAAA,oBAAW,EAAC,iCAAqB,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC,CAAC;AANW,QAAA,IAAI,QAMf","sourcesContent":["import { SetMetadata } from '@nestjs/common';\nimport { MCP_TOOL_METADATA_KEY } from './constants';\nimport { z } from 'zod';\nimport { ToolAnnotations as SdkToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\n\nexport interface ToolMetadata {\n name: string;\n description: string;\n parameters?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n annotations?: SdkToolAnnotations;\n _meta?: Record<string, any>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface ToolAnnotations extends SdkToolAnnotations {}\n\nexport interface ToolOptions {\n name?: string;\n description?: string;\n parameters?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n annotations?: ToolAnnotations;\n _meta?: Record<string, any>;\n}\n\n/**\n * Decorator that marks a controller method as an MCP tool.\n * @param {Object} options - The options for the decorator\n * @param {string} options.name - The name of the tool\n * @param {string} options.description - The description of the tool\n * @param {z.ZodTypeAny} [options.parameters] - The parameters of the tool\n * @param {z.ZodTypeAny} [options.outputSchema] - The output schema of the tool\n * @returns {MethodDecorator} - The decorator\n */\nexport const Tool = (options: ToolOptions) => {\n if (options.parameters === undefined) {\n options.parameters = z.object({});\n }\n\n return SetMetadata(MCP_TOOL_METADATA_KEY, options);\n};\n"]}
1
+ {"version":3,"file":"tool.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/tool.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAC7C,2CAAoD;AACpD,6BAAwB;AA6CjB,MAAM,IAAI,GAAG,CAAC,OAAoB,EAAE,EAAE;IAC3C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO,CAAC,UAAU,GAAG,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,IAAA,oBAAW,EAAC,iCAAqB,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC,CAAC;AANW,QAAA,IAAI,QAMf","sourcesContent":["import { SetMetadata } from '@nestjs/common';\nimport { MCP_TOOL_METADATA_KEY } from './constants';\nimport { z } from 'zod';\nimport { ToolAnnotations as SdkToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Security scheme type for MCP tools\n */\nexport type SecurityScheme =\n | { type: 'noauth' }\n | { type: 'oauth2'; scopes?: string[] };\n\nexport interface ToolMetadata {\n name: string;\n description: string;\n parameters?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n annotations?: SdkToolAnnotations;\n _meta?: Record<string, any>;\n // Security-related metadata\n securitySchemes?: SecurityScheme[];\n isPublic?: boolean;\n requiredScopes?: string[];\n requiredRoles?: string[];\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface ToolAnnotations extends SdkToolAnnotations {}\n\nexport interface ToolOptions {\n name?: string;\n description?: string;\n parameters?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n annotations?: ToolAnnotations;\n _meta?: Record<string, any>;\n}\n\n/**\n * Decorator that marks a controller method as an MCP tool.\n * @param {Object} options - The options for the decorator\n * @param {string} options.name - The name of the tool\n * @param {string} options.description - The description of the tool\n * @param {z.ZodTypeAny} [options.parameters] - The parameters of the tool\n * @param {z.ZodTypeAny} [options.outputSchema] - The output schema of the tool\n * @returns {MethodDecorator} - The decorator\n */\nexport const Tool = (options: ToolOptions) => {\n if (options.parameters === undefined) {\n options.parameters = z.object({});\n }\n\n return SetMetadata(MCP_TOOL_METADATA_KEY, options);\n};\n"]}
@@ -17,6 +17,7 @@ export interface McpOptions {
17
17
  globalApiPrefix?: never;
18
18
  apiPrefix?: string;
19
19
  guards?: Type<CanActivate>[];
20
+ allowUnauthenticatedAccess?: boolean;
20
21
  decorators?: ClassDecorator[];
21
22
  sse?: {
22
23
  pingEnabled?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-options.interface.d.ts","sourceRoot":"","sources":["../../../src/mcp/interfaces/mcp-options.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEnE,oBAAY,gBAAgB;IAC1B,GAAG,QAAQ;IACX,eAAe,oBAAoB;IACnC,KAAK,UAAU;CAChB;AAED,MAAM,WAAW,UAAU;IAGzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,SAAS,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,GAAG,CAAC,EAAE;QACJ,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,cAAc,CAAC,EAAE;QACf,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;QAIlC,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;IAOF,OAAO,CAAC,EACJ,KAAK,GACL;QACE,KAAK,EAAE,CAAC,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,EAAE,CAAC;KAC3D,CAAC;CACP;AAGD,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;CAChE;AAED,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC;IAC5E,WAAW,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;IAC5E,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,cAAc,CAAC,EAAE,GAAG,EAAE,CAAC;CACxB"}
1
+ {"version":3,"file":"mcp-options.interface.d.ts","sourceRoot":"","sources":["../../../src/mcp/interfaces/mcp-options.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEnE,oBAAY,gBAAgB;IAC1B,GAAG,QAAQ;IACX,eAAe,oBAAoB;IACnC,KAAK,UAAU;CAChB;AAED,MAAM,WAAW,UAAU;IAGzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,SAAS,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;IAgB7B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,GAAG,CAAC,EAAE;QACJ,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,cAAc,CAAC,EAAE;QACf,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;QAIlC,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;IAOF,OAAO,CAAC,EACJ,KAAK,GACL;QACE,KAAK,EAAE,CAAC,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,EAAE,CAAC;KAC3D,CAAC;CACP;AAGD,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;CAChE;AAED,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC;IAC5E,WAAW,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;IAC5E,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,cAAc,CAAC,EAAE,GAAG,EAAE,CAAC;CACxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-options.interface.js","sourceRoot":"","sources":["../../../src/mcp/interfaces/mcp-options.interface.ts"],"names":[],"mappings":";;;AAGA,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,+BAAW,CAAA;IACX,uDAAmC,CAAA;IACnC,mCAAe,CAAA;AACjB,CAAC,EAJW,gBAAgB,gCAAhB,gBAAgB,QAI3B","sourcesContent":["import { ServerCapabilities } from '@modelcontextprotocol/sdk/types.js';\nimport { CanActivate, ModuleMetadata, Type } from '@nestjs/common';\n\nexport enum McpTransportType {\n SSE = 'sse',\n STREAMABLE_HTTP = 'streamable-http',\n STDIO = 'stdio',\n}\n\nexport interface McpOptions {\n // When and if, additional properties are introduced in ServerOptions or ServerInfo,\n // consider deprecating these fields in favor of using ServerOptions and ServerInfo directly.\n name: string;\n version: string;\n capabilities?: ServerCapabilities;\n instructions?: string;\n\n transport?: McpTransportType | McpTransportType[];\n sseEndpoint?: string;\n messagesEndpoint?: string;\n mcpEndpoint?: string;\n /**\n * @deprecated Use `app.setGlobalPrefix()` for global api prefix. Use apiPrefix to attach a prefix to the handshake.\n */\n globalApiPrefix?: never;\n apiPrefix?: string;\n guards?: Type<CanActivate>[];\n decorators?: ClassDecorator[];\n sse?: {\n pingEnabled?: boolean;\n pingIntervalMs?: number;\n };\n streamableHttp?: {\n enableJsonResponse?: boolean;\n sessionIdGenerator?: () => string;\n /**\n * @experimental: The current implementation does not fully comply with the MCP Specification.\n */\n statelessMode?: boolean;\n };\n /**\n * Configure logging for the MCP module.\n * - `false` to disable all MCP logging\n * - `{ level: LogLevel[] }` to specify which log levels to show\n * - `undefined` (default) to use standard NestJS logging\n */\n logging?:\n | false\n | {\n level: ('log' | 'error' | 'warn' | 'debug' | 'verbose')[];\n };\n}\n\n// Async variant omits transport since controllers are not auto-registered in forRootAsync\nexport type McpAsyncOptions = Omit<McpOptions, 'transport'>;\n\nexport interface McpOptionsFactory {\n createMcpOptions(): Promise<McpAsyncOptions> | McpAsyncOptions;\n}\n\nexport interface McpModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n useExisting?: Type<McpOptionsFactory>;\n useClass?: Type<McpOptionsFactory>;\n useFactory?: (...args: any[]) => Promise<McpAsyncOptions> | McpAsyncOptions;\n inject?: any[];\n extraProviders?: any[]; // allow user to provide additional providers in async mode\n}\n"]}
1
+ {"version":3,"file":"mcp-options.interface.js","sourceRoot":"","sources":["../../../src/mcp/interfaces/mcp-options.interface.ts"],"names":[],"mappings":";;;AAGA,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,+BAAW,CAAA;IACX,uDAAmC,CAAA;IACnC,mCAAe,CAAA;AACjB,CAAC,EAJW,gBAAgB,gCAAhB,gBAAgB,QAI3B","sourcesContent":["import { ServerCapabilities } from '@modelcontextprotocol/sdk/types.js';\nimport { CanActivate, ModuleMetadata, Type } from '@nestjs/common';\n\nexport enum McpTransportType {\n SSE = 'sse',\n STREAMABLE_HTTP = 'streamable-http',\n STDIO = 'stdio',\n}\n\nexport interface McpOptions {\n // When and if, additional properties are introduced in ServerOptions or ServerInfo,\n // consider deprecating these fields in favor of using ServerOptions and ServerInfo directly.\n name: string;\n version: string;\n capabilities?: ServerCapabilities;\n instructions?: string;\n\n transport?: McpTransportType | McpTransportType[];\n sseEndpoint?: string;\n messagesEndpoint?: string;\n mcpEndpoint?: string;\n /**\n * @deprecated Use `app.setGlobalPrefix()` for global api prefix. Use apiPrefix to attach a prefix to the handshake.\n */\n globalApiPrefix?: never;\n apiPrefix?: string;\n guards?: Type<CanActivate>[];\n /**\n * Allow unauthenticated sessions to connect and access @PublicTool() tools.\n *\n * When true (freemium mode):\n * - Unauthenticated requests are allowed through guards\n * - Can access tools marked with @PublicTool()\n * - Must authenticate to access protected tools (based on scopes/roles)\n *\n * When false or undefined (standard OAuth flow - default):\n * - Unauthenticated requests receive 401 response\n * - Triggers MCP OAuth authorization flow\n * - All tools require authentication\n *\n * @default false\n */\n allowUnauthenticatedAccess?: boolean;\n decorators?: ClassDecorator[];\n sse?: {\n pingEnabled?: boolean;\n pingIntervalMs?: number;\n };\n streamableHttp?: {\n enableJsonResponse?: boolean;\n sessionIdGenerator?: () => string;\n /**\n * @experimental: The current implementation does not fully comply with the MCP Specification.\n */\n statelessMode?: boolean;\n };\n /**\n * Configure logging for the MCP module.\n * - `false` to disable all MCP logging\n * - `{ level: LogLevel[] }` to specify which log levels to show\n * - `undefined` (default) to use standard NestJS logging\n */\n logging?:\n | false\n | {\n level: ('log' | 'error' | 'warn' | 'debug' | 'verbose')[];\n };\n}\n\n// Async variant omits transport since controllers are not auto-registered in forRootAsync\nexport type McpAsyncOptions = Omit<McpOptions, 'transport'>;\n\nexport interface McpOptionsFactory {\n createMcpOptions(): Promise<McpAsyncOptions> | McpAsyncOptions;\n}\n\nexport interface McpModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n useExisting?: Type<McpOptionsFactory>;\n useClass?: Type<McpOptionsFactory>;\n useFactory?: (...args: any[]) => Promise<McpAsyncOptions> | McpAsyncOptions;\n inject?: any[];\n extraProviders?: any[]; // allow user to provide additional providers in async mode\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.module.d.ts","sourceRoot":"","sources":["../../src/mcp/mcp.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA0B,MAAM,gBAAgB,CAAC;AAGvE,OAAO,KAAK,EACV,UAAU,EACV,qBAAqB,EAGtB,MAAM,cAAc,CAAC;AAatB,qBAIa,SAAS;IAIpB,QAAQ,CAAC,aAAa,QAAQ;IAE9B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,aAAa;IAoDlD,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,qBAAqB,GAAG,aAAa;IA8BlE,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAgDnC,OAAO,CAAC,MAAM,CAAC,6BAA6B;IA2B5C,OAAO,CAAC,MAAM,CAAC,4BAA4B;IA4C3C,OAAO,CAAC,MAAM,CAAC,0BAA0B;CAuB1C"}
1
+ {"version":3,"file":"mcp.module.d.ts","sourceRoot":"","sources":["../../src/mcp/mcp.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA0B,MAAM,gBAAgB,CAAC;AAGvE,OAAO,KAAK,EACV,UAAU,EACV,qBAAqB,EAGtB,MAAM,cAAc,CAAC;AActB,qBAIa,SAAS;IAIpB,QAAQ,CAAC,aAAa,QAAQ;IAE9B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,aAAa;IAoDlD,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,qBAAqB,GAAG,aAAa;IA+BlE,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAgDnC,OAAO,CAAC,MAAM,CAAC,6BAA6B;IA2B5C,OAAO,CAAC,MAAM,CAAC,4BAA4B;IA4C3C,OAAO,CAAC,MAAM,CAAC,0BAA0B;CAwB1C"}
@@ -16,6 +16,7 @@ const mcp_registry_service_1 = require("./services/mcp-registry.service");
16
16
  const mcp_sse_service_1 = require("./services/mcp-sse.service");
17
17
  const mcp_streamable_http_service_1 = require("./services/mcp-streamable-http.service");
18
18
  const sse_ping_service_1 = require("./services/sse-ping.service");
19
+ const tool_authorization_service_1 = require("./services/tool-authorization.service");
19
20
  const sse_controller_factory_1 = require("./transport/sse.controller.factory");
20
21
  const stdio_service_1 = require("./transport/stdio.service");
21
22
  const streamable_http_controller_factory_1 = require("./transport/streamable-http.controller.factory");
@@ -71,6 +72,7 @@ let McpModule = McpModule_1 = class McpModule {
71
72
  },
72
73
  mcp_registry_service_1.McpRegistryService,
73
74
  mcp_executor_service_1.McpExecutorService,
75
+ tool_authorization_service_1.ToolAuthorizationService,
74
76
  sse_ping_service_1.SsePingService,
75
77
  mcp_sse_service_1.McpSseService,
76
78
  mcp_streamable_http_service_1.McpStreamableHttpService,
@@ -184,6 +186,7 @@ let McpModule = McpModule_1 = class McpModule {
184
186
  },
185
187
  mcp_registry_service_1.McpRegistryService,
186
188
  mcp_executor_service_1.McpExecutorService,
189
+ tool_authorization_service_1.ToolAuthorizationService,
187
190
  sse_ping_service_1.SsePingService,
188
191
  mcp_sse_service_1.McpSseService,
189
192
  mcp_streamable_http_service_1.McpStreamableHttpService,
@@ -196,7 +199,7 @@ exports.McpModule = McpModule;
196
199
  exports.McpModule = McpModule = McpModule_1 = __decorate([
197
200
  (0, common_1.Module)({
198
201
  imports: [core_1.DiscoveryModule],
199
- providers: [mcp_registry_service_1.McpRegistryService, mcp_executor_service_1.McpExecutorService],
202
+ providers: [mcp_registry_service_1.McpRegistryService, mcp_executor_service_1.McpExecutorService, tool_authorization_service_1.ToolAuthorizationService],
200
203
  })
201
204
  ], McpModule);
202
205
  //# sourceMappingURL=mcp.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.module.js","sourceRoot":"","sources":["../../src/mcp/mcp.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { DynamicModule, Module, Provider, Type } from '@nestjs/common';\nimport { DiscoveryModule } from '@nestjs/core';\nimport { McpTransportType } from './interfaces';\nimport type {\n McpOptions,\n McpModuleAsyncOptions,\n McpOptionsFactory,\n McpAsyncOptions,\n} from './interfaces';\nimport { McpExecutorService } from './services/mcp-executor.service';\nimport { McpRegistryService } from './services/mcp-registry.service';\nimport { McpSseService } from './services/mcp-sse.service';\nimport { McpStreamableHttpService } from './services/mcp-streamable-http.service';\nimport { SsePingService } from './services/sse-ping.service';\nimport { createSseController } from './transport/sse.controller.factory';\nimport { StdioService } from './transport/stdio.service';\nimport { createStreamableHttpController } from './transport/streamable-http.controller.factory';\nimport { normalizeEndpoint } from './utils/normalize-endpoint';\n\nlet instanceIdCounter = 0;\n\n@Module({\n imports: [DiscoveryModule],\n providers: [McpRegistryService, McpExecutorService],\n})\nexport class McpModule {\n /**\n * To avoid import circular dependency issues, we use a marker property.\n */\n readonly __isMcpModule = true;\n\n static forRoot(options: McpOptions): DynamicModule {\n const defaultOptions: Partial<McpOptions> = {\n transport: [\n McpTransportType.SSE,\n McpTransportType.STREAMABLE_HTTP,\n McpTransportType.STDIO,\n ],\n sseEndpoint: 'sse',\n messagesEndpoint: 'messages',\n mcpEndpoint: 'mcp',\n guards: [],\n decorators: [],\n streamableHttp: {\n enableJsonResponse: true,\n sessionIdGenerator: undefined,\n statelessMode: true,\n },\n sse: {\n pingEnabled: true,\n pingIntervalMs: 30000,\n },\n };\n const mergedOptions = { ...defaultOptions, ...options } as McpOptions;\n mergedOptions.sseEndpoint = normalizeEndpoint(mergedOptions.sseEndpoint);\n mergedOptions.messagesEndpoint = normalizeEndpoint(\n mergedOptions.messagesEndpoint,\n );\n mergedOptions.mcpEndpoint = normalizeEndpoint(mergedOptions.mcpEndpoint);\n\n const moduleId = `mcp-module-${instanceIdCounter++}`;\n const providers = this.createProvidersFromOptions(mergedOptions, moduleId);\n const controllers = this.createControllersFromOptions(mergedOptions);\n return {\n module: McpModule,\n controllers,\n providers,\n exports: [McpRegistryService, McpSseService, McpStreamableHttpService],\n };\n }\n\n /**\n * Asynchronous variant of forRoot. Controllers are NOT auto-registered here because\n * they must be declared synchronously at module definition time. This keeps the\n * API explicit: when using forRootAsync, you are responsible for creating and\n * registering any transport controllers (e.g. via createSseController / createStreamableHttpController).\n *\n * The exposed async options intentionally omit the `transport` property. Transport\n * selection only influences automatic controller creation (which does not occur here)\n * and STDIO auto-start. If you need STDIO with forRootAsync, manually instantiate\n * and bootstrap it (e.g. by importing a module that injects StdioService) or add\n * an explicit provider that sets options.transport before use.\n */\n static forRootAsync(options: McpModuleAsyncOptions): DynamicModule {\n const moduleId = `mcp-module-${instanceIdCounter++}`;\n const asyncProviders = this.createAsyncProviders(options);\n const baseProviders: Provider[] = [\n {\n provide: 'MCP_MODULE_ID',\n useValue: moduleId,\n },\n McpRegistryService,\n McpExecutorService,\n SsePingService,\n McpSseService,\n McpStreamableHttpService,\n StdioService,\n ];\n\n return {\n module: McpModule,\n imports: options.imports ?? [],\n // No automatic controllers in async mode\n controllers: [],\n providers: [\n ...asyncProviders,\n ...baseProviders,\n ...(options.extraProviders ?? []),\n ],\n exports: [McpRegistryService, McpSseService, McpStreamableHttpService],\n };\n }\n\n private static createAsyncProviders(\n options: McpModuleAsyncOptions,\n ): Provider[] {\n if (options.useFactory) {\n return [\n {\n provide: 'MCP_OPTIONS',\n useFactory: async (...args: unknown[]) => {\n const resolved: McpAsyncOptions = await options.useFactory!(\n ...args,\n );\n return this.mergeAndNormalizeAsyncOptions(resolved);\n },\n inject: options.inject ?? [],\n },\n ];\n }\n\n // useClass / useExisting path\n const inject: any[] = [];\n let optionsFactoryProvider: Provider | undefined;\n\n if (options.useExisting || options.useClass) {\n const useExisting = options.useExisting || options.useClass!;\n inject.push(useExisting);\n if (options.useClass) {\n optionsFactoryProvider = {\n provide: options.useClass,\n useClass: options.useClass,\n } as Provider;\n }\n\n return [\n ...(optionsFactoryProvider ? [optionsFactoryProvider] : []),\n {\n provide: 'MCP_OPTIONS',\n useFactory: async (factory: McpOptionsFactory) => {\n const resolved = await factory.createMcpOptions();\n return this.mergeAndNormalizeAsyncOptions(resolved);\n },\n inject,\n },\n ];\n }\n\n throw new Error('Invalid McpModuleAsyncOptions configuration.');\n }\n\n private static mergeAndNormalizeAsyncOptions(\n resolved: McpAsyncOptions,\n ): McpOptions {\n const defaultOptions: Partial<McpOptions> = {\n sseEndpoint: 'sse',\n messagesEndpoint: 'messages',\n mcpEndpoint: 'mcp',\n guards: [],\n decorators: [],\n streamableHttp: {\n enableJsonResponse: true,\n sessionIdGenerator: undefined,\n statelessMode: true,\n },\n sse: {\n pingEnabled: true,\n pingIntervalMs: 30000,\n },\n };\n // Note: transport intentionally omitted\n const merged = { ...defaultOptions, ...resolved } as McpOptions;\n merged.sseEndpoint = normalizeEndpoint(merged.sseEndpoint);\n merged.messagesEndpoint = normalizeEndpoint(merged.messagesEndpoint);\n merged.mcpEndpoint = normalizeEndpoint(merged.mcpEndpoint);\n return merged;\n }\n\n private static createControllersFromOptions(\n options: McpOptions,\n ): Type<any>[] {\n const sseEndpoint = options.sseEndpoint ?? 'sse';\n const messagesEndpoint = options.messagesEndpoint ?? 'messages';\n const mcpEndpoint = options.mcpEndpoint ?? 'mcp';\n const guards = options.guards ?? [];\n const transports = Array.isArray(options.transport)\n ? options.transport\n : [options.transport ?? McpTransportType.SSE];\n const controllers: Type<any>[] = [];\n const decorators = options.decorators ?? [];\n const apiPrefix = options.apiPrefix ?? '';\n\n if (transports.includes(McpTransportType.SSE)) {\n const sseController = createSseController(\n sseEndpoint,\n messagesEndpoint,\n apiPrefix,\n guards,\n decorators,\n options,\n );\n controllers.push(sseController);\n }\n\n if (transports.includes(McpTransportType.STREAMABLE_HTTP)) {\n const streamableHttpController = createStreamableHttpController(\n mcpEndpoint,\n apiPrefix,\n guards,\n decorators,\n options,\n );\n controllers.push(streamableHttpController);\n }\n\n if (transports.includes(McpTransportType.STDIO)) {\n // STDIO transport is handled by injectable StdioService, no controller\n }\n\n return controllers;\n }\n\n private static createProvidersFromOptions(\n options: McpOptions,\n moduleId: string,\n ): Provider[] {\n const providers: Provider[] = [\n {\n provide: 'MCP_OPTIONS',\n useValue: options,\n },\n {\n provide: 'MCP_MODULE_ID',\n useValue: moduleId,\n },\n McpRegistryService,\n McpExecutorService,\n SsePingService,\n McpSseService,\n McpStreamableHttpService,\n StdioService,\n ];\n\n return providers;\n }\n}\n"]}
1
+ {"version":3,"file":"mcp.module.js","sourceRoot":"","sources":["../../src/mcp/mcp.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { DynamicModule, Module, Provider, Type } from '@nestjs/common';\nimport { DiscoveryModule } from '@nestjs/core';\nimport { McpTransportType } from './interfaces';\nimport type {\n McpOptions,\n McpModuleAsyncOptions,\n McpOptionsFactory,\n McpAsyncOptions,\n} from './interfaces';\nimport { McpExecutorService } from './services/mcp-executor.service';\nimport { McpRegistryService } from './services/mcp-registry.service';\nimport { McpSseService } from './services/mcp-sse.service';\nimport { McpStreamableHttpService } from './services/mcp-streamable-http.service';\nimport { SsePingService } from './services/sse-ping.service';\nimport { ToolAuthorizationService } from './services/tool-authorization.service';\nimport { createSseController } from './transport/sse.controller.factory';\nimport { StdioService } from './transport/stdio.service';\nimport { createStreamableHttpController } from './transport/streamable-http.controller.factory';\nimport { normalizeEndpoint } from './utils/normalize-endpoint';\n\nlet instanceIdCounter = 0;\n\n@Module({\n imports: [DiscoveryModule],\n providers: [McpRegistryService, McpExecutorService, ToolAuthorizationService],\n})\nexport class McpModule {\n /**\n * To avoid import circular dependency issues, we use a marker property.\n */\n readonly __isMcpModule = true;\n\n static forRoot(options: McpOptions): DynamicModule {\n const defaultOptions: Partial<McpOptions> = {\n transport: [\n McpTransportType.SSE,\n McpTransportType.STREAMABLE_HTTP,\n McpTransportType.STDIO,\n ],\n sseEndpoint: 'sse',\n messagesEndpoint: 'messages',\n mcpEndpoint: 'mcp',\n guards: [],\n decorators: [],\n streamableHttp: {\n enableJsonResponse: true,\n sessionIdGenerator: undefined,\n statelessMode: true,\n },\n sse: {\n pingEnabled: true,\n pingIntervalMs: 30000,\n },\n };\n const mergedOptions = { ...defaultOptions, ...options } as McpOptions;\n mergedOptions.sseEndpoint = normalizeEndpoint(mergedOptions.sseEndpoint);\n mergedOptions.messagesEndpoint = normalizeEndpoint(\n mergedOptions.messagesEndpoint,\n );\n mergedOptions.mcpEndpoint = normalizeEndpoint(mergedOptions.mcpEndpoint);\n\n const moduleId = `mcp-module-${instanceIdCounter++}`;\n const providers = this.createProvidersFromOptions(mergedOptions, moduleId);\n const controllers = this.createControllersFromOptions(mergedOptions);\n return {\n module: McpModule,\n controllers,\n providers,\n exports: [McpRegistryService, McpSseService, McpStreamableHttpService],\n };\n }\n\n /**\n * Asynchronous variant of forRoot. Controllers are NOT auto-registered here because\n * they must be declared synchronously at module definition time. This keeps the\n * API explicit: when using forRootAsync, you are responsible for creating and\n * registering any transport controllers (e.g. via createSseController / createStreamableHttpController).\n *\n * The exposed async options intentionally omit the `transport` property. Transport\n * selection only influences automatic controller creation (which does not occur here)\n * and STDIO auto-start. If you need STDIO with forRootAsync, manually instantiate\n * and bootstrap it (e.g. by importing a module that injects StdioService) or add\n * an explicit provider that sets options.transport before use.\n */\n static forRootAsync(options: McpModuleAsyncOptions): DynamicModule {\n const moduleId = `mcp-module-${instanceIdCounter++}`;\n const asyncProviders = this.createAsyncProviders(options);\n const baseProviders: Provider[] = [\n {\n provide: 'MCP_MODULE_ID',\n useValue: moduleId,\n },\n McpRegistryService,\n McpExecutorService,\n ToolAuthorizationService,\n SsePingService,\n McpSseService,\n McpStreamableHttpService,\n StdioService,\n ];\n\n return {\n module: McpModule,\n imports: options.imports ?? [],\n // No automatic controllers in async mode\n controllers: [],\n providers: [\n ...asyncProviders,\n ...baseProviders,\n ...(options.extraProviders ?? []),\n ],\n exports: [McpRegistryService, McpSseService, McpStreamableHttpService],\n };\n }\n\n private static createAsyncProviders(\n options: McpModuleAsyncOptions,\n ): Provider[] {\n if (options.useFactory) {\n return [\n {\n provide: 'MCP_OPTIONS',\n useFactory: async (...args: unknown[]) => {\n const resolved: McpAsyncOptions = await options.useFactory!(\n ...args,\n );\n return this.mergeAndNormalizeAsyncOptions(resolved);\n },\n inject: options.inject ?? [],\n },\n ];\n }\n\n // useClass / useExisting path\n const inject: any[] = [];\n let optionsFactoryProvider: Provider | undefined;\n\n if (options.useExisting || options.useClass) {\n const useExisting = options.useExisting || options.useClass!;\n inject.push(useExisting);\n if (options.useClass) {\n optionsFactoryProvider = {\n provide: options.useClass,\n useClass: options.useClass,\n } as Provider;\n }\n\n return [\n ...(optionsFactoryProvider ? [optionsFactoryProvider] : []),\n {\n provide: 'MCP_OPTIONS',\n useFactory: async (factory: McpOptionsFactory) => {\n const resolved = await factory.createMcpOptions();\n return this.mergeAndNormalizeAsyncOptions(resolved);\n },\n inject,\n },\n ];\n }\n\n throw new Error('Invalid McpModuleAsyncOptions configuration.');\n }\n\n private static mergeAndNormalizeAsyncOptions(\n resolved: McpAsyncOptions,\n ): McpOptions {\n const defaultOptions: Partial<McpOptions> = {\n sseEndpoint: 'sse',\n messagesEndpoint: 'messages',\n mcpEndpoint: 'mcp',\n guards: [],\n decorators: [],\n streamableHttp: {\n enableJsonResponse: true,\n sessionIdGenerator: undefined,\n statelessMode: true,\n },\n sse: {\n pingEnabled: true,\n pingIntervalMs: 30000,\n },\n };\n // Note: transport intentionally omitted\n const merged = { ...defaultOptions, ...resolved } as McpOptions;\n merged.sseEndpoint = normalizeEndpoint(merged.sseEndpoint);\n merged.messagesEndpoint = normalizeEndpoint(merged.messagesEndpoint);\n merged.mcpEndpoint = normalizeEndpoint(merged.mcpEndpoint);\n return merged;\n }\n\n private static createControllersFromOptions(\n options: McpOptions,\n ): Type<any>[] {\n const sseEndpoint = options.sseEndpoint ?? 'sse';\n const messagesEndpoint = options.messagesEndpoint ?? 'messages';\n const mcpEndpoint = options.mcpEndpoint ?? 'mcp';\n const guards = options.guards ?? [];\n const transports = Array.isArray(options.transport)\n ? options.transport\n : [options.transport ?? McpTransportType.SSE];\n const controllers: Type<any>[] = [];\n const decorators = options.decorators ?? [];\n const apiPrefix = options.apiPrefix ?? '';\n\n if (transports.includes(McpTransportType.SSE)) {\n const sseController = createSseController(\n sseEndpoint,\n messagesEndpoint,\n apiPrefix,\n guards,\n decorators,\n options,\n );\n controllers.push(sseController);\n }\n\n if (transports.includes(McpTransportType.STREAMABLE_HTTP)) {\n const streamableHttpController = createStreamableHttpController(\n mcpEndpoint,\n apiPrefix,\n guards,\n decorators,\n options,\n );\n controllers.push(streamableHttpController);\n }\n\n if (transports.includes(McpTransportType.STDIO)) {\n // STDIO transport is handled by injectable StdioService, no controller\n }\n\n return controllers;\n }\n\n private static createProvidersFromOptions(\n options: McpOptions,\n moduleId: string,\n ): Provider[] {\n const providers: Provider[] = [\n {\n provide: 'MCP_OPTIONS',\n useValue: options,\n },\n {\n provide: 'MCP_MODULE_ID',\n useValue: moduleId,\n },\n McpRegistryService,\n McpExecutorService,\n ToolAuthorizationService,\n SsePingService,\n McpSseService,\n McpStreamableHttpService,\n StdioService,\n ];\n\n return providers;\n }\n}\n"]}
@@ -3,10 +3,14 @@ import { ModuleRef } from '@nestjs/core';
3
3
  import { McpRegistryService } from '../mcp-registry.service';
4
4
  import { McpHandlerBase } from './mcp-handler.base';
5
5
  import { HttpRequest } from '../../interfaces/http-adapter.interface';
6
- import { McpOptions } from '../../interfaces';
6
+ import { ToolAuthorizationService } from '../tool-authorization.service';
7
+ import { McpOptions } from '../../interfaces/mcp-options.interface';
7
8
  export declare class McpToolsHandler extends McpHandlerBase {
8
9
  private readonly mcpModuleId;
9
- constructor(moduleRef: ModuleRef, registry: McpRegistryService, mcpModuleId: string, options?: McpOptions);
10
+ private readonly options;
11
+ private readonly authService;
12
+ private readonly moduleHasGuards;
13
+ constructor(moduleRef: ModuleRef, registry: McpRegistryService, mcpModuleId: string, options: McpOptions, authService: ToolAuthorizationService);
10
14
  private buildDefaultContentBlock;
11
15
  private formatToolResult;
12
16
  registerHandlers(mcpServer: McpServer, httpRequest: HttpRequest): void;
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-tools.handler.d.ts","sourceRoot":"","sources":["../../../../src/mcp/services/handlers/mcp-tools.handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,qBACa,eAAgB,SAAQ,cAAc;IAItB,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAFrD,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,kBAAkB,EACc,WAAW,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE,UAAU;IAKzD,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,gBAAgB;IAwBxB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW;CA4HhE"}
1
+ {"version":3,"file":"mcp-tools.handler.d.ts","sourceRoot":"","sources":["../../../../src/mcp/services/handlers/mcp-tools.handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAEtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEpE,qBACa,eAAgB,SAAQ,cAAc;IAMtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAP9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;gBAGxC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,kBAAkB,EACc,WAAW,EAAE,MAAM,EACrB,OAAO,EAAE,UAAU,EAC1C,WAAW,EAAE,wBAAwB;IAOxD,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,gBAAgB;IAwBxB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW;CA4KhE"}