@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.
- package/dist/mcp/decorators/tool-guards.decorator.d.ts.map +1 -1
- package/dist/mcp/decorators/tool-guards.decorator.js.map +1 -1
- package/dist/mcp/services/handlers/mcp-tools.handler.d.ts.map +1 -1
- package/dist/mcp/services/handlers/mcp-tools.handler.js +9 -5
- package/dist/mcp/services/handlers/mcp-tools.handler.js.map +1 -1
- package/package.json +1 -1
- package/src/mcp/decorators/tool-guards.decorator.ts +6 -1
- package/src/mcp/services/handlers/mcp-tools.handler.ts +21 -3
|
@@ -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;
|
|
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;
|
|
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;
|
|
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: () =>
|
|
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":";;;;;;;;;;;;;;;;AACA,iEAM4C;AAC5C,2CAOwB;AACxB,uCAAsE;AACtE,sFAG2C;AAE3C,yDAAoD;AAIpD,8EAAyE;AACzE,0GAAgG;AAChG,kFAAuF;AAEvF,kFAGyC;AAGlC,IAAM,eAAe,uBAArB,MAAM,eAAgB,SAAQ,iCAAc;IAGjD,YACE,SAAoB,EACpB,QAAqC,EACrC,SAAoB,EACsB,WAAmB,EACrB,OAAmB,EAC1C,WAAqC;QAEtD,KAAK,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAJ3B,gBAAW,GAAX,WAAW,CAAQ;QACrB,YAAO,GAAP,OAAO,CAAY;QAC1C,gBAAW,GAAX,WAAW,CAA0B;QAGtD,IAAI,CAAC,eAAe;YAClB,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACxE,CAAC;IAEO,wBAAwB,CAAC,MAAW;QAC1C,OAAO;YACL;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;aAC7B;SACF,CAAC;IACJ,CAAC;IAEO,gBAAgB,CAAC,MAAW,EAAE,YAAsB;QAC1D,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1E,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,UAAU,GAAG,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAClD,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;gBACxB,MAAM,IAAI,mBAAQ,CAChB,oBAAS,CAAC,aAAa,EACvB,4CAA4C,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,CACvE,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,iBAAiB,EAAE,UAAU,CAAC,IAAI;gBAClC,OAAO,EAAE,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC;aAC/C,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC;SAC/C,CAAC;IACJ,CAAC;IAEkB,mBAAmB,CACpC,SAAiB;QAEjB,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YAC5C,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IASO,+BAA+B,CACrC,WAAwB,EACxB,IAAwC;QAExC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAqB,CAAC;QACjD,MAAM,aAAa,GACjB,aAAa,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAE3D,MAAM,WAAW,GAAG,CAAC,MAAc,EAAS,EAAE;YAC5C,MAAM,IAAI,KAAK,CACb,GAAG,MAAM,8CAA8C;gBACrD,6EAA6E;gBAC7E,sDAAsD,CACzD,CAAC;QACJ,CAAC,CAAC;QAEF,OAAO;YACL,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;gBACnB,UAAU,EAAE,GAAgB,EAAE,CAAC,WAAW,CAAC,GAAQ;gBACnD,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,8BAA8B,CAAC;gBAC9D,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,0BAA0B,CAAC;aACvD,CAAC;YACF,QAAQ,EAAE,GAAgB,EAAE,CAAC,aAAwB;YACrD,UAAU,EAAE,GAAG,EAAE,CAAC,aAA2B;YAC7C,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC;YACvC,aAAa,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC;YACnD,OAAO,EAAE,GAAqC,EAAE,CAAC,MAAkB;YACnE,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,eAAe,CAAC;YAC/C,UAAU,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,cAAc,CAAC;SAC9C,CAAC;IACJ,CAAC;IAMO,KAAK,CAAC,eAAe,CAC3B,IAAwC,EACxC,WAAwB;QAExB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,0BAA0B,IAAI,CAAC,QAAQ,CAAC,IAAI,gEAAgE;gBAC1G,uEAAuE,CAC1E,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,+BAA+B,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAExE,KAAK,MAAM,UAAU,IAAI,MAAM,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAc,UAAU,EAAE;oBACxD,MAAM,EAAE,KAAK;iBACd,CAAC,CAAC;gBACH,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;gBAC1C,MAAM,WAAW,GAAG,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;gBACtE,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,uBAAuB,UAAU,CAAC,IAAI,mBAAmB,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,IAAI;oBAChG,6EAA6E;oBAC7E,iDAAiD,CACpD,CAAC;gBACF,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IACD,gBAAgB,CAAC,SAAoB,EAAE,WAAwB;QAC7D,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,SAAS,CAAC,MAAM,CAAC,iBAAiB,CAAC,iCAAsB,EAAE,KAAK,IAAI,EAAE;YAGpE,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG;gBAC1B,CAAC,CAAE,WAAW,CAAC,GAA0B,CAAC,IAAI;gBAC9C,CAAC,CAAC,SAAS,CAAC;YAId,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1D,MAAM,wBAAwB,GAAG,WAAW,CAAC,GAAG;gBAC9C,CAAC,CAAC,IAAI,CAAC,eAAe;gBACtB,CAAC,CAAC,KAAK,CAAC;YACV,MAAM,0BAA0B,GAC9B,IAAI,CAAC,OAAO,CAAC,0BAA0B,IAAI,KAAK,CAAC;YAGnD,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAClD,IAAI,CAAC,WAAW,CAAC,aAAa,CAC5B,IAAI,EACJ,IAAI,EACJ,wBAAwB,EACxB,0BAA0B,CAC3B,CACF,CAAC;YAGF,MAAM,eAAe,GAA8B,EAAE,CAAC;YACtD,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;gBACtC,IAAI,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;oBAClD,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;YAED,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBAEzC,MAAM,UAAU,GAAG;oBACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;oBACxB,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;oBACtC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;oBACtC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK;iBAC3B,CAAC;gBAGF,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,uBAAuB,CAC9D,IAAI,EACJ,wBAAwB,CACzB,CAAC;gBACF,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC/B,UAAU,CAAC,iBAAiB,CAAC,GAAG,eAAe,CAAC;oBAGhD,UAAU,CAAC,KAAK,GAAG;wBACjB,GAAG,UAAU,CAAC,KAAK;wBACnB,eAAe;qBAChB,CAAC;gBACJ,CAAC;gBAGD,MAAM,yBAAyB,GAAG,IAAA,qCAAqB,EACrD,IAAI,CAAC,QAAQ,CAAC,UAAU,CACzB,CAAC;gBACF,IAAI,yBAAyB,EAAE,CAAC;oBAC9B,UAAU,CAAC,aAAa,CAAC,GAAG,IAAA,8CAAkB,EAC5C,yBAAyB,CAC1B,CAAC;gBACJ,CAAC;gBAGD,MAAM,sBAAsB,GAAG,IAAA,qCAAqB,EAClD,IAAI,CAAC,QAAQ,CAAC,YAAY,CAC3B,CAAC;gBACF,IAAI,sBAAsB,EAAE,CAAC;oBAC3B,MAAM,YAAY,GAAG,IAAA,8CAAkB,EAAC,sBAAsB,CAAC,CAAC;oBAGhE,MAAM,UAAU,GAAG;wBACjB,GAAG,YAAY;wBACf,IAAI,EAAE,QAAQ;qBACf,CAAC;oBAEF,UAAU,CAAC,cAAc,CAAC,GAAG,UAAU,CAAC;gBAC1C,CAAC;gBAED,OAAO,UAAU,CAAC;YACpB,CAAC,CAAC,CAAC;YAEH,OAAO;gBACL,KAAK;aACN,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,MAAM,CAAC,iBAAiB,CAChC,gCAAqB,EACrB,KAAK,EAAE,OAAO,EAAE,EAAE;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAE3D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CACrC,IAAI,CAAC,WAAW,EAChB,OAAO,CAAC,MAAM,CAAC,IAAI,CACpB,CAAC;YAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,mBAAQ,CAChB,oBAAS,CAAC,cAAc,EACxB,iBAAiB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CACvC,CAAC;YACJ,CAAC;YAID,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG;gBAC1B,CAAC,CAAE,WAAW,CAAC,GAA0B,CAAC,IAAI;gBAC9C,CAAC,CAAC,SAAS,CAAC;YACd,MAAM,wBAAwB,GAAG,WAAW,CAAC,GAAG;gBAC9C,CAAC,CAAC,IAAI,CAAC,eAAe;gBACtB,CAAC,CAAC,KAAK,CAAC;YACV,MAAM,0BAA0B,GAC9B,IAAI,CAAC,OAAO,CAAC,0BAA0B,IAAI,KAAK,CAAC;YACnD,IAAI,CAAC,WAAW,CAAC,kBAAkB,CACjC,IAAI,EACJ,QAAQ,EACR,wBAAwB,EACxB,0BAA0B,CAC3B,CAAC;YAGF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YACvE,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,mBAAQ,CAChB,oBAAS,CAAC,cAAc,EACxB,qDAAqD,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,CAC5E,CAAC;YACJ,CAAC;YAED,IAAI,CAAC;gBAEH,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;oBACjC,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CACvD,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAC/B,CAAC;oBACF,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;wBACxB,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM;6BACnC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;4BACb,MAAM,IAAI,GACR,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;4BACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;4BAC3C,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;wBACvC,CAAC,CAAC;6BACD,IAAI,CAAC,IAAI,CAAC,CAAC;wBACd,OAAO;4BACL,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,MAAM;oCACZ,IAAI,EAAE,uBAAuB,MAAM,EAAE;iCACtC;6BACF;4BACD,OAAO,EAAE,IAAI;yBACd,CAAC;oBACJ,CAAC;oBAED,OAAO,CAAC,MAAM,CAAC,SAAS,GAAG,UAAU,CAAC,IAGrC,CAAC;gBACJ,CAAC;gBAED,MAAM,SAAS,GAAG,uBAAgB,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAC7D,IAAI,CAAC,SAAS,CAAC,0BAA0B,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;gBAElE,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBACvD,IAAI,MAAW,CAAC;gBAGhB,IAAI,QAAQ,CAAC,aAAa,KAAK,yDAA0B,EAAE,CAAC;oBAE1D,MAAM,OAAO,GAAG,iDAAkB,CAAC,oBAAoB,CACrD,IAAI,CAAC,WAAW,EAChB,OAAO,CAAC,MAAM,CAAC,IAAI,CACpB,CAAC;oBAEF,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,MAAM,IAAI,mBAAQ,CAChB,oBAAS,CAAC,cAAc,EACxB,uCAAuC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAC7D,CAAC;oBACJ,CAAC;oBAED,MAAM,GAAG,MAAM,OAAO,CACpB,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,EAC9B,OAAO,EACP,WAAW,CAAC,GAAyB,CACtC,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBAEN,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAC/C,QAAQ,CAAC,aAAa,EACtB,SAAS,EACT,EAAE,MAAM,EAAE,KAAK,EAAE,CAClB,CAAC;oBAEF,IAAI,CAAC,YAAY,EAAE,CAAC;wBAClB,MAAM,IAAI,mBAAQ,CAChB,oBAAS,CAAC,cAAc,EACxB,iBAAiB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CACvC,CAAC;oBACJ,CAAC;oBAED,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CACnD,YAAY,EACZ,OAAO,CAAC,MAAM,CAAC,SAAS,EACxB,OAAO,EACP,WAAW,CAAC,GAAyB,CACtC,CAAC;gBACJ,CAAC;gBAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,CAC7C,MAAM,EACN,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAC/B,CAAC;gBAEF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,iBAAiB,CAAC,CAAC;gBAGrE,OAAO,iBAAiB,CAAC;YAC3B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAEf,OAAO,IAAI,CAAC,WAAW,CAAC,KAAc,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;YACjE,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC;CACF,CAAA;AA7XY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,EAAC,EAAE,KAAK,EAAE,cAAK,CAAC,OAAO,EAAE,CAAC;IAQhC,WAAA,IAAA,eAAM,EAAC,eAAe,CAAC,CAAA;IACvB,WAAA,IAAA,eAAM,EAAC,aAAa,CAAC,CAAA;qCAJX,gBAAS;QACV,4DAA2B;QAC1B,gBAAS,kBAGU,qDAAwB;GAT7C,eAAe,CA6X3B","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
|
@@ -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
|
|
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>() =>
|
|
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,
|