@rekog/mcp-nest 1.9.7 → 1.9.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"tool-guards.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-guards.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAKhE,eAAO,MAAM,uBAAuB,eAAe,CAAC;AAqBpD,MAAM,WAAW,yBAAyB;IACxC,YAAY,IAAI;QACd,UAAU,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC;KAC9B,CAAC;IACF,QAAQ,CAAC,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,UAAU,IAAI,QAAQ,CAAC;IACvB,OAAO,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,KAAK,QAAQ,CAAC;CACvD;AAoCD,eAAO,MAAM,UAAU,GAAI,QAAQ,IAAI,CAAC,WAAW,CAAC,EAAE,qDAOrD,CAAC"}
1
+ {"version":3,"file":"tool-guards.decorator.d.ts","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-guards.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAKhE,eAAO,MAAM,uBAAuB,eAAe,CAAC;AA0BpD,MAAM,WAAW,yBAAyB;IACxC,YAAY,IAAI;QACd,UAAU,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC;KAC9B,CAAC;IACF,QAAQ,CAAC,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,UAAU,IAAI,QAAQ,CAAC;IACvB,OAAO,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,KAAK,QAAQ,CAAC;CACvD;AAoCD,eAAO,MAAM,UAAU,GAAI,QAAQ,IAAI,CAAC,WAAW,CAAC,EAAE,qDAOrD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-guards.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-guards.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAgE;AAKnD,QAAA,uBAAuB,GAAG,YAAY,CAAC;AAgE7C,MAAM,UAAU,GAAG,CAAC,MAA2B,EAAE,EAAE;IACxD,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 { CanActivate, SetMetadata, Type } from '@nestjs/common';\n\n/**\n * Metadata key for storing tool-level NestJS guards\n */\nexport const MCP_GUARDS_METADATA_KEY = 'mcp:guards';\n\n/**\n * The execution context available to guards used with @ToolGuards().\n *\n * MCP tools don't run inside NestJS's request pipeline (all tools share a single\n * HTTP endpoint), so the full ExecutionContext is not available. This type\n * describes exactly what IS available.\n *\n * Available:\n * - `switchToHttp().getRequest()` - the real HTTP request object\n * - `getClass()` - the tool's provider class (works with Reflector)\n * - `getHandler()` - the tool's method reference (works with Reflector)\n * - `getType()` - always returns `'http'`\n *\n * Not available (will throw if called):\n * - `switchToHttp().getResponse()` - MCP handles responses via protocol layer\n * - `switchToHttp().getNext()` - no middleware chain\n * - `switchToRpc()` / `switchToWs()` - not an RPC/WS context\n * - `getArgs()` / `getArgByIndex()` - no NestJS argument array\n */\nexport interface ToolGuardExecutionContext {\n switchToHttp(): {\n getRequest<T = unknown>(): T;\n };\n getClass<T = unknown>(): Type<T>;\n getHandler(): Function;\n getType<TContext extends string = string>(): TContext;\n}\n\n/**\n * Decorator to specify NestJS guards that control access to a tool.\n *\n * When applied, each guard's `canActivate()` is evaluated before listing or executing the tool.\n * If any guard rejects, the tool is hidden from `tools/list` and blocked from execution.\n * ALL guards must pass (AND logic).\n *\n * Guards receive an execution context with the fields described by {@link ToolGuardExecutionContext}.\n * Standard NestJS guards that only use `switchToHttp().getRequest()` will work. Guards that\n * access the response object, RPC context, or WebSocket context will throw at runtime.\n *\n * Note: Guards require an HTTP context and are not supported with STDIO transport.\n * Tools with guards will be hidden when using STDIO.\n *\n * @param guards - Array of NestJS guard classes implementing CanActivate\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class MyTools {\n * @Tool({ name: 'admin-action', description: 'Admin only' })\n * @ToolGuards([AdminGuard])\n * async adminAction() {\n * return { content: [{ type: 'text', text: 'Done' }] };\n * }\n *\n * @Tool({ name: 'secure-action', description: 'Requires both guards' })\n * @ToolGuards([AuthGuard, RoleGuard])\n * async secureAction() {\n * return { content: [{ type: 'text', text: 'Done' }] };\n * }\n * }\n * ```\n */\nexport const ToolGuards = (guards: Type<CanActivate>[]) => {\n if (!Array.isArray(guards) || guards.length === 0) {\n throw new Error(\n '@ToolGuards() requires a non-empty array of guard classes',\n );\n }\n return SetMetadata(MCP_GUARDS_METADATA_KEY, guards);\n};\n"]}
1
+ {"version":3,"file":"tool-guards.decorator.js","sourceRoot":"","sources":["../../../src/mcp/decorators/tool-guards.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAgE;AAKnD,QAAA,uBAAuB,GAAG,YAAY,CAAC;AAqE7C,MAAM,UAAU,GAAG,CAAC,MAA2B,EAAE,EAAE;IACxD,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 { CanActivate, SetMetadata, Type } from '@nestjs/common';\n\n/**\n * Metadata key for storing tool-level NestJS guards\n */\nexport const MCP_GUARDS_METADATA_KEY = 'mcp:guards';\n\n/**\n * The execution context available to guards used with @ToolGuards().\n *\n * MCP tools don't run inside NestJS's request pipeline (all tools share a single\n * HTTP endpoint), so the full ExecutionContext is not available. This type\n * describes exactly what IS available.\n *\n * Available:\n * - `switchToHttp().getRequest()` - the HTTP request object, enriched with:\n * - `body` - during `tools/call`, contains the validated tool arguments;\n * during `tools/list`, contains the raw HTTP request body (if any)\n * - `params` - parsed route params from the HTTP adapter\n * - `user` - if set by a transport-level auth guard\n * - `headers` - original request headers\n * - `getClass()` - the tool's provider class (works with Reflector)\n * - `getHandler()` - the tool's method reference (works with Reflector)\n * - `getType()` - always returns `'http'`\n *\n * Not available (will throw if called):\n * - `switchToHttp().getResponse()` - MCP handles responses via protocol layer\n * - `switchToHttp().getNext()` - no middleware chain\n * - `switchToRpc()` / `switchToWs()` - not an RPC/WS context\n * - `getArgs()` / `getArgByIndex()` - no NestJS argument array\n */\nexport interface ToolGuardExecutionContext {\n switchToHttp(): {\n getRequest<T = unknown>(): T;\n };\n getClass<T = unknown>(): Type<T>;\n getHandler(): Function;\n getType<TContext extends string = string>(): TContext;\n}\n\n/**\n * Decorator to specify NestJS guards that control access to a tool.\n *\n * When applied, each guard's `canActivate()` is evaluated before listing or executing the tool.\n * If any guard rejects, the tool is hidden from `tools/list` and blocked from execution.\n * ALL guards must pass (AND logic).\n *\n * Guards receive an execution context with the fields described by {@link ToolGuardExecutionContext}.\n * Standard NestJS guards that only use `switchToHttp().getRequest()` will work. Guards that\n * access the response object, RPC context, or WebSocket context will throw at runtime.\n *\n * Note: Guards require an HTTP context and are not supported with STDIO transport.\n * Tools with guards will be hidden when using STDIO.\n *\n * @param guards - Array of NestJS guard classes implementing CanActivate\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class MyTools {\n * @Tool({ name: 'admin-action', description: 'Admin only' })\n * @ToolGuards([AdminGuard])\n * async adminAction() {\n * return { content: [{ type: 'text', text: 'Done' }] };\n * }\n *\n * @Tool({ name: 'secure-action', description: 'Requires both guards' })\n * @ToolGuards([AuthGuard, RoleGuard])\n * async secureAction() {\n * return { content: [{ type: 'text', text: 'Done' }] };\n * }\n * }\n * ```\n */\nexport const ToolGuards = (guards: Type<CanActivate>[]) => {\n if (!Array.isArray(guards) || guards.length === 0) {\n throw new Error(\n '@ToolGuards() requires a non-empty array of guard classes',\n );\n }\n return SetMetadata(MCP_GUARDS_METADATA_KEY, guards);\n};\n"]}
@@ -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;AACpE,OAAO,EAEL,cAAc,EAIf,MAAM,oCAAoC,CAAC;AAS5C,OAAO,EAAoB,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAEL,2BAA2B,EAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAEtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAGzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAMzE,qBACa,eAAgB,SAAQ,cAAc;IAOtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAR9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;gBAGxC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,2BAA2B,EACrC,SAAS,EAAE,SAAS,EACsB,WAAW,EAAE,MAAM,EACrB,OAAO,EAAE,UAAU,EAC1C,WAAW,EAAE,wBAAwB;IAOxD,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,gBAAgB;cAwBL,mBAAmB,CACpC,SAAS,EAAE,MAAM,GAChB,cAAc,GAAG,KAAK;IAczB,OAAO,CAAC,+BAA+B;YAoCzB,eAAe;IA0C7B,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW;CA8OhE"}
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;AACpE,OAAO,EAEL,cAAc,EAIf,MAAM,oCAAoC,CAAC;AAS5C,OAAO,EAAoB,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAEL,2BAA2B,EAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAEtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAGzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAMzE,qBACa,eAAgB,SAAQ,cAAc;IAOtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAR9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;gBAGxC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,2BAA2B,EACrC,SAAS,EAAE,SAAS,EACsB,WAAW,EAAE,MAAM,EACrB,OAAO,EAAE,UAAU,EAC1C,WAAW,EAAE,wBAAwB;IAOxD,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,gBAAgB;cAwBL,mBAAmB,CACpC,SAAS,EAAE,MAAM,GAChB,cAAc,GAAG,KAAK;IAmBzB,OAAO,CAAC,+BAA+B;YAgDzB,eAAe;IA2C7B,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW;CA8OhE"}
@@ -64,7 +64,7 @@ let McpToolsHandler = McpToolsHandler_1 = class McpToolsHandler extends mcp_hand
64
64
  isError: true,
65
65
  };
66
66
  }
67
- createToolGuardExecutionContext(httpRequest, tool) {
67
+ createToolGuardExecutionContext(httpRequest, tool, toolArguments) {
68
68
  const providerClass = tool.providerClass;
69
69
  const methodHandler = providerClass.prototype?.[tool.methodName] ?? (() => { });
70
70
  const unavailable = (method) => {
@@ -72,9 +72,13 @@ let McpToolsHandler = McpToolsHandler_1 = class McpToolsHandler extends mcp_hand
72
72
  `MCP tools share a single HTTP endpoint, so only a limited API is available.` +
73
73
  `See ToolGuardExecutionContext for the supported API.`);
74
74
  };
75
+ const guardRequest = Object.assign(Object.create(Object.getPrototypeOf(httpRequest.raw ?? {})), httpRequest.raw ?? {}, {
76
+ body: toolArguments ?? httpRequest.body,
77
+ params: httpRequest.params ?? {},
78
+ });
75
79
  return {
76
80
  switchToHttp: () => ({
77
- getRequest: () => httpRequest.raw,
81
+ getRequest: () => guardRequest,
78
82
  getResponse: () => unavailable('switchToHttp().getResponse()'),
79
83
  getNext: () => unavailable('switchToHttp().getNext()'),
80
84
  }),
@@ -87,7 +91,7 @@ let McpToolsHandler = McpToolsHandler_1 = class McpToolsHandler extends mcp_hand
87
91
  switchToWs: () => unavailable('switchToWs()'),
88
92
  };
89
93
  }
90
- async checkToolGuards(tool, httpRequest) {
94
+ async checkToolGuards(tool, httpRequest, toolArguments) {
91
95
  const guards = tool.metadata.guards;
92
96
  if (!guards || guards.length === 0) {
93
97
  return true;
@@ -97,7 +101,7 @@ let McpToolsHandler = McpToolsHandler_1 = class McpToolsHandler extends mcp_hand
97
101
  `The tool will be hidden. Use HTTP transport to support guarded tools.`);
98
102
  return false;
99
103
  }
100
- const context = this.createToolGuardExecutionContext(httpRequest, tool);
104
+ const context = this.createToolGuardExecutionContext(httpRequest, tool, toolArguments);
101
105
  for (const GuardClass of guards) {
102
106
  try {
103
107
  const guard = this.moduleRef.get(GuardClass, {
@@ -187,7 +191,7 @@ let McpToolsHandler = McpToolsHandler_1 = class McpToolsHandler extends mcp_hand
187
191
  : false;
188
192
  const allowUnauthenticatedAccess = this.options.allowUnauthenticatedAccess ?? false;
189
193
  this.authService.validateToolAccess(user, toolInfo, effectiveModuleHasGuards, allowUnauthenticatedAccess);
190
- const guardsPassed = await this.checkToolGuards(toolInfo, httpRequest);
194
+ const guardsPassed = await this.checkToolGuards(toolInfo, httpRequest, request.params.arguments);
191
195
  if (!guardsPassed) {
192
196
  throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Access denied: insufficient permissions for tool '${request.params.name}'`);
193
197
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-tools.handler.js","sourceRoot":"","sources":["../../../../src/mcp/services/handlers/mcp-tools.handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {\n CallToolRequestSchema,\n CallToolResult,\n ErrorCode,\n ListToolsRequestSchema,\n McpError,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n CanActivate,\n ExecutionContext,\n Inject,\n Injectable,\n Scope,\n Type,\n} from '@nestjs/common';\nimport { ContextIdFactory, ModuleRef, Reflector } from '@nestjs/core';\nimport {\n DiscoveredCapability,\n McpRegistryDiscoveryService,\n} from '../mcp-registry-discovery.service';\nimport { ToolGuardExecutionContext, ToolMetadata } from '../../decorators';\nimport { McpHandlerBase } from './mcp-handler.base';\nimport { ZodType } from 'zod';\nimport { HttpRequest } from '../../interfaces/http-adapter.interface';\nimport { McpRequestWithUser } from 'src/authz';\nimport { ToolAuthorizationService } from '../tool-authorization.service';\nimport { toJsonSchemaCompat } from '@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';\nimport { normalizeObjectSchema } from '@modelcontextprotocol/sdk/server/zod-compat.js';\nimport type { McpOptions } from '../../interfaces/mcp-options.interface';\nimport {\n McpRegistryService,\n DYNAMIC_TOOL_HANDLER_TOKEN,\n} from '../mcp-dynamic-registry.service';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class McpToolsHandler extends McpHandlerBase {\n private readonly moduleHasGuards: boolean;\n\n constructor(\n moduleRef: ModuleRef,\n registry: McpRegistryDiscoveryService,\n reflector: Reflector,\n @Inject('MCP_MODULE_ID') private readonly mcpModuleId: string,\n @Inject('MCP_OPTIONS') private readonly options: McpOptions,\n private readonly authService: ToolAuthorizationService,\n ) {\n super(moduleRef, registry, reflector, McpToolsHandler.name, options);\n this.moduleHasGuards =\n this.options.guards !== undefined && this.options.guards.length > 0;\n }\n\n private buildDefaultContentBlock(result: any) {\n return [\n {\n type: 'text',\n text: JSON.stringify(result),\n },\n ];\n }\n\n private formatToolResult(result: any, outputSchema?: ZodType): any {\n if (result && typeof result === 'object' && Array.isArray(result.content)) {\n return result;\n }\n\n if (outputSchema) {\n const validation = outputSchema.safeParse(result);\n if (!validation.success) {\n throw new McpError(\n ErrorCode.InternalError,\n `Tool result does not match outputSchema: ${validation.error.message}`,\n );\n }\n return {\n structuredContent: validation.data,\n content: this.buildDefaultContentBlock(result),\n };\n }\n\n return {\n content: this.buildDefaultContentBlock(result),\n };\n }\n\n protected override createErrorResponse(\n errorText: string,\n ): CallToolResult | never {\n return {\n content: [{ type: 'text', text: errorText }],\n isError: true,\n };\n }\n\n /**\n * Creates an ExecutionContext for @ToolGuards() evaluation.\n *\n * Only the fields documented in ToolGuardExecutionContext are available.\n * Invalid fields throw with a descriptive message rather than silently\n * returning garbage.\n */\n private createToolGuardExecutionContext(\n httpRequest: HttpRequest,\n tool: DiscoveredCapability<ToolMetadata>,\n ): ToolGuardExecutionContext & ExecutionContext {\n const providerClass = tool.providerClass as Type;\n const methodHandler =\n providerClass.prototype?.[tool.methodName] ?? (() => {});\n\n const unavailable = (method: string): never => {\n throw new Error(\n `${method} is not available in @ToolGuards() context. ` +\n `MCP tools share a single HTTP endpoint, so only a limited API is available.` +\n `See ToolGuardExecutionContext for the supported API.`,\n );\n };\n\n return {\n switchToHttp: () => ({\n getRequest: <T = unknown>() => httpRequest.raw as T,\n getResponse: () => unavailable('switchToHttp().getResponse()'),\n getNext: () => unavailable('switchToHttp().getNext()'),\n }),\n getClass: <T = unknown>() => providerClass as Type<T>,\n getHandler: () => methodHandler as () => void,\n getArgs: () => unavailable('getArgs()'),\n getArgByIndex: () => unavailable('getArgByIndex()'),\n getType: <TContext extends string = string>() => 'http' as TContext,\n switchToRpc: () => unavailable('switchToRpc()'),\n switchToWs: () => unavailable('switchToWs()'),\n };\n }\n\n /**\n * Evaluates all @ToolGuards() for a tool.\n * Returns true if the tool has no guards or all guards pass.\n */\n private async checkToolGuards(\n tool: DiscoveredCapability<ToolMetadata>,\n httpRequest: HttpRequest,\n ): Promise<boolean> {\n const guards = tool.metadata.guards;\n if (!guards || guards.length === 0) {\n return true;\n }\n\n // Guards require HTTP context - not available on STDIO\n if (!httpRequest.raw) {\n this.logger.warn(\n `@ToolGuards() on tool '${tool.metadata.name}' cannot be evaluated without HTTP context (STDIO transport). ` +\n `The tool will be hidden. Use HTTP transport to support guarded tools.`,\n );\n return false;\n }\n\n const context = this.createToolGuardExecutionContext(httpRequest, tool);\n\n for (const GuardClass of guards) {\n try {\n const guard = this.moduleRef.get<CanActivate>(GuardClass, {\n strict: false,\n });\n const result = guard.canActivate(context);\n const canActivate = result instanceof Promise ? await result : result;\n if (!canActivate) {\n return false;\n }\n } catch (error) {\n this.logger.warn(\n `@ToolGuards() guard ${GuardClass.name} threw on tool '${tool.metadata.name}': ${error.message}. ` +\n `The tool will be hidden. If this is unexpected, ensure the guard only uses ` +\n `the API available in ToolGuardExecutionContext.`,\n );\n return false;\n }\n }\n\n return true;\n }\n registerHandlers(mcpServer: McpServer, httpRequest: HttpRequest) {\n if (this.registry.getTools(this.mcpModuleId).length === 0) {\n this.logger.debug('No tools registered, skipping tool handlers');\n return;\n }\n\n mcpServer.server.setRequestHandler(ListToolsRequestSchema, async () => {\n // Extract user from request (may be undefined if not authenticated or STDIO)\n // For STDIO transport, httpRequest.raw is undefined, so bypass auth entirely\n const user = httpRequest.raw\n ? (httpRequest.raw as McpRequestWithUser).user\n : undefined;\n\n // Get all tools and filter based on user permissions\n // STDIO: If no httpRequest.raw, disable guards (local dev mode)\n const allTools = this.registry.getTools(this.mcpModuleId);\n const effectiveModuleHasGuards = httpRequest.raw\n ? this.moduleHasGuards\n : false;\n const allowUnauthenticatedAccess =\n this.options.allowUnauthenticatedAccess ?? false;\n\n // Filter by JWT-based authorization (scopes, roles, public)\n const jwtAuthorizedTools = allTools.filter((tool) =>\n this.authService.canAccessTool(\n user,\n tool,\n effectiveModuleHasGuards,\n allowUnauthenticatedAccess,\n ),\n );\n\n // Filter by @ToolGuards() - evaluate each tool's guards\n const authorizedTools: typeof jwtAuthorizedTools = [];\n for (const tool of jwtAuthorizedTools) {\n if (await this.checkToolGuards(tool, httpRequest)) {\n authorizedTools.push(tool);\n }\n }\n\n const tools = authorizedTools.map((tool) => {\n // Create base schema\n const toolSchema = {\n name: tool.metadata.name,\n description: tool.metadata.description,\n annotations: tool.metadata.annotations,\n _meta: tool.metadata._meta,\n };\n\n // Add security schemes\n const securitySchemes = this.authService.generateSecuritySchemes(\n tool,\n effectiveModuleHasGuards,\n );\n if (securitySchemes.length > 0) {\n toolSchema['securitySchemes'] = securitySchemes;\n // Note: Currently securitySchemes are not supported in MCP sdk, adding to _meta as workaround\n // (see https://developers.openai.com/apps-sdk/reference/)\n toolSchema._meta = {\n ...toolSchema._meta,\n securitySchemes,\n };\n }\n\n // Add input schema if defined\n const normalizedInputParameters = normalizeObjectSchema(\n tool.metadata.parameters,\n );\n if (normalizedInputParameters) {\n toolSchema['inputSchema'] = toJsonSchemaCompat(\n normalizedInputParameters,\n );\n }\n\n // Add output schema if defined, ensuring it has type: 'object'\n const normalizedOutputSchema = normalizeObjectSchema(\n tool.metadata.outputSchema,\n );\n if (normalizedOutputSchema) {\n const outputSchema = toJsonSchemaCompat(normalizedOutputSchema);\n\n // Create a new object that explicitly includes type: 'object'\n const jsonSchema = {\n ...outputSchema,\n type: 'object',\n };\n\n toolSchema['outputSchema'] = jsonSchema;\n }\n\n return toolSchema;\n });\n\n return {\n tools,\n };\n });\n\n mcpServer.server.setRequestHandler(\n CallToolRequestSchema,\n async (request) => {\n this.logger.debug('CallToolRequestSchema is being called');\n\n const toolInfo = this.registry.findTool(\n this.mcpModuleId,\n request.params.name,\n );\n\n if (!toolInfo) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n // Validate authorization before execution\n // For STDIO transport, bypass auth entirely (local dev mode)\n const user = httpRequest.raw\n ? (httpRequest.raw as McpRequestWithUser).user\n : undefined;\n const effectiveModuleHasGuards = httpRequest.raw\n ? this.moduleHasGuards\n : false;\n const allowUnauthenticatedAccess =\n this.options.allowUnauthenticatedAccess ?? false;\n this.authService.validateToolAccess(\n user,\n toolInfo,\n effectiveModuleHasGuards,\n allowUnauthenticatedAccess,\n );\n\n // Validate @ToolGuards()\n const guardsPassed = await this.checkToolGuards(toolInfo, httpRequest);\n if (!guardsPassed) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Access denied: insufficient permissions for tool '${request.params.name}'`,\n );\n }\n\n try {\n // Validate input parameters against the tool's schema\n if (toolInfo.metadata.parameters) {\n const validation = toolInfo.metadata.parameters.safeParse(\n request.params.arguments || {},\n );\n if (!validation.success) {\n const issues = validation.error.issues\n .map((issue) => {\n const path =\n issue.path.length > 0 ? issue.path.join('.') : '';\n const location = path ? `[${path}]: ` : '';\n return `${location}${issue.message}`;\n })\n .join('; ');\n return {\n content: [\n {\n type: 'text',\n text: `Invalid parameters: ${issues}`,\n },\n ],\n isError: true,\n };\n }\n // Use validated arguments to ensure defaults and transformations are applied\n request.params.arguments = validation.data as Record<\n string,\n unknown\n >;\n }\n\n const contextId = ContextIdFactory.getByRequest(httpRequest);\n this.moduleRef.registerRequestByContextId(httpRequest, contextId);\n\n const context = this.createContext(mcpServer, request);\n let result: any;\n\n // Check if this is a dynamic tool (registered via McpRegistryService)\n if (toolInfo.providerClass === DYNAMIC_TOOL_HANDLER_TOKEN) {\n // Dynamic tool - get handler using static method with the correct moduleId\n const handler = McpRegistryService.getHandlerByModuleId(\n this.mcpModuleId,\n request.params.name,\n );\n\n if (!handler) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Handler not found for dynamic tool: ${request.params.name}`,\n );\n }\n\n result = await handler(\n request.params.arguments || {},\n context,\n httpRequest.raw as McpRequestWithUser,\n );\n } else {\n // Decorator-based tool - resolve provider instance and call method\n const toolInstance = await this.moduleRef.resolve(\n toolInfo.providerClass,\n contextId,\n { strict: false },\n );\n\n if (!toolInstance) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n result = await toolInstance[toolInfo.methodName].call(\n toolInstance,\n request.params.arguments,\n context,\n httpRequest.raw as McpRequestWithUser,\n );\n }\n\n const transformedResult = this.formatToolResult(\n result,\n toolInfo.metadata.outputSchema,\n );\n\n this.logger.debug('CallToolRequestSchema result', transformedResult);\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return transformedResult;\n } catch (error) {\n // We are assuming error as at least a message property\n return this.handleError(error as Error, toolInfo, httpRequest);\n }\n },\n );\n }\n}\n"]}
1
+ {"version":3,"file":"mcp-tools.handler.js","sourceRoot":"","sources":["../../../../src/mcp/services/handlers/mcp-tools.handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {\n CallToolRequestSchema,\n CallToolResult,\n ErrorCode,\n ListToolsRequestSchema,\n McpError,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n CanActivate,\n ExecutionContext,\n Inject,\n Injectable,\n Scope,\n Type,\n} from '@nestjs/common';\nimport { ContextIdFactory, ModuleRef, Reflector } from '@nestjs/core';\nimport {\n DiscoveredCapability,\n McpRegistryDiscoveryService,\n} from '../mcp-registry-discovery.service';\nimport { ToolGuardExecutionContext, ToolMetadata } from '../../decorators';\nimport { McpHandlerBase } from './mcp-handler.base';\nimport { ZodType } from 'zod';\nimport { HttpRequest } from '../../interfaces/http-adapter.interface';\nimport { McpRequestWithUser } from 'src/authz';\nimport { ToolAuthorizationService } from '../tool-authorization.service';\nimport { toJsonSchemaCompat } from '@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';\nimport { normalizeObjectSchema } from '@modelcontextprotocol/sdk/server/zod-compat.js';\nimport type { McpOptions } from '../../interfaces/mcp-options.interface';\nimport {\n McpRegistryService,\n DYNAMIC_TOOL_HANDLER_TOKEN,\n} from '../mcp-dynamic-registry.service';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class McpToolsHandler extends McpHandlerBase {\n private readonly moduleHasGuards: boolean;\n\n constructor(\n moduleRef: ModuleRef,\n registry: McpRegistryDiscoveryService,\n reflector: Reflector,\n @Inject('MCP_MODULE_ID') private readonly mcpModuleId: string,\n @Inject('MCP_OPTIONS') private readonly options: McpOptions,\n private readonly authService: ToolAuthorizationService,\n ) {\n super(moduleRef, registry, reflector, McpToolsHandler.name, options);\n this.moduleHasGuards =\n this.options.guards !== undefined && this.options.guards.length > 0;\n }\n\n private buildDefaultContentBlock(result: any) {\n return [\n {\n type: 'text',\n text: JSON.stringify(result),\n },\n ];\n }\n\n private formatToolResult(result: any, outputSchema?: ZodType): any {\n if (result && typeof result === 'object' && Array.isArray(result.content)) {\n return result;\n }\n\n if (outputSchema) {\n const validation = outputSchema.safeParse(result);\n if (!validation.success) {\n throw new McpError(\n ErrorCode.InternalError,\n `Tool result does not match outputSchema: ${validation.error.message}`,\n );\n }\n return {\n structuredContent: validation.data,\n content: this.buildDefaultContentBlock(result),\n };\n }\n\n return {\n content: this.buildDefaultContentBlock(result),\n };\n }\n\n protected override createErrorResponse(\n errorText: string,\n ): CallToolResult | never {\n return {\n content: [{ type: 'text', text: errorText }],\n isError: true,\n };\n }\n\n /**\n * Creates an ExecutionContext for @ToolGuards() evaluation.\n *\n * Only the fields documented in ToolGuardExecutionContext are available.\n * Invalid fields throw with a descriptive message rather than silently\n * returning garbage.\n *\n * The request object returned by `switchToHttp().getRequest()` is the raw\n * framework request enriched with `body` and `params` from the adapted\n * HttpRequest. During `tools/call`, `toolArguments` overrides `body` so\n * guards can inspect the validated tool input.\n */\n private createToolGuardExecutionContext(\n httpRequest: HttpRequest,\n tool: DiscoveredCapability<ToolMetadata>,\n toolArguments?: Record<string, unknown>,\n ): ToolGuardExecutionContext & ExecutionContext {\n const providerClass = tool.providerClass as Type;\n const methodHandler =\n providerClass.prototype?.[tool.methodName] ?? (() => {});\n\n const unavailable = (method: string): never => {\n throw new Error(\n `${method} is not available in @ToolGuards() context. ` +\n `MCP tools share a single HTTP endpoint, so only a limited API is available.` +\n `See ToolGuardExecutionContext for the supported API.`,\n );\n };\n\n // Build the guard request from the raw request, enriched with parsed body and params.\n // During tools/call, toolArguments is passed so guards can inspect the tool input as `body`.\n const guardRequest = Object.assign(\n Object.create(Object.getPrototypeOf(httpRequest.raw ?? {})),\n httpRequest.raw ?? {},\n {\n body: toolArguments ?? httpRequest.body,\n params: httpRequest.params ?? {},\n },\n );\n\n return {\n switchToHttp: () => ({\n getRequest: <T = unknown>() => guardRequest as T,\n getResponse: () => unavailable('switchToHttp().getResponse()'),\n getNext: () => unavailable('switchToHttp().getNext()'),\n }),\n getClass: <T = unknown>() => providerClass as Type<T>,\n getHandler: () => methodHandler as () => void,\n getArgs: () => unavailable('getArgs()'),\n getArgByIndex: () => unavailable('getArgByIndex()'),\n getType: <TContext extends string = string>() => 'http' as TContext,\n switchToRpc: () => unavailable('switchToRpc()'),\n switchToWs: () => unavailable('switchToWs()'),\n };\n }\n\n /**\n * Evaluates all @ToolGuards() for a tool.\n * Returns true if the tool has no guards or all guards pass.\n */\n private async checkToolGuards(\n tool: DiscoveredCapability<ToolMetadata>,\n httpRequest: HttpRequest,\n toolArguments?: Record<string, unknown>,\n ): Promise<boolean> {\n const guards = tool.metadata.guards;\n if (!guards || guards.length === 0) {\n return true;\n }\n\n // Guards require HTTP context - not available on STDIO\n if (!httpRequest.raw) {\n this.logger.warn(\n `@ToolGuards() on tool '${tool.metadata.name}' cannot be evaluated without HTTP context (STDIO transport). ` +\n `The tool will be hidden. Use HTTP transport to support guarded tools.`,\n );\n return false;\n }\n\n const context = this.createToolGuardExecutionContext(httpRequest, tool, toolArguments);\n\n for (const GuardClass of guards) {\n try {\n const guard = this.moduleRef.get<CanActivate>(GuardClass, {\n strict: false,\n });\n const result = guard.canActivate(context);\n const canActivate = result instanceof Promise ? await result : result;\n if (!canActivate) {\n return false;\n }\n } catch (error) {\n this.logger.warn(\n `@ToolGuards() guard ${GuardClass.name} threw on tool '${tool.metadata.name}': ${error.message}. ` +\n `The tool will be hidden. If this is unexpected, ensure the guard only uses ` +\n `the API available in ToolGuardExecutionContext.`,\n );\n return false;\n }\n }\n\n return true;\n }\n registerHandlers(mcpServer: McpServer, httpRequest: HttpRequest) {\n if (this.registry.getTools(this.mcpModuleId).length === 0) {\n this.logger.debug('No tools registered, skipping tool handlers');\n return;\n }\n\n mcpServer.server.setRequestHandler(ListToolsRequestSchema, async () => {\n // Extract user from request (may be undefined if not authenticated or STDIO)\n // For STDIO transport, httpRequest.raw is undefined, so bypass auth entirely\n const user = httpRequest.raw\n ? (httpRequest.raw as McpRequestWithUser).user\n : undefined;\n\n // Get all tools and filter based on user permissions\n // STDIO: If no httpRequest.raw, disable guards (local dev mode)\n const allTools = this.registry.getTools(this.mcpModuleId);\n const effectiveModuleHasGuards = httpRequest.raw\n ? this.moduleHasGuards\n : false;\n const allowUnauthenticatedAccess =\n this.options.allowUnauthenticatedAccess ?? false;\n\n // Filter by JWT-based authorization (scopes, roles, public)\n const jwtAuthorizedTools = allTools.filter((tool) =>\n this.authService.canAccessTool(\n user,\n tool,\n effectiveModuleHasGuards,\n allowUnauthenticatedAccess,\n ),\n );\n\n // Filter by @ToolGuards() - evaluate each tool's guards\n const authorizedTools: typeof jwtAuthorizedTools = [];\n for (const tool of jwtAuthorizedTools) {\n if (await this.checkToolGuards(tool, httpRequest)) {\n authorizedTools.push(tool);\n }\n }\n\n const tools = authorizedTools.map((tool) => {\n // Create base schema\n const toolSchema = {\n name: tool.metadata.name,\n description: tool.metadata.description,\n annotations: tool.metadata.annotations,\n _meta: tool.metadata._meta,\n };\n\n // Add security schemes\n const securitySchemes = this.authService.generateSecuritySchemes(\n tool,\n effectiveModuleHasGuards,\n );\n if (securitySchemes.length > 0) {\n toolSchema['securitySchemes'] = securitySchemes;\n // Note: Currently securitySchemes are not supported in MCP sdk, adding to _meta as workaround\n // (see https://developers.openai.com/apps-sdk/reference/)\n toolSchema._meta = {\n ...toolSchema._meta,\n securitySchemes,\n };\n }\n\n // Add input schema if defined\n const normalizedInputParameters = normalizeObjectSchema(\n tool.metadata.parameters,\n );\n if (normalizedInputParameters) {\n toolSchema['inputSchema'] = toJsonSchemaCompat(\n normalizedInputParameters,\n );\n }\n\n // Add output schema if defined, ensuring it has type: 'object'\n const normalizedOutputSchema = normalizeObjectSchema(\n tool.metadata.outputSchema,\n );\n if (normalizedOutputSchema) {\n const outputSchema = toJsonSchemaCompat(normalizedOutputSchema);\n\n // Create a new object that explicitly includes type: 'object'\n const jsonSchema = {\n ...outputSchema,\n type: 'object',\n };\n\n toolSchema['outputSchema'] = jsonSchema;\n }\n\n return toolSchema;\n });\n\n return {\n tools,\n };\n });\n\n mcpServer.server.setRequestHandler(\n CallToolRequestSchema,\n async (request) => {\n this.logger.debug('CallToolRequestSchema is being called');\n\n const toolInfo = this.registry.findTool(\n this.mcpModuleId,\n request.params.name,\n );\n\n if (!toolInfo) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n // Validate authorization before execution\n // For STDIO transport, bypass auth entirely (local dev mode)\n const user = httpRequest.raw\n ? (httpRequest.raw as McpRequestWithUser).user\n : undefined;\n const effectiveModuleHasGuards = httpRequest.raw\n ? this.moduleHasGuards\n : false;\n const allowUnauthenticatedAccess =\n this.options.allowUnauthenticatedAccess ?? false;\n this.authService.validateToolAccess(\n user,\n toolInfo,\n effectiveModuleHasGuards,\n allowUnauthenticatedAccess,\n );\n\n // Validate @ToolGuards()\n const guardsPassed = await this.checkToolGuards(toolInfo, httpRequest, request.params.arguments as Record<string, unknown>);\n if (!guardsPassed) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Access denied: insufficient permissions for tool '${request.params.name}'`,\n );\n }\n\n try {\n // Validate input parameters against the tool's schema\n if (toolInfo.metadata.parameters) {\n const validation = toolInfo.metadata.parameters.safeParse(\n request.params.arguments || {},\n );\n if (!validation.success) {\n const issues = validation.error.issues\n .map((issue) => {\n const path =\n issue.path.length > 0 ? issue.path.join('.') : '';\n const location = path ? `[${path}]: ` : '';\n return `${location}${issue.message}`;\n })\n .join('; ');\n return {\n content: [\n {\n type: 'text',\n text: `Invalid parameters: ${issues}`,\n },\n ],\n isError: true,\n };\n }\n // Use validated arguments to ensure defaults and transformations are applied\n request.params.arguments = validation.data as Record<\n string,\n unknown\n >;\n }\n\n const contextId = ContextIdFactory.getByRequest(httpRequest);\n this.moduleRef.registerRequestByContextId(httpRequest, contextId);\n\n const context = this.createContext(mcpServer, request);\n let result: any;\n\n // Check if this is a dynamic tool (registered via McpRegistryService)\n if (toolInfo.providerClass === DYNAMIC_TOOL_HANDLER_TOKEN) {\n // Dynamic tool - get handler using static method with the correct moduleId\n const handler = McpRegistryService.getHandlerByModuleId(\n this.mcpModuleId,\n request.params.name,\n );\n\n if (!handler) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Handler not found for dynamic tool: ${request.params.name}`,\n );\n }\n\n result = await handler(\n request.params.arguments || {},\n context,\n httpRequest.raw as McpRequestWithUser,\n );\n } else {\n // Decorator-based tool - resolve provider instance and call method\n const toolInstance = await this.moduleRef.resolve(\n toolInfo.providerClass,\n contextId,\n { strict: false },\n );\n\n if (!toolInstance) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n result = await toolInstance[toolInfo.methodName].call(\n toolInstance,\n request.params.arguments,\n context,\n httpRequest.raw as McpRequestWithUser,\n );\n }\n\n const transformedResult = this.formatToolResult(\n result,\n toolInfo.metadata.outputSchema,\n );\n\n this.logger.debug('CallToolRequestSchema result', transformedResult);\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return transformedResult;\n } catch (error) {\n // We are assuming error as at least a message property\n return this.handleError(error as Error, toolInfo, httpRequest);\n }\n },\n );\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rekog/mcp-nest",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "description": "NestJS module for creating Model Context Protocol (MCP) servers",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -13,7 +13,12 @@ export const MCP_GUARDS_METADATA_KEY = 'mcp:guards';
13
13
  * describes exactly what IS available.
14
14
  *
15
15
  * Available:
16
- * - `switchToHttp().getRequest()` - the real HTTP request object
16
+ * - `switchToHttp().getRequest()` - the HTTP request object, enriched with:
17
+ * - `body` - during `tools/call`, contains the validated tool arguments;
18
+ * during `tools/list`, contains the raw HTTP request body (if any)
19
+ * - `params` - parsed route params from the HTTP adapter
20
+ * - `user` - if set by a transport-level auth guard
21
+ * - `headers` - original request headers
17
22
  * - `getClass()` - the tool's provider class (works with Reflector)
18
23
  * - `getHandler()` - the tool's method reference (works with Reflector)
19
24
  * - `getType()` - always returns `'http'`
@@ -98,10 +98,16 @@ export class McpToolsHandler extends McpHandlerBase {
98
98
  * Only the fields documented in ToolGuardExecutionContext are available.
99
99
  * Invalid fields throw with a descriptive message rather than silently
100
100
  * returning garbage.
101
+ *
102
+ * The request object returned by `switchToHttp().getRequest()` is the raw
103
+ * framework request enriched with `body` and `params` from the adapted
104
+ * HttpRequest. During `tools/call`, `toolArguments` overrides `body` so
105
+ * guards can inspect the validated tool input.
101
106
  */
102
107
  private createToolGuardExecutionContext(
103
108
  httpRequest: HttpRequest,
104
109
  tool: DiscoveredCapability<ToolMetadata>,
110
+ toolArguments?: Record<string, unknown>,
105
111
  ): ToolGuardExecutionContext & ExecutionContext {
106
112
  const providerClass = tool.providerClass as Type;
107
113
  const methodHandler =
@@ -115,9 +121,20 @@ export class McpToolsHandler extends McpHandlerBase {
115
121
  );
116
122
  };
117
123
 
124
+ // Build the guard request from the raw request, enriched with parsed body and params.
125
+ // During tools/call, toolArguments is passed so guards can inspect the tool input as `body`.
126
+ const guardRequest = Object.assign(
127
+ Object.create(Object.getPrototypeOf(httpRequest.raw ?? {})),
128
+ httpRequest.raw ?? {},
129
+ {
130
+ body: toolArguments ?? httpRequest.body,
131
+ params: httpRequest.params ?? {},
132
+ },
133
+ );
134
+
118
135
  return {
119
136
  switchToHttp: () => ({
120
- getRequest: <T = unknown>() => httpRequest.raw as T,
137
+ getRequest: <T = unknown>() => guardRequest as T,
121
138
  getResponse: () => unavailable('switchToHttp().getResponse()'),
122
139
  getNext: () => unavailable('switchToHttp().getNext()'),
123
140
  }),
@@ -138,6 +155,7 @@ export class McpToolsHandler extends McpHandlerBase {
138
155
  private async checkToolGuards(
139
156
  tool: DiscoveredCapability<ToolMetadata>,
140
157
  httpRequest: HttpRequest,
158
+ toolArguments?: Record<string, unknown>,
141
159
  ): Promise<boolean> {
142
160
  const guards = tool.metadata.guards;
143
161
  if (!guards || guards.length === 0) {
@@ -153,7 +171,7 @@ export class McpToolsHandler extends McpHandlerBase {
153
171
  return false;
154
172
  }
155
173
 
156
- const context = this.createToolGuardExecutionContext(httpRequest, tool);
174
+ const context = this.createToolGuardExecutionContext(httpRequest, tool, toolArguments);
157
175
 
158
176
  for (const GuardClass of guards) {
159
177
  try {
@@ -310,7 +328,7 @@ export class McpToolsHandler extends McpHandlerBase {
310
328
  );
311
329
 
312
330
  // Validate @ToolGuards()
313
- const guardsPassed = await this.checkToolGuards(toolInfo, httpRequest);
331
+ const guardsPassed = await this.checkToolGuards(toolInfo, httpRequest, request.params.arguments as Record<string, unknown>);
314
332
  if (!guardsPassed) {
315
333
  throw new McpError(
316
334
  ErrorCode.InvalidRequest,