@rekog/mcp-nest 1.9.4 → 1.9.6

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 (128) hide show
  1. package/README.md +5 -1
  2. package/dist/mcp/decorators/prompt.decorator.d.ts +1 -2
  3. package/dist/mcp/decorators/prompt.decorator.d.ts.map +1 -1
  4. package/dist/mcp/decorators/prompt.decorator.js.map +1 -1
  5. package/dist/mcp/index.d.ts +2 -2
  6. package/dist/mcp/index.d.ts.map +1 -1
  7. package/dist/mcp/index.js +2 -2
  8. package/dist/mcp/index.js.map +1 -1
  9. package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts +11 -0
  10. package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts.map +1 -0
  11. package/dist/mcp/interfaces/dynamic-prompt.interface.js +3 -0
  12. package/dist/mcp/interfaces/dynamic-prompt.interface.js.map +1 -0
  13. package/dist/mcp/interfaces/dynamic-resource.interface.d.ts +11 -0
  14. package/dist/mcp/interfaces/dynamic-resource.interface.d.ts.map +1 -0
  15. package/dist/mcp/interfaces/dynamic-resource.interface.js +3 -0
  16. package/dist/mcp/interfaces/dynamic-resource.interface.js.map +1 -0
  17. package/dist/mcp/interfaces/dynamic-tool.interface.js.map +1 -1
  18. package/dist/mcp/interfaces/index.d.ts +2 -0
  19. package/dist/mcp/interfaces/index.d.ts.map +1 -1
  20. package/dist/mcp/interfaces/index.js.map +1 -1
  21. package/dist/mcp/mcp.module.d.ts.map +1 -1
  22. package/dist/mcp/mcp.module.js +15 -11
  23. package/dist/mcp/mcp.module.js.map +1 -1
  24. package/dist/mcp/services/handlers/mcp-handler.base.d.ts +4 -4
  25. package/dist/mcp/services/handlers/mcp-handler.base.d.ts.map +1 -1
  26. package/dist/mcp/services/handlers/mcp-handler.base.js.map +1 -1
  27. package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts +2 -2
  28. package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts.map +1 -1
  29. package/dist/mcp/services/handlers/mcp-prompts.handler.js +13 -3
  30. package/dist/mcp/services/handlers/mcp-prompts.handler.js.map +1 -1
  31. package/dist/mcp/services/handlers/mcp-resources.handler.d.ts +2 -2
  32. package/dist/mcp/services/handlers/mcp-resources.handler.d.ts.map +1 -1
  33. package/dist/mcp/services/handlers/mcp-resources.handler.js +12 -2
  34. package/dist/mcp/services/handlers/mcp-resources.handler.js.map +1 -1
  35. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts +2 -2
  36. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts.map +1 -1
  37. package/dist/mcp/services/handlers/mcp-tools.handler.js +5 -5
  38. package/dist/mcp/services/handlers/mcp-tools.handler.js.map +1 -1
  39. package/dist/mcp/services/mcp-dynamic-registry.service.d.ts +26 -0
  40. package/dist/mcp/services/mcp-dynamic-registry.service.d.ts.map +1 -0
  41. package/dist/mcp/services/mcp-dynamic-registry.service.js +133 -0
  42. package/dist/mcp/services/mcp-dynamic-registry.service.js.map +1 -0
  43. package/dist/mcp/services/mcp-executor.service.d.ts +2 -2
  44. package/dist/mcp/services/mcp-executor.service.d.ts.map +1 -1
  45. package/dist/mcp/services/mcp-executor.service.js +2 -2
  46. package/dist/mcp/services/mcp-executor.service.js.map +1 -1
  47. package/dist/mcp/services/{mcp-registry.service.d.ts → mcp-registry-discovery.service.d.ts} +16 -15
  48. package/dist/mcp/services/mcp-registry-discovery.service.d.ts.map +1 -0
  49. package/dist/mcp/services/{mcp-registry.service.js → mcp-registry-discovery.service.js} +41 -25
  50. package/dist/mcp/services/mcp-registry-discovery.service.js.map +1 -0
  51. package/dist/mcp/services/mcp-sse.service.d.ts +2 -2
  52. package/dist/mcp/services/mcp-sse.service.d.ts.map +1 -1
  53. package/dist/mcp/services/mcp-sse.service.js +2 -2
  54. package/dist/mcp/services/mcp-sse.service.js.map +1 -1
  55. package/dist/mcp/services/mcp-streamable-http.service.d.ts +2 -2
  56. package/dist/mcp/services/mcp-streamable-http.service.d.ts.map +1 -1
  57. package/dist/mcp/services/mcp-streamable-http.service.js +2 -2
  58. package/dist/mcp/services/mcp-streamable-http.service.js.map +1 -1
  59. package/dist/mcp/services/tool-authorization.service.d.ts +4 -4
  60. package/dist/mcp/services/tool-authorization.service.d.ts.map +1 -1
  61. package/dist/mcp/services/tool-authorization.service.js.map +1 -1
  62. package/dist/mcp/transport/stdio.service.d.ts +2 -2
  63. package/dist/mcp/transport/stdio.service.d.ts.map +1 -1
  64. package/dist/mcp/transport/stdio.service.js +7 -7
  65. package/dist/mcp/transport/stdio.service.js.map +1 -1
  66. package/dist/mcp/utils/capabilities-builder.d.ts +2 -2
  67. package/dist/mcp/utils/capabilities-builder.d.ts.map +1 -1
  68. package/dist/mcp/utils/capabilities-builder.js.map +1 -1
  69. package/dist/mcp/utils/mcp-server.factory.d.ts +2 -2
  70. package/dist/mcp/utils/mcp-server.factory.d.ts.map +1 -1
  71. package/dist/mcp/utils/mcp-server.factory.js.map +1 -1
  72. package/package.json +9 -9
  73. package/src/mcp/decorators/prompt.decorator.ts +1 -1
  74. package/src/mcp/index.ts +2 -2
  75. package/src/mcp/interfaces/dynamic-prompt.interface.ts +20 -0
  76. package/src/mcp/interfaces/dynamic-resource.interface.ts +22 -0
  77. package/src/mcp/interfaces/dynamic-tool.interface.ts +2 -2
  78. package/src/mcp/interfaces/index.ts +10 -0
  79. package/src/mcp/mcp.module.ts +15 -11
  80. package/src/mcp/services/handlers/mcp-handler.base.ts +6 -3
  81. package/src/mcp/services/handlers/mcp-prompts.handler.ts +36 -4
  82. package/src/mcp/services/handlers/mcp-resources.handler.ts +24 -2
  83. package/src/mcp/services/handlers/mcp-tools.handler.ts +11 -8
  84. package/src/mcp/services/mcp-dynamic-registry.service.ts +236 -0
  85. package/src/mcp/services/mcp-executor.service.ts +2 -2
  86. package/src/mcp/services/{mcp-registry.service.spec.ts → mcp-registry-discovery.service.spec.ts} +18 -12
  87. package/src/mcp/services/{mcp-registry.service.ts → mcp-registry-discovery.service.ts} +77 -35
  88. package/src/mcp/services/mcp-sse.service.ts +2 -2
  89. package/src/mcp/services/mcp-streamable-http.service.ts +2 -2
  90. package/src/mcp/services/tool-authorization.service.ts +4 -4
  91. package/src/mcp/transport/stdio.service.ts +8 -8
  92. package/src/mcp/utils/capabilities-builder.ts +2 -2
  93. package/src/mcp/utils/mcp-server.factory.ts +2 -2
  94. package/dist/authz/services/jwt-token.service.spec.d.ts +0 -2
  95. package/dist/authz/services/jwt-token.service.spec.d.ts.map +0 -1
  96. package/dist/authz/services/jwt-token.service.spec.js +0 -86
  97. package/dist/authz/services/jwt-token.service.spec.js.map +0 -1
  98. package/dist/authz/stores/memory-store.service.spec.d.ts +0 -2
  99. package/dist/authz/stores/memory-store.service.spec.d.ts.map +0 -1
  100. package/dist/authz/stores/memory-store.service.spec.js +0 -382
  101. package/dist/authz/stores/memory-store.service.spec.js.map +0 -1
  102. package/dist/authz/stores/typeorm/typeorm-store.service.spec.d.ts +0 -2
  103. package/dist/authz/stores/typeorm/typeorm-store.service.spec.d.ts.map +0 -1
  104. package/dist/authz/stores/typeorm/typeorm-store.service.spec.js +0 -340
  105. package/dist/authz/stores/typeorm/typeorm-store.service.spec.js.map +0 -1
  106. package/dist/mcp/services/mcp-registry.service.d.ts.map +0 -1
  107. package/dist/mcp/services/mcp-registry.service.js.map +0 -1
  108. package/dist/mcp/services/mcp-registry.service.spec.d.ts +0 -2
  109. package/dist/mcp/services/mcp-registry.service.spec.d.ts.map +0 -1
  110. package/dist/mcp/services/mcp-registry.service.spec.js +0 -245
  111. package/dist/mcp/services/mcp-registry.service.spec.js.map +0 -1
  112. package/dist/mcp/services/mcp-tool-builder.service.d.ts +0 -15
  113. package/dist/mcp/services/mcp-tool-builder.service.d.ts.map +0 -1
  114. package/dist/mcp/services/mcp-tool-builder.service.js +0 -70
  115. package/dist/mcp/services/mcp-tool-builder.service.js.map +0 -1
  116. package/dist/mcp/transport/custom-decorator.spec.d.ts +0 -2
  117. package/dist/mcp/transport/custom-decorator.spec.d.ts.map +0 -1
  118. package/dist/mcp/transport/custom-decorator.spec.js +0 -34
  119. package/dist/mcp/transport/custom-decorator.spec.js.map +0 -1
  120. package/dist/mcp/utils/mcp-logger.factory.spec.d.ts +0 -2
  121. package/dist/mcp/utils/mcp-logger.factory.spec.d.ts.map +0 -1
  122. package/dist/mcp/utils/mcp-logger.factory.spec.js +0 -150
  123. package/dist/mcp/utils/mcp-logger.factory.spec.js.map +0 -1
  124. package/dist/mcp/utils/normalize-endpoint.spec.d.ts +0 -2
  125. package/dist/mcp/utils/normalize-endpoint.spec.d.ts.map +0 -1
  126. package/dist/mcp/utils/normalize-endpoint.spec.js +0 -40
  127. package/dist/mcp/utils/normalize-endpoint.spec.js.map +0 -1
  128. package/src/mcp/services/mcp-tool-builder.service.ts +0 -151
@@ -1,245 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var __metadata = (this && this.__metadata) || function (k, v) {
9
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const common_1 = require("@nestjs/common");
13
- const testing_1 = require("@nestjs/testing");
14
- const mcp_registry_service_1 = require("./mcp-registry.service");
15
- const core_1 = require("@nestjs/core");
16
- const tool_decorator_1 = require("../decorators/tool.decorator");
17
- const mcp_module_1 = require("../mcp.module");
18
- describe('McpRegistryService', () => {
19
- let service;
20
- const mockMcpModuleId = 'test-mcp-module-id';
21
- const mockResource = (name, uri) => ({
22
- type: 'resource',
23
- metadata: { name, uri },
24
- providerClass: Symbol(name),
25
- methodName: 'someMethod',
26
- });
27
- const mockResourceTemplate = (name, uriTemplate) => ({
28
- type: 'resource-template',
29
- metadata: { name, uriTemplate },
30
- providerClass: Symbol(name),
31
- methodName: 'someMethod',
32
- });
33
- beforeEach(async () => {
34
- const module = await testing_1.Test.createTestingModule({
35
- providers: [
36
- mcp_registry_service_1.McpRegistryService,
37
- {
38
- provide: core_1.DiscoveryService,
39
- useValue: {
40
- getProviders: jest.fn(() => []),
41
- getControllers: jest.fn(() => []),
42
- },
43
- },
44
- core_1.MetadataScanner,
45
- ],
46
- }).compile();
47
- service = module.get(mcp_registry_service_1.McpRegistryService);
48
- const mockResources = [
49
- mockResource('res0', '/posts/comments'),
50
- mockResource('res1', '/users/{id}'),
51
- mockResource('res2', '/posts/:postId/comments'),
52
- mockResource('res3', 'mcp://hello-world'),
53
- ];
54
- const mockResourceTemplates = [
55
- mockResourceTemplate('resTemplate1', '/templates/{id}'),
56
- mockResourceTemplate('resTemplate2', '/templates/{type}/{id}'),
57
- ];
58
- service.discoveredToolsByMcpModuleId = new Map([
59
- [mockMcpModuleId, [...mockResources, ...mockResourceTemplates]],
60
- ]);
61
- });
62
- it('should return the correct resource by URI', () => {
63
- const result = service.findResourceByUri(mockMcpModuleId, '/users/123');
64
- expect(result?.resource.metadata.name).toBe('res1');
65
- expect(result?.params).toEqual({ id: '123' });
66
- });
67
- it('should return the correct resource by URI', () => {
68
- const result = service.findResourceByUri(mockMcpModuleId, '/users/123');
69
- expect(result?.resource.metadata.name).toBe('res1');
70
- expect(result?.params).toEqual({ id: '123' });
71
- });
72
- it('should return undefined for unknown URI', () => {
73
- const result = service.findResourceByUri(mockMcpModuleId, '/unknown/path');
74
- expect(result).toBeUndefined();
75
- });
76
- it('should match complex URI template', () => {
77
- const result = service.findResourceByUri(mockMcpModuleId, '/posts/456/comments');
78
- expect(result?.resource.metadata.name).toBe('res2');
79
- expect(result?.params).toEqual({ postId: '456' });
80
- });
81
- it('should match simple URI template', () => {
82
- const result = service.findResourceByUri(mockMcpModuleId, '/posts/comments');
83
- expect(result?.resource.metadata.name).toBe('res0');
84
- expect(result?.params).toEqual({});
85
- });
86
- it('should match mcp URI', () => {
87
- const result = service.findResourceByUri(mockMcpModuleId, 'mcp://hello-world');
88
- expect(result?.resource.metadata.name).toBe('res3');
89
- expect(result?.params).toEqual({});
90
- });
91
- it('should return the correct resource template by URI', () => {
92
- const result = service.findResourceTemplateByUri(mockMcpModuleId, '/templates/123');
93
- expect(result?.resourceTemplate.metadata.name).toBe('resTemplate1');
94
- expect(result?.params).toEqual({ id: '123' });
95
- });
96
- });
97
- describe('McpRegistryService - Multiple discovery roots', () => {
98
- const mcpModuleA = mcp_module_1.McpModule.forRoot({ name: 'server-a', version: '0.0.1' });
99
- const mcpModuleB = mcp_module_1.McpModule.forRoot({ name: 'server-b', version: '0.0.1' });
100
- let ToolsA = class ToolsA {
101
- toolA() {
102
- return 'Tool A result';
103
- }
104
- };
105
- __decorate([
106
- (0, tool_decorator_1.Tool)({
107
- name: 'toolA',
108
- description: 'Tool A from ModuleA',
109
- }),
110
- __metadata("design:type", Function),
111
- __metadata("design:paramtypes", []),
112
- __metadata("design:returntype", void 0)
113
- ], ToolsA.prototype, "toolA", null);
114
- ToolsA = __decorate([
115
- (0, common_1.Injectable)()
116
- ], ToolsA);
117
- let ToolsB = class ToolsB {
118
- toolB() {
119
- return 'Tool B result';
120
- }
121
- };
122
- __decorate([
123
- (0, tool_decorator_1.Tool)({
124
- name: 'toolB',
125
- description: 'Tool B from ModuleB',
126
- }),
127
- __metadata("design:type", Function),
128
- __metadata("design:paramtypes", []),
129
- __metadata("design:returntype", void 0)
130
- ], ToolsB.prototype, "toolB", null);
131
- ToolsB = __decorate([
132
- (0, common_1.Injectable)()
133
- ], ToolsB);
134
- let ModuleA = class ModuleA {
135
- };
136
- ModuleA = __decorate([
137
- (0, common_1.Module)({
138
- imports: [mcpModuleA],
139
- providers: [ToolsA],
140
- exports: [ToolsA],
141
- })
142
- ], ModuleA);
143
- let ModuleB = class ModuleB {
144
- };
145
- ModuleB = __decorate([
146
- (0, common_1.Module)({
147
- imports: [mcpModuleB],
148
- providers: [ToolsB],
149
- exports: [ToolsB],
150
- })
151
- ], ModuleB);
152
- let service;
153
- const idModuleA = getMcpModuleId(mcpModuleA);
154
- const idModuleB = getMcpModuleId(mcpModuleB);
155
- beforeAll(async () => {
156
- const module = await testing_1.Test.createTestingModule({
157
- imports: [ModuleA, ModuleB],
158
- }).compile();
159
- service = module.get(mcp_registry_service_1.McpRegistryService);
160
- service.onApplicationBootstrap();
161
- });
162
- it('server-a discovered toolA only', () => {
163
- const tools = service.getTools(idModuleA);
164
- expect(tools.length).toBe(1);
165
- const tool = tools.find((tool) => tool.metadata.name === 'toolA');
166
- expect(tool).toBeDefined();
167
- });
168
- it('server-b discovered toolB only', () => {
169
- const tools = service.getTools(idModuleB);
170
- expect(tools.length).toBe(1);
171
- const tool = tools.find((tool) => tool.metadata.name === 'toolB');
172
- expect(tool).toBeDefined();
173
- });
174
- });
175
- describe('McpRegistryService - Single discovery root with multiple MCP servers', () => {
176
- const mcpModuleA = mcp_module_1.McpModule.forRoot({ name: 'server-a', version: '0.0.1' });
177
- const mcpModuleB = mcp_module_1.McpModule.forRoot({ name: 'server-b', version: '0.0.1' });
178
- const idModuleA = getMcpModuleId(mcpModuleA);
179
- const idModuleB = getMcpModuleId(mcpModuleB);
180
- let Tools = class Tools {
181
- tool() {
182
- return 'Tool result';
183
- }
184
- };
185
- __decorate([
186
- (0, tool_decorator_1.Tool)({
187
- name: 'tool',
188
- description: 'Tool from AppModule',
189
- }),
190
- __metadata("design:type", Function),
191
- __metadata("design:paramtypes", []),
192
- __metadata("design:returntype", void 0)
193
- ], Tools.prototype, "tool", null);
194
- Tools = __decorate([
195
- (0, common_1.Injectable)()
196
- ], Tools);
197
- let ToolsModule = class ToolsModule {
198
- };
199
- ToolsModule = __decorate([
200
- (0, common_1.Module)({
201
- imports: [
202
- mcp_module_1.McpModule.forFeature([Tools], 'server-a'),
203
- mcp_module_1.McpModule.forFeature([Tools], 'server-b'),
204
- ],
205
- providers: [Tools],
206
- exports: [Tools],
207
- })
208
- ], ToolsModule);
209
- let AppModule = class AppModule {
210
- };
211
- AppModule = __decorate([
212
- (0, common_1.Module)({
213
- imports: [mcpModuleA, mcpModuleB, ToolsModule],
214
- })
215
- ], AppModule);
216
- let service;
217
- beforeAll(async () => {
218
- const module = await testing_1.Test.createTestingModule({
219
- imports: [AppModule],
220
- }).compile();
221
- service = module.get(mcp_registry_service_1.McpRegistryService);
222
- service.onApplicationBootstrap();
223
- });
224
- it('server-a discovered the tool', () => {
225
- const tools = service.getTools(idModuleA);
226
- expect(tools.length).toBe(1);
227
- const tool = tools.find((tool) => tool.metadata.name === 'tool');
228
- expect(tool).toBeDefined();
229
- });
230
- it('server-b discovered the tool', () => {
231
- const tools = service.getTools(idModuleB);
232
- expect(tools.length).toBe(1);
233
- const tool = tools.find((tool) => tool.metadata.name === 'tool');
234
- expect(tool).toBeDefined();
235
- });
236
- });
237
- function getMcpModuleId(module) {
238
- const valueProvider = module?.providers?.find((provider) => typeof provider === 'object' &&
239
- provider.provide === 'MCP_MODULE_ID');
240
- if (!valueProvider) {
241
- throw new Error('MCP_MODULE_ID provider not found in module. This should not happen.');
242
- }
243
- return valueProvider.useValue;
244
- }
245
- //# sourceMappingURL=mcp-registry.service.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-registry.service.spec.js","sourceRoot":"","sources":["../../../src/mcp/services/mcp-registry.service.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n DynamicModule,\n Injectable,\n Module,\n ValueProvider,\n} from '@nestjs/common';\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { McpRegistryService } from './mcp-registry.service';\nimport { DiscoveryService, MetadataScanner } from '@nestjs/core';\nimport { Tool } from '../decorators/tool.decorator';\nimport { McpModule } from '../mcp.module';\n\ndescribe('McpRegistryService', () => {\n let service: McpRegistryService;\n const mockMcpModuleId = 'test-mcp-module-id';\n\n const mockResource = (name: string, uri: string) => ({\n type: 'resource',\n metadata: { name, uri },\n providerClass: Symbol(name),\n methodName: 'someMethod',\n });\n\n const mockResourceTemplate = (name: string, uriTemplate: string) => ({\n type: 'resource-template',\n metadata: { name, uriTemplate },\n providerClass: Symbol(name),\n methodName: 'someMethod',\n });\n\n beforeEach(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n McpRegistryService,\n {\n provide: DiscoveryService,\n useValue: {\n getProviders: jest.fn(() => []),\n getControllers: jest.fn(() => []),\n },\n },\n MetadataScanner,\n ],\n }).compile();\n\n service = module.get<McpRegistryService>(McpRegistryService);\n\n const mockResources = [\n mockResource('res0', '/posts/comments'),\n mockResource('res1', '/users/{id}'),\n mockResource('res2', '/posts/:postId/comments'),\n mockResource('res3', 'mcp://hello-world'),\n ];\n\n const mockResourceTemplates = [\n mockResourceTemplate('resTemplate1', '/templates/{id}'),\n mockResourceTemplate('resTemplate2', '/templates/{type}/{id}'),\n ];\n\n (service as any).discoveredToolsByMcpModuleId = new Map([\n [mockMcpModuleId, [...mockResources, ...mockResourceTemplates]],\n ]);\n });\n\n it('should return the correct resource by URI', () => {\n const result = service.findResourceByUri(mockMcpModuleId, '/users/123');\n expect(result?.resource.metadata.name).toBe('res1');\n expect(result?.params).toEqual({ id: '123' });\n });\n\n it('should return the correct resource by URI', () => {\n const result = service.findResourceByUri(mockMcpModuleId, '/users/123');\n expect(result?.resource.metadata.name).toBe('res1');\n expect(result?.params).toEqual({ id: '123' });\n });\n\n it('should return undefined for unknown URI', () => {\n const result = service.findResourceByUri(mockMcpModuleId, '/unknown/path');\n expect(result).toBeUndefined();\n });\n\n it('should match complex URI template', () => {\n const result = service.findResourceByUri(\n mockMcpModuleId,\n '/posts/456/comments',\n );\n expect(result?.resource.metadata.name).toBe('res2');\n expect(result?.params).toEqual({ postId: '456' });\n });\n\n it('should match simple URI template', () => {\n const result = service.findResourceByUri(\n mockMcpModuleId,\n '/posts/comments',\n );\n expect(result?.resource.metadata.name).toBe('res0');\n expect(result?.params).toEqual({});\n });\n\n it('should match mcp URI', () => {\n const result = service.findResourceByUri(\n mockMcpModuleId,\n 'mcp://hello-world',\n );\n expect(result?.resource.metadata.name).toBe('res3');\n expect(result?.params).toEqual({});\n });\n\n it('should return the correct resource template by URI', () => {\n const result = service.findResourceTemplateByUri(\n mockMcpModuleId,\n '/templates/123',\n );\n expect(result?.resourceTemplate.metadata.name).toBe('resTemplate1');\n expect(result?.params).toEqual({ id: '123' });\n });\n});\n\n/**\n * In the case of multiple MCP servers in different modules, the discovery should be scoped to each MCP root.\n * The structure of test modules is the following:\n *\n * TestModule\n * / \\\n * / \\\n * / \\\n * ModuleA (server-a) ModuleB (server-b)\n * | |\n * | |\n * ToolsA ToolsB\n */\ndescribe('McpRegistryService - Multiple discovery roots', () => {\n const mcpModuleA = McpModule.forRoot({ name: 'server-a', version: '0.0.1' });\n const mcpModuleB = McpModule.forRoot({ name: 'server-b', version: '0.0.1' });\n\n @Injectable()\n class ToolsA {\n @Tool({\n name: 'toolA',\n description: 'Tool A from ModuleA',\n })\n toolA() {\n return 'Tool A result';\n }\n }\n\n @Injectable()\n class ToolsB {\n @Tool({\n name: 'toolB',\n description: 'Tool B from ModuleB',\n })\n toolB() {\n return 'Tool B result';\n }\n }\n\n @Module({\n imports: [mcpModuleA],\n providers: [ToolsA],\n exports: [ToolsA],\n })\n class ModuleA {}\n\n @Module({\n imports: [mcpModuleB],\n providers: [ToolsB],\n exports: [ToolsB],\n })\n class ModuleB {}\n\n let service: McpRegistryService;\n const idModuleA = getMcpModuleId(mcpModuleA);\n const idModuleB = getMcpModuleId(mcpModuleB);\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n imports: [ModuleA, ModuleB],\n }).compile();\n\n service = module.get<McpRegistryService>(McpRegistryService);\n service.onApplicationBootstrap();\n });\n\n it('server-a discovered toolA only', () => {\n const tools = service.getTools(idModuleA);\n\n expect(tools.length).toBe(1);\n\n const tool = tools.find((tool) => tool.metadata.name === 'toolA');\n expect(tool).toBeDefined();\n });\n\n it('server-b discovered toolB only', () => {\n const tools = service.getTools(idModuleB);\n\n expect(tools.length).toBe(1);\n\n const tool = tools.find((tool) => tool.metadata.name === 'toolB');\n expect(tool).toBeDefined();\n });\n});\n\n/**\n * In the case of multiple MCP servers in a single module, the discovery should discover the same tools for all MCP servers.\n * The structure of test modules is the following:\n *\n * TestModule\n * |\n * |\n * AppModule (server-a, server-b)\n * |\n * |\n * ToolsModule\n * |\n * Tools (forFeature to both)\n */\ndescribe('McpRegistryService - Single discovery root with multiple MCP servers', () => {\n const mcpModuleA = McpModule.forRoot({ name: 'server-a', version: '0.0.1' });\n const mcpModuleB = McpModule.forRoot({ name: 'server-b', version: '0.0.1' });\n\n const idModuleA = getMcpModuleId(mcpModuleA);\n const idModuleB = getMcpModuleId(mcpModuleB);\n\n @Injectable()\n class Tools {\n @Tool({\n name: 'tool',\n description: 'Tool from AppModule',\n })\n tool() {\n return 'Tool result';\n }\n }\n\n @Module({\n imports: [\n McpModule.forFeature([Tools], 'server-a'),\n McpModule.forFeature([Tools], 'server-b'),\n ],\n providers: [Tools],\n exports: [Tools],\n })\n class ToolsModule {}\n\n @Module({\n imports: [mcpModuleA, mcpModuleB, ToolsModule],\n })\n class AppModule {}\n\n let service: McpRegistryService;\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n\n service = module.get<McpRegistryService>(McpRegistryService);\n service.onApplicationBootstrap();\n });\n\n it('server-a discovered the tool', () => {\n const tools = service.getTools(idModuleA);\n\n expect(tools.length).toBe(1);\n\n const tool = tools.find((tool) => tool.metadata.name === 'tool');\n expect(tool).toBeDefined();\n });\n\n it('server-b discovered the tool', () => {\n const tools = service.getTools(idModuleB);\n\n expect(tools.length).toBe(1);\n\n const tool = tools.find((tool) => tool.metadata.name === 'tool');\n expect(tool).toBeDefined();\n });\n});\n\n/**\n * Helper function to get the MCP module ID from a DynamicModule.\n * Pulling the IDs from the compiled TestingModule doesn't work as expected.\n * It returns the same ID for both modules, which is the ID of the module registered last.\n */\nfunction getMcpModuleId(module: DynamicModule): string {\n const valueProvider = module?.providers?.find(\n (provider) =>\n typeof provider === 'object' &&\n (provider as ValueProvider).provide === 'MCP_MODULE_ID',\n ) as ValueProvider<string> | undefined;\n\n if (!valueProvider) {\n throw new Error(\n 'MCP_MODULE_ID provider not found in module. This should not happen.',\n );\n }\n\n return valueProvider.useValue;\n}\n"]}
@@ -1,15 +0,0 @@
1
- import { DynamicToolDefinition, DynamicToolHandler } from '../interfaces/dynamic-tool.interface';
2
- import { McpRegistryService } from './mcp-registry.service';
3
- import type { McpOptions } from '../interfaces';
4
- export declare const DYNAMIC_TOOL_HANDLER_TOKEN: unique symbol;
5
- export declare class McpToolBuilder {
6
- private readonly registry;
7
- private readonly mcpModuleId;
8
- private readonly options;
9
- private readonly logger;
10
- constructor(registry: McpRegistryService, mcpModuleId: string, options: McpOptions);
11
- registerTool(definition: DynamicToolDefinition): void;
12
- getHandler(toolName: string): DynamicToolHandler | undefined;
13
- static getHandlerByModuleId(mcpModuleId: string, toolName: string): DynamicToolHandler | undefined;
14
- }
15
- //# sourceMappingURL=mcp-tool-builder.service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-tool-builder.service.d.ts","sourceRoot":"","sources":["../../../src/mcp/services/mcp-tool-builder.service.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAQhD,eAAO,MAAM,0BAA0B,eAAiC,CAAC;AAwCzE,qBACa,cAAc;IAIvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACA,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IALjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAGb,QAAQ,EAAE,kBAAkB,EACH,WAAW,EAAE,MAAM,EACrB,OAAO,EAAE,UAAU;IA8B7D,YAAY,CAAC,UAAU,EAAE,qBAAqB,GAAG,IAAI;IAuCrD,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAa5D,MAAM,CAAC,oBAAoB,CACzB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,SAAS;CAGlC"}
@@ -1,70 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var __metadata = (this && this.__metadata) || function (k, v) {
9
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
- };
11
- var __param = (this && this.__param) || function (paramIndex, decorator) {
12
- return function (target, key) { decorator(target, key, paramIndex); }
13
- };
14
- var McpToolBuilder_1;
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.McpToolBuilder = exports.DYNAMIC_TOOL_HANDLER_TOKEN = void 0;
17
- const common_1 = require("@nestjs/common");
18
- const zod_1 = require("zod");
19
- const mcp_registry_service_1 = require("./mcp-registry.service");
20
- const mcp_logger_factory_1 = require("../utils/mcp-logger.factory");
21
- exports.DYNAMIC_TOOL_HANDLER_TOKEN = Symbol('DYNAMIC_TOOL_HANDLER');
22
- const globalHandlers = new Map();
23
- let McpToolBuilder = McpToolBuilder_1 = class McpToolBuilder {
24
- constructor(registry, mcpModuleId, options) {
25
- this.registry = registry;
26
- this.mcpModuleId = mcpModuleId;
27
- this.options = options;
28
- this.logger = (0, mcp_logger_factory_1.createMcpLogger)(McpToolBuilder_1.name, this.options);
29
- if (!globalHandlers.has(mcpModuleId)) {
30
- globalHandlers.set(mcpModuleId, new Map());
31
- }
32
- }
33
- registerTool(definition) {
34
- this.logger.debug(`Registering dynamic tool: ${definition.name}`);
35
- const moduleHandlers = globalHandlers.get(this.mcpModuleId);
36
- moduleHandlers.set(definition.name, definition.handler);
37
- const parameters = definition.parameters ?? zod_1.z.object({});
38
- const metadata = {
39
- name: definition.name,
40
- description: definition.description,
41
- parameters,
42
- outputSchema: definition.outputSchema,
43
- annotations: definition.annotations,
44
- _meta: definition._meta,
45
- isPublic: definition.isPublic,
46
- requiredScopes: definition.requiredScopes,
47
- requiredRoles: definition.requiredRoles,
48
- };
49
- this.registry.registerDynamicTool(this.mcpModuleId, {
50
- type: 'tool',
51
- metadata,
52
- providerClass: exports.DYNAMIC_TOOL_HANDLER_TOKEN,
53
- methodName: definition.name,
54
- });
55
- }
56
- getHandler(toolName) {
57
- return globalHandlers.get(this.mcpModuleId)?.get(toolName);
58
- }
59
- static getHandlerByModuleId(mcpModuleId, toolName) {
60
- return globalHandlers.get(mcpModuleId)?.get(toolName);
61
- }
62
- };
63
- exports.McpToolBuilder = McpToolBuilder;
64
- exports.McpToolBuilder = McpToolBuilder = McpToolBuilder_1 = __decorate([
65
- (0, common_1.Injectable)(),
66
- __param(1, (0, common_1.Inject)('MCP_MODULE_ID')),
67
- __param(2, (0, common_1.Inject)('MCP_OPTIONS')),
68
- __metadata("design:paramtypes", [mcp_registry_service_1.McpRegistryService, String, Object])
69
- ], McpToolBuilder);
70
- //# sourceMappingURL=mcp-tool-builder.service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-tool-builder.service.js","sourceRoot":"","sources":["../../../src/mcp/services/mcp-tool-builder.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAC5D,6BAAwB;AAKxB,iEAA4D;AAE5D,oEAA8D;AAOjD,QAAA,0BAA0B,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAOzE,MAAM,cAAc,GAAG,IAAI,GAAG,EAA2C,CAAC;AAkCnE,IAAM,cAAc,sBAApB,MAAM,cAAc;IAGzB,YACmB,QAA4B,EACH,WAAmB,EACrB,OAAmB;QAF1C,aAAQ,GAAR,QAAQ,CAAoB;QACH,gBAAW,GAAX,WAAW,CAAQ;QACrB,YAAO,GAAP,OAAO,CAAY;QAE3D,IAAI,CAAC,MAAM,GAAG,IAAA,oCAAe,EAAC,gBAAc,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAEjE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACrC,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAuBD,YAAY,CAAC,UAAiC;QAC5C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QAGlE,MAAM,cAAc,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAE,CAAC;QAC7D,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;QAGxD,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,IAAI,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAGzD,MAAM,QAAQ,GAAiB;YAC7B,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,WAAW,EAAE,UAAU,CAAC,WAAW;YACnC,UAAU;YACV,YAAY,EAAE,UAAU,CAAC,YAAY;YACrC,WAAW,EAAE,UAAU,CAAC,WAAW;YACnC,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,cAAc,EAAE,UAAU,CAAC,cAAc;YACzC,aAAa,EAAE,UAAU,CAAC,aAAa;SACxC,CAAC;QAGF,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE;YAClD,IAAI,EAAE,MAAM;YACZ,QAAQ;YACR,aAAa,EAAE,kCAA0B;YACzC,UAAU,EAAE,UAAU,CAAC,IAAI;SAC5B,CAAC,CAAC;IACL,CAAC;IASD,UAAU,CAAC,QAAgB;QACzB,OAAO,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAWD,MAAM,CAAC,oBAAoB,CACzB,WAAmB,EACnB,QAAgB;QAEhB,OAAO,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;CACF,CAAA;AA9FY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,mBAAU,GAAE;IAMR,WAAA,IAAA,eAAM,EAAC,eAAe,CAAC,CAAA;IACvB,WAAA,IAAA,eAAM,EAAC,aAAa,CAAC,CAAA;qCAFK,yCAAkB;GAJpC,cAAc,CA8F1B","sourcesContent":["import { Injectable, Inject, Logger } from '@nestjs/common';\nimport { z } from 'zod';\nimport {\n DynamicToolDefinition,\n DynamicToolHandler,\n} from '../interfaces/dynamic-tool.interface';\nimport { McpRegistryService } from './mcp-registry.service';\nimport type { McpOptions } from '../interfaces';\nimport { createMcpLogger } from '../utils/mcp-logger.factory';\nimport { ToolMetadata } from '../decorators/tool.decorator';\n\n/**\n * Symbol used to identify dynamic tools in the registry.\n * When a tool's providerClass equals this token, it's a dynamic tool.\n */\nexport const DYNAMIC_TOOL_HANDLER_TOKEN = Symbol('DYNAMIC_TOOL_HANDLER');\n\n/**\n * Global map of dynamic tool handlers, scoped by moduleId.\n * Using a module-level Map ensures handlers persist across different\n * McpToolBuilder instances that may be created by the DI container.\n */\nconst globalHandlers = new Map<string, Map<string, DynamicToolHandler>>();\n\n/**\n * Service for programmatically registering MCP tools at runtime.\n *\n * Use this to register tools with descriptions/parameters from databases\n * or other dynamic sources during application bootstrap.\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class DynamicToolsService implements OnModuleInit {\n * constructor(\n * private readonly toolBuilder: McpToolBuilder,\n * private readonly dbService: DatabaseService,\n * ) {}\n *\n * async onModuleInit() {\n * const collections = await this.dbService.getCollections();\n *\n * this.toolBuilder.registerTool({\n * name: 'search-knowledge',\n * description: `Search collections: ${collections.join(', ')}`,\n * parameters: z.object({ query: z.string() }),\n * handler: async (args, context) => {\n * const results = await this.dbService.search(args.query);\n * return { content: [{ type: 'text', text: JSON.stringify(results) }] };\n * },\n * });\n * }\n * }\n * ```\n */\n@Injectable()\nexport class McpToolBuilder {\n private readonly logger: Logger;\n\n constructor(\n private readonly registry: McpRegistryService,\n @Inject('MCP_MODULE_ID') private readonly mcpModuleId: string,\n @Inject('MCP_OPTIONS') private readonly options: McpOptions,\n ) {\n this.logger = createMcpLogger(McpToolBuilder.name, this.options);\n // Initialize handler map for this module if it doesn't exist\n if (!globalHandlers.has(mcpModuleId)) {\n globalHandlers.set(mcpModuleId, new Map());\n }\n }\n\n /**\n * Register a dynamic tool for the current MCP server.\n *\n * Tools registered here will appear in the `tools/list` response and\n * can be called via `tools/call` just like decorator-based tools.\n *\n * @param definition - The tool definition including name, description, parameters, and handler\n *\n * @example\n * ```typescript\n * toolBuilder.registerTool({\n * name: 'search-knowledge',\n * description: await getDescriptionFromDB(),\n * parameters: z.object({ query: z.string() }),\n * handler: async (args, context) => {\n * const results = await searchService.search(args.query);\n * return { content: [{ type: 'text', text: JSON.stringify(results) }] };\n * },\n * });\n * ```\n */\n registerTool(definition: DynamicToolDefinition): void {\n this.logger.debug(`Registering dynamic tool: ${definition.name}`);\n\n // Store the handler for later execution (scoped by moduleId)\n const moduleHandlers = globalHandlers.get(this.mcpModuleId)!;\n moduleHandlers.set(definition.name, definition.handler);\n\n // Default to empty object schema if no parameters provided (matches @Tool decorator behavior)\n const parameters = definition.parameters ?? z.object({});\n\n // Build metadata matching ToolMetadata interface\n const metadata: ToolMetadata = {\n name: definition.name,\n description: definition.description,\n parameters,\n outputSchema: definition.outputSchema,\n annotations: definition.annotations,\n _meta: definition._meta,\n isPublic: definition.isPublic,\n requiredScopes: definition.requiredScopes,\n requiredRoles: definition.requiredRoles,\n };\n\n // Register with the registry\n this.registry.registerDynamicTool(this.mcpModuleId, {\n type: 'tool',\n metadata,\n providerClass: DYNAMIC_TOOL_HANDLER_TOKEN,\n methodName: definition.name,\n });\n }\n\n /**\n * Get the handler function for a dynamic tool.\n * Used internally by McpToolsHandler to execute dynamic tools.\n *\n * @param toolName - The name of the tool\n * @returns The handler function, or undefined if not found\n */\n getHandler(toolName: string): DynamicToolHandler | undefined {\n return globalHandlers.get(this.mcpModuleId)?.get(toolName);\n }\n\n /**\n * Get the handler function for a dynamic tool by module ID.\n * Static method used when the module ID is known but the correct\n * McpToolBuilder instance may not be available.\n *\n * @param mcpModuleId - The module ID to look up handlers for\n * @param toolName - The name of the tool\n * @returns The handler function, or undefined if not found\n */\n static getHandlerByModuleId(\n mcpModuleId: string,\n toolName: string,\n ): DynamicToolHandler | undefined {\n return globalHandlers.get(mcpModuleId)?.get(toolName);\n }\n}\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=custom-decorator.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"custom-decorator.spec.d.ts","sourceRoot":"","sources":["../../../src/mcp/transport/custom-decorator.spec.ts"],"names":[],"mappings":""}
@@ -1,34 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const common_1 = require("@nestjs/common");
4
- const sse_controller_factory_1 = require("./sse.controller.factory");
5
- const streamable_http_controller_factory_1 = require("./streamable-http.controller.factory");
6
- describe('Custom Decorators', () => {
7
- const testCustomDecorator = (0, common_1.SetMetadata)('test:decorator', true);
8
- describe('SSE Controller Factory', () => {
9
- it('should apply custom decorators to the SSE controller', () => {
10
- const decorators = [testCustomDecorator];
11
- const sseController = (0, sse_controller_factory_1.createSseController)('test-sse-endpoint', 'test-messages-endpoint', '/api', [], decorators);
12
- expect(sseController).toBeDefined();
13
- expect(Reflect.getMetadata('test:decorator', sseController)).toBeTruthy();
14
- });
15
- it('should work without custom decorators', () => {
16
- const sseController = (0, sse_controller_factory_1.createSseController)('test-sse-endpoint', 'test-messages-endpoint', '/api');
17
- expect(sseController).toBeDefined();
18
- expect(Reflect.getMetadata('test:decorator', sseController)).toBeUndefined();
19
- });
20
- });
21
- describe('Streamable HTTP Controller Factory', () => {
22
- it('should apply custom decorators to the Streamable HTTP controller', () => {
23
- const decorators = [testCustomDecorator];
24
- const streamableController = (0, streamable_http_controller_factory_1.createStreamableHttpController)('test-http-endpoint', '/api', [], decorators);
25
- expect(streamableController).toBeDefined();
26
- expect(Reflect.getMetadata('test:decorator', streamableController)).toBeTruthy();
27
- });
28
- it('should work without custom decorators', () => {
29
- const StreamableController = (0, streamable_http_controller_factory_1.createStreamableHttpController)('test-http-endpoint', '/api');
30
- expect(StreamableController).toBeDefined();
31
- });
32
- });
33
- });
34
- //# sourceMappingURL=custom-decorator.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"custom-decorator.spec.js","sourceRoot":"","sources":["../../../src/mcp/transport/custom-decorator.spec.ts"],"names":[],"mappings":";;AAAA,2CAA6C;AAC7C,qEAA+D;AAC/D,6FAAsF;AAEtF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IAEjC,MAAM,mBAAmB,GAAG,IAAA,oBAAW,EAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAEhE,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAE9D,MAAM,UAAU,GAAG,CAAC,mBAAmB,CAAC,CAAC;YAGzC,MAAM,aAAa,GAAG,IAAA,4CAAmB,EACvC,mBAAmB,EACnB,wBAAwB,EACxB,MAAM,EACN,EAAE,EACF,UAAU,CACX,CAAC;YAGF,MAAM,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;YACpC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;QAC5E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAE/C,MAAM,aAAa,GAAG,IAAA,4CAAmB,EACvC,mBAAmB,EACnB,wBAAwB,EACxB,MAAM,CACP,CAAC;YAGF,MAAM,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;YACpC,MAAM,CACJ,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,aAAa,CAAC,CACrD,CAAC,aAAa,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAClD,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;YAE1E,MAAM,UAAU,GAAG,CAAC,mBAAmB,CAAC,CAAC;YAGzC,MAAM,oBAAoB,GAAG,IAAA,mEAA8B,EACzD,oBAAoB,EACpB,MAAM,EACN,EAAE,EACF,UAAU,CACX,CAAC;YAGF,MAAM,CAAC,oBAAoB,CAAC,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,CACJ,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,CAC5D,CAAC,UAAU,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAE/C,MAAM,oBAAoB,GAAG,IAAA,mEAA8B,EACzD,oBAAoB,EACpB,MAAM,CACP,CAAC;YAGF,MAAM,CAAC,oBAAoB,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { SetMetadata } from '@nestjs/common';\nimport { createSseController } from './sse.controller.factory';\nimport { createStreamableHttpController } from './streamable-http.controller.factory';\n\ndescribe('Custom Decorators', () => {\n // Custom decorator for testing\n const testCustomDecorator = SetMetadata('test:decorator', true);\n\n describe('SSE Controller Factory', () => {\n it('should apply custom decorators to the SSE controller', () => {\n // Arrange\n const decorators = [testCustomDecorator];\n\n // Act\n const sseController = createSseController(\n 'test-sse-endpoint',\n 'test-messages-endpoint',\n '/api',\n [],\n decorators,\n );\n\n // Assert\n expect(sseController).toBeDefined();\n expect(Reflect.getMetadata('test:decorator', sseController)).toBeTruthy();\n });\n\n it('should work without custom decorators', () => {\n // Act\n const sseController = createSseController(\n 'test-sse-endpoint',\n 'test-messages-endpoint',\n '/api',\n );\n\n // Assert\n expect(sseController).toBeDefined();\n expect(\n Reflect.getMetadata('test:decorator', sseController),\n ).toBeUndefined();\n });\n });\n\n describe('Streamable HTTP Controller Factory', () => {\n it('should apply custom decorators to the Streamable HTTP controller', () => {\n // Arrange\n const decorators = [testCustomDecorator];\n\n // Act\n const streamableController = createStreamableHttpController(\n 'test-http-endpoint',\n '/api',\n [],\n decorators,\n );\n\n // Assert\n expect(streamableController).toBeDefined();\n expect(\n Reflect.getMetadata('test:decorator', streamableController),\n ).toBeTruthy();\n });\n\n it('should work without custom decorators', () => {\n // Act\n const StreamableController = createStreamableHttpController(\n 'test-http-endpoint',\n '/api',\n );\n\n // Assert\n expect(StreamableController).toBeDefined();\n });\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=mcp-logger.factory.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-logger.factory.spec.d.ts","sourceRoot":"","sources":["../../../src/mcp/utils/mcp-logger.factory.spec.ts"],"names":[],"mappings":""}
@@ -1,150 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const common_1 = require("@nestjs/common");
4
- const mcp_logger_factory_1 = require("./mcp-logger.factory");
5
- describe('McpLoggerFactory', () => {
6
- describe('createMcpLogger', () => {
7
- it('should create standard logger when no options provided', () => {
8
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', undefined);
9
- expect(logger).toBeInstanceOf(common_1.Logger);
10
- });
11
- it('should create standard logger when logging is undefined', () => {
12
- const options = {
13
- name: 'test',
14
- version: '1.0.0',
15
- };
16
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', options);
17
- expect(logger).toBeInstanceOf(common_1.Logger);
18
- });
19
- it('should create no-op logger when logging is false', () => {
20
- const options = {
21
- name: 'test',
22
- version: '1.0.0',
23
- logging: false,
24
- };
25
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', options);
26
- expect(logger).toBeInstanceOf(common_1.Logger);
27
- expect(() => {
28
- logger.log('test message');
29
- logger.error('test error');
30
- logger.warn('test warning');
31
- logger.debug('test debug');
32
- logger.verbose('test verbose');
33
- }).not.toThrow();
34
- });
35
- it('should create filtered logger with specified levels', () => {
36
- const options = {
37
- name: 'test',
38
- version: '1.0.0',
39
- logging: {
40
- level: ['error', 'warn'],
41
- },
42
- };
43
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', options);
44
- expect(logger).toBeInstanceOf(common_1.Logger);
45
- expect(() => {
46
- logger.log('test message');
47
- logger.error('test error');
48
- logger.warn('test warning');
49
- logger.debug('test debug');
50
- logger.verbose('test verbose');
51
- }).not.toThrow();
52
- });
53
- it('should create logger with all log levels when specified', () => {
54
- const options = {
55
- name: 'test',
56
- version: '1.0.0',
57
- logging: {
58
- level: ['log', 'error', 'warn', 'debug', 'verbose'],
59
- },
60
- };
61
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', options);
62
- expect(logger).toBeInstanceOf(common_1.Logger);
63
- });
64
- it('should handle empty level array gracefully', () => {
65
- const options = {
66
- name: 'test',
67
- version: '1.0.0',
68
- logging: {
69
- level: [],
70
- },
71
- };
72
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', options);
73
- expect(logger).toBeInstanceOf(common_1.Logger);
74
- expect(() => {
75
- logger.log('test message');
76
- logger.error('test error');
77
- logger.warn('test warning');
78
- logger.debug('test debug');
79
- logger.verbose('test verbose');
80
- }).not.toThrow();
81
- });
82
- });
83
- describe('FilteredLogger behavior', () => {
84
- it('should only call parent logger methods for enabled levels', () => {
85
- const options = {
86
- name: 'test',
87
- version: '1.0.0',
88
- logging: {
89
- level: ['error', 'warn'],
90
- },
91
- };
92
- const logSpy = jest.spyOn(common_1.Logger.prototype, 'log').mockImplementation();
93
- const errorSpy = jest
94
- .spyOn(common_1.Logger.prototype, 'error')
95
- .mockImplementation();
96
- const warnSpy = jest.spyOn(common_1.Logger.prototype, 'warn').mockImplementation();
97
- const debugSpy = jest
98
- .spyOn(common_1.Logger.prototype, 'debug')
99
- .mockImplementation();
100
- const verboseSpy = jest
101
- .spyOn(common_1.Logger.prototype, 'verbose')
102
- .mockImplementation();
103
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', options);
104
- logger.log('log message');
105
- logger.error('error message');
106
- logger.warn('warn message');
107
- logger.debug('debug message');
108
- logger.verbose('verbose message');
109
- expect(errorSpy).toHaveBeenCalled();
110
- expect(warnSpy).toHaveBeenCalled();
111
- logSpy.mockRestore();
112
- errorSpy.mockRestore();
113
- warnSpy.mockRestore();
114
- debugSpy.mockRestore();
115
- verboseSpy.mockRestore();
116
- });
117
- });
118
- describe('NoOpLogger behavior', () => {
119
- it('should not call parent logger methods when logging is disabled', () => {
120
- const options = {
121
- name: 'test',
122
- version: '1.0.0',
123
- logging: false,
124
- };
125
- const logSpy = jest.spyOn(common_1.Logger.prototype, 'log').mockImplementation();
126
- const errorSpy = jest
127
- .spyOn(common_1.Logger.prototype, 'error')
128
- .mockImplementation();
129
- const warnSpy = jest.spyOn(common_1.Logger.prototype, 'warn').mockImplementation();
130
- const debugSpy = jest
131
- .spyOn(common_1.Logger.prototype, 'debug')
132
- .mockImplementation();
133
- const verboseSpy = jest
134
- .spyOn(common_1.Logger.prototype, 'verbose')
135
- .mockImplementation();
136
- const logger = (0, mcp_logger_factory_1.createMcpLogger)('TestContext', options);
137
- logger.log('log message');
138
- logger.error('error message');
139
- logger.warn('warn message');
140
- logger.debug('debug message');
141
- logger.verbose('verbose message');
142
- logSpy.mockRestore();
143
- errorSpy.mockRestore();
144
- warnSpy.mockRestore();
145
- debugSpy.mockRestore();
146
- verboseSpy.mockRestore();
147
- });
148
- });
149
- });
150
- //# sourceMappingURL=mcp-logger.factory.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-logger.factory.spec.js","sourceRoot":"","sources":["../../../src/mcp/utils/mcp-logger.factory.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger } from '@nestjs/common';\nimport { createMcpLogger } from './mcp-logger.factory';\nimport type { McpOptions } from '../interfaces';\n\ndescribe('McpLoggerFactory', () => {\n describe('createMcpLogger', () => {\n it('should create standard logger when no options provided', () => {\n const logger = createMcpLogger('TestContext', undefined);\n expect(logger).toBeInstanceOf(Logger);\n });\n\n it('should create standard logger when logging is undefined', () => {\n const options: McpOptions = {\n name: 'test',\n version: '1.0.0',\n // logging is undefined\n };\n const logger = createMcpLogger('TestContext', options);\n expect(logger).toBeInstanceOf(Logger);\n });\n\n it('should create no-op logger when logging is false', () => {\n const options: McpOptions = {\n name: 'test',\n version: '1.0.0',\n logging: false,\n };\n const logger = createMcpLogger('TestContext', options);\n expect(logger).toBeInstanceOf(Logger);\n\n // Verify that log methods don't throw and don't produce output\n expect(() => {\n logger.log('test message');\n logger.error('test error');\n logger.warn('test warning');\n logger.debug('test debug');\n logger.verbose('test verbose');\n }).not.toThrow();\n });\n\n it('should create filtered logger with specified levels', () => {\n const options: McpOptions = {\n name: 'test',\n version: '1.0.0',\n logging: {\n level: ['error', 'warn'],\n },\n };\n const logger = createMcpLogger('TestContext', options);\n expect(logger).toBeInstanceOf(Logger);\n\n // Verify that log methods don't throw\n expect(() => {\n logger.log('test message');\n logger.error('test error');\n logger.warn('test warning');\n logger.debug('test debug');\n logger.verbose('test verbose');\n }).not.toThrow();\n });\n\n it('should create logger with all log levels when specified', () => {\n const options: McpOptions = {\n name: 'test',\n version: '1.0.0',\n logging: {\n level: ['log', 'error', 'warn', 'debug', 'verbose'],\n },\n };\n const logger = createMcpLogger('TestContext', options);\n expect(logger).toBeInstanceOf(Logger);\n });\n\n it('should handle empty level array gracefully', () => {\n const options: McpOptions = {\n name: 'test',\n version: '1.0.0',\n logging: {\n level: [],\n },\n };\n const logger = createMcpLogger('TestContext', options);\n expect(logger).toBeInstanceOf(Logger);\n\n // With empty levels, nothing should be logged\n expect(() => {\n logger.log('test message');\n logger.error('test error');\n logger.warn('test warning');\n logger.debug('test debug');\n logger.verbose('test verbose');\n }).not.toThrow();\n });\n });\n\n describe('FilteredLogger behavior', () => {\n it('should only call parent logger methods for enabled levels', () => {\n const options: McpOptions = {\n name: 'test',\n version: '1.0.0',\n logging: {\n level: ['error', 'warn'],\n },\n };\n\n // Mock the Logger prototype methods\n const logSpy = jest.spyOn(Logger.prototype, 'log').mockImplementation();\n const errorSpy = jest\n .spyOn(Logger.prototype, 'error')\n .mockImplementation();\n const warnSpy = jest.spyOn(Logger.prototype, 'warn').mockImplementation();\n const debugSpy = jest\n .spyOn(Logger.prototype, 'debug')\n .mockImplementation();\n const verboseSpy = jest\n .spyOn(Logger.prototype, 'verbose')\n .mockImplementation();\n\n const logger = createMcpLogger('TestContext', options);\n\n // Call all methods\n logger.log('log message');\n logger.error('error message');\n logger.warn('warn message');\n logger.debug('debug message');\n logger.verbose('verbose message');\n\n // Only error and warn should have been called on the parent\n // Note: The constructor call also invokes these, so we check if they were called\n expect(errorSpy).toHaveBeenCalled();\n expect(warnSpy).toHaveBeenCalled();\n\n // Clean up\n logSpy.mockRestore();\n errorSpy.mockRestore();\n warnSpy.mockRestore();\n debugSpy.mockRestore();\n verboseSpy.mockRestore();\n });\n });\n\n describe('NoOpLogger behavior', () => {\n it('should not call parent logger methods when logging is disabled', () => {\n const options: McpOptions = {\n name: 'test',\n version: '1.0.0',\n logging: false,\n };\n\n // Mock the Logger prototype methods\n const logSpy = jest.spyOn(Logger.prototype, 'log').mockImplementation();\n const errorSpy = jest\n .spyOn(Logger.prototype, 'error')\n .mockImplementation();\n const warnSpy = jest.spyOn(Logger.prototype, 'warn').mockImplementation();\n const debugSpy = jest\n .spyOn(Logger.prototype, 'debug')\n .mockImplementation();\n const verboseSpy = jest\n .spyOn(Logger.prototype, 'verbose')\n .mockImplementation();\n\n const logger = createMcpLogger('TestContext', options);\n\n // Call all methods\n logger.log('log message');\n logger.error('error message');\n logger.warn('warn message');\n logger.debug('debug message');\n logger.verbose('verbose message');\n\n // Clean up\n logSpy.mockRestore();\n errorSpy.mockRestore();\n warnSpy.mockRestore();\n debugSpy.mockRestore();\n verboseSpy.mockRestore();\n });\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=normalize-endpoint.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"normalize-endpoint.spec.d.ts","sourceRoot":"","sources":["../../../src/mcp/utils/normalize-endpoint.spec.ts"],"names":[],"mappings":""}