synapse-mcp 1.0.0 → 1.0.2
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 +1820 -147
- package/dist/constants.d.ts +10 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +18 -8
- package/dist/constants.js.map +1 -1
- package/dist/events/emitter.d.ts +63 -0
- package/dist/events/emitter.d.ts.map +1 -0
- package/dist/events/emitter.js +112 -0
- package/dist/events/emitter.js.map +1 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +3 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/types.d.ts +51 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +3 -0
- package/dist/events/types.js.map +1 -0
- package/dist/formatters/compose.d.ts +185 -0
- package/dist/formatters/compose.d.ts.map +1 -0
- package/dist/formatters/compose.js +397 -0
- package/dist/formatters/compose.js.map +1 -0
- package/dist/formatters/container.d.ts +84 -0
- package/dist/formatters/container.d.ts.map +1 -0
- package/dist/formatters/container.js +323 -0
- package/dist/formatters/container.js.map +1 -0
- package/dist/formatters/diagnostics.d.ts +20 -0
- package/dist/formatters/diagnostics.d.ts.map +1 -0
- package/dist/formatters/diagnostics.js +73 -0
- package/dist/formatters/diagnostics.js.map +1 -0
- package/dist/formatters/docker.d.ts +139 -0
- package/dist/formatters/docker.d.ts.map +1 -0
- package/dist/formatters/docker.js +216 -0
- package/dist/formatters/docker.js.map +1 -0
- package/dist/formatters/host.d.ts +137 -0
- package/dist/formatters/host.d.ts.map +1 -0
- package/dist/formatters/host.js +198 -0
- package/dist/formatters/host.js.map +1 -0
- package/dist/formatters/index.d.ts +17 -270
- package/dist/formatters/index.d.ts.map +1 -1
- package/dist/formatters/index.js +21 -456
- package/dist/formatters/index.js.map +1 -1
- package/dist/formatters/scout.d.ts +424 -0
- package/dist/formatters/scout.d.ts.map +1 -0
- package/dist/formatters/scout.js +687 -0
- package/dist/formatters/scout.js.map +1 -0
- package/dist/formatters/strategy.d.ts +105 -0
- package/dist/formatters/strategy.d.ts.map +1 -0
- package/dist/formatters/strategy.js +120 -0
- package/dist/formatters/strategy.js.map +1 -0
- package/dist/formatters/utils.d.ts +84 -0
- package/dist/formatters/utils.d.ts.map +1 -0
- package/dist/formatters/utils.js +129 -0
- package/dist/formatters/utils.js.map +1 -0
- package/dist/health-rate-limiter.d.ts +59 -0
- package/dist/health-rate-limiter.d.ts.map +1 -0
- package/dist/health-rate-limiter.js +159 -0
- package/dist/health-rate-limiter.js.map +1 -0
- package/dist/index.js +61 -100
- package/dist/index.js.map +1 -1
- package/dist/middleware/async-handler.d.ts +62 -0
- package/dist/middleware/async-handler.d.ts.map +1 -0
- package/dist/middleware/async-handler.js +58 -0
- package/dist/middleware/async-handler.js.map +1 -0
- package/dist/middleware/auth.d.ts +32 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +63 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/csrf-protection.d.ts +58 -0
- package/dist/middleware/csrf-protection.d.ts.map +1 -0
- package/dist/middleware/csrf-protection.js +123 -0
- package/dist/middleware/csrf-protection.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +49 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +90 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/error-mapper.d.ts +44 -0
- package/dist/middleware/error-mapper.d.ts.map +1 -0
- package/dist/middleware/error-mapper.js +127 -0
- package/dist/middleware/error-mapper.js.map +1 -0
- package/dist/middleware/index.d.ts +13 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +13 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/request-id.d.ts +22 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +31 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/middleware/types.d.ts +33 -0
- package/dist/middleware/types.d.ts.map +1 -0
- package/dist/middleware/types.js +2 -0
- package/dist/middleware/types.js.map +1 -0
- package/dist/schemas/common.d.ts +205 -8
- package/dist/schemas/common.d.ts.map +1 -1
- package/dist/schemas/common.js +290 -17
- package/dist/schemas/common.js.map +1 -1
- package/dist/schemas/flux/compose.d.ts +307 -44
- package/dist/schemas/flux/compose.d.ts.map +1 -1
- package/dist/schemas/flux/compose.js +74 -48
- package/dist/schemas/flux/compose.js.map +1 -1
- package/dist/schemas/flux/container.d.ts +423 -56
- package/dist/schemas/flux/container.d.ts.map +1 -1
- package/dist/schemas/flux/container.js +83 -61
- package/dist/schemas/flux/container.js.map +1 -1
- package/dist/schemas/flux/docker.d.ts +254 -37
- package/dist/schemas/flux/docker.d.ts.map +1 -1
- package/dist/schemas/flux/docker.js +69 -39
- package/dist/schemas/flux/docker.js.map +1 -1
- package/dist/schemas/flux/host.d.ts +312 -29
- package/dist/schemas/flux/host.d.ts.map +1 -1
- package/dist/schemas/flux/host.js +74 -31
- package/dist/schemas/flux/host.js.map +1 -1
- package/dist/schemas/flux/index.d.ts +503 -11
- package/dist/schemas/flux/index.d.ts.map +1 -1
- package/dist/schemas/flux/index.js +34 -70
- package/dist/schemas/flux/index.js.map +1 -1
- package/dist/schemas/host-config.d.ts +76 -0
- package/dist/schemas/host-config.d.ts.map +1 -0
- package/dist/schemas/host-config.js +105 -0
- package/dist/schemas/host-config.js.map +1 -0
- package/dist/schemas/scout/index.d.ts +80 -23
- package/dist/schemas/scout/index.d.ts.map +1 -1
- package/dist/schemas/scout/index.js +26 -11
- package/dist/schemas/scout/index.js.map +1 -1
- package/dist/schemas/scout/logs.d.ts +17 -5
- package/dist/schemas/scout/logs.d.ts.map +1 -1
- package/dist/schemas/scout/logs.js +41 -31
- package/dist/schemas/scout/logs.js.map +1 -1
- package/dist/schemas/scout/simple.d.ts +126 -11
- package/dist/schemas/scout/simple.d.ts.map +1 -1
- package/dist/schemas/scout/simple.js +112 -57
- package/dist/schemas/scout/simple.js.map +1 -1
- package/dist/schemas/scout/zfs.d.ts +17 -5
- package/dist/schemas/scout/zfs.d.ts.map +1 -1
- package/dist/schemas/scout/zfs.js +34 -25
- package/dist/schemas/scout/zfs.js.map +1 -1
- package/dist/services/cache-layer.d.ts +160 -0
- package/dist/services/cache-layer.d.ts.map +1 -0
- package/dist/services/cache-layer.js +138 -0
- package/dist/services/cache-layer.js.map +1 -0
- package/dist/services/compose-cache.d.ts +75 -0
- package/dist/services/compose-cache.d.ts.map +1 -0
- package/dist/services/compose-cache.js +178 -0
- package/dist/services/compose-cache.js.map +1 -0
- package/dist/services/compose-discovery.d.ts +46 -0
- package/dist/services/compose-discovery.d.ts.map +1 -0
- package/dist/services/compose-discovery.js +219 -0
- package/dist/services/compose-discovery.js.map +1 -0
- package/dist/services/compose-project-lister.d.ts +27 -0
- package/dist/services/compose-project-lister.d.ts.map +1 -0
- package/dist/services/compose-project-lister.js +71 -0
- package/dist/services/compose-project-lister.js.map +1 -0
- package/dist/services/compose-scanner.d.ts +63 -0
- package/dist/services/compose-scanner.d.ts.map +1 -0
- package/dist/services/compose-scanner.js +253 -0
- package/dist/services/compose-scanner.js.map +1 -0
- package/dist/services/compose.d.ts +64 -28
- package/dist/services/compose.d.ts.map +1 -1
- package/dist/services/compose.js +220 -98
- package/dist/services/compose.js.map +1 -1
- package/dist/services/config-loader.d.ts +23 -0
- package/dist/services/config-loader.d.ts.map +1 -0
- package/dist/services/config-loader.js +124 -0
- package/dist/services/config-loader.js.map +1 -0
- package/dist/services/config-service.d.ts +38 -0
- package/dist/services/config-service.d.ts.map +1 -0
- package/dist/services/config-service.js +225 -0
- package/dist/services/config-service.js.map +1 -0
- package/dist/services/container-host-map-cache.d.ts +121 -0
- package/dist/services/container-host-map-cache.d.ts.map +1 -0
- package/dist/services/container-host-map-cache.js +188 -0
- package/dist/services/container-host-map-cache.js.map +1 -0
- package/dist/services/container.d.ts +194 -6
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +386 -11
- package/dist/services/container.js.map +1 -1
- package/dist/services/diagnostics.d.ts +57 -0
- package/dist/services/diagnostics.d.ts.map +1 -0
- package/dist/services/diagnostics.js +271 -0
- package/dist/services/diagnostics.js.map +1 -0
- package/dist/services/docker/container-service.d.ts +123 -0
- package/dist/services/docker/container-service.d.ts.map +1 -0
- package/dist/services/docker/container-service.js +347 -0
- package/dist/services/docker/container-service.js.map +1 -0
- package/dist/services/docker/image-service.d.ts +82 -0
- package/dist/services/docker/image-service.d.ts.map +1 -0
- package/dist/services/docker/image-service.js +193 -0
- package/dist/services/docker/image-service.js.map +1 -0
- package/dist/services/docker/index.d.ts +80 -0
- package/dist/services/docker/index.d.ts.map +1 -0
- package/dist/services/docker/index.js +103 -0
- package/dist/services/docker/index.js.map +1 -0
- package/dist/services/docker/network-service.d.ts +22 -0
- package/dist/services/docker/network-service.d.ts.map +1 -0
- package/dist/services/docker/network-service.js +43 -0
- package/dist/services/docker/network-service.js.map +1 -0
- package/dist/services/docker/system-service.d.ts +49 -0
- package/dist/services/docker/system-service.d.ts.map +1 -0
- package/dist/services/docker/system-service.js +215 -0
- package/dist/services/docker/system-service.js.map +1 -0
- package/dist/services/docker/utils/client-factory.d.ts +56 -0
- package/dist/services/docker/utils/client-factory.d.ts.map +1 -0
- package/dist/services/docker/utils/client-factory.js +139 -0
- package/dist/services/docker/utils/client-factory.js.map +1 -0
- package/dist/services/docker/utils/client-manager.d.ts +88 -0
- package/dist/services/docker/utils/client-manager.d.ts.map +1 -0
- package/dist/services/docker/utils/client-manager.js +124 -0
- package/dist/services/docker/utils/client-manager.js.map +1 -0
- package/dist/services/docker/utils/exec-handler.d.ts +94 -0
- package/dist/services/docker/utils/exec-handler.d.ts.map +1 -0
- package/dist/services/docker/utils/exec-handler.js +197 -0
- package/dist/services/docker/utils/exec-handler.js.map +1 -0
- package/dist/services/docker/utils/formatters.d.ts +13 -0
- package/dist/services/docker/utils/formatters.d.ts.map +1 -0
- package/dist/services/docker/utils/formatters.js +33 -0
- package/dist/services/docker/utils/formatters.js.map +1 -0
- package/dist/services/docker/utils/log-parser.d.ts +10 -0
- package/dist/services/docker/utils/log-parser.d.ts.map +1 -0
- package/dist/services/docker/utils/log-parser.js +48 -0
- package/dist/services/docker/utils/log-parser.js.map +1 -0
- package/dist/services/docker/utils/stats-calculator.d.ts +68 -0
- package/dist/services/docker/utils/stats-calculator.d.ts.map +1 -0
- package/dist/services/docker/utils/stats-calculator.js +61 -0
- package/dist/services/docker/utils/stats-calculator.js.map +1 -0
- package/dist/services/docker/volume-service.d.ts +22 -0
- package/dist/services/docker/volume-service.d.ts.map +1 -0
- package/dist/services/docker/volume-service.js +48 -0
- package/dist/services/docker/volume-service.js.map +1 -0
- package/dist/services/docker-interfaces.d.ts +283 -0
- package/dist/services/docker-interfaces.d.ts.map +1 -0
- package/dist/services/docker-interfaces.js +13 -0
- package/dist/services/docker-interfaces.js.map +1 -0
- package/dist/services/docker.d.ts +42 -5
- package/dist/services/docker.d.ts.map +1 -1
- package/dist/services/docker.js +335 -127
- package/dist/services/docker.js.map +1 -1
- package/dist/services/file-service.d.ts +6 -2
- package/dist/services/file-service.d.ts.map +1 -1
- package/dist/services/file-service.js +156 -52
- package/dist/services/file-service.js.map +1 -1
- package/dist/services/host-config-repository.d.ts +133 -0
- package/dist/services/host-config-repository.d.ts.map +1 -0
- package/dist/services/host-config-repository.js +323 -0
- package/dist/services/host-config-repository.js.map +1 -0
- package/dist/services/host-resolver.d.ts +49 -0
- package/dist/services/host-resolver.d.ts.map +1 -0
- package/dist/services/host-resolver.js +176 -0
- package/dist/services/host-resolver.js.map +1 -0
- package/dist/services/interfaces.d.ts +61 -194
- package/dist/services/interfaces.d.ts.map +1 -1
- package/dist/services/local-executor.d.ts +31 -0
- package/dist/services/local-executor.d.ts.map +1 -0
- package/dist/services/local-executor.js +71 -0
- package/dist/services/local-executor.js.map +1 -0
- package/dist/services/ssh-config-loader.d.ts +35 -0
- package/dist/services/ssh-config-loader.d.ts.map +1 -0
- package/dist/services/ssh-config-loader.js +218 -0
- package/dist/services/ssh-config-loader.js.map +1 -0
- package/dist/services/ssh-pool.d.ts +26 -1
- package/dist/services/ssh-pool.d.ts.map +1 -1
- package/dist/services/ssh-pool.js +166 -25
- package/dist/services/ssh-pool.js.map +1 -1
- package/dist/services/ssh-service.d.ts +3 -0
- package/dist/services/ssh-service.d.ts.map +1 -1
- package/dist/services/ssh-service.js +53 -31
- package/dist/services/ssh-service.js.map +1 -1
- package/dist/services/ssh.d.ts +2 -6
- package/dist/services/ssh.d.ts.map +1 -1
- package/dist/services/ssh.js +9 -40
- package/dist/services/ssh.js.map +1 -1
- package/dist/tools/definitions/flux.d.ts +13 -0
- package/dist/tools/definitions/flux.d.ts.map +1 -0
- package/dist/tools/definitions/flux.js +101 -0
- package/dist/tools/definitions/flux.js.map +1 -0
- package/dist/tools/definitions/index.d.ts +8 -0
- package/dist/tools/definitions/index.d.ts.map +1 -0
- package/dist/tools/definitions/index.js +8 -0
- package/dist/tools/definitions/index.js.map +1 -0
- package/dist/tools/definitions/scout.d.ts +13 -0
- package/dist/tools/definitions/scout.d.ts.map +1 -0
- package/dist/tools/definitions/scout.js +78 -0
- package/dist/tools/definitions/scout.js.map +1 -0
- package/dist/tools/flux.d.ts +16 -8
- package/dist/tools/flux.d.ts.map +1 -1
- package/dist/tools/flux.js +27 -66
- package/dist/tools/flux.js.map +1 -1
- package/dist/tools/handlers/base-handler.d.ts +172 -0
- package/dist/tools/handlers/base-handler.d.ts.map +1 -0
- package/dist/tools/handlers/base-handler.js +234 -0
- package/dist/tools/handlers/base-handler.js.map +1 -0
- package/dist/tools/handlers/compose-handlers.d.ts +108 -0
- package/dist/tools/handlers/compose-handlers.d.ts.map +1 -0
- package/dist/tools/handlers/compose-handlers.js +293 -0
- package/dist/tools/handlers/compose-handlers.js.map +1 -0
- package/dist/tools/handlers/compose-utils.d.ts +35 -0
- package/dist/tools/handlers/compose-utils.d.ts.map +1 -0
- package/dist/tools/handlers/compose-utils.js +76 -0
- package/dist/tools/handlers/compose-utils.js.map +1 -0
- package/dist/tools/handlers/compose.d.ts +23 -0
- package/dist/tools/handlers/compose.d.ts.map +1 -0
- package/dist/tools/handlers/compose.js +125 -0
- package/dist/tools/handlers/compose.js.map +1 -0
- package/dist/tools/handlers/container.d.ts +23 -0
- package/dist/tools/handlers/container.d.ts.map +1 -0
- package/dist/tools/handlers/container.js +333 -0
- package/dist/tools/handlers/container.js.map +1 -0
- package/dist/tools/handlers/docker.d.ts +24 -0
- package/dist/tools/handlers/docker.d.ts.map +1 -0
- package/dist/tools/handlers/docker.js +155 -0
- package/dist/tools/handlers/docker.js.map +1 -0
- package/dist/tools/handlers/host.d.ts +23 -0
- package/dist/tools/handlers/host.d.ts.map +1 -0
- package/dist/tools/handlers/host.js +196 -0
- package/dist/tools/handlers/host.js.map +1 -0
- package/dist/tools/handlers/scout-logs.d.ts +24 -0
- package/dist/tools/handlers/scout-logs.d.ts.map +1 -0
- package/dist/tools/handlers/scout-logs.js +119 -0
- package/dist/tools/handlers/scout-logs.js.map +1 -0
- package/dist/tools/handlers/scout-simple.d.ts +23 -0
- package/dist/tools/handlers/scout-simple.d.ts.map +1 -0
- package/dist/tools/handlers/scout-simple.js +286 -0
- package/dist/tools/handlers/scout-simple.js.map +1 -0
- package/dist/tools/handlers/scout-zfs.d.ts +23 -0
- package/dist/tools/handlers/scout-zfs.d.ts.map +1 -0
- package/dist/tools/handlers/scout-zfs.js +82 -0
- package/dist/tools/handlers/scout-zfs.js.map +1 -0
- package/dist/tools/index.d.ts +32 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +41 -35
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/registry.d.ts +135 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +151 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/scout.d.ts +16 -8
- package/dist/tools/scout.d.ts.map +1 -1
- package/dist/tools/scout.js +36 -78
- package/dist/tools/scout.js.map +1 -1
- package/dist/types.d.ts +629 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/command-security.d.ts +82 -0
- package/dist/utils/command-security.d.ts.map +1 -0
- package/dist/utils/command-security.js +122 -0
- package/dist/utils/command-security.js.map +1 -0
- package/dist/utils/error-sanitization.d.ts +77 -0
- package/dist/utils/error-sanitization.d.ts.map +1 -0
- package/dist/utils/error-sanitization.js +107 -0
- package/dist/utils/error-sanitization.js.map +1 -0
- package/dist/utils/errors.d.ts +30 -6
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +91 -12
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/help-handler.d.ts +23 -0
- package/dist/utils/help-handler.d.ts.map +1 -0
- package/dist/utils/help-handler.js +21 -0
- package/dist/utils/help-handler.js.map +1 -0
- package/dist/utils/help.d.ts +1 -1
- package/dist/utils/help.d.ts.map +1 -1
- package/dist/utils/help.js +57 -16
- package/dist/utils/help.js.map +1 -1
- package/dist/utils/host-utils.d.ts +31 -0
- package/dist/utils/host-utils.d.ts.map +1 -0
- package/dist/utils/host-utils.js +80 -0
- package/dist/utils/host-utils.js.map +1 -0
- package/dist/utils/index.d.ts +8 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +8 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/init-detection.d.ts +36 -0
- package/dist/utils/init-detection.d.ts.map +1 -0
- package/dist/utils/init-detection.js +79 -0
- package/dist/utils/init-detection.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/pagination.d.ts +20 -0
- package/dist/utils/pagination.d.ts.map +1 -0
- package/dist/utils/pagination.js +29 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/path-security.d.ts +132 -18
- package/dist/utils/path-security.d.ts.map +1 -1
- package/dist/utils/path-security.js +164 -35
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/sorting.d.ts +33 -0
- package/dist/utils/sorting.d.ts.map +1 -0
- package/dist/utils/sorting.js +57 -0
- package/dist/utils/sorting.js.map +1 -0
- package/dist/utils/text-filters.d.ts +13 -0
- package/dist/utils/text-filters.d.ts.map +1 -0
- package/dist/utils/text-filters.js +18 -0
- package/dist/utils/text-filters.js.map +1 -0
- package/dist/utils/time.d.ts +11 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +13 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/validation.d.ts +25 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +56 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +45 -19
- package/dist/schemas/discriminator.d.ts +0 -20
- package/dist/schemas/discriminator.d.ts.map +0 -1
- package/dist/schemas/discriminator.js +0 -25
- package/dist/schemas/discriminator.js.map +0 -1
- package/dist/schemas/unified.d.ts +0 -674
- package/dist/schemas/unified.d.ts.map +0 -1
- package/dist/schemas/unified.js +0 -453
- package/dist/schemas/unified.js.map +0 -1
- package/dist/tools/unified.d.ts +0 -7
- package/dist/tools/unified.d.ts.map +0 -1
- package/dist/tools/unified.js +0 -827
- package/dist/tools/unified.js.map +0 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import rateLimit from "express-rate-limit";
|
|
2
|
+
/**
|
|
3
|
+
* Destructive subactions that require stricter rate limiting.
|
|
4
|
+
*
|
|
5
|
+
* These operations can cause data loss, service disruption, or consume
|
|
6
|
+
* significant resources on remote hosts. Mapped by tool action category.
|
|
7
|
+
*
|
|
8
|
+
* Flux container: exec, recreate
|
|
9
|
+
* Flux compose: down, recreate
|
|
10
|
+
* Flux docker: prune, rmi, build
|
|
11
|
+
* Scout: exec, emit (arbitrary command execution)
|
|
12
|
+
*/
|
|
13
|
+
const DESTRUCTIVE_SUBACTIONS = new Set([
|
|
14
|
+
// Flux container operations
|
|
15
|
+
"recreate",
|
|
16
|
+
"exec",
|
|
17
|
+
// Flux compose operations
|
|
18
|
+
"down",
|
|
19
|
+
"recreate",
|
|
20
|
+
// Flux docker operations
|
|
21
|
+
"prune",
|
|
22
|
+
"rmi",
|
|
23
|
+
"build",
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Scout actions that are inherently destructive (arbitrary command execution)
|
|
27
|
+
*/
|
|
28
|
+
const DESTRUCTIVE_SCOUT_ACTIONS = new Set(["exec", "emit"]);
|
|
29
|
+
/**
|
|
30
|
+
* Determine whether an MCP request body represents a destructive operation.
|
|
31
|
+
*
|
|
32
|
+
* Inspects the JSON-RPC payload for `tools/call` method and checks whether
|
|
33
|
+
* the tool arguments indicate a destructive subaction.
|
|
34
|
+
*
|
|
35
|
+
* @param body - Parsed JSON-RPC request body
|
|
36
|
+
* @returns true if the operation is destructive
|
|
37
|
+
*/
|
|
38
|
+
export function isDestructiveOperation(body) {
|
|
39
|
+
if (typeof body !== "object" || body === null)
|
|
40
|
+
return false;
|
|
41
|
+
const rpc = body;
|
|
42
|
+
if (rpc.method !== "tools/call")
|
|
43
|
+
return false;
|
|
44
|
+
const params = rpc.params;
|
|
45
|
+
if (typeof params !== "object" || params === null)
|
|
46
|
+
return false;
|
|
47
|
+
const { name, arguments: args } = params;
|
|
48
|
+
if (typeof name !== "string")
|
|
49
|
+
return false;
|
|
50
|
+
if (typeof args !== "object" || args === null)
|
|
51
|
+
return false;
|
|
52
|
+
const toolArgs = args;
|
|
53
|
+
// Scout tool: exec and emit are inherently destructive
|
|
54
|
+
if (name === "scout") {
|
|
55
|
+
const action = toolArgs.action;
|
|
56
|
+
return typeof action === "string" && DESTRUCTIVE_SCOUT_ACTIONS.has(action);
|
|
57
|
+
}
|
|
58
|
+
// Flux tool: check subaction against destructive set
|
|
59
|
+
if (name === "flux") {
|
|
60
|
+
const subaction = toolArgs.subaction;
|
|
61
|
+
return typeof subaction === "string" && DESTRUCTIVE_SUBACTIONS.has(subaction);
|
|
62
|
+
}
|
|
63
|
+
// Manual type narrowing is pragmatic for this hot-path function.
|
|
64
|
+
// Zod validation on every request would add unnecessary overhead.
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a rate limiter middleware for the health endpoint.
|
|
69
|
+
*
|
|
70
|
+
* Health endpoints should be accessible for monitoring but protected from DDoS.
|
|
71
|
+
* Default: 30 requests per 60 seconds per IP.
|
|
72
|
+
*
|
|
73
|
+
* @returns Express rate limiter middleware
|
|
74
|
+
*/
|
|
75
|
+
export function createHealthRateLimiter() {
|
|
76
|
+
return rateLimit({
|
|
77
|
+
windowMs: 60 * 1000, // 1 minute
|
|
78
|
+
max: 30, // 30 requests per minute (reasonable for health checks)
|
|
79
|
+
standardHeaders: true, // Return rate limit info in RateLimit-* headers
|
|
80
|
+
legacyHeaders: false, // Disable X-RateLimit-* headers
|
|
81
|
+
message: {
|
|
82
|
+
error: "Too many requests to health endpoint, please try again later",
|
|
83
|
+
},
|
|
84
|
+
skipSuccessfulRequests: false,
|
|
85
|
+
skipFailedRequests: false,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Creates a rate limiter middleware for the MCP endpoint.
|
|
90
|
+
*
|
|
91
|
+
* Protects against DoS attacks on the MCP endpoint which can trigger
|
|
92
|
+
* expensive operations (SSH commands, Docker API calls, filesystem scans).
|
|
93
|
+
*
|
|
94
|
+
* CWE-770: Allocation of Resources Without Limits or Throttling
|
|
95
|
+
* CVSS 7.5 (High) - DoS vulnerability if unprotected
|
|
96
|
+
*
|
|
97
|
+
* Default: 60 requests per 60 seconds per IP (general operations)
|
|
98
|
+
*
|
|
99
|
+
* @returns Express rate limiter middleware
|
|
100
|
+
*/
|
|
101
|
+
export function createMcpRateLimiter() {
|
|
102
|
+
return rateLimit({
|
|
103
|
+
windowMs: 60 * 1000, // 1 minute
|
|
104
|
+
max: 60, // 60 requests per minute (allows bursts but prevents abuse)
|
|
105
|
+
standardHeaders: true, // Return rate limit info in RateLimit-* headers
|
|
106
|
+
legacyHeaders: false, // Disable X-RateLimit-* headers
|
|
107
|
+
message: {
|
|
108
|
+
error: "Too many requests to MCP endpoint, please try again later",
|
|
109
|
+
},
|
|
110
|
+
skipSuccessfulRequests: false,
|
|
111
|
+
skipFailedRequests: false,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Creates a stricter rate limiter for destructive MCP operations.
|
|
116
|
+
*
|
|
117
|
+
* Destructive operations (prune, remove, down, exec, etc.) are expensive
|
|
118
|
+
* and potentially dangerous. This limiter is tighter than the general MCP limiter:
|
|
119
|
+
* 10 requests per 60 seconds per IP.
|
|
120
|
+
*
|
|
121
|
+
* Applied conditionally via createDestructiveRateLimitMiddleware.
|
|
122
|
+
*
|
|
123
|
+
* @returns Express rate limiter middleware
|
|
124
|
+
*/
|
|
125
|
+
export function createDestructiveOperationRateLimiter() {
|
|
126
|
+
return rateLimit({
|
|
127
|
+
windowMs: 60 * 1000, // 1 minute
|
|
128
|
+
max: 10, // 10 destructive requests per minute (strict)
|
|
129
|
+
standardHeaders: true,
|
|
130
|
+
legacyHeaders: false,
|
|
131
|
+
message: {
|
|
132
|
+
error: "Too many destructive operation requests, please try again later",
|
|
133
|
+
},
|
|
134
|
+
skipSuccessfulRequests: false,
|
|
135
|
+
skipFailedRequests: false,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Creates middleware that conditionally applies destructive rate limiting.
|
|
140
|
+
*
|
|
141
|
+
* Inspects each MCP request body to determine if it's a destructive operation.
|
|
142
|
+
* If so, applies the stricter destructive rate limiter (10 req/min/IP).
|
|
143
|
+
* Non-destructive requests pass through without additional limiting
|
|
144
|
+
* (they are still subject to the general 60 req/min/IP MCP limiter).
|
|
145
|
+
*
|
|
146
|
+
* @returns Express middleware
|
|
147
|
+
*/
|
|
148
|
+
export function createDestructiveRateLimitMiddleware() {
|
|
149
|
+
const destructiveLimiter = createDestructiveOperationRateLimiter();
|
|
150
|
+
return (req, res, next) => {
|
|
151
|
+
if (isDestructiveOperation(req.body)) {
|
|
152
|
+
destructiveLimiter(req, res, next);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
next();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=health-rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-rate-limiter.js","sourceRoot":"","sources":["../src/health-rate-limiter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -3,25 +3,28 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
5
|
import express from "express";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import { createDestructiveRateLimitMiddleware, createHealthRateLimiter, createMcpRateLimiter, } from "./health-rate-limiter.js";
|
|
7
|
+
import { asyncHandler, authMiddleware, csrfProtectionMiddleware, errorHandler, fallbackErrorHandler, requestIdMiddleware, } from "./middleware/index.js";
|
|
8
8
|
import { createDefaultContainer } from "./services/container.js";
|
|
9
|
+
import { registerTools } from "./tools/index.js";
|
|
10
|
+
import { getCurrentTimestamp } from "./utils/time.js";
|
|
9
11
|
// Server metadata
|
|
10
|
-
const SERVER_NAME = "
|
|
12
|
+
const SERVER_NAME = "synapse-mcp";
|
|
11
13
|
const SERVER_VERSION = "1.0.0";
|
|
12
14
|
// Global service container instance
|
|
13
15
|
let globalContainer;
|
|
14
16
|
/**
|
|
15
17
|
* Create and configure the MCP server
|
|
16
18
|
*/
|
|
17
|
-
function createServer() {
|
|
19
|
+
async function createServer() {
|
|
18
20
|
const server = new McpServer({
|
|
19
21
|
name: SERVER_NAME,
|
|
20
|
-
version: SERVER_VERSION
|
|
22
|
+
version: SERVER_VERSION,
|
|
21
23
|
});
|
|
22
|
-
// Create and
|
|
24
|
+
// Create and initialize service container (preloads host configs, enables caching)
|
|
23
25
|
globalContainer = createDefaultContainer();
|
|
24
|
-
|
|
26
|
+
await globalContainer.initialize();
|
|
27
|
+
// Register all tools
|
|
25
28
|
registerTools(server, globalContainer);
|
|
26
29
|
return server;
|
|
27
30
|
}
|
|
@@ -29,130 +32,90 @@ function createServer() {
|
|
|
29
32
|
* Run server with stdio transport (for Claude Code, local integrations)
|
|
30
33
|
*/
|
|
31
34
|
async function runStdio() {
|
|
32
|
-
const server = createServer();
|
|
35
|
+
const server = await createServer();
|
|
33
36
|
const transport = new StdioServerTransport();
|
|
34
37
|
await server.connect(transport);
|
|
35
|
-
// Log to stderr (stdout is reserved for MCP protocol)
|
|
36
|
-
console.error(`${SERVER_NAME} v${SERVER_VERSION} running on stdio`);
|
|
37
38
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Rate limiter for HTTP API
|
|
40
|
-
*/
|
|
41
|
-
const limiter = rateLimit({
|
|
42
|
-
windowMs: 60 * 1000, // 1 minute
|
|
43
|
-
max: 100, // 100 requests per minute
|
|
44
|
-
standardHeaders: true,
|
|
45
|
-
legacyHeaders: false,
|
|
46
|
-
message: { error: "Too many requests, please try again later" }
|
|
47
|
-
});
|
|
48
39
|
/**
|
|
49
40
|
* Run server with HTTP transport (for remote access, multiple clients)
|
|
50
41
|
*/
|
|
51
42
|
async function runHTTP() {
|
|
52
|
-
|
|
43
|
+
// SECURITY (CWE-306): Warn when HTTP mode runs without authentication
|
|
44
|
+
if (!process.env.SYNAPSE_API_KEY) {
|
|
45
|
+
console.error("[SECURITY WARNING] HTTP transport active without SYNAPSE_API_KEY. " +
|
|
46
|
+
"All requests will be unauthenticated. Set SYNAPSE_API_KEY to enable API key authentication.");
|
|
47
|
+
}
|
|
48
|
+
const server = await createServer();
|
|
53
49
|
const app = express();
|
|
54
|
-
|
|
50
|
+
// Create transport once at startup and reuse across requests
|
|
51
|
+
// This eliminates 50-200ms per-request overhead from repeated server.connect() calls
|
|
52
|
+
const transport = new StreamableHTTPServerTransport({
|
|
53
|
+
sessionIdGenerator: undefined,
|
|
54
|
+
enableJsonResponse: true,
|
|
55
|
+
});
|
|
56
|
+
await server.connect(transport);
|
|
57
|
+
// Request ID middleware MUST be first
|
|
58
|
+
app.use(requestIdMiddleware);
|
|
59
|
+
app.use(express.json({ limit: "100kb" }));
|
|
55
60
|
// Request logging middleware
|
|
56
61
|
app.use((req, _res, next) => {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
console.error(`[${timestamp}] ${req.method} ${req.path} from ${req.ip} (fwd: ${forwarded})`);
|
|
62
|
+
const _timestamp = getCurrentTimestamp();
|
|
63
|
+
const _forwarded = req.headers["x-forwarded-for"] || req.headers["x-real-ip"] || "";
|
|
60
64
|
next();
|
|
61
65
|
});
|
|
62
|
-
// Health check endpoint
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
enableJsonResponse: true
|
|
66
|
+
// Health check endpoint with rate limiting to prevent DDoS
|
|
67
|
+
const healthLimiter = createHealthRateLimiter();
|
|
68
|
+
app.get("/health", healthLimiter, (req, res) => {
|
|
69
|
+
res.json({
|
|
70
|
+
status: "ok",
|
|
71
|
+
server: SERVER_NAME,
|
|
72
|
+
version: SERVER_VERSION,
|
|
73
|
+
requestId: req.requestId,
|
|
71
74
|
});
|
|
72
|
-
res.on("close", () => transport.close());
|
|
73
|
-
await server.connect(transport);
|
|
74
|
-
await transport.handleRequest(req, res, req.body);
|
|
75
75
|
});
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
// MCP endpoint - reuses shared transport
|
|
77
|
+
// Rate limiting (S-C1) to prevent DoS attacks from expensive operations:
|
|
78
|
+
// 1. General limiter: 60 req/min/IP for all MCP operations
|
|
79
|
+
// 2. Destructive limiter: 10 req/min/IP for destructive ops (prune, remove, exec, etc.)
|
|
80
|
+
// CSRF protection middleware (S-M6) BEFORE auth to prevent CSRF attacks
|
|
81
|
+
// Auth middleware (S-C1) protects this endpoint when SYNAPSE_API_KEY is configured
|
|
82
|
+
const mcpLimiter = createMcpRateLimiter();
|
|
83
|
+
const destructiveLimiter = createDestructiveRateLimitMiddleware();
|
|
84
|
+
app.post("/mcp", mcpLimiter, destructiveLimiter, csrfProtectionMiddleware, authMiddleware, asyncHandler(async (req, res) => {
|
|
85
|
+
await transport.handleRequest(req, res, req.body);
|
|
86
|
+
}));
|
|
87
|
+
// Error handling middleware MUST be after all routes
|
|
88
|
+
app.use(errorHandler);
|
|
89
|
+
app.use(fallbackErrorHandler);
|
|
90
|
+
const port = Number.parseInt(process.env.SYNAPSE_PORT || "53000", 10);
|
|
91
|
+
const host = process.env.SYNAPSE_HOST || "127.0.0.1";
|
|
78
92
|
app.listen(port, host, () => {
|
|
79
|
-
|
|
93
|
+
/* Server started successfully - intentionally no logging to preserve stdio for MCP protocol */
|
|
80
94
|
});
|
|
81
95
|
}
|
|
82
96
|
/**
|
|
83
97
|
* Print usage information
|
|
84
98
|
*/
|
|
85
99
|
function printUsage() {
|
|
86
|
-
|
|
87
|
-
${SERVER_NAME} v${SERVER_VERSION}
|
|
88
|
-
|
|
89
|
-
MCP server for managing homelab Docker infrastructure across multiple hosts.
|
|
90
|
-
|
|
91
|
-
USAGE:
|
|
92
|
-
node dist/index.js [--stdio | --http]
|
|
93
|
-
|
|
94
|
-
OPTIONS:
|
|
95
|
-
--stdio Run with stdio transport (default, for Claude Code)
|
|
96
|
-
--http Run with HTTP transport (for remote access)
|
|
97
|
-
--help Show this help message
|
|
98
|
-
|
|
99
|
-
CONFIGURATION:
|
|
100
|
-
Create a config file at one of these locations (checked in order):
|
|
101
|
-
1. Path specified by HOMELAB_CONFIG_FILE env var
|
|
102
|
-
2. ./homelab.config.json (current directory)
|
|
103
|
-
3. ~/.config/homelab-mcp/config.json
|
|
104
|
-
4. ~/.homelab-mcp.json
|
|
105
|
-
|
|
106
|
-
Example config file:
|
|
107
|
-
{
|
|
108
|
-
"hosts": [
|
|
109
|
-
{"name": "unraid", "host": "unraid.local", "port": 2375, "protocol": "http"},
|
|
110
|
-
{"name": "proxmox", "host": "proxmox.local", "port": 2375, "protocol": "http"},
|
|
111
|
-
{"name": "local", "host": "localhost", "dockerSocketPath": "/var/run/docker.sock"}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
ENVIRONMENT VARIABLES:
|
|
116
|
-
HOMELAB_CONFIG_FILE Path to config file (optional, overrides default paths)
|
|
117
|
-
HOMELAB_HOSTS_CONFIG JSON config as env var (fallback if no config file)
|
|
118
|
-
HOMELAB_PORT HTTP server port (default: 3000)
|
|
119
|
-
HOMELAB_HOST HTTP server bind address (default: 127.0.0.1)
|
|
120
|
-
|
|
121
|
-
CLAUDE CODE CONFIG (~/.claude/claude_code_config.json):
|
|
122
|
-
{
|
|
123
|
-
"mcpServers": {
|
|
124
|
-
"homelab": {
|
|
125
|
-
"command": "node",
|
|
126
|
-
"args": ["/path/to/homelab-mcp-server/dist/index.js"],
|
|
127
|
-
"env": {
|
|
128
|
-
"HOMELAB_CONFIG_FILE": "/path/to/your/homelab.config.json"
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
`);
|
|
100
|
+
/* Reserved for future CLI usage documentation */
|
|
134
101
|
}
|
|
135
102
|
/**
|
|
136
103
|
* Graceful shutdown handler
|
|
137
104
|
*/
|
|
138
|
-
async function shutdown(
|
|
139
|
-
console.error(`\nReceived ${signal}, shutting down gracefully...`);
|
|
105
|
+
async function shutdown(_signal) {
|
|
140
106
|
if (globalContainer) {
|
|
141
|
-
await globalContainer.
|
|
107
|
+
await globalContainer.shutdown();
|
|
142
108
|
}
|
|
143
|
-
console.error("Cleanup complete");
|
|
144
109
|
process.exit(0);
|
|
145
110
|
}
|
|
146
111
|
// Register signal handlers for graceful shutdown
|
|
147
112
|
process.on("SIGINT", () => {
|
|
148
|
-
shutdown("SIGINT").catch((
|
|
149
|
-
console.error("Error during shutdown:", error);
|
|
113
|
+
shutdown("SIGINT").catch((_error) => {
|
|
150
114
|
process.exit(1);
|
|
151
115
|
});
|
|
152
116
|
});
|
|
153
117
|
process.on("SIGTERM", () => {
|
|
154
|
-
shutdown("SIGTERM").catch((
|
|
155
|
-
console.error("Error during shutdown:", error);
|
|
118
|
+
shutdown("SIGTERM").catch((_error) => {
|
|
156
119
|
process.exit(1);
|
|
157
120
|
});
|
|
158
121
|
});
|
|
@@ -164,14 +127,12 @@ if (args.includes("--help") || args.includes("-h")) {
|
|
|
164
127
|
}
|
|
165
128
|
const transportMode = args.includes("--http") ? "http" : "stdio";
|
|
166
129
|
if (transportMode === "http") {
|
|
167
|
-
runHTTP().catch((
|
|
168
|
-
console.error("Server error:", error);
|
|
130
|
+
runHTTP().catch((_error) => {
|
|
169
131
|
process.exit(1);
|
|
170
132
|
});
|
|
171
133
|
}
|
|
172
134
|
else {
|
|
173
|
-
runStdio().catch((
|
|
174
|
-
console.error("Server error:", error);
|
|
135
|
+
runStdio().catch((_error) => {
|
|
175
136
|
process.exit(1);
|
|
176
137
|
});
|
|
177
138
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async Handler Wrapper - Eliminates try-catch boilerplate
|
|
3
|
+
*
|
|
4
|
+
* Wraps async route handlers to automatically catch promise rejections
|
|
5
|
+
* and forward them to Express error handling middleware.
|
|
6
|
+
*/
|
|
7
|
+
import type { NextFunction, Request, RequestHandler, Response } from "express";
|
|
8
|
+
/**
|
|
9
|
+
* Async route handler function type
|
|
10
|
+
*
|
|
11
|
+
* Standard Express handler signature but returns a Promise.
|
|
12
|
+
* Used by asyncHandler to wrap async route handlers.
|
|
13
|
+
*/
|
|
14
|
+
export type AsyncRouteHandler = (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Wraps async route handlers to catch promise rejections
|
|
17
|
+
*
|
|
18
|
+
* Eliminates the need for try-catch blocks in every async route handler.
|
|
19
|
+
* Any promise rejection is automatically caught and forwarded to the
|
|
20
|
+
* Express error handling middleware via next(error).
|
|
21
|
+
*
|
|
22
|
+
* Uses Promise.resolve() to handle both async functions and functions
|
|
23
|
+
* that return promises, ensuring all rejections are caught.
|
|
24
|
+
*
|
|
25
|
+
* @param handler - Async route handler function to wrap
|
|
26
|
+
* @returns Wrapped Express RequestHandler that catches errors
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // Without asyncHandler (verbose):
|
|
31
|
+
* app.get("/data", async (req, res, next) => {
|
|
32
|
+
* try {
|
|
33
|
+
* const data = await fetchData();
|
|
34
|
+
* res.json(data);
|
|
35
|
+
* } catch (error) {
|
|
36
|
+
* next(error);
|
|
37
|
+
* }
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // With asyncHandler (clean):
|
|
41
|
+
* app.get("/data", asyncHandler(async (req, res) => {
|
|
42
|
+
* const data = await fetchData(); // Errors automatically caught
|
|
43
|
+
* res.json(data);
|
|
44
|
+
* }));
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // Works with any async operation:
|
|
50
|
+
* app.post("/users", asyncHandler(async (req, res) => {
|
|
51
|
+
* const user = await createUser(req.body);
|
|
52
|
+
* res.status(201).json(user);
|
|
53
|
+
* }));
|
|
54
|
+
*
|
|
55
|
+
* app.delete("/users/:id", asyncHandler(async (req, res) => {
|
|
56
|
+
* await deleteUser(req.params.id);
|
|
57
|
+
* res.status(204).send();
|
|
58
|
+
* }));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function asyncHandler(handler: AsyncRouteHandler): RequestHandler;
|
|
62
|
+
//# sourceMappingURL=async-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/async-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,CAIvE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async Handler Wrapper - Eliminates try-catch boilerplate
|
|
3
|
+
*
|
|
4
|
+
* Wraps async route handlers to automatically catch promise rejections
|
|
5
|
+
* and forward them to Express error handling middleware.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Wraps async route handlers to catch promise rejections
|
|
9
|
+
*
|
|
10
|
+
* Eliminates the need for try-catch blocks in every async route handler.
|
|
11
|
+
* Any promise rejection is automatically caught and forwarded to the
|
|
12
|
+
* Express error handling middleware via next(error).
|
|
13
|
+
*
|
|
14
|
+
* Uses Promise.resolve() to handle both async functions and functions
|
|
15
|
+
* that return promises, ensuring all rejections are caught.
|
|
16
|
+
*
|
|
17
|
+
* @param handler - Async route handler function to wrap
|
|
18
|
+
* @returns Wrapped Express RequestHandler that catches errors
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Without asyncHandler (verbose):
|
|
23
|
+
* app.get("/data", async (req, res, next) => {
|
|
24
|
+
* try {
|
|
25
|
+
* const data = await fetchData();
|
|
26
|
+
* res.json(data);
|
|
27
|
+
* } catch (error) {
|
|
28
|
+
* next(error);
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // With asyncHandler (clean):
|
|
33
|
+
* app.get("/data", asyncHandler(async (req, res) => {
|
|
34
|
+
* const data = await fetchData(); // Errors automatically caught
|
|
35
|
+
* res.json(data);
|
|
36
|
+
* }));
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // Works with any async operation:
|
|
42
|
+
* app.post("/users", asyncHandler(async (req, res) => {
|
|
43
|
+
* const user = await createUser(req.body);
|
|
44
|
+
* res.status(201).json(user);
|
|
45
|
+
* }));
|
|
46
|
+
*
|
|
47
|
+
* app.delete("/users/:id", asyncHandler(async (req, res) => {
|
|
48
|
+
* await deleteUser(req.params.id);
|
|
49
|
+
* res.status(204).send();
|
|
50
|
+
* }));
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function asyncHandler(handler) {
|
|
54
|
+
return (req, res, next) => {
|
|
55
|
+
Promise.resolve(handler(req, res, next)).catch(next);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=async-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-handler.js","sourceRoot":"","sources":["../../src/middleware/async-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,UAAU,YAAY,CAAC,OAA0B;IACrD,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvD,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from "express";
|
|
2
|
+
/**
|
|
3
|
+
* Authentication middleware for HTTP transport.
|
|
4
|
+
*
|
|
5
|
+
* Security: Prevents CWE-306 (Missing Authentication for Critical Function) by
|
|
6
|
+
* requiring API key authentication when SYNAPSE_API_KEY is configured.
|
|
7
|
+
*
|
|
8
|
+
* If SYNAPSE_API_KEY is not set, authentication is disabled and all requests are allowed.
|
|
9
|
+
* This provides backward compatibility and allows local development without authentication.
|
|
10
|
+
*
|
|
11
|
+
* When enabled, requires X-API-Key header that matches SYNAPSE_API_KEY exactly.
|
|
12
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
13
|
+
*
|
|
14
|
+
* @see https://cwe.mitre.org/data/definitions/306.html
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Disable authentication (development/local only)
|
|
19
|
+
* // No SYNAPSE_API_KEY env var set
|
|
20
|
+
*
|
|
21
|
+
* // Enable authentication
|
|
22
|
+
* process.env.SYNAPSE_API_KEY = "my-secret-key-12345";
|
|
23
|
+
* app.use('/mcp', authMiddleware);
|
|
24
|
+
*
|
|
25
|
+
* // Client request
|
|
26
|
+
* fetch('/mcp', {
|
|
27
|
+
* headers: { 'X-API-Key': 'my-secret-key-12345' }
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function authMiddleware(req: Request, res: Response, next: NextFunction): void;
|
|
32
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAsCpF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Authentication middleware for HTTP transport.
|
|
4
|
+
*
|
|
5
|
+
* Security: Prevents CWE-306 (Missing Authentication for Critical Function) by
|
|
6
|
+
* requiring API key authentication when SYNAPSE_API_KEY is configured.
|
|
7
|
+
*
|
|
8
|
+
* If SYNAPSE_API_KEY is not set, authentication is disabled and all requests are allowed.
|
|
9
|
+
* This provides backward compatibility and allows local development without authentication.
|
|
10
|
+
*
|
|
11
|
+
* When enabled, requires X-API-Key header that matches SYNAPSE_API_KEY exactly.
|
|
12
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
13
|
+
*
|
|
14
|
+
* @see https://cwe.mitre.org/data/definitions/306.html
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Disable authentication (development/local only)
|
|
19
|
+
* // No SYNAPSE_API_KEY env var set
|
|
20
|
+
*
|
|
21
|
+
* // Enable authentication
|
|
22
|
+
* process.env.SYNAPSE_API_KEY = "my-secret-key-12345";
|
|
23
|
+
* app.use('/mcp', authMiddleware);
|
|
24
|
+
*
|
|
25
|
+
* // Client request
|
|
26
|
+
* fetch('/mcp', {
|
|
27
|
+
* headers: { 'X-API-Key': 'my-secret-key-12345' }
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function authMiddleware(req, res, next) {
|
|
32
|
+
const configuredKey = process.env.SYNAPSE_API_KEY;
|
|
33
|
+
// If no API key is configured, skip authentication (allow all)
|
|
34
|
+
if (!configuredKey) {
|
|
35
|
+
next();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Get provided API key from header (case-insensitive)
|
|
39
|
+
const providedKey = req.headers["x-api-key"];
|
|
40
|
+
// Reject if no key provided or key is empty/whitespace
|
|
41
|
+
if (!providedKey || providedKey.trim().length === 0) {
|
|
42
|
+
res.status(401).json({
|
|
43
|
+
error: "Unauthorized",
|
|
44
|
+
message: "Missing or invalid X-API-Key header",
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Use timing-safe comparison to prevent timing attacks
|
|
49
|
+
// Both strings must be same length for timingSafeEqual, so hash both
|
|
50
|
+
const providedHash = createHash("sha256").update(providedKey).digest();
|
|
51
|
+
const configuredHash = createHash("sha256").update(configuredKey).digest();
|
|
52
|
+
const isValid = timingSafeEqual(providedHash, configuredHash);
|
|
53
|
+
if (!isValid) {
|
|
54
|
+
res.status(401).json({
|
|
55
|
+
error: "Unauthorized",
|
|
56
|
+
message: "Missing or invalid X-API-Key header",
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Authentication successful
|
|
61
|
+
next();
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC5E,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAElD,+DAA+D;IAC/D,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IAED,sDAAsD;IACtD,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAuB,CAAC;IAEnE,uDAAuD;IACvD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,qCAAqC;SAC/C,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,uDAAuD;IACvD,qEAAqE;IACrE,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC;IACvE,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,CAAC;IAE3E,MAAM,OAAO,GAAG,eAAe,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAE9D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,qCAAqC;SAC/C,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,4BAA4B;IAC5B,IAAI,EAAE,CAAC;AACT,CAAC"}
|