@rekog/mcp-nest 1.9.10 → 2.0.0-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 +76 -29
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/decorators/constants.d.ts +1 -0
- package/dist/mcp/decorators/constants.d.ts.map +1 -1
- package/dist/mcp/decorators/constants.js +2 -1
- package/dist/mcp/decorators/constants.js.map +1 -1
- package/dist/mcp/decorators/index.d.ts +3 -1
- package/dist/mcp/decorators/index.d.ts.map +1 -1
- package/dist/mcp/decorators/index.js +3 -1
- package/dist/mcp/decorators/index.js.map +1 -1
- package/dist/mcp/decorators/mcp-controller.decorator.d.ts +6 -0
- package/dist/mcp/decorators/mcp-controller.decorator.d.ts.map +1 -0
- package/dist/mcp/decorators/mcp-controller.decorator.js +43 -0
- package/dist/mcp/decorators/mcp-controller.decorator.js.map +1 -0
- package/dist/mcp/decorators/mcp-message-pattern.d.ts +3 -0
- package/dist/mcp/decorators/mcp-message-pattern.d.ts.map +1 -0
- package/dist/mcp/decorators/mcp-message-pattern.js +13 -0
- package/dist/mcp/decorators/mcp-message-pattern.js.map +1 -0
- package/dist/mcp/decorators/prompt.decorator.d.ts +4 -1
- package/dist/mcp/decorators/prompt.decorator.d.ts.map +1 -1
- package/dist/mcp/decorators/prompt.decorator.js +2 -1
- package/dist/mcp/decorators/prompt.decorator.js.map +1 -1
- package/dist/mcp/decorators/public.decorator.js.map +1 -1
- package/dist/mcp/decorators/raw-request.decorator.d.ts +2 -0
- package/dist/mcp/decorators/raw-request.decorator.d.ts.map +1 -0
- package/dist/mcp/decorators/raw-request.decorator.js +6 -0
- package/dist/mcp/decorators/raw-request.decorator.js.map +1 -0
- package/dist/mcp/decorators/resource-template.decorator.d.ts +1 -1
- package/dist/mcp/decorators/resource-template.decorator.d.ts.map +1 -1
- package/dist/mcp/decorators/resource-template.decorator.js +2 -1
- package/dist/mcp/decorators/resource-template.decorator.js.map +1 -1
- package/dist/mcp/decorators/resource.decorator.d.ts +1 -1
- package/dist/mcp/decorators/resource.decorator.d.ts.map +1 -1
- package/dist/mcp/decorators/resource.decorator.js +2 -1
- package/dist/mcp/decorators/resource.decorator.js.map +1 -1
- package/dist/mcp/decorators/tool.decorator.d.ts +1 -3
- package/dist/mcp/decorators/tool.decorator.d.ts.map +1 -1
- package/dist/mcp/decorators/tool.decorator.js +2 -1
- package/dist/mcp/decorators/tool.decorator.js.map +1 -1
- package/dist/mcp/filters/mcp-exception.filter.d.ts +6 -0
- package/dist/mcp/filters/mcp-exception.filter.d.ts.map +1 -0
- package/dist/mcp/filters/mcp-exception.filter.js +26 -0
- package/dist/mcp/filters/mcp-exception.filter.js.map +1 -0
- package/dist/mcp/index.d.ts +11 -7
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +11 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/interfaces/authenticated-user.interface.d.ts +9 -0
- package/dist/mcp/interfaces/authenticated-user.interface.d.ts.map +1 -0
- package/dist/{authz/interfaces/request-with-user.js → mcp/interfaces/authenticated-user.interface.js} +1 -1
- package/dist/mcp/interfaces/authenticated-user.interface.js.map +1 -0
- package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts +1 -1
- package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts.map +1 -1
- package/dist/mcp/interfaces/dynamic-prompt.interface.js.map +1 -1
- package/dist/mcp/interfaces/dynamic-resource.interface.d.ts +1 -1
- package/dist/mcp/interfaces/dynamic-resource.interface.d.ts.map +1 -1
- package/dist/mcp/interfaces/dynamic-resource.interface.js.map +1 -1
- package/dist/mcp/interfaces/dynamic-tool.interface.d.ts +1 -1
- package/dist/mcp/interfaces/dynamic-tool.interface.d.ts.map +1 -1
- package/dist/mcp/interfaces/dynamic-tool.interface.js.map +1 -1
- package/dist/mcp/interfaces/index.d.ts +2 -2
- package/dist/mcp/interfaces/index.d.ts.map +1 -1
- package/dist/mcp/interfaces/index.js +0 -3
- package/dist/mcp/interfaces/index.js.map +1 -1
- package/dist/mcp/services/tool-authorization.service.d.ts +7 -5
- package/dist/mcp/services/tool-authorization.service.d.ts.map +1 -1
- package/dist/mcp/services/tool-authorization.service.js +9 -6
- package/dist/mcp/services/tool-authorization.service.js.map +1 -1
- package/dist/mcp/transport/mcp-context.d.ts +34 -0
- package/dist/mcp/transport/mcp-context.d.ts.map +1 -0
- package/dist/mcp/transport/mcp-context.js +74 -0
- package/dist/mcp/transport/mcp-context.js.map +1 -0
- package/dist/mcp/transport/mcp-http-handler.d.ts +7 -0
- package/dist/mcp/transport/mcp-http-handler.d.ts.map +1 -0
- package/dist/mcp/transport/mcp-http-handler.js +5 -0
- package/dist/mcp/transport/mcp-http-handler.js.map +1 -0
- package/dist/mcp/transport/mcp-server-options.interface.d.ts +23 -0
- package/dist/mcp/transport/mcp-server-options.interface.d.ts.map +1 -0
- package/dist/{authz/providers/oauth-provider.interface.js → mcp/transport/mcp-server-options.interface.js} +1 -1
- package/dist/mcp/transport/mcp-server-options.interface.js.map +1 -0
- package/dist/mcp/transport/mcp-transport.constants.d.ts +19 -0
- package/dist/mcp/transport/mcp-transport.constants.d.ts.map +1 -0
- package/dist/mcp/transport/mcp-transport.constants.js +21 -0
- package/dist/mcp/transport/mcp-transport.constants.js.map +1 -0
- package/dist/mcp/transport/mcp-transport.interface.d.ts +17 -0
- package/dist/mcp/transport/mcp-transport.interface.d.ts.map +1 -0
- package/dist/{authz/interfaces/oauth-common.interface.js → mcp/transport/mcp-transport.interface.js} +1 -1
- package/dist/mcp/transport/mcp-transport.interface.js.map +1 -0
- package/dist/mcp/transport/mcp.strategy.d.ts +56 -0
- package/dist/mcp/transport/mcp.strategy.d.ts.map +1 -0
- package/dist/mcp/transport/mcp.strategy.js +446 -0
- package/dist/mcp/transport/mcp.strategy.js.map +1 -0
- package/dist/mcp/transport/resource-matcher.d.ts +13 -0
- package/dist/mcp/transport/resource-matcher.d.ts.map +1 -0
- package/dist/mcp/transport/resource-matcher.js +83 -0
- package/dist/mcp/transport/resource-matcher.js.map +1 -0
- package/dist/mcp/transport/streamable-http.controller.d.ts +16 -0
- package/dist/mcp/transport/streamable-http.controller.d.ts.map +1 -0
- package/dist/mcp/transport/streamable-http.controller.js +98 -0
- package/dist/mcp/transport/streamable-http.controller.js.map +1 -0
- package/dist/mcp/transport/transports/index.d.ts +3 -0
- package/dist/mcp/transport/transports/index.d.ts.map +1 -0
- package/dist/{authz → mcp/transport/transports}/index.js +2 -10
- package/dist/mcp/transport/transports/index.js.map +1 -0
- package/dist/mcp/transport/transports/read-body.d.ts +3 -0
- package/dist/mcp/transport/transports/read-body.d.ts.map +1 -0
- package/dist/mcp/transport/transports/read-body.js +32 -0
- package/dist/mcp/transport/transports/read-body.js.map +1 -0
- package/dist/mcp/transport/transports/stdio.transport.d.ts +9 -0
- package/dist/mcp/transport/transports/stdio.transport.d.ts.map +1 -0
- package/dist/mcp/transport/transports/stdio.transport.js +27 -0
- package/dist/mcp/transport/transports/stdio.transport.js.map +1 -0
- package/dist/mcp/transport/transports/streamable-http.transport.d.ts +33 -0
- package/dist/mcp/transport/transports/streamable-http.transport.d.ts.map +1 -0
- package/dist/mcp/transport/transports/streamable-http.transport.js +216 -0
- package/dist/mcp/transport/transports/streamable-http.transport.js.map +1 -0
- package/dist/mcp/utils/mcp-logger.factory.d.ts +6 -2
- package/dist/mcp/utils/mcp-logger.factory.d.ts.map +1 -1
- package/dist/mcp/utils/mcp-logger.factory.js.map +1 -1
- package/package.json +3 -66
- package/src/index.ts +0 -1
- package/src/mcp/decorators/constants.ts +1 -0
- package/src/mcp/decorators/index.ts +3 -1
- package/src/mcp/decorators/mcp-controller.decorator.ts +126 -0
- package/src/mcp/decorators/mcp-message-pattern.ts +38 -0
- package/src/mcp/decorators/prompt.decorator.ts +32 -2
- package/src/mcp/decorators/public.decorator.ts +3 -3
- package/src/mcp/decorators/raw-request.decorator.ts +32 -0
- package/src/mcp/decorators/resource-template.decorator.ts +6 -2
- package/src/mcp/decorators/resource.decorator.ts +6 -2
- package/src/mcp/decorators/tool.decorator.ts +6 -3
- package/src/mcp/filters/mcp-exception.filter.ts +47 -0
- package/src/mcp/index.ts +13 -7
- package/src/mcp/interfaces/authenticated-user.interface.ts +22 -0
- package/src/mcp/interfaces/dynamic-prompt.interface.ts +1 -1
- package/src/mcp/interfaces/dynamic-resource.interface.ts +1 -1
- package/src/mcp/interfaces/dynamic-tool.interface.ts +2 -2
- package/src/mcp/interfaces/index.ts +3 -7
- package/src/mcp/services/tool-authorization.service.ts +52 -72
- package/src/mcp/transport/mcp-context.ts +138 -0
- package/src/mcp/transport/mcp-http-handler.ts +32 -0
- package/src/mcp/transport/mcp-server-options.interface.ts +75 -0
- package/src/mcp/transport/mcp-transport.constants.ts +99 -0
- package/src/mcp/transport/mcp-transport.interface.ts +50 -0
- package/src/mcp/transport/mcp.strategy.ts +752 -0
- package/src/mcp/transport/resource-matcher.ts +107 -0
- package/src/mcp/transport/streamable-http.controller.ts +114 -0
- package/src/mcp/transport/transports/index.ts +2 -0
- package/src/mcp/transport/transports/read-body.ts +39 -0
- package/src/mcp/transport/transports/stdio.transport.ts +35 -0
- package/src/mcp/transport/transports/streamable-http.transport.ts +384 -0
- package/src/mcp/utils/mcp-logger.factory.spec.ts +8 -22
- package/src/mcp/utils/mcp-logger.factory.ts +13 -2
- package/dist/authz/guards/jwt-auth.guard.d.ts +0 -19
- package/dist/authz/guards/jwt-auth.guard.d.ts.map +0 -1
- package/dist/authz/guards/jwt-auth.guard.js +0 -108
- package/dist/authz/guards/jwt-auth.guard.js.map +0 -1
- package/dist/authz/index.d.ts +0 -11
- package/dist/authz/index.d.ts.map +0 -1
- package/dist/authz/index.js.map +0 -1
- package/dist/authz/interfaces/oauth-common.interface.d.ts +0 -21
- package/dist/authz/interfaces/oauth-common.interface.d.ts.map +0 -1
- package/dist/authz/interfaces/oauth-common.interface.js.map +0 -1
- package/dist/authz/interfaces/request-with-user.d.ts +0 -13
- package/dist/authz/interfaces/request-with-user.d.ts.map +0 -1
- package/dist/authz/interfaces/request-with-user.js.map +0 -1
- package/dist/authz/mcp-oauth.controller.d.ts +0 -81
- package/dist/authz/mcp-oauth.controller.d.ts.map +0 -1
- package/dist/authz/mcp-oauth.controller.js +0 -540
- package/dist/authz/mcp-oauth.controller.js.map +0 -1
- package/dist/authz/mcp-oauth.module.d.ts +0 -12
- package/dist/authz/mcp-oauth.module.d.ts.map +0 -1
- package/dist/authz/mcp-oauth.module.js +0 -271
- package/dist/authz/mcp-oauth.module.js.map +0 -1
- package/dist/authz/providers/azure-ad.provider.d.ts +0 -3
- package/dist/authz/providers/azure-ad.provider.d.ts.map +0 -1
- package/dist/authz/providers/azure-ad.provider.js +0 -37
- package/dist/authz/providers/azure-ad.provider.js.map +0 -1
- package/dist/authz/providers/github.provider.d.ts +0 -3
- package/dist/authz/providers/github.provider.d.ts.map +0 -1
- package/dist/authz/providers/github.provider.js +0 -24
- package/dist/authz/providers/github.provider.js.map +0 -1
- package/dist/authz/providers/google.provider.d.ts +0 -3
- package/dist/authz/providers/google.provider.d.ts.map +0 -1
- package/dist/authz/providers/google.provider.js +0 -25
- package/dist/authz/providers/google.provider.js.map +0 -1
- package/dist/authz/providers/oauth-provider.interface.d.ts +0 -107
- package/dist/authz/providers/oauth-provider.interface.d.ts.map +0 -1
- package/dist/authz/providers/oauth-provider.interface.js.map +0 -1
- package/dist/authz/services/client.service.d.ts +0 -12
- package/dist/authz/services/client.service.d.ts.map +0 -1
- package/dist/authz/services/client.service.js +0 -81
- package/dist/authz/services/client.service.js.map +0 -1
- package/dist/authz/services/jwt-token.service.d.ts +0 -37
- package/dist/authz/services/jwt-token.service.d.ts.map +0 -1
- package/dist/authz/services/jwt-token.service.js +0 -182
- package/dist/authz/services/jwt-token.service.js.map +0 -1
- package/dist/authz/services/oauth-strategy.service.d.ts +0 -13
- package/dist/authz/services/oauth-strategy.service.d.ts.map +0 -1
- package/dist/authz/services/oauth-strategy.service.js +0 -71
- package/dist/authz/services/oauth-strategy.service.js.map +0 -1
- package/dist/authz/stores/memory-store.service.d.ts +0 -27
- package/dist/authz/stores/memory-store.service.d.ts.map +0 -1
- package/dist/authz/stores/memory-store.service.js +0 -107
- package/dist/authz/stores/memory-store.service.js.map +0 -1
- package/dist/authz/stores/oauth-store.interface.d.ts +0 -61
- package/dist/authz/stores/oauth-store.interface.d.ts.map +0 -1
- package/dist/authz/stores/oauth-store.interface.js +0 -5
- package/dist/authz/stores/oauth-store.interface.js.map +0 -1
- package/dist/authz/stores/typeorm/constants.d.ts +0 -3
- package/dist/authz/stores/typeorm/constants.d.ts.map +0 -1
- package/dist/authz/stores/typeorm/constants.js +0 -6
- package/dist/authz/stores/typeorm/constants.js.map +0 -1
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts +0 -15
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts.map +0 -1
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.js +0 -69
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.js.map +0 -1
- package/dist/authz/stores/typeorm/entities/index.d.ts +0 -5
- package/dist/authz/stores/typeorm/entities/index.d.ts.map +0 -1
- package/dist/authz/stores/typeorm/entities/index.js +0 -12
- package/dist/authz/stores/typeorm/entities/index.js.map +0 -1
- package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts +0 -17
- package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts.map +0 -1
- package/dist/authz/stores/typeorm/entities/oauth-client.entity.js +0 -77
- package/dist/authz/stores/typeorm/entities/oauth-client.entity.js.map +0 -1
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts +0 -14
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts.map +0 -1
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.js +0 -65
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.js.map +0 -1
- package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts +0 -13
- package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts.map +0 -1
- package/dist/authz/stores/typeorm/entities/user-profile.entity.js +0 -62
- package/dist/authz/stores/typeorm/entities/user-profile.entity.js.map +0 -1
- package/dist/authz/stores/typeorm/typeorm-store.service.d.ts +0 -28
- package/dist/authz/stores/typeorm/typeorm-store.service.d.ts.map +0 -1
- package/dist/authz/stores/typeorm/typeorm-store.service.js +0 -138
- package/dist/authz/stores/typeorm/typeorm-store.service.js.map +0 -1
- package/dist/mcp/constants/feature-registration.constants.d.ts +0 -7
- package/dist/mcp/constants/feature-registration.constants.d.ts.map +0 -1
- package/dist/mcp/constants/feature-registration.constants.js +0 -5
- package/dist/mcp/constants/feature-registration.constants.js.map +0 -1
- package/dist/mcp/decorators/tool-guards.decorator.d.ts +0 -12
- package/dist/mcp/decorators/tool-guards.decorator.d.ts.map +0 -1
- package/dist/mcp/decorators/tool-guards.decorator.js +0 -13
- package/dist/mcp/decorators/tool-guards.decorator.js.map +0 -1
- package/dist/mcp/interfaces/mcp-options.interface.d.ts +0 -53
- package/dist/mcp/interfaces/mcp-options.interface.d.ts.map +0 -1
- package/dist/mcp/interfaces/mcp-options.interface.js +0 -10
- package/dist/mcp/interfaces/mcp-options.interface.js.map +0 -1
- package/dist/mcp/mcp.module.d.ts +0 -15
- package/dist/mcp/mcp.module.d.ts.map +0 -1
- package/dist/mcp/mcp.module.js +0 -248
- package/dist/mcp/mcp.module.js.map +0 -1
- package/dist/mcp/services/handlers/mcp-handler.base.d.ts +0 -117
- package/dist/mcp/services/handlers/mcp-handler.base.d.ts.map +0 -1
- package/dist/mcp/services/handlers/mcp-handler.base.js +0 -125
- package/dist/mcp/services/handlers/mcp-handler.base.js.map +0 -1
- package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts +0 -12
- package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts.map +0 -1
- package/dist/mcp/services/handlers/mcp-prompts.handler.js +0 -98
- package/dist/mcp/services/handlers/mcp-prompts.handler.js.map +0 -1
- package/dist/mcp/services/handlers/mcp-resources.handler.d.ts +0 -13
- package/dist/mcp/services/handlers/mcp-resources.handler.d.ts.map +0 -1
- package/dist/mcp/services/handlers/mcp-resources.handler.js +0 -117
- package/dist/mcp/services/handlers/mcp-resources.handler.js.map +0 -1
- package/dist/mcp/services/handlers/mcp-tools.handler.d.ts +0 -22
- package/dist/mcp/services/handlers/mcp-tools.handler.d.ts.map +0 -1
- package/dist/mcp/services/handlers/mcp-tools.handler.js +0 -258
- package/dist/mcp/services/handlers/mcp-tools.handler.js.map +0 -1
- package/dist/mcp/services/mcp-dynamic-registry.service.d.ts +0 -26
- package/dist/mcp/services/mcp-dynamic-registry.service.d.ts.map +0 -1
- package/dist/mcp/services/mcp-dynamic-registry.service.js +0 -133
- package/dist/mcp/services/mcp-dynamic-registry.service.js.map +0 -1
- package/dist/mcp/services/mcp-executor.service.d.ts +0 -15
- package/dist/mcp/services/mcp-executor.service.d.ts.map +0 -1
- package/dist/mcp/services/mcp-executor.service.js +0 -47
- package/dist/mcp/services/mcp-executor.service.js.map +0 -1
- package/dist/mcp/services/mcp-registry-discovery.service.d.ts +0 -63
- package/dist/mcp/services/mcp-registry-discovery.service.d.ts.map +0 -1
- package/dist/mcp/services/mcp-registry-discovery.service.js +0 -397
- package/dist/mcp/services/mcp-registry-discovery.service.js.map +0 -1
- package/dist/mcp/services/mcp-sse.service.d.ts +0 -20
- package/dist/mcp/services/mcp-sse.service.d.ts.map +0 -1
- package/dist/mcp/services/mcp-sse.service.js +0 -91
- package/dist/mcp/services/mcp-sse.service.js.map +0 -1
- package/dist/mcp/services/mcp-streamable-http.service.d.ts +0 -32
- package/dist/mcp/services/mcp-streamable-http.service.d.ts.map +0 -1
- package/dist/mcp/services/mcp-streamable-http.service.js +0 -327
- package/dist/mcp/services/mcp-streamable-http.service.js.map +0 -1
- package/dist/mcp/services/sse-ping.service.d.ts +0 -23
- package/dist/mcp/services/sse-ping.service.d.ts.map +0 -1
- package/dist/mcp/services/sse-ping.service.js +0 -99
- package/dist/mcp/services/sse-ping.service.js.map +0 -1
- package/dist/mcp/transport/sse.controller.factory.d.ts +0 -14
- package/dist/mcp/transport/sse.controller.factory.d.ts.map +0 -1
- package/dist/mcp/transport/sse.controller.factory.js +0 -67
- package/dist/mcp/transport/sse.controller.factory.js.map +0 -1
- package/dist/mcp/transport/stdio.service.d.ts +0 -14
- package/dist/mcp/transport/stdio.service.d.ts.map +0 -1
- package/dist/mcp/transport/stdio.service.js +0 -66
- package/dist/mcp/transport/stdio.service.js.map +0 -1
- package/dist/mcp/transport/streamable-http.controller.factory.d.ts +0 -14
- package/dist/mcp/transport/streamable-http.controller.factory.d.ts.map +0 -1
- package/dist/mcp/transport/streamable-http.controller.factory.js +0 -74
- package/dist/mcp/transport/streamable-http.controller.factory.js.map +0 -1
- package/dist/mcp/utils/capabilities-builder.d.ts +0 -5
- package/dist/mcp/utils/capabilities-builder.d.ts.map +0 -1
- package/dist/mcp/utils/capabilities-builder.js +0 -25
- package/dist/mcp/utils/capabilities-builder.js.map +0 -1
- package/dist/mcp/utils/mcp-server.factory.d.ts +0 -6
- package/dist/mcp/utils/mcp-server.factory.d.ts.map +0 -1
- package/dist/mcp/utils/mcp-server.factory.js +0 -22
- package/dist/mcp/utils/mcp-server.factory.js.map +0 -1
- package/src/authz/guards/jwt-auth.guard.ts +0 -127
- package/src/authz/index.ts +0 -10
- package/src/authz/interfaces/oauth-common.interface.ts +0 -21
- package/src/authz/interfaces/request-with-user.ts +0 -16
- package/src/authz/mcp-oauth.controller.ts +0 -860
- package/src/authz/mcp-oauth.module.ts +0 -384
- package/src/authz/providers/azure-ad.provider.ts +0 -40
- package/src/authz/providers/github.provider.ts +0 -22
- package/src/authz/providers/google.provider.ts +0 -23
- package/src/authz/providers/oauth-provider.interface.ts +0 -147
- package/src/authz/services/client.service.ts +0 -125
- package/src/authz/services/jwt-token.service.spec.ts +0 -67
- package/src/authz/services/jwt-token.service.ts +0 -188
- package/src/authz/services/oauth-strategy.service.ts +0 -64
- package/src/authz/stores/memory-store.service.spec.ts +0 -475
- package/src/authz/stores/memory-store.service.ts +0 -141
- package/src/authz/stores/oauth-store.interface.ts +0 -131
- package/src/authz/stores/typeorm/README.md +0 -140
- package/src/authz/stores/typeorm/constants.ts +0 -6
- package/src/authz/stores/typeorm/entities/authorization-code.entity.ts +0 -41
- package/src/authz/stores/typeorm/entities/index.ts +0 -4
- package/src/authz/stores/typeorm/entities/oauth-client.entity.ts +0 -53
- package/src/authz/stores/typeorm/entities/oauth-session.entity.ts +0 -38
- package/src/authz/stores/typeorm/entities/user-profile.entity.ts +0 -46
- package/src/authz/stores/typeorm/typeorm-store.service.spec.ts +0 -494
- package/src/authz/stores/typeorm/typeorm-store.service.ts +0 -165
- package/src/mcp/constants/feature-registration.constants.ts +0 -24
- package/src/mcp/decorators/tool-guards.decorator.ts +0 -82
- package/src/mcp/interfaces/mcp-options.interface.ts +0 -95
- package/src/mcp/mcp.module.ts +0 -349
- package/src/mcp/services/handlers/mcp-handler.base.ts +0 -203
- package/src/mcp/services/handlers/mcp-prompts.handler.ts +0 -143
- package/src/mcp/services/handlers/mcp-resources.handler.ts +0 -183
- package/src/mcp/services/handlers/mcp-tools.handler.spec.ts +0 -41
- package/src/mcp/services/handlers/mcp-tools.handler.ts +0 -436
- package/src/mcp/services/mcp-dynamic-registry.service.ts +0 -236
- package/src/mcp/services/mcp-executor.service.ts +0 -64
- package/src/mcp/services/mcp-registry-discovery.service.spec.ts +0 -306
- package/src/mcp/services/mcp-registry-discovery.service.ts +0 -849
- package/src/mcp/services/mcp-sse.service.ts +0 -124
- package/src/mcp/services/mcp-streamable-http.service.ts +0 -472
- package/src/mcp/services/sse-ping.service.ts +0 -144
- package/src/mcp/transport/custom-decorator.spec.ts +0 -75
- package/src/mcp/transport/sse.controller.factory.ts +0 -84
- package/src/mcp/transport/stdio.service.ts +0 -75
- package/src/mcp/transport/streamable-http.controller.factory.ts +0 -80
- package/src/mcp/utils/capabilities-builder.ts +0 -43
- package/src/mcp/utils/mcp-server.factory.ts +0 -33
|
@@ -9,10 +9,10 @@ export const MCP_PUBLIC_METADATA_KEY = 'mcp:public-tool';
|
|
|
9
9
|
* Decorator to mark a tool as publicly accessible, bypassing authentication requirements.
|
|
10
10
|
*
|
|
11
11
|
* Use this when you want a tool to be available even to unauthenticated users
|
|
12
|
-
* when `allowUnauthenticatedAccess` is enabled
|
|
12
|
+
* when `allowUnauthenticatedAccess` is enabled on the {@link McpStrategy}.
|
|
13
13
|
*
|
|
14
|
-
* When applied to a tool method, it allows the tool to be
|
|
15
|
-
* even
|
|
14
|
+
* When applied to a tool method, it allows the tool to be listed and called
|
|
15
|
+
* without authentication, even when other tools on the server require it.
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```typescript
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
|
2
|
+
import type { McpContext } from '../transport/mcp-context';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Injects the raw transport request into an MCP capability handler — the MCP
|
|
6
|
+
* analog of NestJS's `@Req()`.
|
|
7
|
+
*
|
|
8
|
+
* Returns the underlying HTTP request object (Express `Request` / Fastify
|
|
9
|
+
* `FastifyRequest`) for HTTP-based transports, or `undefined` for STDIO, which
|
|
10
|
+
* is stream-oriented and has no per-call request object. Annotate the parameter
|
|
11
|
+
* with your framework's request type — the decorator itself does not type it,
|
|
12
|
+
* exactly like `@Req()`:
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import type { Request } from 'express';
|
|
17
|
+
*
|
|
18
|
+
* @Tool({ name: 'whoami', description: 'Echo the caller' })
|
|
19
|
+
* whoami(@McpRawRequest() req?: Request) {
|
|
20
|
+
* return { content: [{ type: 'text', text: req?.ip ?? 'stdio' }] };
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* This is sugar for `ctx.getRawRequest()` on the `@Ctx()` context; reach for it
|
|
25
|
+
* when the request is all you need from the context. Note that, like every
|
|
26
|
+
* NestJS param decorator, using this means the data parameter must also be
|
|
27
|
+
* annotated (with `@Payload()`).
|
|
28
|
+
*/
|
|
29
|
+
export const McpRawRequest = createParamDecorator(
|
|
30
|
+
(_data: unknown, ctx: ExecutionContext) =>
|
|
31
|
+
ctx.switchToRpc().getContext<McpContext>()?.getRawRequest(),
|
|
32
|
+
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SetMetadata } from '@nestjs/common';
|
|
1
|
+
import { applyDecorators, SetMetadata } from '@nestjs/common';
|
|
2
2
|
import { MCP_RESOURCE_TEMPLATE_METADATA_KEY } from './constants';
|
|
3
|
+
import { mcpMessagePattern } from './mcp-message-pattern';
|
|
3
4
|
|
|
4
5
|
export type ResourceTemplateOptions =
|
|
5
6
|
// https://modelcontextprotocol.io/docs/concepts/resources#resource-templates
|
|
@@ -27,5 +28,8 @@ export interface ResourceTemplateMetadata {
|
|
|
27
28
|
* @returns {MethodDecorator} - The decorator
|
|
28
29
|
*/
|
|
29
30
|
export const ResourceTemplate = (options: ResourceTemplateOptions) => {
|
|
30
|
-
return
|
|
31
|
+
return applyDecorators(
|
|
32
|
+
SetMetadata(MCP_RESOURCE_TEMPLATE_METADATA_KEY, options),
|
|
33
|
+
mcpMessagePattern('resource-template', options.uriTemplate),
|
|
34
|
+
);
|
|
31
35
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SetMetadata } from '@nestjs/common';
|
|
1
|
+
import { applyDecorators, SetMetadata } from '@nestjs/common';
|
|
2
2
|
import { MCP_RESOURCE_METADATA_KEY } from './constants';
|
|
3
|
+
import { mcpMessagePattern } from './mcp-message-pattern';
|
|
3
4
|
|
|
4
5
|
export type ResourceOptions =
|
|
5
6
|
// https://modelcontextprotocol.io/docs/concepts/resources#direct-resources
|
|
@@ -27,5 +28,8 @@ export interface ResourceMetadata {
|
|
|
27
28
|
* @returns {MethodDecorator} - The decorator
|
|
28
29
|
*/
|
|
29
30
|
export const Resource = (options: ResourceOptions) => {
|
|
30
|
-
return
|
|
31
|
+
return applyDecorators(
|
|
32
|
+
SetMetadata(MCP_RESOURCE_METADATA_KEY, options),
|
|
33
|
+
mcpMessagePattern('resource', options.uri),
|
|
34
|
+
);
|
|
31
35
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { applyDecorators, SetMetadata } from '@nestjs/common';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { ToolAnnotations as SdkToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
4
4
|
import { MCP_TOOL_METADATA_KEY } from './constants';
|
|
5
|
+
import { mcpMessagePattern } from './mcp-message-pattern';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Security scheme type for MCP tools
|
|
@@ -22,7 +23,6 @@ export interface ToolMetadata {
|
|
|
22
23
|
isPublic?: boolean;
|
|
23
24
|
requiredScopes?: string[];
|
|
24
25
|
requiredRoles?: string[];
|
|
25
|
-
guards?: Type<CanActivate>[];
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
@@ -51,5 +51,8 @@ export const Tool = (options: ToolOptions) => {
|
|
|
51
51
|
options.parameters = z.object({});
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
return
|
|
54
|
+
return applyDecorators(
|
|
55
|
+
SetMetadata(MCP_TOOL_METADATA_KEY, options),
|
|
56
|
+
mcpMessagePattern('tool', options.name),
|
|
57
|
+
);
|
|
55
58
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ArgumentsHost, Catch, RpcExceptionFilter } from '@nestjs/common';
|
|
2
|
+
import { RpcException } from '@nestjs/microservices';
|
|
3
|
+
import { Observable, throwError } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Surfaces the real error message of any exception thrown by an MCP
|
|
7
|
+
* tool/resource/prompt handler, instead of NestJS's default "Internal server
|
|
8
|
+
* error" masking.
|
|
9
|
+
*
|
|
10
|
+
* By default NestJS's RPC pipeline masks any non-`RpcException` to a generic
|
|
11
|
+
* "Internal server error" before the strategy can read it, so a plain
|
|
12
|
+
* `throw new Error('Order #42 not found')` reaches the agent as an opaque
|
|
13
|
+
* failure. That is a safe default (it avoids leaking internals), but it is poor
|
|
14
|
+
* DX when the message is meant for the caller. Register this filter to opt into
|
|
15
|
+
* passing the original message through:
|
|
16
|
+
*
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Globally (recommended) — applies to every MCP handler, but never overrides
|
|
19
|
+
* // a more specific `@UseFilters()` you put on a controller/method.
|
|
20
|
+
* providers: [{ provide: APP_FILTER, useClass: McpExceptionFilter }]
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Or per controller/method:
|
|
25
|
+
* @UseFilters(McpExceptionFilter)
|
|
26
|
+
* @McpController()
|
|
27
|
+
* class MyTools { ... }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* The surfaced message becomes an `isError: true` tool result (or a JSON-RPC
|
|
31
|
+
* error for resources/prompts), so the agent can tell a real failure from a
|
|
32
|
+
* successful call. For input problems, prefer the built-in Zod validation
|
|
33
|
+
* (a clear "Invalid parameters: …" result) or `throw new RpcException(...)` /
|
|
34
|
+
* a NestJS exception — those are already surfaced without this filter.
|
|
35
|
+
*/
|
|
36
|
+
@Catch()
|
|
37
|
+
export class McpExceptionFilter implements RpcExceptionFilter {
|
|
38
|
+
catch(exception: unknown, _host: ArgumentsHost): Observable<never> {
|
|
39
|
+
// RpcException already carries an explicit, client-facing payload.
|
|
40
|
+
if (exception instanceof RpcException) {
|
|
41
|
+
return throwError(() => exception.getError());
|
|
42
|
+
}
|
|
43
|
+
const message =
|
|
44
|
+
exception instanceof Error ? exception.message : 'Internal server error';
|
|
45
|
+
return throwError(() => ({ status: 'error', message }));
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/mcp/index.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
export * from './decorators';
|
|
2
2
|
export * from './interfaces';
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './
|
|
3
|
+
export * from './services/tool-authorization.service';
|
|
4
|
+
export * from './filters/mcp-exception.filter';
|
|
5
|
+
export * from './utils/normalize-endpoint';
|
|
6
|
+
|
|
7
|
+
// Microservice transport strategy API
|
|
8
|
+
export * from './transport/mcp-transport.constants';
|
|
9
|
+
export * from './transport/mcp-context';
|
|
10
|
+
export * from './transport/mcp-server-options.interface';
|
|
11
|
+
export * from './transport/mcp-transport.interface';
|
|
12
|
+
export * from './transport/mcp-http-handler';
|
|
13
|
+
export * from './transport/mcp.strategy';
|
|
14
|
+
export * from './transport/streamable-http.controller';
|
|
15
|
+
export * from './transport/transports';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal shape of an authenticated principal as far as the core per-tool
|
|
3
|
+
* authorization logic is concerned.
|
|
4
|
+
*
|
|
5
|
+
* The core module never authenticates anyone itself — a guard or transport-level
|
|
6
|
+
* auth middleware resolves the user and places it on `req.user`. Per-tool checks
|
|
7
|
+
* (`@ToolScopes()`, `@ToolRoles()`) only read scopes and roles off that object, so
|
|
8
|
+
* core depends on this structural type rather than on any concrete token payload.
|
|
9
|
+
*
|
|
10
|
+
* The auth package's richer `JwtPayload` is structurally compatible with this
|
|
11
|
+
* interface, so no coupling back to `@rekog/mcp-nest-auth` is required.
|
|
12
|
+
*/
|
|
13
|
+
export interface AuthenticatedUser {
|
|
14
|
+
/** OAuth 2.0 space-delimited scope string. */
|
|
15
|
+
scope?: string;
|
|
16
|
+
/** Roles carried directly on the principal. */
|
|
17
|
+
roles?: string[];
|
|
18
|
+
/** Provider-specific user data; may carry roles. */
|
|
19
|
+
user_data?: { roles?: string[] } & Record<string, any>;
|
|
20
|
+
/** Allow additional, provider-specific claims without widening the read surface. */
|
|
21
|
+
[key: string]: any;
|
|
22
|
+
}
|
|
@@ -10,11 +10,11 @@ export type DynamicToolHandler = (
|
|
|
10
10
|
args: Record<string, unknown>,
|
|
11
11
|
context: Context,
|
|
12
12
|
request: any,
|
|
13
|
-
) =>
|
|
13
|
+
) => any;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Definition for a dynamically registered tool.
|
|
17
|
-
* Use this with
|
|
17
|
+
* Use this with `McpStrategy.registerTool()` to register tools at runtime.
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```typescript
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
3
|
-
McpOptions,
|
|
4
|
-
McpAsyncOptions,
|
|
5
|
-
McpOptionsFactory,
|
|
6
|
-
McpModuleAsyncOptions,
|
|
7
|
-
} from './mcp-options.interface';
|
|
1
|
+
export type { Icon } from '@modelcontextprotocol/sdk/types.js';
|
|
8
2
|
|
|
9
3
|
export type {
|
|
10
4
|
Literal,
|
|
@@ -16,6 +10,8 @@ export type {
|
|
|
16
10
|
|
|
17
11
|
export type { HttpRequest } from './http-adapter.interface';
|
|
18
12
|
|
|
13
|
+
export type { AuthenticatedUser } from './authenticated-user.interface';
|
|
14
|
+
|
|
19
15
|
export type {
|
|
20
16
|
DynamicToolDefinition,
|
|
21
17
|
DynamicToolHandler,
|
|
@@ -1,24 +1,42 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
2
|
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
-
import { DiscoveredCapability } from './mcp-registry-discovery.service';
|
|
4
3
|
import { ToolMetadata, SecurityScheme } from '../decorators/tool.decorator';
|
|
5
|
-
import {
|
|
4
|
+
import { AuthenticatedUser } from '../interfaces/authenticated-user.interface';
|
|
5
|
+
|
|
6
|
+
/** Minimal shape the authorization logic needs: a capability carrying tool metadata. */
|
|
7
|
+
export interface AuthorizableTool {
|
|
8
|
+
metadata: ToolMetadata;
|
|
9
|
+
}
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
|
-
*
|
|
12
|
+
* Per-tool authorization.
|
|
13
|
+
*
|
|
14
|
+
* This service powers `tools/list` filtering and the `tools/call` access check
|
|
15
|
+
* based purely on the per-tool decorators (`@PublicTool()`, `@ToolScopes()`,
|
|
16
|
+
* `@ToolRoles()`) and the user resolved off the raw request (`req.user`, set by
|
|
17
|
+
* a guard or by transport-level auth middleware).
|
|
18
|
+
*
|
|
19
|
+
* It is intentionally NOT an authentication mechanism: real enforcement is the
|
|
20
|
+
* job of standard NestJS `@UseGuards()` (which run inside the RPC pipeline at
|
|
21
|
+
* call time) and/or auth middleware on the HTTP routes. This service only
|
|
22
|
+
* decides which tools a *known* principal may see and invoke.
|
|
9
23
|
*/
|
|
10
24
|
@Injectable()
|
|
11
25
|
export class ToolAuthorizationService {
|
|
12
26
|
/**
|
|
13
|
-
* Generate security schemes for a tool
|
|
27
|
+
* Generate security schemes for a tool, advertised to clients (e.g. ChatGPT)
|
|
28
|
+
* via the OpenAI `securitySchemes` spec so they know which tools need auth.
|
|
14
29
|
*
|
|
15
30
|
* @param tool - The discovered tool
|
|
16
|
-
* @param
|
|
31
|
+
* @param freemiumMode - Whether the server runs in freemium mode
|
|
32
|
+
* (`allowUnauthenticatedAccess`). In freemium mode an undecorated,
|
|
33
|
+
* non-public tool still requires authentication, so it is advertised as
|
|
34
|
+
* `oauth2`.
|
|
17
35
|
* @returns Array of security schemes for the tool
|
|
18
36
|
*/
|
|
19
37
|
generateSecuritySchemes(
|
|
20
|
-
tool:
|
|
21
|
-
|
|
38
|
+
tool: AuthorizableTool,
|
|
39
|
+
freemiumMode: boolean,
|
|
22
40
|
): SecurityScheme[] {
|
|
23
41
|
const metadata = tool.metadata;
|
|
24
42
|
const schemes: SecurityScheme[] = [];
|
|
@@ -32,8 +50,12 @@ export class ToolAuthorizationService {
|
|
|
32
50
|
if (metadata.requiredScopes && metadata.requiredScopes.length > 0) {
|
|
33
51
|
schemes.push({ type: 'oauth2', scopes: metadata.requiredScopes });
|
|
34
52
|
}
|
|
35
|
-
// Else if
|
|
36
|
-
else if (
|
|
53
|
+
// Else if tool requires specific roles, advertise that auth is needed
|
|
54
|
+
else if (metadata.requiredRoles && metadata.requiredRoles.length > 0) {
|
|
55
|
+
schemes.push({ type: 'oauth2' });
|
|
56
|
+
}
|
|
57
|
+
// Else, in freemium mode a non-public tool still requires authentication
|
|
58
|
+
else if (freemiumMode && !metadata.isPublic) {
|
|
37
59
|
schemes.push({ type: 'oauth2' });
|
|
38
60
|
}
|
|
39
61
|
|
|
@@ -46,18 +68,16 @@ export class ToolAuthorizationService {
|
|
|
46
68
|
}
|
|
47
69
|
|
|
48
70
|
/**
|
|
49
|
-
* Check if a user can access a tool based on
|
|
71
|
+
* Check if a user can access a tool based on its per-tool requirements.
|
|
50
72
|
*
|
|
51
73
|
* @param user - The authenticated user (may be undefined)
|
|
52
74
|
* @param tool - The discovered tool
|
|
53
|
-
* @param moduleHasGuards - Whether the module has guards configured
|
|
54
75
|
* @param allowUnauthenticatedAccess - Whether unauthenticated access is allowed (freemium mode)
|
|
55
|
-
* @returns true if user can access the tool, false otherwise
|
|
76
|
+
* @returns true if the user can access the tool, false otherwise
|
|
56
77
|
*/
|
|
57
78
|
canAccessTool(
|
|
58
|
-
user:
|
|
59
|
-
tool:
|
|
60
|
-
moduleHasGuards: boolean,
|
|
79
|
+
user: AuthenticatedUser | undefined,
|
|
80
|
+
tool: AuthorizableTool,
|
|
61
81
|
allowUnauthenticatedAccess: boolean = false,
|
|
62
82
|
): boolean {
|
|
63
83
|
const metadata = tool.metadata;
|
|
@@ -90,50 +110,33 @@ export class ToolAuthorizationService {
|
|
|
90
110
|
}
|
|
91
111
|
}
|
|
92
112
|
|
|
93
|
-
// At this point
|
|
94
|
-
//
|
|
95
|
-
// - Tool has no specific scope/role requirements (or they passed)
|
|
96
|
-
//
|
|
97
|
-
// Decision logic based on allowUnauthenticatedAccess:
|
|
98
|
-
//
|
|
99
|
-
// allowUnauthenticatedAccess = false (default, standard auth mode):
|
|
100
|
-
// - Guards are expected to fully authorize requests (via JWT, API keys, etc)
|
|
101
|
-
// - If guard let request through AND there's no user object:
|
|
102
|
-
// * Guard used non-JWT auth mechanism (API key, IP whitelist, etc)
|
|
103
|
-
// * Trust the guard's decision to authorize
|
|
104
|
-
// - If no guards configured, allow access (no auth required)
|
|
113
|
+
// At this point the tool is not public and has no (or satisfied) scope/role
|
|
114
|
+
// requirements. The only remaining question is the undecorated tool:
|
|
105
115
|
//
|
|
106
|
-
// allowUnauthenticatedAccess = true
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
// -
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// This tool has no decorators, so it requires authentication
|
|
116
|
+
// - Freemium mode (allowUnauthenticatedAccess = true): anonymous callers may
|
|
117
|
+
// only reach @PublicTool() (or specifically-scoped) tools, so an
|
|
118
|
+
// undecorated tool requires a user.
|
|
119
|
+
// - Standard mode (default): real enforcement is delegated to @UseGuards /
|
|
120
|
+
// auth middleware, so we trust that decision and allow access. (On stdio
|
|
121
|
+
// there is no request and no user — all undecorated tools are reachable.)
|
|
122
|
+
if (allowUnauthenticatedAccess && !user) {
|
|
114
123
|
return false;
|
|
115
124
|
}
|
|
116
125
|
|
|
117
|
-
// Standard mode: If we're here, either:
|
|
118
|
-
// - No guards (open access)
|
|
119
|
-
// - Guards authorized it (trust guard decision, even without user object)
|
|
120
|
-
// - User is present and passed all checks
|
|
121
126
|
return true;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
/**
|
|
125
|
-
* Validate that a user can access a tool, throwing an error if not authorized
|
|
130
|
+
* Validate that a user can access a tool, throwing an error if not authorized.
|
|
126
131
|
*
|
|
127
132
|
* @param user - The authenticated user (may be undefined)
|
|
128
133
|
* @param tool - The discovered tool
|
|
129
|
-
* @param moduleHasGuards - Whether the module has guards configured
|
|
130
134
|
* @param allowUnauthenticatedAccess - Whether unauthenticated access is allowed (freemium mode)
|
|
131
135
|
* @throws McpError if user is not authorized to access the tool
|
|
132
136
|
*/
|
|
133
137
|
validateToolAccess(
|
|
134
|
-
user:
|
|
135
|
-
tool:
|
|
136
|
-
moduleHasGuards: boolean,
|
|
138
|
+
user: AuthenticatedUser | undefined,
|
|
139
|
+
tool: AuthorizableTool,
|
|
137
140
|
allowUnauthenticatedAccess: boolean = false,
|
|
138
141
|
): void {
|
|
139
142
|
const metadata = tool.metadata;
|
|
@@ -176,37 +179,14 @@ export class ToolAuthorizationService {
|
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
181
|
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
// Decision logic based on allowUnauthenticatedAccess:
|
|
184
|
-
//
|
|
185
|
-
// allowUnauthenticatedAccess = false (default, standard auth mode):
|
|
186
|
-
// - Guards are expected to fully authorize requests (via JWT, API keys, etc)
|
|
187
|
-
// - If guard let request through AND there's no user object:
|
|
188
|
-
// * Guard used non-JWT auth mechanism (API key, IP whitelist, etc)
|
|
189
|
-
// * Trust the guard's decision to authorize
|
|
190
|
-
// - If no guards configured, allow access (no auth required)
|
|
191
|
-
//
|
|
192
|
-
// allowUnauthenticatedAccess = true (freemium mode):
|
|
193
|
-
// - Guards may let unauthenticated requests through for per-tool auth
|
|
194
|
-
// - Only @PublicTool or tools with specific scopes/roles accessible
|
|
195
|
-
// - Tools without decorators require authentication (user must be present)
|
|
196
|
-
//
|
|
197
|
-
if (allowUnauthenticatedAccess && moduleHasGuards && !user) {
|
|
198
|
-
// Freemium mode: unauthenticated access only for @PublicTool or specific scopes
|
|
199
|
-
// This tool has no decorators, so it requires authentication
|
|
182
|
+
// Freemium mode: an undecorated, non-public tool still requires a user.
|
|
183
|
+
// Standard mode trusts @UseGuards / auth middleware (see canAccessTool).
|
|
184
|
+
if (allowUnauthenticatedAccess && !user) {
|
|
200
185
|
throw new McpError(
|
|
201
186
|
ErrorCode.InvalidRequest,
|
|
202
187
|
`Tool '${toolName}' requires authentication`,
|
|
203
188
|
);
|
|
204
189
|
}
|
|
205
|
-
|
|
206
|
-
// Standard mode: If we're here, either:
|
|
207
|
-
// - No guards (open access)
|
|
208
|
-
// - Guards authorized it (trust guard decision, even without user object)
|
|
209
|
-
// - User is present and passed all checks
|
|
210
190
|
}
|
|
211
191
|
|
|
212
192
|
/**
|
|
@@ -217,7 +197,7 @@ export class ToolAuthorizationService {
|
|
|
217
197
|
* @returns true if user has all required scopes
|
|
218
198
|
*/
|
|
219
199
|
private hasRequiredScopes(
|
|
220
|
-
user:
|
|
200
|
+
user: AuthenticatedUser | undefined,
|
|
221
201
|
requiredScopes: string[],
|
|
222
202
|
): boolean {
|
|
223
203
|
if (!user) {
|
|
@@ -247,7 +227,7 @@ export class ToolAuthorizationService {
|
|
|
247
227
|
* @returns true if user has all required roles
|
|
248
228
|
*/
|
|
249
229
|
private hasRequiredRoles(
|
|
250
|
-
user:
|
|
230
|
+
user: AuthenticatedUser | undefined,
|
|
251
231
|
requiredRoles: string[],
|
|
252
232
|
): boolean {
|
|
253
233
|
if (!user) {
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
2
|
+
import { BaseRpcContext } from '@nestjs/microservices';
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { Progress } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { Context, McpRequest, SerializableValue } from '../interfaces';
|
|
6
|
+
|
|
7
|
+
export type McpTransportKind = 'stdio' | 'streamable-http';
|
|
8
|
+
|
|
9
|
+
export interface McpSessionInfo {
|
|
10
|
+
/** The MCP session id, when the transport is session-aware. */
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
/** Which transport delivered this request. */
|
|
13
|
+
transport: McpTransportKind;
|
|
14
|
+
/**
|
|
15
|
+
* `true` only for the per-request streamable-HTTP stateless mode, where the
|
|
16
|
+
* server cannot push notifications/progress back to the client. stdio and
|
|
17
|
+
* stateful streamable-HTTP are both session-aware (`false`).
|
|
18
|
+
*/
|
|
19
|
+
stateless: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type McpContextArgs = [
|
|
23
|
+
mcpServer: McpServer,
|
|
24
|
+
mcpRequest: McpRequest,
|
|
25
|
+
session: McpSessionInfo,
|
|
26
|
+
rawRequest: unknown,
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Execution context handed to every MCP capability handler via `@Ctx()`.
|
|
31
|
+
*
|
|
32
|
+
* Extends NestJS's {@link BaseRpcContext} so it is resolved as the RPC context
|
|
33
|
+
* argument (the strategy invokes handlers as `handler(payload, mcpContext)`),
|
|
34
|
+
* and implements the library's {@link Context} surface (`reportProgress`, `log`,
|
|
35
|
+
* `mcpServer`, `mcpRequest`) so existing handler code keeps working.
|
|
36
|
+
*
|
|
37
|
+
* Additional accessors expose the session and the raw transport request.
|
|
38
|
+
*/
|
|
39
|
+
export class McpContext
|
|
40
|
+
extends BaseRpcContext<McpContextArgs>
|
|
41
|
+
implements Context
|
|
42
|
+
{
|
|
43
|
+
public readonly reportProgress: (progress: Progress) => Promise<void>;
|
|
44
|
+
public readonly log: Context['log'];
|
|
45
|
+
|
|
46
|
+
constructor(
|
|
47
|
+
args: McpContextArgs,
|
|
48
|
+
private readonly logger?: Logger,
|
|
49
|
+
) {
|
|
50
|
+
super(args);
|
|
51
|
+
this.reportProgress = this.getSession().stateless
|
|
52
|
+
? this.createStatelessReportProgress()
|
|
53
|
+
: this.createReportProgress();
|
|
54
|
+
this.log = this.getSession().stateless
|
|
55
|
+
? this.createStatelessLog()
|
|
56
|
+
: this.createLog();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** The underlying MCP SDK server instance. */
|
|
60
|
+
get mcpServer(): McpServer {
|
|
61
|
+
return this.args[0];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The parsed JSON-RPC request (tools/call, resources/read, prompts/get, ...). */
|
|
65
|
+
get mcpRequest(): McpRequest {
|
|
66
|
+
return this.args[1];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Session metadata for this request. */
|
|
70
|
+
getSession(): McpSessionInfo {
|
|
71
|
+
return this.args[2];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** The raw transport request (Express/Fastify request for HTTP; `undefined` for stdio). */
|
|
75
|
+
getRawRequest<T = unknown>(): T | undefined {
|
|
76
|
+
return this.args[3] as T | undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private get progressToken(): string | number | undefined {
|
|
80
|
+
return this.mcpRequest.params?._meta?.progressToken;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private createReportProgress(): (progress: Progress) => Promise<void> {
|
|
84
|
+
return async (progress: Progress) => {
|
|
85
|
+
const progressToken = this.progressToken;
|
|
86
|
+
if (progressToken === undefined) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
await this.mcpServer.server.notification({
|
|
90
|
+
method: 'notifications/progress',
|
|
91
|
+
params: { ...progress, progressToken } as Progress,
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private createLog(): Context['log'] {
|
|
97
|
+
const send = (
|
|
98
|
+
level: 'debug' | 'info' | 'warning' | 'error',
|
|
99
|
+
message: string,
|
|
100
|
+
context?: SerializableValue,
|
|
101
|
+
) => {
|
|
102
|
+
void this.mcpServer.server.sendLoggingMessage({
|
|
103
|
+
level,
|
|
104
|
+
data: { message, context },
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
debug: (message, context) => send('debug', message, context),
|
|
109
|
+
info: (message, context) => send('info', message, context),
|
|
110
|
+
warn: (message, context) => send('warning', message, context),
|
|
111
|
+
error: (message, context) => send('error', message, context),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private createStatelessReportProgress(): (
|
|
116
|
+
progress: Progress,
|
|
117
|
+
) => Promise<void> {
|
|
118
|
+
return () => {
|
|
119
|
+
this.logger?.warn(
|
|
120
|
+
"Stateless context: 'reportProgress' is not supported.",
|
|
121
|
+
);
|
|
122
|
+
return Promise.resolve();
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private createStatelessLog(): Context['log'] {
|
|
127
|
+
const warn = () =>
|
|
128
|
+
this.logger?.warn(
|
|
129
|
+
'Stateless context: server-side logging is not supported.',
|
|
130
|
+
);
|
|
131
|
+
return {
|
|
132
|
+
debug: () => warn(),
|
|
133
|
+
info: () => warn(),
|
|
134
|
+
warn: () => warn(),
|
|
135
|
+
error: () => warn(),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HTTP verb handlers a streamable-HTTP MCP endpoint needs: one per method
|
|
3
|
+
* the transport mounts (`POST` messages, `GET` SSE stream, `DELETE` session
|
|
4
|
+
* teardown). This is the seam for "bring your own controller" setups.
|
|
5
|
+
*
|
|
6
|
+
* The transport owns the implementation (session handling, streaming, raw-body
|
|
7
|
+
* reading); you only decide HOW the route is mounted:
|
|
8
|
+
*
|
|
9
|
+
* - Do nothing — the transport self-mounts the route (no guards possible).
|
|
10
|
+
* - Extend {@link StreamableHttpController} (or write your own `@Controller`)
|
|
11
|
+
* and delegate to these handlers, so the route is a real Nest route that
|
|
12
|
+
* `@UseGuards()` / `@UseInterceptors()` / `@Version()` apply to.
|
|
13
|
+
*
|
|
14
|
+
* Obtain an instance from a transport via `transport.httpHandlers` and provide
|
|
15
|
+
* it under {@link MCP_HTTP_HANDLER} so the controller can inject it.
|
|
16
|
+
*/
|
|
17
|
+
export interface McpHttpHandler {
|
|
18
|
+
handlePost(req: unknown, res: unknown): Promise<void> | void;
|
|
19
|
+
handleGet(req: unknown, res: unknown): Promise<void> | void;
|
|
20
|
+
handleDelete(req: unknown, res: unknown): Promise<void> | void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* DI token for an {@link McpHttpHandler}. Provide a transport's `httpHandlers`
|
|
25
|
+
* under this token so {@link StreamableHttpController} (or your own controller)
|
|
26
|
+
* can inject it:
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* { provide: MCP_HTTP_HANDLER, useValue: mcpTransport.httpHandlers }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const MCP_HTTP_HANDLER = Symbol('MCP_HTTP_HANDLER');
|