@rekog/mcp-nest 1.9.10 → 2.0.0-alpha.0
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 +1 -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 +6 -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
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamableHttpTransport = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
6
|
+
const http_adapter_factory_1 = require("../../adapters/http-adapter.factory");
|
|
7
|
+
const read_body_1 = require("./read-body");
|
|
8
|
+
class StreamableHttpTransport {
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.kind = 'streamable-http';
|
|
11
|
+
this.handlersClaimed = false;
|
|
12
|
+
this.transports = {};
|
|
13
|
+
this.servers = {};
|
|
14
|
+
this.endpoint = ensureLeadingSlash(options.endpoint ?? 'mcp');
|
|
15
|
+
this.endpointExplicit = options.endpoint !== undefined;
|
|
16
|
+
this.statefulMode = options.statefulMode ?? false;
|
|
17
|
+
this.enableJsonResponse =
|
|
18
|
+
options.enableJsonResponse ?? !this.statefulMode;
|
|
19
|
+
this.sessionIdGenerator =
|
|
20
|
+
options.sessionIdGenerator ?? (() => (0, crypto_1.randomUUID)());
|
|
21
|
+
this.mountOption = options.mount;
|
|
22
|
+
}
|
|
23
|
+
get httpHandlers() {
|
|
24
|
+
this.handlersClaimed = true;
|
|
25
|
+
return {
|
|
26
|
+
handlePost: (req, res) => this.handlePost(req, res),
|
|
27
|
+
handleGet: (req, res) => this.handleGet(req, res),
|
|
28
|
+
handleDelete: (req, res) => this.handleDelete(req, res),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
start(ctx) {
|
|
32
|
+
this.ctx = ctx;
|
|
33
|
+
const shouldMount = this.mountOption ?? !this.handlersClaimed;
|
|
34
|
+
if (!shouldMount) {
|
|
35
|
+
if (this.endpointExplicit) {
|
|
36
|
+
ctx.logger.warn(`StreamableHttpTransport: \`endpoint: '${this.endpoint}'\` is ignored because a controller owns the route. Set the path on your @Controller(...) decorator instead (it also picks up global prefix and versioning).`);
|
|
37
|
+
}
|
|
38
|
+
ctx.logger.log(`MCP streamable-http transport ready (${this.statefulMode ? 'stateful' : 'stateless'}, self-mount disabled — a controller owns the route)`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!ctx.httpAdapter) {
|
|
42
|
+
throw new Error('StreamableHttpTransport requires an HTTP adapter to self-mount. Pass it via new McpStrategy({ httpAdapter }) or strategy.setHttpAdapter(app.getHttpAdapter()) — or mount your own controller (provide MCP_HTTP_HANDLER with transport.httpHandlers).');
|
|
43
|
+
}
|
|
44
|
+
const adapter = ctx.httpAdapter;
|
|
45
|
+
adapter.post(this.endpoint, (req, res) => this.handlePost(req, res));
|
|
46
|
+
adapter.get(this.endpoint, (req, res) => this.handleGet(req, res));
|
|
47
|
+
adapter.delete(this.endpoint, (req, res) => this.handleDelete(req, res));
|
|
48
|
+
ctx.logger.log(`MCP streamable-http transport mounted at ${this.endpoint} (${this.statefulMode ? 'stateful' : 'stateless'})`);
|
|
49
|
+
}
|
|
50
|
+
async close() {
|
|
51
|
+
for (const sessionId of Object.keys(this.transports)) {
|
|
52
|
+
await this.cleanupSession(sessionId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async handlePost(req, res) {
|
|
56
|
+
const adapter = http_adapter_factory_1.HttpAdapterFactory.getAdapter(req, res);
|
|
57
|
+
const adaptedReq = adapter.adaptRequest(req);
|
|
58
|
+
const adaptedRes = adapter.adaptResponse(res);
|
|
59
|
+
const body = await (0, read_body_1.readJsonBody)(adaptedReq);
|
|
60
|
+
try {
|
|
61
|
+
if (this.statefulMode) {
|
|
62
|
+
await this.handleStateful(adaptedReq, adaptedRes, body);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
await this.handleStateless(adaptedReq, adaptedRes, body);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
this.ctx.logger.error('Error handling MCP request', error);
|
|
70
|
+
if (!adaptedRes.headersSent) {
|
|
71
|
+
adaptedRes.status(500).json({
|
|
72
|
+
jsonrpc: '2.0',
|
|
73
|
+
error: { code: -32603, message: 'Internal server error' },
|
|
74
|
+
id: null,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async handleStateless(req, res, body) {
|
|
80
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
81
|
+
sessionIdGenerator: undefined,
|
|
82
|
+
enableJsonResponse: this.enableJsonResponse,
|
|
83
|
+
});
|
|
84
|
+
const server = this.ctx.createServer();
|
|
85
|
+
await server.connect(transport);
|
|
86
|
+
this.ctx.bindRequestHandlers(server, { transport: this.kind, stateless: true }, req.raw);
|
|
87
|
+
res.raw.on('finish', () => {
|
|
88
|
+
void transport.close();
|
|
89
|
+
void server.close();
|
|
90
|
+
});
|
|
91
|
+
await transport.handleRequest(req.raw, res.raw, body);
|
|
92
|
+
}
|
|
93
|
+
async handleStateful(req, res, body) {
|
|
94
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
95
|
+
if (!sessionId && isInitializeRequest(body)) {
|
|
96
|
+
const server = this.ctx.createServer();
|
|
97
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
98
|
+
sessionIdGenerator: this.sessionIdGenerator,
|
|
99
|
+
enableJsonResponse: this.enableJsonResponse,
|
|
100
|
+
onsessioninitialized: (sid) => {
|
|
101
|
+
this.transports[sid] = transport;
|
|
102
|
+
this.servers[sid] = server;
|
|
103
|
+
},
|
|
104
|
+
onsessionclosed: (sid) => {
|
|
105
|
+
void this.cleanupSession(sid);
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
await server.connect(transport);
|
|
109
|
+
this.ctx.bindRequestHandlers(server, { transport: this.kind, stateless: false }, req.raw);
|
|
110
|
+
await transport.handleRequest(req.raw, res.raw, body);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (sessionId) {
|
|
114
|
+
const transport = this.transports[sessionId];
|
|
115
|
+
const server = this.servers[sessionId];
|
|
116
|
+
if (!transport || !server) {
|
|
117
|
+
res.status(404).json({
|
|
118
|
+
jsonrpc: '2.0',
|
|
119
|
+
error: { code: -32001, message: 'Session not found' },
|
|
120
|
+
id: null,
|
|
121
|
+
});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.ctx.bindRequestHandlers(server, { transport: this.kind, stateless: false, sessionId }, req.raw);
|
|
125
|
+
await transport.handleRequest(req.raw, res.raw, body);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
res.status(400).json({
|
|
129
|
+
jsonrpc: '2.0',
|
|
130
|
+
error: {
|
|
131
|
+
code: -32000,
|
|
132
|
+
message: 'Bad Request: Mcp-Session-Id header is required',
|
|
133
|
+
},
|
|
134
|
+
id: null,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async handleGet(req, res) {
|
|
138
|
+
const adapter = http_adapter_factory_1.HttpAdapterFactory.getAdapter(req, res);
|
|
139
|
+
const adaptedReq = adapter.adaptRequest(req);
|
|
140
|
+
const adaptedRes = adapter.adaptResponse(res);
|
|
141
|
+
if (!this.statefulMode) {
|
|
142
|
+
adaptedRes.status(405).json({
|
|
143
|
+
jsonrpc: '2.0',
|
|
144
|
+
error: {
|
|
145
|
+
code: -32000,
|
|
146
|
+
message: 'Method not allowed in stateless mode',
|
|
147
|
+
},
|
|
148
|
+
id: null,
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const sessionId = adaptedReq.headers['mcp-session-id'];
|
|
153
|
+
const transport = sessionId ? this.transports[sessionId] : undefined;
|
|
154
|
+
if (!transport) {
|
|
155
|
+
adaptedRes.status(404).json({
|
|
156
|
+
jsonrpc: '2.0',
|
|
157
|
+
error: { code: -32001, message: 'Session not found' },
|
|
158
|
+
id: null,
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
await transport.handleRequest(adaptedReq.raw, adaptedRes.raw);
|
|
163
|
+
}
|
|
164
|
+
async handleDelete(req, res) {
|
|
165
|
+
const adapter = http_adapter_factory_1.HttpAdapterFactory.getAdapter(req, res);
|
|
166
|
+
const adaptedReq = adapter.adaptRequest(req);
|
|
167
|
+
const adaptedRes = adapter.adaptResponse(res);
|
|
168
|
+
if (!this.statefulMode) {
|
|
169
|
+
adaptedRes.status(405).json({
|
|
170
|
+
jsonrpc: '2.0',
|
|
171
|
+
error: {
|
|
172
|
+
code: -32000,
|
|
173
|
+
message: 'Method not allowed in stateless mode',
|
|
174
|
+
},
|
|
175
|
+
id: null,
|
|
176
|
+
});
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const sessionId = adaptedReq.headers['mcp-session-id'];
|
|
180
|
+
const transport = sessionId ? this.transports[sessionId] : undefined;
|
|
181
|
+
if (!transport) {
|
|
182
|
+
adaptedRes.status(404).json({
|
|
183
|
+
jsonrpc: '2.0',
|
|
184
|
+
error: { code: -32001, message: 'Session not found' },
|
|
185
|
+
id: null,
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
await transport.handleRequest(adaptedReq.raw, adaptedRes.raw);
|
|
190
|
+
}
|
|
191
|
+
async cleanupSession(sessionId) {
|
|
192
|
+
const transport = this.transports[sessionId];
|
|
193
|
+
const server = this.servers[sessionId];
|
|
194
|
+
delete this.transports[sessionId];
|
|
195
|
+
delete this.servers[sessionId];
|
|
196
|
+
try {
|
|
197
|
+
await transport?.close();
|
|
198
|
+
await server?.close();
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
exports.StreamableHttpTransport = StreamableHttpTransport;
|
|
205
|
+
function isInitializeRequest(body) {
|
|
206
|
+
const isInit = (msg) => typeof msg === 'object' &&
|
|
207
|
+
msg !== null &&
|
|
208
|
+
'method' in msg &&
|
|
209
|
+
msg.method === 'initialize';
|
|
210
|
+
return Array.isArray(body) ? body.some(isInit) : isInit(body);
|
|
211
|
+
}
|
|
212
|
+
function ensureLeadingSlash(endpoint) {
|
|
213
|
+
const trimmed = endpoint.trim();
|
|
214
|
+
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=streamable-http.transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-http.transport.js","sourceRoot":"","sources":["../../../../src/mcp/transport/transports/streamable-http.transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from 'crypto';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { HttpAdapterFactory } from '../../adapters/http-adapter.factory';\nimport { HttpResponse } from '../../interfaces/http-adapter.interface';\nimport { McpTransport, McpTransportContext } from '../mcp-transport.interface';\nimport type { McpHttpHandler } from '../mcp-http-handler';\nimport { readJsonBody } from './read-body';\n\nexport interface StreamableHttpTransportOptions {\n /**\n * Path of the transport's **self-mounted** route.\n *\n * This ONLY applies when the transport self-mounts (no controller owns the\n * route). A self-mounted route is registered directly on the HTTP adapter,\n * OUTSIDE Nest's routing pipeline — so it does not pick up\n * `app.setGlobalPrefix(...)`, URI versioning, guards, or interceptors. Use\n * `endpoint` for a trivial path change on a no-auth server.\n *\n * When you bring your own controller, the path comes from your\n * `@Controller(...)` decorator (and global prefix / versioning apply normally)\n * — `endpoint` is ignored. The transport logs a warning if you set it anyway.\n *\n * @default '/mcp'\n */\n endpoint?: string;\n /**\n * Enable session management (a long-lived MCP server per session, identified\n * by the `mcp-session-id` header, with `GET`/`DELETE` support for SSE streams\n * and session teardown).\n *\n * Left off (the default), the transport is **stateless**: every request is\n * self-contained, a fresh server is created and torn down per request, and\n * `GET`/`DELETE` return `405`. Stateless is the simplest mode and the right\n * default for most servers; turn this on only when you need server-initiated\n * streaming/notifications tied to a session.\n *\n * @default false (stateless)\n */\n statefulMode?: boolean;\n /**\n * Return a single JSON response instead of opening an SSE stream.\n *\n * When unset, this **follows the session mode**: `true` in stateless mode (so\n * a plain POST gets a JSON reply with no stream to manage) and `false` in\n * stateful mode (SSE, so server-initiated messages can flow). Set it\n * explicitly to override that pairing.\n *\n * @default `!statefulMode` (JSON when stateless, SSE when stateful)\n */\n enableJsonResponse?: boolean;\n /** Custom session id generator (stateful mode). */\n sessionIdGenerator?: () => string;\n /**\n * Whether the transport mounts its own `POST`/`GET`/`DELETE` routes on the\n * Nest HTTP adapter.\n *\n * Leave it unset (the default) for **auto-detection**: the transport\n * self-mounts UNLESS something has read {@link httpHandlers} — which happens\n * exactly when you wire a bring-your-own `@Controller` (e.g. via\n * `{ provide: MCP_HTTP_HANDLER, useValue: transport.httpHandlers }`). So\n * providing a controller automatically suppresses self-mounting; doing\n * nothing keeps the zero-config self-mount. This read happens at module\n * definition time, before the transport starts, so the timing is reliable.\n *\n * Set it explicitly to override the heuristic:\n * - `true`: always self-mount (bypasses the Nest pipeline — no guards).\n * - `false`: never self-mount (you own the route via a controller).\n *\n * @default undefined (auto: self-mount unless `httpHandlers` was accessed)\n */\n mount?: boolean;\n}\n\n/**\n * Streamable-HTTP transport. Mounts `POST`/`GET`/`DELETE` on the Nest HTTP server\n * and delegates to the MCP SDK `StreamableHTTPServerTransport`. Supports both the\n * stateless (one server per request) and stateful (session-managed) modes.\n */\nexport class StreamableHttpTransport implements McpTransport {\n readonly kind = 'streamable-http' as const;\n\n private readonly endpoint: string;\n private readonly statefulMode: boolean;\n private readonly enableJsonResponse: boolean;\n private readonly sessionIdGenerator: () => string;\n /** Whether `endpoint` was set explicitly (vs defaulted) — for the ignored-option warning. */\n private readonly endpointExplicit: boolean;\n /** Explicit `mount` override; `undefined` means auto-detect. */\n private readonly mountOption?: boolean;\n /** Set the first time {@link httpHandlers} is read — implies a BYO controller. */\n private handlersClaimed = false;\n\n private readonly transports: Record<string, StreamableHTTPServerTransport> =\n {};\n private readonly servers: Record<string, McpServer> = {};\n private ctx?: McpTransportContext;\n\n constructor(options: StreamableHttpTransportOptions = {}) {\n this.endpoint = ensureLeadingSlash(options.endpoint ?? 'mcp');\n this.endpointExplicit = options.endpoint !== undefined;\n this.statefulMode = options.statefulMode ?? false;\n // Default follows the session mode: JSON in stateless, SSE in stateful.\n this.enableJsonResponse =\n options.enableJsonResponse ?? !this.statefulMode;\n this.sessionIdGenerator =\n options.sessionIdGenerator ?? (() => randomUUID());\n this.mountOption = options.mount;\n }\n\n /**\n * The HTTP verb handlers, for bring-your-own-controller setups. Provide this\n * under `MCP_HTTP_HANDLER` and delegate to it from a `@Controller` (see\n * {@link StreamableHttpController}). The returned functions are bound to this\n * transport and read their context lazily, so it is safe to grab this getter\n * at module-construction time — before `start()` has run.\n *\n * Reading this getter also marks the route as claimed, so the transport\n * auto-disables its own self-mount (unless `mount` was set explicitly). That\n * is how `{ provide: MCP_HTTP_HANDLER, useValue: transport.httpHandlers }`\n * suppresses self-mounting without any extra flag.\n */\n get httpHandlers(): McpHttpHandler {\n this.handlersClaimed = true;\n return {\n handlePost: (req: unknown, res: unknown) => this.handlePost(req, res),\n handleGet: (req: unknown, res: unknown) => this.handleGet(req, res),\n handleDelete: (req: unknown, res: unknown) => this.handleDelete(req, res),\n };\n }\n\n start(ctx: McpTransportContext): void {\n // The context (server factory, request-handler binding, logger) is always\n // needed — the handlers read it lazily whether we self-mount or a user\n // controller calls them.\n this.ctx = ctx;\n\n // Auto-detect: self-mount unless a controller claimed the route by reading\n // `httpHandlers`. An explicit `mount` option overrides the heuristic.\n const shouldMount = this.mountOption ?? !this.handlersClaimed;\n\n if (!shouldMount) {\n // The path now comes from the user's @Controller(...), so a self-mount\n // `endpoint` would be silently ignored. Don't let that pass quietly.\n if (this.endpointExplicit) {\n ctx.logger.warn(\n `StreamableHttpTransport: \\`endpoint: '${this.endpoint}'\\` is ignored because a controller owns the route. Set the path on your @Controller(...) decorator instead (it also picks up global prefix and versioning).`,\n );\n }\n ctx.logger.log(\n `MCP streamable-http transport ready (${this.statefulMode ? 'stateful' : 'stateless'}, self-mount disabled — a controller owns the route)`,\n );\n return;\n }\n\n if (!ctx.httpAdapter) {\n throw new Error(\n 'StreamableHttpTransport requires an HTTP adapter to self-mount. Pass it via new McpStrategy({ httpAdapter }) or strategy.setHttpAdapter(app.getHttpAdapter()) — or mount your own controller (provide MCP_HTTP_HANDLER with transport.httpHandlers).',\n );\n }\n const adapter = ctx.httpAdapter as unknown as {\n post(path: string, handler: (req: any, res: any) => unknown): unknown;\n get(path: string, handler: (req: any, res: any) => unknown): unknown;\n delete(path: string, handler: (req: any, res: any) => unknown): unknown;\n };\n\n adapter.post(this.endpoint, (req, res) => this.handlePost(req, res));\n adapter.get(this.endpoint, (req, res) => this.handleGet(req, res));\n adapter.delete(this.endpoint, (req, res) => this.handleDelete(req, res));\n\n ctx.logger.log(\n `MCP streamable-http transport mounted at ${this.endpoint} (${this.statefulMode ? 'stateful' : 'stateless'})`,\n );\n }\n\n async close(): Promise<void> {\n for (const sessionId of Object.keys(this.transports)) {\n await this.cleanupSession(sessionId);\n }\n }\n\n private async handlePost(req: any, res: any): Promise<void> {\n const adapter = HttpAdapterFactory.getAdapter(req, res);\n const adaptedReq = adapter.adaptRequest(req);\n const adaptedRes = adapter.adaptResponse(res);\n const body = await readJsonBody(adaptedReq);\n\n try {\n if (this.statefulMode) {\n await this.handleStateful(adaptedReq, adaptedRes, body);\n } else {\n await this.handleStateless(adaptedReq, adaptedRes, body);\n }\n } catch (error) {\n this.ctx!.logger.error('Error handling MCP request', error as Error);\n if (!adaptedRes.headersSent) {\n adaptedRes.status(500).json({\n jsonrpc: '2.0',\n error: { code: -32603, message: 'Internal server error' },\n id: null,\n });\n }\n }\n }\n\n private async handleStateless(\n req: ReturnType<\n ReturnType<typeof HttpAdapterFactory.getAdapter>['adaptRequest']\n >,\n res: HttpResponse,\n body: unknown,\n ): Promise<void> {\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: this.enableJsonResponse,\n });\n const server = this.ctx!.createServer();\n await server.connect(transport);\n this.ctx!.bindRequestHandlers(\n server,\n { transport: this.kind, stateless: true },\n req.raw,\n );\n\n res.raw.on('finish', () => {\n void transport.close();\n void server.close();\n });\n\n await transport.handleRequest(req.raw, res.raw, body);\n }\n\n private async handleStateful(\n req: ReturnType<\n ReturnType<typeof HttpAdapterFactory.getAdapter>['adaptRequest']\n >,\n res: HttpResponse,\n body: unknown,\n ): Promise<void> {\n const sessionId = req.headers['mcp-session-id'] as string | undefined;\n\n if (!sessionId && isInitializeRequest(body)) {\n const server = this.ctx!.createServer();\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: this.sessionIdGenerator,\n enableJsonResponse: this.enableJsonResponse,\n onsessioninitialized: (sid: string) => {\n this.transports[sid] = transport;\n this.servers[sid] = server;\n },\n onsessionclosed: (sid: string) => {\n void this.cleanupSession(sid);\n },\n });\n await server.connect(transport);\n this.ctx!.bindRequestHandlers(\n server,\n { transport: this.kind, stateless: false },\n req.raw,\n );\n await transport.handleRequest(req.raw, res.raw, body);\n return;\n }\n\n if (sessionId) {\n const transport = this.transports[sessionId];\n const server = this.servers[sessionId];\n if (!transport || !server) {\n res.status(404).json({\n jsonrpc: '2.0',\n error: { code: -32001, message: 'Session not found' },\n id: null,\n });\n return;\n }\n // Re-bind so the per-request auth context is current.\n this.ctx!.bindRequestHandlers(\n server,\n { transport: this.kind, stateless: false, sessionId },\n req.raw,\n );\n await transport.handleRequest(req.raw, res.raw, body);\n return;\n }\n\n res.status(400).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Bad Request: Mcp-Session-Id header is required',\n },\n id: null,\n });\n }\n\n private async handleGet(req: any, res: any): Promise<void> {\n const adapter = HttpAdapterFactory.getAdapter(req, res);\n const adaptedReq = adapter.adaptRequest(req);\n const adaptedRes = adapter.adaptResponse(res);\n\n if (!this.statefulMode) {\n adaptedRes.status(405).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Method not allowed in stateless mode',\n },\n id: null,\n });\n return;\n }\n const sessionId = adaptedReq.headers['mcp-session-id'] as\n | string\n | undefined;\n const transport = sessionId ? this.transports[sessionId] : undefined;\n if (!transport) {\n adaptedRes.status(404).json({\n jsonrpc: '2.0',\n error: { code: -32001, message: 'Session not found' },\n id: null,\n });\n return;\n }\n await transport.handleRequest(adaptedReq.raw, adaptedRes.raw);\n }\n\n private async handleDelete(req: any, res: any): Promise<void> {\n const adapter = HttpAdapterFactory.getAdapter(req, res);\n const adaptedReq = adapter.adaptRequest(req);\n const adaptedRes = adapter.adaptResponse(res);\n\n if (!this.statefulMode) {\n adaptedRes.status(405).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Method not allowed in stateless mode',\n },\n id: null,\n });\n return;\n }\n const sessionId = adaptedReq.headers['mcp-session-id'] as\n | string\n | undefined;\n const transport = sessionId ? this.transports[sessionId] : undefined;\n if (!transport) {\n adaptedRes.status(404).json({\n jsonrpc: '2.0',\n error: { code: -32001, message: 'Session not found' },\n id: null,\n });\n return;\n }\n await transport.handleRequest(adaptedReq.raw, adaptedRes.raw);\n }\n\n private async cleanupSession(sessionId: string): Promise<void> {\n const transport = this.transports[sessionId];\n const server = this.servers[sessionId];\n delete this.transports[sessionId];\n delete this.servers[sessionId];\n try {\n await transport?.close();\n await server?.close();\n } catch {\n // best-effort cleanup\n }\n }\n}\n\nfunction isInitializeRequest(body: unknown): boolean {\n const isInit = (msg: unknown): boolean =>\n typeof msg === 'object' &&\n msg !== null &&\n 'method' in msg &&\n (msg as { method?: unknown }).method === 'initialize';\n return Array.isArray(body) ? body.some(isInit) : isInit(body);\n}\n\nfunction ensureLeadingSlash(endpoint: string): string {\n const trimmed = endpoint.trim();\n return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;\n}\n"]}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { Logger } from '@nestjs/common';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
export interface McpLoggingOptions {
|
|
3
|
+
logging?: false | {
|
|
4
|
+
level: ('log' | 'error' | 'warn' | 'debug' | 'verbose')[];
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export declare function createMcpLogger(context: string, options: McpLoggingOptions | undefined): Logger;
|
|
4
8
|
//# sourceMappingURL=mcp-logger.factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-logger.factory.d.ts","sourceRoot":"","sources":["../../../src/mcp/utils/mcp-logger.factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-logger.factory.d.ts","sourceRoot":"","sources":["../../../src/mcp/utils/mcp-logger.factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,gBAAgB,CAAC;AAMlD,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EACJ,KAAK,GACL;QACE,KAAK,EAAE,CAAC,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,EAAE,CAAC;KAC3D,CAAC;CACP;AAoFD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,GAAG,SAAS,GACrC,MAAM,CAkBR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-logger.factory.js","sourceRoot":"","sources":["../../../src/mcp/utils/mcp-logger.factory.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"mcp-logger.factory.js","sourceRoot":"","sources":["../../../src/mcp/utils/mcp-logger.factory.ts"],"names":[],"mappings":";;AAgGA,0CAqBC;AArHD,2CAAkD;AAiBlD,MAAM,cAAe,SAAQ,eAAM;IAGjC,YAAY,OAAe,EAAE,aAAyB;QACpD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;IAC9C,CAAC;IAED,GAAG,CAAC,OAAY,EAAE,OAAgB;QAChC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAID,KAAK,CAAC,OAAY,EAAE,GAAG,cAAqB;QAC1C,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAY,EAAE,OAAgB;QACjC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAY,EAAE,OAAgB;QAClC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,OAAY,EAAE,OAAgB;QACpC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACtC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;CACF;AAKD,MAAM,UAAW,SAAQ,eAAM;IAE7B,GAAG,CAAC,OAAY,EAAE,OAAgB;IAElC,CAAC;IAKD,KAAK,CAAC,OAAY,EAAE,GAAG,cAAqB;IAE5C,CAAC;IAGD,IAAI,CAAC,OAAY,EAAE,OAAgB;IAEnC,CAAC;IAGD,KAAK,CAAC,OAAY,EAAE,OAAgB;IAEpC,CAAC;IAGD,OAAO,CAAC,OAAY,EAAE,OAAgB;IAEtC,CAAC;CACF;AAQD,SAAgB,eAAe,CAC7B,OAAe,EACf,OAAsC;IAGtC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9C,OAAO,IAAI,eAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAGD,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC9B,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAGD,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClE,OAAO,IAAI,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAmB,CAAC,CAAC;IAC1E,CAAC;IAGD,OAAO,IAAI,eAAM,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC","sourcesContent":["import { Logger, LogLevel } from '@nestjs/common';\n\n/**\n * The subset of server options the logger factory cares about. Matches the\n * `logging` field on {@link McpServerOptions}.\n */\nexport interface McpLoggingOptions {\n logging?:\n | false\n | {\n level: ('log' | 'error' | 'warn' | 'debug' | 'verbose')[];\n };\n}\n\n/**\n * Logger that filters log messages based on configured log levels\n */\nclass FilteredLogger extends Logger {\n private enabledLevels: Set<LogLevel>;\n\n constructor(context: string, enabledLevels: LogLevel[]) {\n super(context);\n this.enabledLevels = new Set(enabledLevels);\n }\n\n log(message: any, context?: string): void {\n if (this.enabledLevels.has('log')) {\n super.log(message, context);\n }\n }\n\n error(message: any, stack?: string, context?: string): void;\n error(message: any, ...optionalParams: [...any, string?, string?]): void;\n error(message: any, ...optionalParams: any[]): void {\n if (this.enabledLevels.has('error')) {\n super.error(message, ...optionalParams);\n }\n }\n\n warn(message: any, context?: string): void {\n if (this.enabledLevels.has('warn')) {\n super.warn(message, context);\n }\n }\n\n debug(message: any, context?: string): void {\n if (this.enabledLevels.has('debug')) {\n super.debug(message, context);\n }\n }\n\n verbose(message: any, context?: string): void {\n if (this.enabledLevels.has('verbose')) {\n super.verbose(message, context);\n }\n }\n}\n\n/**\n * No-op logger that discards all log messages\n */\nclass NoOpLogger extends Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n log(message: any, context?: string): void {\n // No-op\n }\n\n error(message: any, stack?: string, context?: string): void;\n error(message: any, ...optionalParams: [...any, string?, string?]): void;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(message: any, ...optionalParams: any[]): void {\n // No-op\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n warn(message: any, context?: string): void {\n // No-op\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n debug(message: any, context?: string): void {\n // No-op\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n verbose(message: any, context?: string): void {\n // No-op\n }\n}\n\n/**\n * Factory function to create a logger instance based on MCP logging configuration\n * @param context - Logger context (typically the class name)\n * @param options - MCP options containing logging configuration\n * @returns Logger instance (standard, filtered, or no-op based on configuration)\n */\nexport function createMcpLogger(\n context: string,\n options: McpLoggingOptions | undefined,\n): Logger {\n // If no options provided or logging not configured, use standard logger\n if (!options || options.logging === undefined) {\n return new Logger(context);\n }\n\n // If logging is explicitly disabled, return no-op logger\n if (options.logging === false) {\n return new NoOpLogger(context);\n }\n\n // If specific log levels are configured, return filtered logger\n if (options.logging.level && Array.isArray(options.logging.level)) {\n return new FilteredLogger(context, options.logging.level as LogLevel[]);\n }\n\n // Fallback to standard logger\n return new Logger(context);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rekog/mcp-nest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.0",
|
|
4
4
|
"description": "NestJS module for creating Model Context Protocol (MCP) servers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,9 +11,6 @@
|
|
|
11
11
|
"README.md",
|
|
12
12
|
"LICENSE"
|
|
13
13
|
],
|
|
14
|
-
"workspaces": [
|
|
15
|
-
"playground"
|
|
16
|
-
],
|
|
17
14
|
"publishConfig": {
|
|
18
15
|
"access": "public"
|
|
19
16
|
},
|
|
@@ -22,86 +19,26 @@
|
|
|
22
19
|
"url": "https://github.com/rekog-labs/MCP-Nest"
|
|
23
20
|
},
|
|
24
21
|
"scripts": {
|
|
25
|
-
"build": "tsc -p tsconfig.build.json --sourceMap --inlineSources"
|
|
26
|
-
"prepare": "npm run build",
|
|
27
|
-
"smoke": "npm -w playground run smoke:local",
|
|
28
|
-
"start:playground": "TS_NODE_PROJECT=tsconfig.playground.json ts-node-dev --respawn -r tsconfig-paths/register playground/servers/server-stateful.ts",
|
|
29
|
-
"start:fastify": "TS_NODE_PROJECT=tsconfig.playground.json ts-node-dev --respawn -r tsconfig-paths/register playground/servers/server-fastify.ts",
|
|
30
|
-
"start:multi-server": "TS_NODE_PROJECT=tsconfig.playground.json ts-node-dev --respawn -r tsconfig-paths/register playground/servers/multi-server-example/main.ts",
|
|
31
|
-
"test": "bun test src tests",
|
|
32
|
-
"test:watch": "bun test src tests --watch",
|
|
33
|
-
"lint": "eslint \"{src,apps,libs,tests}/**/*.ts\" --fix",
|
|
34
|
-
"format": "prettier --write \"src/**/*.ts\" \"playground/**/*.ts\" \"tests/**/*.ts\""
|
|
22
|
+
"build": "tsc -p tsconfig.build.json --sourceMap --inlineSources"
|
|
35
23
|
},
|
|
36
24
|
"peerDependencies": {
|
|
37
25
|
"@modelcontextprotocol/sdk": ">=1.10.0",
|
|
38
26
|
"@nestjs/common": ">=9.0.0",
|
|
39
27
|
"@nestjs/core": ">=9.0.0",
|
|
40
|
-
"@nestjs/
|
|
41
|
-
"@nestjs/passport": "^11.0.5",
|
|
28
|
+
"@nestjs/microservices": ">=9.0.0",
|
|
42
29
|
"@nestjs/platform-fastify": "^11.1.5",
|
|
43
|
-
"@nestjs/typeorm": ">=9.0.0",
|
|
44
30
|
"express": ">=4.0.0",
|
|
45
31
|
"reflect-metadata": "^0.2.2",
|
|
46
|
-
"typeorm": ">=0.3.25",
|
|
47
32
|
"zod": "^4.3.5"
|
|
48
33
|
},
|
|
49
34
|
"peerDependenciesMeta": {
|
|
50
35
|
"@nestjs/platform-fastify": {
|
|
51
36
|
"optional": true
|
|
52
|
-
},
|
|
53
|
-
"@nestjs/typeorm": {
|
|
54
|
-
"optional": true
|
|
55
|
-
},
|
|
56
|
-
"typeorm": {
|
|
57
|
-
"optional": true
|
|
58
37
|
}
|
|
59
38
|
},
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"@eslint/eslintrc": "^3.3.3",
|
|
62
|
-
"@eslint/js": "^9.39.2",
|
|
63
|
-
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
64
|
-
"@nestjs/common": "^11.1.14",
|
|
65
|
-
"@nestjs/core": "^11.1.14",
|
|
66
|
-
"@nestjs/platform-express": "^11.1.14",
|
|
67
|
-
"@nestjs/platform-fastify": "^11.1.14",
|
|
68
|
-
"@nestjs/testing": "^11.1.14",
|
|
69
|
-
"@nestjs/typeorm": "^11.0.1",
|
|
70
|
-
"@types/cookie-parser": "^1.4.10",
|
|
71
|
-
"@types/express": "^5.0.6",
|
|
72
|
-
"@types/jest": "^29.5.14",
|
|
73
|
-
"@types/node": "^22.19.7",
|
|
74
|
-
"@types/passport-github": "^1.1.13",
|
|
75
|
-
"@types/passport-google-oauth20": "^2.0.17",
|
|
76
|
-
"@types/supertest": "^6.0.3",
|
|
77
|
-
"eslint": "^9.39.2",
|
|
78
|
-
"eslint-config-prettier": "^10.1.8",
|
|
79
|
-
"eslint-plugin-prettier": "^5.5.5",
|
|
80
|
-
"express": "^5.2.1",
|
|
81
|
-
"jest": "^29.7.0",
|
|
82
|
-
"supertest": "^7.2.2",
|
|
83
|
-
"ts-jest": "^29.4.6",
|
|
84
|
-
"ts-node-dev": "^2.0.0",
|
|
85
|
-
"tsconfig-paths": "^4.2.0",
|
|
86
|
-
"typeorm": "^1.0.0",
|
|
87
|
-
"typescript": "^5.9.3",
|
|
88
|
-
"typescript-eslint": "^8.56.1"
|
|
89
|
-
},
|
|
90
39
|
"dependencies": {
|
|
91
|
-
"@nestjs/config": "^4.0.3",
|
|
92
|
-
"cookie-parser": "^1.4.7",
|
|
93
40
|
"multer": "^2.0.2",
|
|
94
|
-
"passport": "^0.7.0",
|
|
95
|
-
"passport-azure-ad-oauth2": "^0.0.4",
|
|
96
|
-
"passport-github": "^1.1.0",
|
|
97
|
-
"passport-google-oauth20": "^2.0.0",
|
|
98
41
|
"path-to-regexp": "^8.3.0",
|
|
99
42
|
"rxjs": "^7.8.2"
|
|
100
|
-
},
|
|
101
|
-
"overrides": {
|
|
102
|
-
"qs": "^6.14.1",
|
|
103
|
-
"body-parser": "^2.2.1",
|
|
104
|
-
"jws": "^3.2.3",
|
|
105
|
-
"hono": "^4.11.4"
|
|
106
43
|
}
|
|
107
44
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,3 +2,4 @@ export const MCP_TOOL_METADATA_KEY = 'mcp:tool';
|
|
|
2
2
|
export const MCP_RESOURCE_METADATA_KEY = 'mcp:resource';
|
|
3
3
|
export const MCP_RESOURCE_TEMPLATE_METADATA_KEY = 'mcp:resource-template';
|
|
4
4
|
export const MCP_PROMPT_METADATA_KEY = 'mcp:prompt';
|
|
5
|
+
export const MCP_CONTROLLER_METADATA_KEY = 'mcp:controller';
|
|
@@ -6,4 +6,6 @@ export * from './prompt.decorator';
|
|
|
6
6
|
export * from './public.decorator';
|
|
7
7
|
export * from './tool-scopes.decorator';
|
|
8
8
|
export * from './tool-roles.decorator';
|
|
9
|
-
export * from './
|
|
9
|
+
export * from './mcp-controller.decorator';
|
|
10
|
+
export * from './mcp-message-pattern';
|
|
11
|
+
export * from './raw-request.decorator';
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applyDecorators,
|
|
3
|
+
Controller,
|
|
4
|
+
ControllerOptions,
|
|
5
|
+
SetMetadata,
|
|
6
|
+
} from '@nestjs/common';
|
|
7
|
+
import { MCP_CONTROLLER_METADATA_KEY } from './constants';
|
|
8
|
+
import {
|
|
9
|
+
MCP_SERVER_NAME_METADATA_KEY,
|
|
10
|
+
mcpTransportFor,
|
|
11
|
+
} from '../transport/mcp-transport.constants';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* NestJS-internal metadata keys written by `@MessagePattern`. They are NOT
|
|
15
|
+
* re-exported from the `@nestjs/microservices` package entry, so we reference
|
|
16
|
+
* the string literals directly (see `@nestjs/microservices/constants`:
|
|
17
|
+
* `PATTERN_EXTRAS_METADATA` / `TRANSPORT_METADATA`). The multi-server e2e test
|
|
18
|
+
* guards against these drifting on a NestJS bump.
|
|
19
|
+
*/
|
|
20
|
+
const PATTERN_EXTRAS_METADATA = 'microservices:pattern_extras';
|
|
21
|
+
const TRANSPORT_METADATA = 'microservices:transport';
|
|
22
|
+
|
|
23
|
+
/** Options for {@link McpController}: standard `@Controller` options plus a server name. */
|
|
24
|
+
export interface McpControllerOptions extends ControllerOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Logical MCP server name. The controller's MCP methods bind ONLY to a
|
|
27
|
+
* connected `McpStrategy({ server: <name> })`. Omit to use the default shared
|
|
28
|
+
* server (binds to a plain `McpStrategy()`).
|
|
29
|
+
*/
|
|
30
|
+
server?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Re-tags every MCP capability method on `target`'s prototype with the given
|
|
35
|
+
* transport id, overriding the default {@link MCP_TRANSPORT} that the
|
|
36
|
+
* `@Tool`/`@Resource`/`@Prompt` method decorators wrote.
|
|
37
|
+
*
|
|
38
|
+
* This works because class decorators run AFTER the method decorators, and both
|
|
39
|
+
* `@MessagePattern` and this walk reach the SAME function reference via
|
|
40
|
+
* `prototype[key]` — so re-defining the transport metadata on it wins. We
|
|
41
|
+
* recognize MCP methods by the `mcpType` marker stored in their pattern extras.
|
|
42
|
+
*
|
|
43
|
+
* Note: `Object.getOwnPropertyNames` only sees methods declared on this class,
|
|
44
|
+
* not ones inherited from a base class.
|
|
45
|
+
*/
|
|
46
|
+
function retagMcpMethodsTransport(
|
|
47
|
+
target: Function,
|
|
48
|
+
transportId: symbol,
|
|
49
|
+
): void {
|
|
50
|
+
const proto = (target as { prototype?: Record<string, unknown> }).prototype;
|
|
51
|
+
if (!proto) return;
|
|
52
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
53
|
+
if (key === 'constructor') continue;
|
|
54
|
+
const fn = proto[key];
|
|
55
|
+
if (typeof fn !== 'function') continue;
|
|
56
|
+
const extras = Reflect.getMetadata(PATTERN_EXTRAS_METADATA, fn) as
|
|
57
|
+
| { mcpType?: unknown }
|
|
58
|
+
| undefined;
|
|
59
|
+
if (extras && extras.mcpType) {
|
|
60
|
+
Reflect.defineMetadata(TRANSPORT_METADATA, transportId, fn);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Marks a class as an MCP capability controller.
|
|
67
|
+
*
|
|
68
|
+
* NestJS only scans classes registered in a module's `controllers` array for
|
|
69
|
+
* microservice (`@MessagePattern`) handlers, so MCP tool/resource/prompt classes
|
|
70
|
+
* MUST be controllers. `@McpController` composes the standard `@Controller()`
|
|
71
|
+
* decorator (so the framework discovers and binds the `@Tool`/`@Resource`/
|
|
72
|
+
* `@Prompt` handlers) and adds a marker the {@link McpStrategy} uses to recognize
|
|
73
|
+
* MCP controllers.
|
|
74
|
+
*
|
|
75
|
+
* Because `@Tool`/`@Resource`/`@Prompt` do not add HTTP route decorators, methods
|
|
76
|
+
* on an `@McpController` are NOT exposed as HTTP routes — they are reachable only
|
|
77
|
+
* through the MCP transport.
|
|
78
|
+
*
|
|
79
|
+
* To run multiple isolated MCP servers in one app, assign a controller to a
|
|
80
|
+
* named server with `@McpController({ server: 'admin' })`; its tools/resources/
|
|
81
|
+
* prompts then bind ONLY to a matching `McpStrategy({ server: 'admin' })`.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* @McpController()
|
|
86
|
+
* export class GreetingTool {
|
|
87
|
+
* @Tool({ name: 'hello', description: 'Say hello', parameters: z.object({ name: z.string() }) })
|
|
88
|
+
* sayHello(@Payload() { name }: { name: string }, @Ctx() ctx: McpContext) {
|
|
89
|
+
* return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export function McpController(
|
|
95
|
+
prefixOrOptions?: string | string[] | McpControllerOptions,
|
|
96
|
+
): ClassDecorator {
|
|
97
|
+
// Extract the MCP-specific `server` name (if any) and forward the remaining
|
|
98
|
+
// standard controller options to `@Controller`.
|
|
99
|
+
let server: string | undefined;
|
|
100
|
+
let controllerOptions: string | string[] | ControllerOptions | undefined =
|
|
101
|
+
prefixOrOptions;
|
|
102
|
+
if (
|
|
103
|
+
prefixOrOptions &&
|
|
104
|
+
typeof prefixOrOptions === 'object' &&
|
|
105
|
+
!Array.isArray(prefixOrOptions) &&
|
|
106
|
+
'server' in prefixOrOptions
|
|
107
|
+
) {
|
|
108
|
+
const { server: serverName, ...rest } = prefixOrOptions;
|
|
109
|
+
server = serverName;
|
|
110
|
+
controllerOptions = rest;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (target: Function) => {
|
|
114
|
+
applyDecorators(
|
|
115
|
+
Controller(controllerOptions as ControllerOptions),
|
|
116
|
+
SetMetadata(MCP_CONTROLLER_METADATA_KEY, true),
|
|
117
|
+
SetMetadata(MCP_SERVER_NAME_METADATA_KEY, server),
|
|
118
|
+
)(target);
|
|
119
|
+
// A named server re-tags this controller's MCP methods with that server's
|
|
120
|
+
// transport id, so NestJS routes them only to the matching strategy. An
|
|
121
|
+
// unnamed controller keeps the default MCP_TRANSPORT (single-server) behavior.
|
|
122
|
+
if (server) {
|
|
123
|
+
retagMcpMethodsTransport(target, mcpTransportFor(server));
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MessagePattern } from '@nestjs/microservices';
|
|
2
|
+
import {
|
|
3
|
+
buildMcpHandlerExtras,
|
|
4
|
+
buildMcpPattern,
|
|
5
|
+
MCP_TRANSPORT,
|
|
6
|
+
McpCapabilityType,
|
|
7
|
+
} from '../transport/mcp-transport.constants';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Builds the `@MessagePattern` half of an MCP capability decorator.
|
|
11
|
+
*
|
|
12
|
+
* The returned method decorator registers a NestJS RPC handler scoped to the
|
|
13
|
+
* {@link MCP_TRANSPORT} identifier, with:
|
|
14
|
+
* - a structured pattern `{ mcp, name }` so the strategy can deterministically
|
|
15
|
+
* map a discovered capability back to its handler, and
|
|
16
|
+
* - `extras` `{ mcpType, mcpName }` so the strategy can recognize/prune MCP
|
|
17
|
+
* handlers from the shared `messageHandlers` map.
|
|
18
|
+
*
|
|
19
|
+
* When `explicitName` is omitted (e.g. a `@Tool` without `name`), the method
|
|
20
|
+
* name is used — mirroring the name-defaulting in `McpRegistryDiscoveryService`,
|
|
21
|
+
* so the discovered metadata name and the pattern name stay in sync.
|
|
22
|
+
*/
|
|
23
|
+
export function mcpMessagePattern(
|
|
24
|
+
type: McpCapabilityType,
|
|
25
|
+
explicitName?: string,
|
|
26
|
+
): MethodDecorator {
|
|
27
|
+
return (target, propertyKey, descriptor: PropertyDescriptor) => {
|
|
28
|
+
const methodKey = String(propertyKey);
|
|
29
|
+
const name = explicitName ?? methodKey;
|
|
30
|
+
return MessagePattern(
|
|
31
|
+
buildMcpPattern(type, name),
|
|
32
|
+
MCP_TRANSPORT,
|
|
33
|
+
// `descriptor.value` is the decorated method; the strategy reads all MCP
|
|
34
|
+
// metadata (tool options + security decorators) off it at listen() time.
|
|
35
|
+
buildMcpHandlerExtras(type, name, methodKey, descriptor.value),
|
|
36
|
+
)(target, propertyKey, descriptor);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { SetMetadata } from '@nestjs/common';
|
|
1
|
+
import { applyDecorators, SetMetadata } from '@nestjs/common';
|
|
2
2
|
import { MCP_PROMPT_METADATA_KEY } from './constants';
|
|
3
3
|
import { ZodObject, ZodType } from 'zod';
|
|
4
|
+
import { mcpMessagePattern } from './mcp-message-pattern';
|
|
4
5
|
|
|
5
6
|
export type PromptArgsRawShape = {
|
|
6
7
|
[k: string]: ZodType;
|
|
@@ -19,5 +20,8 @@ export interface PromptOptions {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const Prompt = (options: PromptOptions) => {
|
|
22
|
-
return
|
|
23
|
+
return applyDecorators(
|
|
24
|
+
SetMetadata(MCP_PROMPT_METADATA_KEY, options),
|
|
25
|
+
mcpMessagePattern('prompt', options.name),
|
|
26
|
+
);
|
|
23
27
|
};
|
|
@@ -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
|