@rekog/mcp-nest 1.9.2 → 1.9.3-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,7 +21,7 @@ With `@rekog/mcp-nest` you define tools, resources, and prompts in a way that's
21
21
  - 🔧 **[Tools](docs/tools.md)**: Expose NestJS methods as MCP tools with automatic discovery and Zod validation
22
22
  - 🛠️ **[Elicitation](docs/tools.md#interactive-tool-calls)**: Interactive tool calls with user input elicitation
23
23
  - 🌐 **[HTTP Request Access](docs/tools.md#understanding-tool-method-parameters)**: Full access to request context within MCP handlers
24
- - 🔐 **[Per-Tool Authorization](./per-tool-authorization.md)**: Implement fine-grained authorization for tools
24
+ - 🔐 **[Per-Tool Authorization](docs/per-tool-authorization.md)**: Implement fine-grained authorization for tools
25
25
  - 📁 **[Resources](docs/resources.md)**: Serve content and data through MCP resource system
26
26
  - 📚 **[Resource Templates](docs/resource-templates.md)**: Dynamic resources with parameterized URIs
27
27
  - 💬 **[Prompts](docs/prompts.md)**: Define reusable prompt templates for AI interactions
@@ -40,6 +40,9 @@ export declare class McpRegistryService implements OnApplicationBootstrap {
40
40
  getPrompts(mcpModuleId: string): DiscoveredTool<PromptMetadata>[];
41
41
  findPrompt(mcpModuleId: string, name: string): DiscoveredTool<PromptMetadata> | undefined;
42
42
  private convertTemplate;
43
+ private extractTemplateQueryParams;
44
+ private parseQueryString;
45
+ private stripQueryString;
43
46
  private convertUri;
44
47
  findResourceByUri(mcpModuleId: string, uri: string): {
45
48
  resource: DiscoveredTool<ResourceMetadata>;
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-registry.service.d.ts","sourceRoot":"","sources":["../../../src/mcp/services/mcp-registry.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp-registry.service.d.ts","sourceRoot":"","sources":["../../../src/mcp/services/mcp-registry.service.ts"],"names":[],"mappings":"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"}
@@ -168,7 +168,36 @@ let McpRegistryService = McpRegistryService_1 = class McpRegistryService {
168
168
  return this.getPrompts(mcpModuleId).find((tool) => tool.metadata.name === name);
169
169
  }
170
170
  convertTemplate(template) {
171
- return template?.replace(/{(\w+)}/g, ':$1');
171
+ if (!template)
172
+ return template;
173
+ const withoutQueryParams = template.replace(/\{\?[^}]+\}/g, '');
174
+ return withoutQueryParams.replace(/{(\w+)}/g, ':$1');
175
+ }
176
+ extractTemplateQueryParams(template) {
177
+ const queryParamMatch = template.match(/\{\?([^}]+)\}/);
178
+ if (!queryParamMatch)
179
+ return [];
180
+ return queryParamMatch[1].split(',').map((p) => p.trim());
181
+ }
182
+ parseQueryString(uri) {
183
+ const queryIndex = uri.indexOf('?');
184
+ if (queryIndex === -1)
185
+ return {};
186
+ const queryString = uri.substring(queryIndex + 1);
187
+ const params = {};
188
+ for (const pair of queryString.split('&')) {
189
+ const [key, value] = pair.split('=');
190
+ if (key) {
191
+ params[decodeURIComponent(key)] = value
192
+ ? decodeURIComponent(value)
193
+ : '';
194
+ }
195
+ }
196
+ return params;
197
+ }
198
+ stripQueryString(uri) {
199
+ const queryIndex = uri.indexOf('?');
200
+ return queryIndex === -1 ? uri : uri.substring(0, queryIndex);
172
201
  }
173
202
  convertUri(uri) {
174
203
  if (uri.includes('://')) {
@@ -206,7 +235,8 @@ let McpRegistryService = McpRegistryService_1 = class McpRegistryService {
206
235
  name: tool.metadata.name,
207
236
  uriTemplate: tool.metadata.uriTemplate,
208
237
  }));
209
- const strippedInputUri = this.convertUri(uri);
238
+ const strippedInputUri = this.stripQueryString(this.convertUri(uri));
239
+ const inputQueryParams = this.parseQueryString(uri);
210
240
  for (const t of resourceTemplates) {
211
241
  if (!t.uriTemplate)
212
242
  continue;
@@ -218,9 +248,17 @@ let McpRegistryService = McpRegistryService_1 = class McpRegistryService {
218
248
  const foundResourceTemplate = this.findResourceTemplate(mcpModuleId, t.name);
219
249
  if (!foundResourceTemplate)
220
250
  continue;
251
+ const pathParams = result.params;
252
+ const expectedQueryParams = this.extractTemplateQueryParams(rawTemplate);
253
+ const queryParams = {};
254
+ for (const paramName of expectedQueryParams) {
255
+ if (inputQueryParams[paramName] !== undefined) {
256
+ queryParams[paramName] = inputQueryParams[paramName];
257
+ }
258
+ }
221
259
  return {
222
260
  resourceTemplate: foundResourceTemplate,
223
- params: result.params,
261
+ params: { ...pathParams, ...queryParams },
224
262
  };
225
263
  }
226
264
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-registry.service.js","sourceRoot":"","sources":["../../../src/mcp/services/mcp-registry.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n InjectionToken,\n Logger,\n OnApplicationBootstrap,\n Inject,\n Optional,\n} from '@nestjs/common';\nimport {\n DiscoveryService,\n MetadataScanner,\n ModulesContainer,\n} from '@nestjs/core';\nimport {\n MCP_PROMPT_METADATA_KEY,\n MCP_RESOURCE_METADATA_KEY,\n MCP_RESOURCE_TEMPLATE_METADATA_KEY,\n MCP_TOOL_METADATA_KEY,\n MCP_PUBLIC_METADATA_KEY,\n MCP_SCOPES_METADATA_KEY,\n MCP_ROLES_METADATA_KEY,\n ToolMetadata,\n} from '../decorators';\nimport { ResourceMetadata } from '../decorators/resource.decorator';\nimport { match } from 'path-to-regexp';\nimport { PromptMetadata } from '../decorators/prompt.decorator';\nimport { Module } from '@nestjs/core/injector/module';\nimport { ResourceTemplateMetadata } from '../decorators/resource-template.decorator';\nimport type { McpOptions } from '../interfaces';\nimport { createMcpLogger } from '../utils/mcp-logger.factory';\n\n/**\n * Interface representing a discovered tool\n */\nexport type DiscoveredTool<T extends object> = {\n type: 'tool' | 'resource' | 'resource-template' | 'prompt';\n metadata: T;\n providerClass: InjectionToken;\n methodName: string;\n};\n\nexport type InjectionTokenWithName = InjectionToken & { name: string };\n\n/**\n * Singleton service that discovers and registers tools during application bootstrap\n */\n@Injectable()\nexport class McpRegistryService implements OnApplicationBootstrap {\n private readonly logger: Logger;\n private discoveredToolsByMcpModuleId: Map<string, DiscoveredTool<any>[]> =\n new Map();\n\n constructor(\n private readonly discovery: DiscoveryService,\n private readonly metadataScanner: MetadataScanner,\n private readonly modulesContainer: ModulesContainer,\n @Optional() @Inject('MCP_OPTIONS') private readonly options?: McpOptions,\n ) {\n this.logger = createMcpLogger(McpRegistryService.name, this.options);\n }\n\n onApplicationBootstrap() {\n this.discoverTools();\n }\n\n /**\n * Finds all modules that import the McpModule and scans only the root module providers and controllers.\n * This prevents unintentionally exposing tools from imported dependencies.\n */\n private discoverTools() {\n const getImportedMcpModules = (module: Module) =>\n Array.from(module.imports).filter(\n (m) => (m.instance as any).__isMcpModule,\n );\n\n const pairs = Array.from(this.modulesContainer.values())\n .map((module): [Module, Module[]] => [\n module,\n getImportedMcpModules(module),\n ])\n .filter(([, importedMcpModules]) => importedMcpModules.length > 0);\n\n for (const [rootModule, mcpModules] of pairs) {\n this.logger.debug(\n `Discovering tools, resources, resource templates, and prompts for module: ${rootModule.name}`,\n );\n\n for (const mcpModule of mcpModules) {\n const mcpModuleId =\n mcpModule.getProviderByKey<string>('MCP_MODULE_ID')?.instance;\n\n this.discoverToolsForModuleSubtree(mcpModuleId, [rootModule]);\n }\n }\n }\n\n /**\n * Scans all providers and controllers for @Tool decorators\n */\n private discoverToolsForModuleSubtree(\n mcpModuleId: string,\n modules: Module[],\n ) {\n const providers = this.discovery.getProviders(undefined, modules);\n const controllers = this.discovery.getControllers(undefined, modules);\n const allInstances = [...providers, ...controllers]\n .filter(\n (wrapper) =>\n wrapper.instance &&\n typeof wrapper.instance === 'object' &&\n wrapper.instance !== null,\n )\n .map((wrapper) => ({\n instance: wrapper.instance as object,\n token: wrapper.token,\n }));\n\n allInstances.forEach(({ instance, token }) => {\n this.metadataScanner.getAllMethodNames(instance).forEach((methodName) => {\n const methodRef = instance[methodName] as object;\n const methodMetaKeys = Reflect.getOwnMetadataKeys(methodRef);\n\n if (methodMetaKeys.includes(MCP_TOOL_METADATA_KEY)) {\n this.addDiscoveryTool(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n\n if (methodMetaKeys.includes(MCP_RESOURCE_METADATA_KEY)) {\n this.addDiscoveryResource(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n\n if (methodMetaKeys.includes(MCP_RESOURCE_TEMPLATE_METADATA_KEY)) {\n this.addDiscoveryResourceTemplate(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n\n if (methodMetaKeys.includes(MCP_PROMPT_METADATA_KEY)) {\n this.addDiscoveryPrompt(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n });\n });\n }\n\n /**\n * Adds a discovered tool to the registry\n */\n private addDiscovery<T>(\n type: 'tool' | 'resource' | 'resource-template' | 'prompt',\n metadataKey: string,\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n const metadata: T = Reflect.getMetadata(metadataKey, methodRef);\n\n if (!metadata['name']) {\n metadata['name'] = methodName;\n }\n\n if (!this.discoveredToolsByMcpModuleId.has(mcpModuleId)) {\n this.discoveredToolsByMcpModuleId.set(mcpModuleId, []);\n }\n\n this.discoveredToolsByMcpModuleId.get(mcpModuleId)?.push({\n type,\n metadata,\n providerClass: token,\n methodName,\n });\n }\n\n private addDiscoveryPrompt(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Prompt discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n this.addDiscovery<PromptMetadata>(\n 'prompt',\n MCP_PROMPT_METADATA_KEY,\n mcpModuleId,\n methodRef,\n token,\n methodName,\n );\n }\n\n private addDiscoveryTool(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Tool discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n\n // Collect security metadata from decorators\n const isPublic = Reflect.getMetadata(MCP_PUBLIC_METADATA_KEY, methodRef);\n const requiredScopes = Reflect.getMetadata(\n MCP_SCOPES_METADATA_KEY,\n methodRef,\n );\n const requiredRoles = Reflect.getMetadata(\n MCP_ROLES_METADATA_KEY,\n methodRef,\n );\n\n // Add tool with security metadata\n const baseMetadata: ToolMetadata = Reflect.getMetadata(\n MCP_TOOL_METADATA_KEY,\n methodRef,\n );\n\n if (!baseMetadata.name) {\n baseMetadata.name = methodName;\n }\n\n // Enrich with security metadata\n if (isPublic !== undefined) {\n baseMetadata.isPublic = isPublic;\n }\n if (requiredScopes) {\n baseMetadata.requiredScopes = requiredScopes;\n }\n if (requiredRoles) {\n baseMetadata.requiredRoles = requiredRoles;\n }\n\n if (!this.discoveredToolsByMcpModuleId.has(mcpModuleId)) {\n this.discoveredToolsByMcpModuleId.set(mcpModuleId, []);\n }\n\n this.discoveredToolsByMcpModuleId.get(mcpModuleId)?.push({\n type: 'tool',\n metadata: baseMetadata,\n providerClass: token,\n methodName,\n });\n }\n\n private addDiscoveryResource(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Resource discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n this.addDiscovery<ResourceMetadata>(\n 'resource',\n MCP_RESOURCE_METADATA_KEY,\n mcpModuleId,\n methodRef,\n token,\n methodName,\n );\n }\n\n private addDiscoveryResourceTemplate(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Resource Template discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n this.addDiscovery<ResourceTemplateMetadata>(\n 'resource-template',\n MCP_RESOURCE_TEMPLATE_METADATA_KEY,\n mcpModuleId,\n methodRef,\n token,\n methodName,\n );\n }\n\n /**\n * Return all discovered MCP module IDs\n */\n getMcpModuleIds(): string[] {\n return Array.from(this.discoveredToolsByMcpModuleId.keys());\n }\n\n /**\n * Get all discovered tools\n */\n getTools(mcpModuleId: string): DiscoveredTool<ToolMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'tool') ?? []\n );\n }\n\n /**\n * Find a tool by name\n */\n findTool(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<ToolMetadata> | undefined {\n return this.getTools(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n /**\n * Get all discovered resources\n */\n getResources(mcpModuleId: string): DiscoveredTool<ResourceMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'resource') ?? []\n );\n }\n\n /**\n * Find a resource by name\n */\n findResource(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<ResourceMetadata> | undefined {\n return this.getResources(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n /**\n * Get all discovered resource templates\n */\n getResourceTemplates(\n mcpModuleId: string,\n ): DiscoveredTool<ResourceTemplateMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'resource-template') ?? []\n );\n }\n\n /**\n * Find a resource by name\n */\n findResourceTemplate(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<ResourceTemplateMetadata> | undefined {\n return this.getResourceTemplates(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n /**\n * Get all discovered prompts\n */\n getPrompts(mcpModuleId: string): DiscoveredTool<PromptMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'prompt') ?? []\n );\n }\n\n /**\n * Find a prompt by name\n */\n findPrompt(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<PromptMetadata> | undefined {\n return this.getPrompts(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n private convertTemplate(template: string): string {\n return template?.replace(/{(\\w+)}/g, ':$1');\n }\n\n private convertUri(uri: string): string {\n if (uri.includes('://')) {\n return uri.split('://')[1];\n }\n\n return uri;\n }\n\n /**\n * Find a resource by uri\n * @returns An object containing the found resource and extracted parameters, or undefined if no resource is found\n */\n findResourceByUri(\n mcpModuleId: string,\n uri: string,\n ):\n | {\n resource: DiscoveredTool<ResourceMetadata>;\n params: Record<string, string>;\n }\n | undefined {\n const resources = this.getResources(mcpModuleId).map((tool) => ({\n name: tool.metadata.name,\n uri: tool.metadata.uri,\n }));\n\n const strippedInputUri = this.convertUri(uri);\n\n for (const t of resources) {\n if (!t.uri) continue;\n\n const rawTemplate = t.uri;\n const templatePath = this.convertTemplate(this.convertUri(rawTemplate));\n const matcher = match(templatePath, { decode: decodeURIComponent });\n const result = matcher(strippedInputUri);\n\n if (result) {\n const foundResource = this.findResource(mcpModuleId, t.name);\n if (!foundResource) continue;\n\n return {\n resource: foundResource,\n params: result.params as Record<string, string>,\n };\n }\n }\n\n return undefined;\n }\n\n /**\n * Find a resource template by uri\n * @returns An object containing the found resource template and extracted parameters, or undefined if no resource template is found\n */\n findResourceTemplateByUri(\n mcpModuleId: string,\n uri: string,\n ):\n | {\n resourceTemplate: DiscoveredTool<ResourceTemplateMetadata>;\n params: Record<string, string>;\n }\n | undefined {\n const resourceTemplates = this.getResourceTemplates(mcpModuleId).map(\n (tool) => ({\n name: tool.metadata.name,\n uriTemplate: tool.metadata.uriTemplate,\n }),\n );\n\n const strippedInputUri = this.convertUri(uri);\n\n for (const t of resourceTemplates) {\n if (!t.uriTemplate) continue;\n\n const rawTemplate = t.uriTemplate;\n const templatePath = this.convertTemplate(this.convertUri(rawTemplate));\n const matcher = match(templatePath, { decode: decodeURIComponent });\n const result = matcher(strippedInputUri);\n\n if (result) {\n const foundResourceTemplate = this.findResourceTemplate(\n mcpModuleId,\n t.name,\n );\n if (!foundResourceTemplate) continue;\n\n return {\n resourceTemplate: foundResourceTemplate,\n params: result.params as Record<string, string>,\n };\n }\n }\n\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"mcp-registry.service.js","sourceRoot":"","sources":["../../../src/mcp/services/mcp-registry.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n InjectionToken,\n Logger,\n OnApplicationBootstrap,\n Inject,\n Optional,\n} from '@nestjs/common';\nimport {\n DiscoveryService,\n MetadataScanner,\n ModulesContainer,\n} from '@nestjs/core';\nimport {\n MCP_PROMPT_METADATA_KEY,\n MCP_RESOURCE_METADATA_KEY,\n MCP_RESOURCE_TEMPLATE_METADATA_KEY,\n MCP_TOOL_METADATA_KEY,\n MCP_PUBLIC_METADATA_KEY,\n MCP_SCOPES_METADATA_KEY,\n MCP_ROLES_METADATA_KEY,\n ToolMetadata,\n} from '../decorators';\nimport { ResourceMetadata } from '../decorators/resource.decorator';\nimport { match } from 'path-to-regexp';\nimport { PromptMetadata } from '../decorators/prompt.decorator';\nimport { Module } from '@nestjs/core/injector/module';\nimport { ResourceTemplateMetadata } from '../decorators/resource-template.decorator';\nimport type { McpOptions } from '../interfaces';\nimport { createMcpLogger } from '../utils/mcp-logger.factory';\n\n/**\n * Interface representing a discovered tool\n */\nexport type DiscoveredTool<T extends object> = {\n type: 'tool' | 'resource' | 'resource-template' | 'prompt';\n metadata: T;\n providerClass: InjectionToken;\n methodName: string;\n};\n\nexport type InjectionTokenWithName = InjectionToken & { name: string };\n\n/**\n * Singleton service that discovers and registers tools during application bootstrap\n */\n@Injectable()\nexport class McpRegistryService implements OnApplicationBootstrap {\n private readonly logger: Logger;\n private discoveredToolsByMcpModuleId: Map<string, DiscoveredTool<any>[]> =\n new Map();\n\n constructor(\n private readonly discovery: DiscoveryService,\n private readonly metadataScanner: MetadataScanner,\n private readonly modulesContainer: ModulesContainer,\n @Optional() @Inject('MCP_OPTIONS') private readonly options?: McpOptions,\n ) {\n this.logger = createMcpLogger(McpRegistryService.name, this.options);\n }\n\n onApplicationBootstrap() {\n this.discoverTools();\n }\n\n /**\n * Finds all modules that import the McpModule and scans only the root module providers and controllers.\n * This prevents unintentionally exposing tools from imported dependencies.\n */\n private discoverTools() {\n const getImportedMcpModules = (module: Module) =>\n Array.from(module.imports).filter(\n (m) => (m.instance as any).__isMcpModule,\n );\n\n const pairs = Array.from(this.modulesContainer.values())\n .map((module): [Module, Module[]] => [\n module,\n getImportedMcpModules(module),\n ])\n .filter(([, importedMcpModules]) => importedMcpModules.length > 0);\n\n for (const [rootModule, mcpModules] of pairs) {\n this.logger.debug(\n `Discovering tools, resources, resource templates, and prompts for module: ${rootModule.name}`,\n );\n\n for (const mcpModule of mcpModules) {\n const mcpModuleId =\n mcpModule.getProviderByKey<string>('MCP_MODULE_ID')?.instance;\n\n this.discoverToolsForModuleSubtree(mcpModuleId, [rootModule]);\n }\n }\n }\n\n /**\n * Scans all providers and controllers for @Tool decorators\n */\n private discoverToolsForModuleSubtree(\n mcpModuleId: string,\n modules: Module[],\n ) {\n const providers = this.discovery.getProviders(undefined, modules);\n const controllers = this.discovery.getControllers(undefined, modules);\n const allInstances = [...providers, ...controllers]\n .filter(\n (wrapper) =>\n wrapper.instance &&\n typeof wrapper.instance === 'object' &&\n wrapper.instance !== null,\n )\n .map((wrapper) => ({\n instance: wrapper.instance as object,\n token: wrapper.token,\n }));\n\n allInstances.forEach(({ instance, token }) => {\n this.metadataScanner.getAllMethodNames(instance).forEach((methodName) => {\n const methodRef = instance[methodName] as object;\n const methodMetaKeys = Reflect.getOwnMetadataKeys(methodRef);\n\n if (methodMetaKeys.includes(MCP_TOOL_METADATA_KEY)) {\n this.addDiscoveryTool(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n\n if (methodMetaKeys.includes(MCP_RESOURCE_METADATA_KEY)) {\n this.addDiscoveryResource(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n\n if (methodMetaKeys.includes(MCP_RESOURCE_TEMPLATE_METADATA_KEY)) {\n this.addDiscoveryResourceTemplate(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n\n if (methodMetaKeys.includes(MCP_PROMPT_METADATA_KEY)) {\n this.addDiscoveryPrompt(\n mcpModuleId,\n methodRef,\n token as InjectionTokenWithName,\n methodName,\n );\n }\n });\n });\n }\n\n /**\n * Adds a discovered tool to the registry\n */\n private addDiscovery<T>(\n type: 'tool' | 'resource' | 'resource-template' | 'prompt',\n metadataKey: string,\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n const metadata: T = Reflect.getMetadata(metadataKey, methodRef);\n\n if (!metadata['name']) {\n metadata['name'] = methodName;\n }\n\n if (!this.discoveredToolsByMcpModuleId.has(mcpModuleId)) {\n this.discoveredToolsByMcpModuleId.set(mcpModuleId, []);\n }\n\n this.discoveredToolsByMcpModuleId.get(mcpModuleId)?.push({\n type,\n metadata,\n providerClass: token,\n methodName,\n });\n }\n\n private addDiscoveryPrompt(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Prompt discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n this.addDiscovery<PromptMetadata>(\n 'prompt',\n MCP_PROMPT_METADATA_KEY,\n mcpModuleId,\n methodRef,\n token,\n methodName,\n );\n }\n\n private addDiscoveryTool(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Tool discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n\n // Collect security metadata from decorators\n const isPublic = Reflect.getMetadata(MCP_PUBLIC_METADATA_KEY, methodRef);\n const requiredScopes = Reflect.getMetadata(\n MCP_SCOPES_METADATA_KEY,\n methodRef,\n );\n const requiredRoles = Reflect.getMetadata(\n MCP_ROLES_METADATA_KEY,\n methodRef,\n );\n\n // Add tool with security metadata\n const baseMetadata: ToolMetadata = Reflect.getMetadata(\n MCP_TOOL_METADATA_KEY,\n methodRef,\n );\n\n if (!baseMetadata.name) {\n baseMetadata.name = methodName;\n }\n\n // Enrich with security metadata\n if (isPublic !== undefined) {\n baseMetadata.isPublic = isPublic;\n }\n if (requiredScopes) {\n baseMetadata.requiredScopes = requiredScopes;\n }\n if (requiredRoles) {\n baseMetadata.requiredRoles = requiredRoles;\n }\n\n if (!this.discoveredToolsByMcpModuleId.has(mcpModuleId)) {\n this.discoveredToolsByMcpModuleId.set(mcpModuleId, []);\n }\n\n this.discoveredToolsByMcpModuleId.get(mcpModuleId)?.push({\n type: 'tool',\n metadata: baseMetadata,\n providerClass: token,\n methodName,\n });\n }\n\n private addDiscoveryResource(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Resource discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n this.addDiscovery<ResourceMetadata>(\n 'resource',\n MCP_RESOURCE_METADATA_KEY,\n mcpModuleId,\n methodRef,\n token,\n methodName,\n );\n }\n\n private addDiscoveryResourceTemplate(\n mcpModuleId: string,\n methodRef: object,\n token: InjectionTokenWithName,\n methodName: string,\n ) {\n this.logger.debug(\n `Resource Template discovered: ${token.name}.${methodName} in module: ${mcpModuleId}`,\n );\n this.addDiscovery<ResourceTemplateMetadata>(\n 'resource-template',\n MCP_RESOURCE_TEMPLATE_METADATA_KEY,\n mcpModuleId,\n methodRef,\n token,\n methodName,\n );\n }\n\n /**\n * Return all discovered MCP module IDs\n */\n getMcpModuleIds(): string[] {\n return Array.from(this.discoveredToolsByMcpModuleId.keys());\n }\n\n /**\n * Get all discovered tools\n */\n getTools(mcpModuleId: string): DiscoveredTool<ToolMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'tool') ?? []\n );\n }\n\n /**\n * Find a tool by name\n */\n findTool(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<ToolMetadata> | undefined {\n return this.getTools(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n /**\n * Get all discovered resources\n */\n getResources(mcpModuleId: string): DiscoveredTool<ResourceMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'resource') ?? []\n );\n }\n\n /**\n * Find a resource by name\n */\n findResource(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<ResourceMetadata> | undefined {\n return this.getResources(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n /**\n * Get all discovered resource templates\n */\n getResourceTemplates(\n mcpModuleId: string,\n ): DiscoveredTool<ResourceTemplateMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'resource-template') ?? []\n );\n }\n\n /**\n * Find a resource by name\n */\n findResourceTemplate(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<ResourceTemplateMetadata> | undefined {\n return this.getResourceTemplates(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n /**\n * Get all discovered prompts\n */\n getPrompts(mcpModuleId: string): DiscoveredTool<PromptMetadata>[] {\n return (\n this.discoveredToolsByMcpModuleId\n .get(mcpModuleId)\n ?.filter((tool) => tool.type === 'prompt') ?? []\n );\n }\n\n /**\n * Find a prompt by name\n */\n findPrompt(\n mcpModuleId: string,\n name: string,\n ): DiscoveredTool<PromptMetadata> | undefined {\n return this.getPrompts(mcpModuleId).find(\n (tool) => tool.metadata.name === name,\n );\n }\n\n /**\n * Convert RFC 6570 URI template to path-to-regexp compatible format.\n * Handles both path parameters {param} and query parameters {?param} or {?param1,param2}\n */\n private convertTemplate(template: string): string {\n if (!template) return template;\n\n // Remove RFC 6570 query parameter syntax {?...} from the template\n // These will be handled separately via URL query string parsing\n const withoutQueryParams = template.replace(/\\{\\?[^}]+\\}/g, '');\n\n // Convert path parameters {param} to path-to-regexp format :param\n return withoutQueryParams.replace(/{(\\w+)}/g, ':$1');\n }\n\n /**\n * Extract query parameter names from an RFC 6570 URI template.\n * E.g., 'mcp://example{?foo,bar}' returns ['foo', 'bar']\n */\n private extractTemplateQueryParams(template: string): string[] {\n const queryParamMatch = template.match(/\\{\\?([^}]+)\\}/);\n if (!queryParamMatch) return [];\n return queryParamMatch[1].split(',').map((p) => p.trim());\n }\n\n /**\n * Parse query string from a URI and return as key-value pairs.\n */\n private parseQueryString(uri: string): Record<string, string> {\n const queryIndex = uri.indexOf('?');\n if (queryIndex === -1) return {};\n\n const queryString = uri.substring(queryIndex + 1);\n const params: Record<string, string> = {};\n\n for (const pair of queryString.split('&')) {\n const [key, value] = pair.split('=');\n if (key) {\n params[decodeURIComponent(key)] = value\n ? decodeURIComponent(value)\n : '';\n }\n }\n\n return params;\n }\n\n /**\n * Strip query string from a URI, returning only the path portion.\n */\n private stripQueryString(uri: string): string {\n const queryIndex = uri.indexOf('?');\n return queryIndex === -1 ? uri : uri.substring(0, queryIndex);\n }\n\n private convertUri(uri: string): string {\n if (uri.includes('://')) {\n return uri.split('://')[1];\n }\n\n return uri;\n }\n\n /**\n * Find a resource by uri\n * @returns An object containing the found resource and extracted parameters, or undefined if no resource is found\n */\n findResourceByUri(\n mcpModuleId: string,\n uri: string,\n ):\n | {\n resource: DiscoveredTool<ResourceMetadata>;\n params: Record<string, string>;\n }\n | undefined {\n const resources = this.getResources(mcpModuleId).map((tool) => ({\n name: tool.metadata.name,\n uri: tool.metadata.uri,\n }));\n\n const strippedInputUri = this.convertUri(uri);\n\n for (const t of resources) {\n if (!t.uri) continue;\n\n const rawTemplate = t.uri;\n const templatePath = this.convertTemplate(this.convertUri(rawTemplate));\n const matcher = match(templatePath, { decode: decodeURIComponent });\n const result = matcher(strippedInputUri);\n\n if (result) {\n const foundResource = this.findResource(mcpModuleId, t.name);\n if (!foundResource) continue;\n\n return {\n resource: foundResource,\n params: result.params as Record<string, string>,\n };\n }\n }\n\n return undefined;\n }\n\n /**\n * Find a resource template by uri\n * @returns An object containing the found resource template and extracted parameters, or undefined if no resource template is found\n */\n findResourceTemplateByUri(\n mcpModuleId: string,\n uri: string,\n ):\n | {\n resourceTemplate: DiscoveredTool<ResourceTemplateMetadata>;\n params: Record<string, string>;\n }\n | undefined {\n const resourceTemplates = this.getResourceTemplates(mcpModuleId).map(\n (tool) => ({\n name: tool.metadata.name,\n uriTemplate: tool.metadata.uriTemplate,\n }),\n );\n\n // Strip query string from input URI for path matching\n const strippedInputUri = this.stripQueryString(this.convertUri(uri));\n // Parse query parameters from input URI\n const inputQueryParams = this.parseQueryString(uri);\n\n for (const t of resourceTemplates) {\n if (!t.uriTemplate) continue;\n\n const rawTemplate = t.uriTemplate;\n // Convert template (removes {?...} query params and converts {param} to :param)\n const templatePath = this.convertTemplate(this.convertUri(rawTemplate));\n const matcher = match(templatePath, { decode: decodeURIComponent });\n const result = matcher(strippedInputUri);\n\n if (result) {\n const foundResourceTemplate = this.findResourceTemplate(\n mcpModuleId,\n t.name,\n );\n if (!foundResourceTemplate) continue;\n\n // Get path params from matching\n const pathParams = result.params as Record<string, string>;\n\n // Get expected query params from template and filter input query params\n const expectedQueryParams = this.extractTemplateQueryParams(rawTemplate);\n const queryParams: Record<string, string> = {};\n for (const paramName of expectedQueryParams) {\n if (inputQueryParams[paramName] !== undefined) {\n queryParams[paramName] = inputQueryParams[paramName];\n }\n }\n\n return {\n resourceTemplate: foundResourceTemplate,\n params: { ...pathParams, ...queryParams },\n };\n }\n }\n\n return undefined;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rekog/mcp-nest",
3
- "version": "1.9.2",
3
+ "version": "1.9.3-alpha.1",
4
4
  "description": "NestJS module for creating Model Context Protocol (MCP) servers",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -400,8 +400,59 @@ export class McpRegistryService implements OnApplicationBootstrap {
400
400
  );
401
401
  }
402
402
 
403
+ /**
404
+ * Convert RFC 6570 URI template to path-to-regexp compatible format.
405
+ * Handles both path parameters {param} and query parameters {?param} or {?param1,param2}
406
+ */
403
407
  private convertTemplate(template: string): string {
404
- return template?.replace(/{(\w+)}/g, ':$1');
408
+ if (!template) return template;
409
+
410
+ // Remove RFC 6570 query parameter syntax {?...} from the template
411
+ // These will be handled separately via URL query string parsing
412
+ const withoutQueryParams = template.replace(/\{\?[^}]+\}/g, '');
413
+
414
+ // Convert path parameters {param} to path-to-regexp format :param
415
+ return withoutQueryParams.replace(/{(\w+)}/g, ':$1');
416
+ }
417
+
418
+ /**
419
+ * Extract query parameter names from an RFC 6570 URI template.
420
+ * E.g., 'mcp://example{?foo,bar}' returns ['foo', 'bar']
421
+ */
422
+ private extractTemplateQueryParams(template: string): string[] {
423
+ const queryParamMatch = template.match(/\{\?([^}]+)\}/);
424
+ if (!queryParamMatch) return [];
425
+ return queryParamMatch[1].split(',').map((p) => p.trim());
426
+ }
427
+
428
+ /**
429
+ * Parse query string from a URI and return as key-value pairs.
430
+ */
431
+ private parseQueryString(uri: string): Record<string, string> {
432
+ const queryIndex = uri.indexOf('?');
433
+ if (queryIndex === -1) return {};
434
+
435
+ const queryString = uri.substring(queryIndex + 1);
436
+ const params: Record<string, string> = {};
437
+
438
+ for (const pair of queryString.split('&')) {
439
+ const [key, value] = pair.split('=');
440
+ if (key) {
441
+ params[decodeURIComponent(key)] = value
442
+ ? decodeURIComponent(value)
443
+ : '';
444
+ }
445
+ }
446
+
447
+ return params;
448
+ }
449
+
450
+ /**
451
+ * Strip query string from a URI, returning only the path portion.
452
+ */
453
+ private stripQueryString(uri: string): string {
454
+ const queryIndex = uri.indexOf('?');
455
+ return queryIndex === -1 ? uri : uri.substring(0, queryIndex);
405
456
  }
406
457
 
407
458
  private convertUri(uri: string): string {
@@ -474,12 +525,16 @@ export class McpRegistryService implements OnApplicationBootstrap {
474
525
  }),
475
526
  );
476
527
 
477
- const strippedInputUri = this.convertUri(uri);
528
+ // Strip query string from input URI for path matching
529
+ const strippedInputUri = this.stripQueryString(this.convertUri(uri));
530
+ // Parse query parameters from input URI
531
+ const inputQueryParams = this.parseQueryString(uri);
478
532
 
479
533
  for (const t of resourceTemplates) {
480
534
  if (!t.uriTemplate) continue;
481
535
 
482
536
  const rawTemplate = t.uriTemplate;
537
+ // Convert template (removes {?...} query params and converts {param} to :param)
483
538
  const templatePath = this.convertTemplate(this.convertUri(rawTemplate));
484
539
  const matcher = match(templatePath, { decode: decodeURIComponent });
485
540
  const result = matcher(strippedInputUri);
@@ -491,9 +546,21 @@ export class McpRegistryService implements OnApplicationBootstrap {
491
546
  );
492
547
  if (!foundResourceTemplate) continue;
493
548
 
549
+ // Get path params from matching
550
+ const pathParams = result.params as Record<string, string>;
551
+
552
+ // Get expected query params from template and filter input query params
553
+ const expectedQueryParams = this.extractTemplateQueryParams(rawTemplate);
554
+ const queryParams: Record<string, string> = {};
555
+ for (const paramName of expectedQueryParams) {
556
+ if (inputQueryParams[paramName] !== undefined) {
557
+ queryParams[paramName] = inputQueryParams[paramName];
558
+ }
559
+ }
560
+
494
561
  return {
495
562
  resourceTemplate: foundResourceTemplate,
496
- params: result.params as Record<string, string>,
563
+ params: { ...pathParams, ...queryParams },
497
564
  };
498
565
  }
499
566
  }