db-mcp 1.1.1 → 3.0.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 +247 -169
- package/dist/.tsbuildinfo +1 -0
- package/dist/adapters/database-adapter.d.ts +173 -0
- package/dist/adapters/database-adapter.d.ts.map +1 -0
- package/dist/adapters/query-validation.d.ts +20 -0
- package/dist/adapters/query-validation.d.ts.map +1 -0
- package/dist/adapters/registration/index.d.ts +4 -0
- package/dist/adapters/registration/index.d.ts.map +1 -0
- package/dist/adapters/registration/prompts.d.ts +7 -0
- package/dist/adapters/registration/prompts.d.ts.map +1 -0
- package/dist/adapters/registration/resources.d.ts +7 -0
- package/dist/adapters/registration/resources.d.ts.map +1 -0
- package/dist/adapters/registration/tools.d.ts +9 -0
- package/dist/adapters/registration/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite/index.d.ts +9 -0
- package/dist/adapters/sqlite/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/json-utils.d.ts +100 -0
- package/dist/adapters/sqlite/json-utils.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/analysis.d.ts +23 -0
- package/dist/adapters/sqlite/prompts/analysis.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/index.d.ts +16 -0
- package/dist/adapters/sqlite/prompts/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/query.d.ts +19 -0
- package/dist/adapters/sqlite/prompts/query.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/schema.d.ts +20 -0
- package/dist/adapters/sqlite/prompts/schema.d.ts.map +1 -0
- package/dist/adapters/sqlite/query-executor.d.ts +38 -0
- package/dist/adapters/sqlite/query-executor.d.ts.map +1 -0
- package/dist/adapters/sqlite/resources.d.ts +13 -0
- package/dist/adapters/sqlite/resources.d.ts.map +1 -0
- package/dist/adapters/sqlite/schema-manager.d.ts +69 -0
- package/dist/adapters/sqlite/schema-manager.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/admin.d.ts +459 -0
- package/dist/adapters/sqlite/schemas/admin.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/codemode.d.ts +30 -0
- package/dist/adapters/sqlite/schemas/codemode.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/common.d.ts +9 -0
- package/dist/adapters/sqlite/schemas/common.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/core.d.ts +530 -0
- package/dist/adapters/sqlite/schemas/core.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/error-mixin.d.ts +10 -0
- package/dist/adapters/sqlite/schemas/error-mixin.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/fts.d.ts +106 -0
- package/dist/adapters/sqlite/schemas/fts.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/geo.d.ts +135 -0
- package/dist/adapters/sqlite/schemas/geo.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/index.d.ts +23 -0
- package/dist/adapters/sqlite/schemas/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/introspection.d.ts +583 -0
- package/dist/adapters/sqlite/schemas/introspection.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/json.d.ts +849 -0
- package/dist/adapters/sqlite/schemas/json.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/migration.d.ts +220 -0
- package/dist/adapters/sqlite/schemas/migration.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/native.d.ts +235 -0
- package/dist/adapters/sqlite/schemas/native.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/server.d.ts +13 -0
- package/dist/adapters/sqlite/schemas/server.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/spatialite.d.ts +114 -0
- package/dist/adapters/sqlite/schemas/spatialite.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/stats.d.ts +780 -0
- package/dist/adapters/sqlite/schemas/stats.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/text.d.ts +570 -0
- package/dist/adapters/sqlite/schemas/text.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/vector.d.ts +252 -0
- package/dist/adapters/sqlite/schemas/vector.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/virtual.d.ts +257 -0
- package/dist/adapters/sqlite/schemas/virtual.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/where.d.ts +20 -0
- package/dist/adapters/sqlite/schemas/where.d.ts.map +1 -0
- package/dist/adapters/sqlite/sqlite-adapter/lifecycle.d.ts +13 -0
- package/dist/adapters/sqlite/sqlite-adapter/lifecycle.d.ts.map +1 -0
- package/dist/adapters/sqlite/sqlite-adapter/schema.d.ts +7 -0
- package/dist/adapters/sqlite/sqlite-adapter/schema.d.ts.map +1 -0
- package/dist/adapters/sqlite/sqlite-adapter.d.ts +138 -0
- package/dist/adapters/sqlite/sqlite-adapter.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/analyze.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/analyze.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/create.d.ts +11 -0
- package/dist/adapters/sqlite/tools/admin/backup/create.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/index.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/integrity.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/integrity.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/optimize.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/optimize.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/helpers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/admin/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/admin/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/pragma.d.ts +37 -0
- package/dist/adapters/sqlite/tools/admin/pragma.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/reindex.d.ts +10 -0
- package/dist/adapters/sqlite/tools/admin/reindex.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/verify.d.ts +13 -0
- package/dist/adapters/sqlite/tools/admin/verify.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/wal.d.ts +10 -0
- package/dist/adapters/sqlite/tools/admin/wal.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/codemode.d.ts +22 -0
- package/dist/adapters/sqlite/tools/codemode.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/column-validation.d.ts +26 -0
- package/dist/adapters/sqlite/tools/column-validation.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/alter-table.d.ts +11 -0
- package/dist/adapters/sqlite/tools/core/alter-table.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/constraints.d.ts +10 -0
- package/dist/adapters/sqlite/tools/core/constraints.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/convenience-helpers.d.ts +20 -0
- package/dist/adapters/sqlite/tools/core/convenience-helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/convenience-schemas.d.ts +20 -0
- package/dist/adapters/sqlite/tools/core/convenience-schemas.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/convenience.d.ts +29 -0
- package/dist/adapters/sqlite/tools/core/convenience.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/datetime.d.ts +11 -0
- package/dist/adapters/sqlite/tools/core/datetime.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/index.d.ts +14 -0
- package/dist/adapters/sqlite/tools/core/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/indexes.d.ts +20 -0
- package/dist/adapters/sqlite/tools/core/indexes.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/queries.d.ts +16 -0
- package/dist/adapters/sqlite/tools/core/queries.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/tables.d.ts +37 -0
- package/dist/adapters/sqlite/tools/core/tables.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/triggers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/core/triggers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/fts.d.ts +13 -0
- package/dist/adapters/sqlite/tools/fts.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/geo.d.ts +14 -0
- package/dist/adapters/sqlite/tools/geo.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/index.d.ts +33 -0
- package/dist/adapters/sqlite/tools/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/constraints.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/constraints.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/diff.d.ts +11 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/diff.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/risks.d.ts +9 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/risks.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/snapshot.d.ts +40 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/snapshot.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/index.d.ts +9 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/indexes.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/indexes.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/query-plan.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/query-plan.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/storage.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/storage.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/graph/helpers.d.ts +44 -0
- package/dist/adapters/sqlite/tools/introspection/graph/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/graph/index.d.ts +9 -0
- package/dist/adapters/sqlite/tools/introspection/graph/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts +12 -0
- package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/index.d.ts +17 -0
- package/dist/adapters/sqlite/tools/introspection/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/helpers.d.ts +21 -0
- package/dist/adapters/sqlite/tools/json-helpers/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/index.d.ts +17 -0
- package/dist/adapters/sqlite/tools/json-helpers/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/read.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-helpers/read.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/write.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-helpers/write.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/crud.d.ts +39 -0
- package/dist/adapters/sqlite/tools/json-operations/crud.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/diff.d.ts +11 -0
- package/dist/adapters/sqlite/tools/json-operations/diff.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/helpers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/json-operations/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/json-operations/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/query.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-operations/query.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/security.d.ts +19 -0
- package/dist/adapters/sqlite/tools/json-operations/security.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/transform.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-operations/transform.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/helpers.d.ts +34 -0
- package/dist/adapters/sqlite/tools/migration/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/index.d.ts +15 -0
- package/dist/adapters/sqlite/tools/migration/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/apply.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/apply.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/history.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/history.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/index.d.ts +7 -0
- package/dist/adapters/sqlite/tools/migration/tracking/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/init.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/init.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/record.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/record.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/rollback.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/rollback.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/status.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/status.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/advanced.d.ts +28 -0
- package/dist/adapters/sqlite/tools/stats/advanced.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/anomaly-detection.d.ts +22 -0
- package/dist/adapters/sqlite/tools/stats/anomaly-detection.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/basic.d.ts +32 -0
- package/dist/adapters/sqlite/tools/stats/basic.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/helpers.d.ts +27 -0
- package/dist/adapters/sqlite/tools/stats/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/index.d.ts +12 -0
- package/dist/adapters/sqlite/tools/stats/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/hypothesis.d.ts +7 -0
- package/dist/adapters/sqlite/tools/stats/inference/hypothesis.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/index.d.ts +4 -0
- package/dist/adapters/sqlite/tools/stats/inference/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/outlier.d.ts +7 -0
- package/dist/adapters/sqlite/tools/stats/inference/outlier.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/regression.d.ts +7 -0
- package/dist/adapters/sqlite/tools/stats/inference/regression.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/math-helpers.d.ts +17 -0
- package/dist/adapters/sqlite/tools/stats/math-helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/schema-risks.d.ts +15 -0
- package/dist/adapters/sqlite/tools/stats/schema-risks.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/formatting.d.ts +48 -0
- package/dist/adapters/sqlite/tools/text/formatting.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/helpers.d.ts +22 -0
- package/dist/adapters/sqlite/tools/text/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/text/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/regex.d.ts +21 -0
- package/dist/adapters/sqlite/tools/text/regex.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/search.d.ts +17 -0
- package/dist/adapters/sqlite/tools/text/search.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/sentiment.d.ts +13 -0
- package/dist/adapters/sqlite/tools/text/sentiment.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/validate.d.ts +11 -0
- package/dist/adapters/sqlite/tools/text/validate.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/helpers.d.ts +11 -0
- package/dist/adapters/sqlite/tools/vector/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/index.d.ts +14 -0
- package/dist/adapters/sqlite/tools/vector/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/metadata.d.ts +28 -0
- package/dist/adapters/sqlite/tools/vector/metadata.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/search.d.ts +16 -0
- package/dist/adapters/sqlite/tools/vector/search.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/storage.d.ts +24 -0
- package/dist/adapters/sqlite/tools/vector/storage.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/tools.d.ts +9 -0
- package/dist/adapters/sqlite/tools/vector/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/analysis.d.ts +24 -0
- package/dist/adapters/sqlite/tools/virtual/analysis.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/extensions.d.ts +13 -0
- package/dist/adapters/sqlite/tools/virtual/extensions.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/helpers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/virtual/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/virtual/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/views.d.ts +21 -0
- package/dist/adapters/sqlite/tools/virtual/views.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/drop.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/drop.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/index.d.ts +6 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/list.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/list.d.ts.map +1 -0
- package/dist/adapters/sqlite/types.d.ts +89 -0
- package/dist/adapters/sqlite/types.d.ts.map +1 -0
- package/dist/adapters/sqlite-helpers.d.ts +51 -0
- package/dist/adapters/sqlite-helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/extensions.d.ts +17 -0
- package/dist/adapters/sqlite-native/extensions.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/index.d.ts +11 -0
- package/dist/adapters/sqlite-native/index.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/native-query-executor.d.ts +24 -0
- package/dist/adapters/sqlite-native/native-query-executor.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/native-sqlite-adapter.d.ts +160 -0
- package/dist/adapters/sqlite-native/native-sqlite-adapter.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/registration/index.d.ts +12 -0
- package/dist/adapters/sqlite-native/registration/index.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/analysis.d.ts +23 -0
- package/dist/adapters/sqlite-native/tools/spatialite/analysis.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/index.d.ts +15 -0
- package/dist/adapters/sqlite-native/tools/spatialite/index.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/loader.d.ts +22 -0
- package/dist/adapters/sqlite-native/tools/spatialite/loader.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/schemas.d.ts +78 -0
- package/dist/adapters/sqlite-native/tools/spatialite/schemas.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/tools.d.ts +30 -0
- package/dist/adapters/sqlite-native/tools/spatialite/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/transactions.d.ts +12 -0
- package/dist/adapters/sqlite-native/tools/transactions.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/window.d.ts +7 -0
- package/dist/adapters/sqlite-native/tools/window.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/transaction-methods.d.ts +36 -0
- package/dist/adapters/sqlite-native/transaction-methods.d.ts.map +1 -0
- package/dist/audit/backup-manager.d.ts +90 -0
- package/dist/audit/backup-manager.d.ts.map +1 -0
- package/dist/audit/index.d.ts +11 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/interceptor.d.ts +54 -0
- package/dist/audit/interceptor.d.ts.map +1 -0
- package/dist/audit/logger.d.ts +62 -0
- package/dist/audit/logger.d.ts.map +1 -0
- package/dist/audit/types.d.ts +112 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/auth/auth-context.d.ts +28 -0
- package/dist/auth/auth-context.d.ts.map +1 -0
- package/dist/auth/authorization-server-discovery.d.ts +90 -0
- package/dist/auth/authorization-server-discovery.d.ts.map +1 -0
- package/dist/auth/errors.d.ts +74 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/middleware/core.d.ts +22 -0
- package/dist/auth/middleware/core.d.ts.map +1 -0
- package/dist/auth/middleware/express-auth.d.ts +13 -0
- package/dist/auth/middleware/express-auth.d.ts.map +1 -0
- package/dist/auth/middleware/express-scopes.d.ts +6 -0
- package/dist/auth/middleware/express-scopes.d.ts.map +1 -0
- package/dist/auth/middleware/extraction.d.ts +2 -0
- package/dist/auth/middleware/extraction.d.ts.map +1 -0
- package/dist/auth/middleware/index.d.ts +5 -0
- package/dist/auth/middleware/index.d.ts.map +1 -0
- package/dist/auth/oauth-resource-server.d.ts +74 -0
- package/dist/auth/oauth-resource-server.d.ts.map +1 -0
- package/dist/auth/scope-map.d.ts +24 -0
- package/dist/auth/scope-map.d.ts.map +1 -0
- package/dist/auth/scopes/constants.d.ts +40 -0
- package/dist/auth/scopes/constants.d.ts.map +1 -0
- package/dist/auth/scopes/display.d.ts +5 -0
- package/dist/auth/scopes/display.d.ts.map +1 -0
- package/dist/auth/scopes/enforcement.d.ts +27 -0
- package/dist/auth/scopes/enforcement.d.ts.map +1 -0
- package/dist/auth/scopes/index.d.ts +6 -0
- package/dist/auth/scopes/index.d.ts.map +1 -0
- package/dist/auth/scopes/mapping.d.ts +39 -0
- package/dist/auth/scopes/mapping.d.ts.map +1 -0
- package/dist/auth/scopes/validation.d.ts +27 -0
- package/dist/auth/scopes/validation.d.ts.map +1 -0
- package/dist/auth/token-validator.d.ts +63 -0
- package/dist/auth/token-validator.d.ts.map +1 -0
- package/dist/auth/transport-agnostic.d.ts +11 -0
- package/dist/auth/transport-agnostic.d.ts.map +1 -0
- package/dist/auth/types.d.ts +257 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/chunk-E5IESRTK.js +489 -0
- package/dist/{chunk-TVIZ3XJH.js → chunk-FR65YPAH.js} +8509 -3925
- package/dist/{chunk-AOUL5SHS.js → chunk-L552U3QS.js} +880 -252
- package/dist/chunk-THATOQRT.js +2624 -0
- package/dist/chunk-W5WQVNVX.js +568 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +114 -19
- package/dist/codemode/api-constants.d.ts +40 -0
- package/dist/codemode/api-constants.d.ts.map +1 -0
- package/dist/codemode/api.d.ts +70 -0
- package/dist/codemode/api.d.ts.map +1 -0
- package/dist/codemode/auto-return.d.ts +25 -0
- package/dist/codemode/auto-return.d.ts.map +1 -0
- package/dist/codemode/index.d.ts +12 -0
- package/dist/codemode/index.d.ts.map +1 -0
- package/dist/codemode/sandbox-factory.d.ts +72 -0
- package/dist/codemode/sandbox-factory.d.ts.map +1 -0
- package/dist/codemode/sandbox.d.ts +54 -0
- package/dist/codemode/sandbox.d.ts.map +1 -0
- package/dist/codemode/security.d.ts +45 -0
- package/dist/codemode/security.d.ts.map +1 -0
- package/dist/codemode/types.d.ts +167 -0
- package/dist/codemode/types.d.ts.map +1 -0
- package/dist/constants/server-instructions.d.ts +22 -0
- package/dist/constants/server-instructions.d.ts.map +1 -0
- package/dist/filtering/tool-constants.d.ts +45 -0
- package/dist/filtering/tool-constants.d.ts.map +1 -0
- package/dist/filtering/tool-filter.d.ts +82 -0
- package/dist/filtering/tool-filter.d.ts.map +1 -0
- package/dist/{http-VSB7DBJR.js → http-HWTUVFIA.js} +587 -358
- package/dist/index.d.ts +9 -842
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -5
- package/dist/server/mcp-server.d.ts +66 -0
- package/dist/server/mcp-server.d.ts.map +1 -0
- package/dist/server/registration/audit-tools.d.ts +13 -0
- package/dist/server/registration/audit-tools.d.ts.map +1 -0
- package/dist/server/registration/built-in-tools.d.ts +8 -0
- package/dist/server/registration/built-in-tools.d.ts.map +1 -0
- package/dist/server/registration/help-resources.d.ts +7 -0
- package/dist/server/registration/help-resources.d.ts.map +1 -0
- package/dist/server/registration/index.d.ts +4 -0
- package/dist/server/registration/index.d.ts.map +1 -0
- package/dist/{sqlite-26V3Y4MK.js → sqlite-6C3AJI4I.js} +115 -147
- package/dist/{sqlite-native-5O7FZJGB.js → sqlite-native-ZSSWCTYC.js} +1016 -349
- package/dist/transports/http/index.d.ts +8 -0
- package/dist/transports/http/index.d.ts.map +1 -0
- package/dist/transports/http/middleware.d.ts +25 -0
- package/dist/transports/http/middleware.d.ts.map +1 -0
- package/dist/transports/http/oauth.d.ts +24 -0
- package/dist/transports/http/oauth.d.ts.map +1 -0
- package/dist/transports/http/session.d.ts +2 -0
- package/dist/transports/http/session.d.ts.map +1 -0
- package/dist/transports/http/sessions/index.d.ts +4 -0
- package/dist/transports/http/sessions/index.d.ts.map +1 -0
- package/dist/transports/http/sessions/legacy-sse.d.ts +6 -0
- package/dist/transports/http/sessions/legacy-sse.d.ts.map +1 -0
- package/dist/transports/http/sessions/mutex.d.ts +6 -0
- package/dist/transports/http/sessions/mutex.d.ts.map +1 -0
- package/dist/transports/http/sessions/stateful.d.ts +12 -0
- package/dist/transports/http/sessions/stateful.d.ts.map +1 -0
- package/dist/transports/http/sessions/stateless.d.ts +6 -0
- package/dist/transports/http/sessions/stateless.d.ts.map +1 -0
- package/dist/transports/http/transport.d.ts +65 -0
- package/dist/transports/http/transport.d.ts.map +1 -0
- package/dist/transports/http/type-adapters.d.ts +20 -0
- package/dist/transports/http/type-adapters.d.ts.map +1 -0
- package/dist/transports/http/types.d.ts +120 -0
- package/dist/transports/http/types.d.ts.map +1 -0
- package/dist/types/adapter.d.ts +138 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/auth.d.ts +79 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/database.d.ts +100 -0
- package/dist/types/database.d.ts.map +1 -0
- package/dist/types/filtering.d.ts +41 -0
- package/dist/types/filtering.d.ts.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/server.d.ts +48 -0
- package/dist/types/server.d.ts.map +1 -0
- package/dist/utils/annotations.d.ts +62 -0
- package/dist/utils/annotations.d.ts.map +1 -0
- package/dist/utils/errors/base.d.ts +33 -0
- package/dist/utils/errors/base.d.ts.map +1 -0
- package/dist/utils/errors/categories.d.ts +41 -0
- package/dist/utils/errors/categories.d.ts.map +1 -0
- package/dist/utils/errors/classes.d.ts +124 -0
- package/dist/utils/errors/classes.d.ts.map +1 -0
- package/dist/utils/errors/error-response-fields.d.ts +24 -0
- package/dist/utils/errors/error-response-fields.d.ts.map +1 -0
- package/dist/utils/errors/format.d.ts +74 -0
- package/dist/utils/errors/format.d.ts.map +1 -0
- package/dist/utils/errors/index.d.ts +11 -0
- package/dist/utils/errors/index.d.ts.map +1 -0
- package/dist/utils/errors/suggestions.d.ts +16 -0
- package/dist/utils/errors/suggestions.d.ts.map +1 -0
- package/dist/utils/icons.d.ts +19 -0
- package/dist/utils/icons.d.ts.map +1 -0
- package/dist/utils/identifiers.d.ts +121 -0
- package/dist/utils/identifiers.d.ts.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/insights-manager.d.ts +39 -0
- package/dist/utils/insights-manager.d.ts.map +1 -0
- package/dist/utils/logger/error-codes.d.ts +48 -0
- package/dist/utils/logger/error-codes.d.ts.map +1 -0
- package/dist/utils/logger/index.d.ts +22 -0
- package/dist/utils/logger/index.d.ts.map +1 -0
- package/dist/utils/logger/logger.d.ts +94 -0
- package/dist/utils/logger/logger.d.ts.map +1 -0
- package/dist/utils/logger/module-logger.d.ts +28 -0
- package/dist/utils/logger/module-logger.d.ts.map +1 -0
- package/dist/utils/logger/types.d.ts +36 -0
- package/dist/utils/logger/types.d.ts.map +1 -0
- package/dist/utils/progress-utils.d.ts +54 -0
- package/dist/utils/progress-utils.d.ts.map +1 -0
- package/dist/utils/redaction.d.ts +4 -0
- package/dist/utils/redaction.d.ts.map +1 -0
- package/dist/utils/resource-annotations.d.ts +36 -0
- package/dist/utils/resource-annotations.d.ts.map +1 -0
- package/dist/utils/validate-json-path.d.ts +43 -0
- package/dist/utils/validate-json-path.d.ts.map +1 -0
- package/dist/utils/validate-path.d.ts +37 -0
- package/dist/utils/validate-path.d.ts.map +1 -0
- package/dist/utils/where-clause.d.ts +42 -0
- package/dist/utils/where-clause.d.ts.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +33 -20
- package/.gitattributes +0 -2
- package/dist/chunk-4IA3DB5C.js +0 -135
- package/dist/chunk-FW7UCRLN.js +0 -82
- package/dist/chunk-RHVEZ42P.js +0 -873
- package/dist/chunk-Z2GFQU3G.js +0 -363
- package/dist/worker-script.d.ts +0 -2
- package/dist/worker-script.js +0 -126
- package/playwright.config.ts +0 -101
- package/scripts/generate-server-instructions.ts +0 -111
- package/server.json +0 -52
- package/test-server/README.md +0 -118
- package/test-server/code-map.md +0 -409
- package/test-server/fixtures/sample.csv +0 -6
- package/test-server/reset-database.ps1 +0 -373
- package/test-server/sample.csv +0 -11
- package/test-server/test-agent-experience.md +0 -243
- package/test-server/test-database.sql +0 -388
- package/test-server/test-group-tools.md +0 -861
- package/test-server/test-help-resources.mjs +0 -238
- package/test-server/test-preflight.md +0 -53
- package/test-server/test-prompts.md +0 -354
- package/test-server/test-resources.md +0 -245
- package/test-server/test-tool-annotations.mjs +0 -157
- package/test-server/test-tools-advanced-1.md +0 -517
- package/test-server/test-tools-advanced-2.md +0 -487
- package/test-server/test-tools-codemode.md +0 -629
- package/test-server/test-tools.md +0 -176
- package/test-server/tool-reference.md +0 -236
- package/tsconfig.test.json +0 -9
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import './chunk-
|
|
2
|
-
import { createModuleLogger, DbMcpError, ERROR_CODES } from './chunk-AOUL5SHS.js';
|
|
1
|
+
import { createModuleLogger, DbMcpError, runWithAuthContext, ERROR_CODES, logger, SUPPORTED_SCOPES, scopesGrantToolAccess, InsufficientScopeError, hasAdminScope, hasReadScope, isOAuthError, BASE_SCOPES, AuthServerDiscoveryError, JwksFetchError, parseScopes, TokenExpiredError, InvalidSignatureError, InvalidTokenError, TokenMissingError } from './chunk-L552U3QS.js';
|
|
3
2
|
import express from 'express';
|
|
4
3
|
import { localhostHostValidation } from '@modelcontextprotocol/sdk/server/middleware/hostHeaderValidation.js';
|
|
5
4
|
import cors from 'cors';
|
|
6
|
-
import
|
|
5
|
+
import rateLimit from 'express-rate-limit';
|
|
6
|
+
import RedisStore from 'rate-limit-redis';
|
|
7
|
+
import { createClient } from 'redis';
|
|
7
8
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
8
|
-
import {
|
|
9
|
+
import { randomUUID } from 'crypto';
|
|
9
10
|
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
10
12
|
import * as jose from 'jose';
|
|
11
13
|
|
|
12
14
|
// src/auth/middleware/extraction.ts
|
|
@@ -27,155 +29,8 @@ function extractBearerToken(authHeader) {
|
|
|
27
29
|
return token.length > 0 ? token : null;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
// src/auth/errors.ts
|
|
31
|
-
var OAuthError = class extends DbMcpError {
|
|
32
|
-
/** HTTP status code for this error */
|
|
33
|
-
httpStatus;
|
|
34
|
-
/** WWW-Authenticate header value */
|
|
35
|
-
wwwAuthenticate;
|
|
36
|
-
constructor(message, code, httpStatus, details, wwwAuthenticate) {
|
|
37
|
-
super(message, code, "authentication" /* AUTHENTICATION */, { details });
|
|
38
|
-
this.name = "OAuthError";
|
|
39
|
-
this.httpStatus = httpStatus;
|
|
40
|
-
this.wwwAuthenticate = wwwAuthenticate;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
var TokenMissingError = class extends OAuthError {
|
|
44
|
-
constructor(realm = "db-mcp") {
|
|
45
|
-
super(
|
|
46
|
-
"No access token provided",
|
|
47
|
-
ERROR_CODES.AUTH.TOKEN_MISSING.full,
|
|
48
|
-
401,
|
|
49
|
-
void 0,
|
|
50
|
-
`Bearer realm="${realm}"`
|
|
51
|
-
);
|
|
52
|
-
this.name = "TokenMissingError";
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
var InvalidTokenError = class extends OAuthError {
|
|
56
|
-
constructor(message = "Invalid access token", details) {
|
|
57
|
-
super(
|
|
58
|
-
message,
|
|
59
|
-
ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
60
|
-
401,
|
|
61
|
-
details,
|
|
62
|
-
'Bearer error="invalid_token"'
|
|
63
|
-
);
|
|
64
|
-
this.name = "InvalidTokenError";
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
var TokenExpiredError = class extends OAuthError {
|
|
68
|
-
constructor(expiredAt) {
|
|
69
|
-
super(
|
|
70
|
-
"Access token has expired",
|
|
71
|
-
ERROR_CODES.AUTH.TOKEN_EXPIRED.full,
|
|
72
|
-
401,
|
|
73
|
-
expiredAt ? { expiredAt: expiredAt.toISOString() } : void 0,
|
|
74
|
-
'Bearer error="invalid_token", error_description="Token has expired"'
|
|
75
|
-
);
|
|
76
|
-
this.name = "TokenExpiredError";
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
var InvalidSignatureError = class extends OAuthError {
|
|
80
|
-
constructor(message = "Token signature verification failed") {
|
|
81
|
-
super(
|
|
82
|
-
message,
|
|
83
|
-
ERROR_CODES.AUTH.SIGNATURE_INVALID.full,
|
|
84
|
-
401,
|
|
85
|
-
void 0,
|
|
86
|
-
'Bearer error="invalid_token", error_description="Signature verification failed"'
|
|
87
|
-
);
|
|
88
|
-
this.name = "InvalidSignatureError";
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
var AuthServerDiscoveryError = class extends OAuthError {
|
|
92
|
-
constructor(serverUrl, cause) {
|
|
93
|
-
super(
|
|
94
|
-
`Failed to discover authorization server metadata: ${serverUrl}`,
|
|
95
|
-
ERROR_CODES.AUTH.DISCOVERY_FAILED.full,
|
|
96
|
-
500,
|
|
97
|
-
{
|
|
98
|
-
serverUrl,
|
|
99
|
-
cause: cause?.message
|
|
100
|
-
}
|
|
101
|
-
);
|
|
102
|
-
this.name = "AuthServerDiscoveryError";
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
var JwksFetchError = class extends OAuthError {
|
|
106
|
-
constructor(jwksUri, cause) {
|
|
107
|
-
super(
|
|
108
|
-
`Failed to fetch JWKS: ${jwksUri}`,
|
|
109
|
-
ERROR_CODES.AUTH.JWKS_FETCH_FAILED.full,
|
|
110
|
-
500,
|
|
111
|
-
{
|
|
112
|
-
jwksUri,
|
|
113
|
-
cause: cause?.message
|
|
114
|
-
}
|
|
115
|
-
);
|
|
116
|
-
this.name = "JwksFetchError";
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
function isOAuthError(error) {
|
|
120
|
-
return error instanceof OAuthError;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// src/auth/scopes/constants.ts
|
|
124
|
-
var SCOPES = {
|
|
125
|
-
/** Read-only access to all databases */
|
|
126
|
-
READ: "read",
|
|
127
|
-
/** Read and write access to all databases */
|
|
128
|
-
WRITE: "write",
|
|
129
|
-
/** Administrative access */
|
|
130
|
-
ADMIN: "admin"};
|
|
131
|
-
var BASE_SCOPES = ["read", "write", "admin", "full"];
|
|
132
|
-
var SCOPE_PATTERNS = {
|
|
133
|
-
/** Database-specific access pattern */
|
|
134
|
-
DATABASE: /^db:([a-zA-Z0-9_-]+)$/,
|
|
135
|
-
/** Table-specific access pattern */
|
|
136
|
-
TABLE: /^table:([a-zA-Z0-9_-]+):([a-zA-Z0-9_-]+)$/
|
|
137
|
-
};
|
|
138
|
-
var SUPPORTED_SCOPES = [
|
|
139
|
-
"read",
|
|
140
|
-
"write",
|
|
141
|
-
"admin",
|
|
142
|
-
"full",
|
|
143
|
-
"db:{database}",
|
|
144
|
-
"table:{database}:{table}"
|
|
145
|
-
];
|
|
146
|
-
function parseScopes(scopeString) {
|
|
147
|
-
return scopeString.split(/\s+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// src/auth/scopes/mapping.ts
|
|
151
|
-
var TOOL_GROUP_SCOPES = {
|
|
152
|
-
core: SCOPES.READ,
|
|
153
|
-
json: SCOPES.READ,
|
|
154
|
-
text: SCOPES.READ,
|
|
155
|
-
stats: SCOPES.READ,
|
|
156
|
-
vector: SCOPES.READ,
|
|
157
|
-
geo: SCOPES.READ,
|
|
158
|
-
introspection: SCOPES.READ,
|
|
159
|
-
migration: SCOPES.WRITE,
|
|
160
|
-
admin: SCOPES.ADMIN,
|
|
161
|
-
codemode: SCOPES.ADMIN
|
|
162
|
-
};
|
|
163
|
-
var groupsForScope = (maxScope) => {
|
|
164
|
-
const hierarchy = {
|
|
165
|
-
read: 0,
|
|
166
|
-
write: 1,
|
|
167
|
-
admin: 2,
|
|
168
|
-
full: 3
|
|
169
|
-
};
|
|
170
|
-
const maxLevel = hierarchy[maxScope];
|
|
171
|
-
return Object.entries(TOOL_GROUP_SCOPES).filter(([, scope]) => hierarchy[scope] <= maxLevel).map(([group]) => group);
|
|
172
|
-
};
|
|
173
|
-
groupsForScope(SCOPES.READ);
|
|
174
|
-
groupsForScope(SCOPES.WRITE);
|
|
175
|
-
groupsForScope(SCOPES.ADMIN);
|
|
176
|
-
|
|
177
32
|
// src/auth/middleware/express-auth.ts
|
|
178
|
-
var
|
|
33
|
+
var logger2 = createModuleLogger("AUTH");
|
|
179
34
|
function isPublicPath(path, publicPaths) {
|
|
180
35
|
if (path.startsWith("/.well-known/")) {
|
|
181
36
|
return true;
|
|
@@ -198,8 +53,9 @@ function createAuthMiddleware(config) {
|
|
|
198
53
|
return async (req, res, next) => {
|
|
199
54
|
const requestId = crypto.randomUUID();
|
|
200
55
|
req.requestId = requestId;
|
|
56
|
+
res.setHeader("X-Request-ID", requestId);
|
|
201
57
|
if (isPublicPath(req.path, publicPaths)) {
|
|
202
|
-
|
|
58
|
+
logger2.info(`Public path accessed: ${req.path}`, {
|
|
203
59
|
code: "AUTH_PUBLIC_PATH",
|
|
204
60
|
requestId,
|
|
205
61
|
path: req.path
|
|
@@ -210,7 +66,7 @@ function createAuthMiddleware(config) {
|
|
|
210
66
|
const token = extractBearerToken(req.headers.authorization);
|
|
211
67
|
if (!token) {
|
|
212
68
|
const error = new TokenMissingError(resourceServer.getResourceUri());
|
|
213
|
-
|
|
69
|
+
logger2.warning("No access token provided", {
|
|
214
70
|
code: ERROR_CODES.AUTH.TOKEN_MISSING.full,
|
|
215
71
|
requestId,
|
|
216
72
|
path: req.path
|
|
@@ -225,7 +81,7 @@ function createAuthMiddleware(config) {
|
|
|
225
81
|
}
|
|
226
82
|
const result = await tokenValidator.validate(token);
|
|
227
83
|
if (!result.valid) {
|
|
228
|
-
|
|
84
|
+
logger2.warning(
|
|
229
85
|
`Token validation failed: ${result.error ?? "Unknown error"}`,
|
|
230
86
|
{
|
|
231
87
|
code: result.errorCode ?? ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
@@ -236,11 +92,14 @@ function createAuthMiddleware(config) {
|
|
|
236
92
|
res.status(401);
|
|
237
93
|
res.setHeader(
|
|
238
94
|
"WWW-Authenticate",
|
|
239
|
-
resourceServer.getWWWAuthenticateHeader(
|
|
95
|
+
resourceServer.getWWWAuthenticateHeader(
|
|
96
|
+
"invalid_token",
|
|
97
|
+
"Token validation failed"
|
|
98
|
+
)
|
|
240
99
|
);
|
|
241
100
|
res.json({
|
|
242
101
|
error: "invalid_token",
|
|
243
|
-
error_description:
|
|
102
|
+
error_description: "Token validation failed"
|
|
244
103
|
});
|
|
245
104
|
return;
|
|
246
105
|
}
|
|
@@ -251,7 +110,7 @@ function createAuthMiddleware(config) {
|
|
|
251
110
|
}
|
|
252
111
|
req.auth = claims;
|
|
253
112
|
req.accessToken = token;
|
|
254
|
-
|
|
113
|
+
logger2.info(`Request authenticated: ${claims.sub}`, {
|
|
255
114
|
code: "AUTH_SUCCESS",
|
|
256
115
|
requestId,
|
|
257
116
|
sub: claims.sub,
|
|
@@ -289,18 +148,9 @@ var JSONRPC_INTERNAL_ERROR = -32603;
|
|
|
289
148
|
var HTTP_REQUEST_TIMEOUT_MS = 12e4;
|
|
290
149
|
var HTTP_KEEP_ALIVE_TIMEOUT_MS = 65e3;
|
|
291
150
|
var HTTP_HEADERS_TIMEOUT_MS = 66e3;
|
|
292
|
-
function getClientIp(req, trustProxy) {
|
|
293
|
-
if (trustProxy) {
|
|
294
|
-
const forwarded = req.headers["x-forwarded-for"];
|
|
295
|
-
if (typeof forwarded === "string") {
|
|
296
|
-
const firstIp = forwarded.split(",")[0]?.trim();
|
|
297
|
-
if (firstIp) return firstIp;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return req.ip ?? req.socket.remoteAddress ?? "unknown";
|
|
301
|
-
}
|
|
302
151
|
function setupSecurityHeaders(state) {
|
|
303
152
|
if (!state.app) return;
|
|
153
|
+
state.app.disable("x-powered-by");
|
|
304
154
|
state.app.use((_req, res, next) => {
|
|
305
155
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
306
156
|
res.setHeader("X-Frame-Options", "DENY");
|
|
@@ -314,8 +164,12 @@ function setupSecurityHeaders(state) {
|
|
|
314
164
|
"camera=(), microphone=(), geolocation=()"
|
|
315
165
|
);
|
|
316
166
|
res.setHeader("Referrer-Policy", "no-referrer");
|
|
167
|
+
res.setHeader("X-Permitted-Cross-Domain-Policies", "none");
|
|
317
168
|
if (state.config.enableHSTS) {
|
|
318
|
-
const maxAge =
|
|
169
|
+
const maxAge = Math.max(
|
|
170
|
+
state.config.hstsMaxAge ?? DEFAULT_HSTS_MAX_AGE,
|
|
171
|
+
31536e3
|
|
172
|
+
);
|
|
319
173
|
res.setHeader(
|
|
320
174
|
"Strict-Transport-Security",
|
|
321
175
|
`max-age=${String(maxAge)}; includeSubDomains`
|
|
@@ -328,13 +182,15 @@ function matchesCorsOrigin(origin, pattern) {
|
|
|
328
182
|
if (pattern === "*") return true;
|
|
329
183
|
if (pattern.startsWith("*.")) {
|
|
330
184
|
const domain = pattern.slice(1);
|
|
185
|
+
const isLocalDev = origin === "http://localhost" || origin.startsWith("http://localhost:") || origin === "http://127.0.0.1" || origin.startsWith("http://127.0.0.1:") || origin === "http://[::1]" || origin.startsWith("http://[::1]:");
|
|
186
|
+
if (!isLocalDev && !origin.startsWith("https://")) return false;
|
|
331
187
|
return origin.endsWith(domain) && origin.length > domain.length;
|
|
332
188
|
}
|
|
333
189
|
return origin === pattern;
|
|
334
190
|
}
|
|
335
191
|
function setupCors(state) {
|
|
336
192
|
if (!state.app) return;
|
|
337
|
-
const corsOrigins = state.config.corsOrigins ?? [
|
|
193
|
+
const corsOrigins = state.config.corsOrigins ?? [];
|
|
338
194
|
const isWildcard = corsOrigins.includes("*");
|
|
339
195
|
state.app.use((req, res, next) => {
|
|
340
196
|
const origin = req.headers.origin;
|
|
@@ -365,41 +221,41 @@ function setupCors(state) {
|
|
|
365
221
|
function setupRateLimiting(state) {
|
|
366
222
|
if (!state.app) return;
|
|
367
223
|
const windowMs = DEFAULT_RATE_LIMIT_WINDOW_MS;
|
|
368
|
-
const
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
224
|
+
const parsedMax = process.env["MCP_RATE_LIMIT_MAX"] ? parseInt(process.env["MCP_RATE_LIMIT_MAX"], 10) : DEFAULT_RATE_LIMIT_MAX;
|
|
225
|
+
const safeParsedMax = Number.isNaN(parsedMax) ? DEFAULT_RATE_LIMIT_MAX : parsedMax;
|
|
226
|
+
const maxRequests = Math.max(1, Math.min(safeParsedMax, 1e4));
|
|
227
|
+
let store;
|
|
228
|
+
if (process.env["REDIS_URL"]) {
|
|
229
|
+
const redisClient = createClient({ url: process.env["REDIS_URL"] });
|
|
230
|
+
redisClient.connect().catch((err) => {
|
|
231
|
+
logger.error("Redis connection failed", {
|
|
232
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
store = new RedisStore({
|
|
236
|
+
sendCommand: (...args) => redisClient.sendCommand(args)
|
|
237
|
+
});
|
|
238
|
+
logger.info("Configured RedisStore for rate limiting", { module: "HTTP" });
|
|
239
|
+
} else if (process.env["NODE_ENV"] === "production") {
|
|
240
|
+
logger.error(
|
|
241
|
+
"CRITICAL SECURITY WARNING: Using default in-memory rate limit store in production. In multi-instance deployments, rate limits will not be synchronized across instances (leading to amplification attacks). Configure REDIS_URL for production clusters or ensure your proxy handles rate limiting.",
|
|
242
|
+
{ module: "HTTP" }
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
const limiter = rateLimit({
|
|
246
|
+
windowMs,
|
|
247
|
+
max: maxRequests,
|
|
248
|
+
standardHeaders: true,
|
|
249
|
+
legacyHeaders: false,
|
|
250
|
+
...store ? { store } : {},
|
|
251
|
+
skip: (req) => req.path === "/health",
|
|
252
|
+
handler: (_req, res, _next, options) => {
|
|
253
|
+
res.status(options.statusCode).json({
|
|
254
|
+
error: "Too Many Requests"
|
|
398
255
|
});
|
|
399
|
-
return;
|
|
400
256
|
}
|
|
401
|
-
next();
|
|
402
257
|
});
|
|
258
|
+
state.app.use(limiter);
|
|
403
259
|
}
|
|
404
260
|
|
|
405
261
|
// src/transports/http/type-adapters.ts
|
|
@@ -410,8 +266,8 @@ function asServerResponse(res) {
|
|
|
410
266
|
return res;
|
|
411
267
|
}
|
|
412
268
|
|
|
413
|
-
// src/transports/http/
|
|
414
|
-
var
|
|
269
|
+
// src/transports/http/sessions/stateless.ts
|
|
270
|
+
var logger4 = createModuleLogger("HTTP");
|
|
415
271
|
async function setupStatelessEndpoints(state) {
|
|
416
272
|
if (!state.app || !state.mcpServer) {
|
|
417
273
|
throw new DbMcpError(
|
|
@@ -424,14 +280,14 @@ async function setupStatelessEndpoints(state) {
|
|
|
424
280
|
enableJsonResponse: true
|
|
425
281
|
});
|
|
426
282
|
state.statelessTransport.onclose ??= () => {
|
|
427
|
-
|
|
283
|
+
logger4.debug("Stateless transport closed", {
|
|
428
284
|
code: "HTTP_STATELESS_CLOSE"
|
|
429
285
|
});
|
|
430
286
|
};
|
|
431
287
|
await state.mcpServer.connect(
|
|
432
288
|
state.statelessTransport
|
|
433
289
|
);
|
|
434
|
-
|
|
290
|
+
logger4.info("Stateless transport connected", { code: "HTTP_STATELESS" });
|
|
435
291
|
state.app.post("/mcp", (req, res) => {
|
|
436
292
|
if (!state.statelessTransport) {
|
|
437
293
|
res.status(500).json({ error: "Transport not initialized" });
|
|
@@ -457,6 +313,47 @@ async function setupStatelessEndpoints(state) {
|
|
|
457
313
|
res.status(204).end();
|
|
458
314
|
});
|
|
459
315
|
}
|
|
316
|
+
|
|
317
|
+
// src/transports/http/sessions/mutex.ts
|
|
318
|
+
var Mutex = class {
|
|
319
|
+
queue = [];
|
|
320
|
+
locked = false;
|
|
321
|
+
async acquire() {
|
|
322
|
+
return new Promise((resolve) => {
|
|
323
|
+
const lock = () => {
|
|
324
|
+
this.locked = true;
|
|
325
|
+
resolve(() => {
|
|
326
|
+
this.locked = false;
|
|
327
|
+
if (this.queue.length > 0) {
|
|
328
|
+
const next = this.queue.shift();
|
|
329
|
+
next?.();
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
};
|
|
333
|
+
if (this.locked) {
|
|
334
|
+
this.queue.push(lock);
|
|
335
|
+
} else {
|
|
336
|
+
lock();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// src/transports/http/sessions/stateful.ts
|
|
343
|
+
var logger5 = createModuleLogger("HTTP");
|
|
344
|
+
var connectionMutex = new Mutex();
|
|
345
|
+
function verifySessionOwner(state, sessionId, reqAuthSub) {
|
|
346
|
+
const owner = state.sessionOwners.get(sessionId);
|
|
347
|
+
if (owner !== void 0 && owner !== reqAuthSub) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
function isValidSessionId(id) {
|
|
353
|
+
if (!id) return false;
|
|
354
|
+
if (id.length !== 36) return false;
|
|
355
|
+
return /^[0-9a-fA-F-]{36}$/.test(id);
|
|
356
|
+
}
|
|
460
357
|
function setupStatefulEndpoints(state) {
|
|
461
358
|
if (!state.app || !state.mcpServer) {
|
|
462
359
|
throw new DbMcpError(
|
|
@@ -468,6 +365,17 @@ function setupStatefulEndpoints(state) {
|
|
|
468
365
|
const server = state.mcpServer;
|
|
469
366
|
state.app.post("/mcp", (req, res) => {
|
|
470
367
|
const sessionId = req.headers["mcp-session-id"];
|
|
368
|
+
if (sessionId !== void 0 && !isValidSessionId(sessionId)) {
|
|
369
|
+
res.status(400).json({
|
|
370
|
+
jsonrpc: "2.0",
|
|
371
|
+
error: {
|
|
372
|
+
code: JSONRPC_SERVER_ERROR,
|
|
373
|
+
message: "Bad Request: Invalid session ID format"
|
|
374
|
+
},
|
|
375
|
+
id: null
|
|
376
|
+
});
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
471
379
|
if (sessionId && state.sseTransports.has(sessionId)) {
|
|
472
380
|
res.status(400).json({
|
|
473
381
|
jsonrpc: "2.0",
|
|
@@ -491,39 +399,96 @@ function setupStatefulEndpoints(state) {
|
|
|
491
399
|
void (async () => {
|
|
492
400
|
try {
|
|
493
401
|
let httpTransport;
|
|
494
|
-
|
|
495
|
-
|
|
402
|
+
const existingTransport = sessionId ? state.transports.get(sessionId) : void 0;
|
|
403
|
+
if (typeof sessionId === "string" && existingTransport !== void 0) {
|
|
404
|
+
if (!verifySessionOwner(state, sessionId, req.auth?.sub)) {
|
|
405
|
+
res.status(403).json({
|
|
406
|
+
jsonrpc: "2.0",
|
|
407
|
+
error: {
|
|
408
|
+
code: JSONRPC_SERVER_ERROR,
|
|
409
|
+
message: "Forbidden: session belongs to a different client"
|
|
410
|
+
},
|
|
411
|
+
id: null
|
|
412
|
+
});
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
httpTransport = existingTransport;
|
|
496
416
|
} else if (sessionId === void 0 && isNewSessionRequest(req.body)) {
|
|
417
|
+
const maxSessions = state.config.maxSessions ?? 1e3;
|
|
418
|
+
if (state.transports.size >= maxSessions) {
|
|
419
|
+
res.status(429).json({
|
|
420
|
+
jsonrpc: "2.0",
|
|
421
|
+
error: {
|
|
422
|
+
code: JSONRPC_SERVER_ERROR,
|
|
423
|
+
message: "Too Many Requests: Maximum number of concurrent sessions reached"
|
|
424
|
+
},
|
|
425
|
+
id: null
|
|
426
|
+
});
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
497
429
|
const newTransport = new StreamableHTTPServerTransport({
|
|
498
430
|
sessionIdGenerator: () => randomUUID(),
|
|
499
431
|
onsessioninitialized: (sid) => {
|
|
500
|
-
|
|
432
|
+
logger5.info("HTTP session initialized", {
|
|
501
433
|
code: "HTTP_SESSION_INIT",
|
|
502
434
|
sessionId: sid
|
|
503
435
|
});
|
|
504
436
|
state.transports.set(sid, newTransport);
|
|
437
|
+
state.sessionOwners.set(sid, req.auth?.sub);
|
|
505
438
|
}
|
|
506
439
|
});
|
|
507
440
|
newTransport.onclose = () => {
|
|
508
441
|
const sid = newTransport.sessionId;
|
|
509
442
|
if (sid !== void 0 && state.transports.has(sid)) {
|
|
510
|
-
|
|
443
|
+
logger5.info("HTTP transport closed", {
|
|
511
444
|
code: "HTTP_SESSION_CLOSE",
|
|
512
445
|
sessionId: sid
|
|
513
446
|
});
|
|
514
447
|
state.transports.delete(sid);
|
|
448
|
+
state.sessionOwners.delete(sid);
|
|
515
449
|
}
|
|
516
450
|
};
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
451
|
+
await connectionMutex.acquire().then(async (release) => {
|
|
452
|
+
try {
|
|
453
|
+
if (server.server.transport) {
|
|
454
|
+
const oldTransport = server.server.transport;
|
|
455
|
+
logger5.info("Captured oldTransport in /mcp", {
|
|
456
|
+
hasOldTransport: oldTransport !== void 0,
|
|
457
|
+
hasOnclose: oldTransport.onclose !== void 0
|
|
458
|
+
});
|
|
459
|
+
try {
|
|
460
|
+
await Promise.race([
|
|
461
|
+
server.close(),
|
|
462
|
+
new Promise(
|
|
463
|
+
(_, reject) => setTimeout(
|
|
464
|
+
() => reject(new Error("server.close timeout")),
|
|
465
|
+
2e3
|
|
466
|
+
)
|
|
467
|
+
)
|
|
468
|
+
]);
|
|
469
|
+
logger5.info("server.close() succeeded in /mcp");
|
|
470
|
+
} catch (closeErr) {
|
|
471
|
+
logger5.error("server.close() failed or timed out in /mcp", {
|
|
472
|
+
error: closeErr instanceof Error ? closeErr : new Error(String(closeErr))
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
if (server.server.transport === oldTransport && oldTransport.onclose !== void 0) {
|
|
476
|
+
logger5.info(
|
|
477
|
+
"Manually invoking oldTransport.onclose() to clear Protocol state in /mcp"
|
|
478
|
+
);
|
|
479
|
+
oldTransport.onclose();
|
|
480
|
+
}
|
|
481
|
+
delete oldTransport.onclose;
|
|
482
|
+
}
|
|
483
|
+
logger5.info("Attempting server.connect(newTransport)");
|
|
484
|
+
await server.connect(
|
|
485
|
+
newTransport
|
|
486
|
+
);
|
|
487
|
+
logger5.info("server.connect succeeded in /mcp");
|
|
488
|
+
} finally {
|
|
489
|
+
release();
|
|
490
|
+
}
|
|
491
|
+
});
|
|
527
492
|
await newTransport.handleRequest(
|
|
528
493
|
asIncoming(req),
|
|
529
494
|
asServerResponse(res),
|
|
@@ -549,7 +514,7 @@ function setupStatefulEndpoints(state) {
|
|
|
549
514
|
);
|
|
550
515
|
}
|
|
551
516
|
} catch (error) {
|
|
552
|
-
|
|
517
|
+
logger5.error("Error handling MCP request", {
|
|
553
518
|
code: ERROR_CODES.SERVER.TRANSPORT_ERROR.full,
|
|
554
519
|
error: error instanceof Error ? error : void 0
|
|
555
520
|
});
|
|
@@ -568,44 +533,62 @@ function setupStatefulEndpoints(state) {
|
|
|
568
533
|
});
|
|
569
534
|
state.app.get("/mcp", (req, res) => {
|
|
570
535
|
const sessionId = req.headers["mcp-session-id"];
|
|
571
|
-
if (sessionId === void 0 || !
|
|
536
|
+
if (sessionId === void 0 || !isValidSessionId(sessionId)) {
|
|
537
|
+
res.status(400).send("Invalid or missing session ID");
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
const httpTransport = state.transports.get(sessionId);
|
|
541
|
+
if (httpTransport === void 0) {
|
|
572
542
|
res.status(400).send("Invalid or missing session ID");
|
|
573
543
|
return;
|
|
574
544
|
}
|
|
545
|
+
if (!verifySessionOwner(state, sessionId, req.auth?.sub)) {
|
|
546
|
+
res.status(403).send("Forbidden: session belongs to a different client");
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
575
549
|
const lastEventId = req.headers["last-event-id"];
|
|
576
550
|
if (lastEventId !== void 0) {
|
|
577
|
-
|
|
551
|
+
logger5.debug("Client reconnecting with Last-Event-ID", {
|
|
578
552
|
code: "HTTP_SSE_RECONNECT",
|
|
579
553
|
sessionId,
|
|
580
554
|
lastEventId
|
|
581
555
|
});
|
|
582
556
|
}
|
|
583
|
-
const httpTransport = state.transports.get(sessionId);
|
|
584
557
|
if (httpTransport !== void 0) {
|
|
585
558
|
void httpTransport.handleRequest(asIncoming(req), asServerResponse(res));
|
|
586
559
|
}
|
|
587
560
|
});
|
|
588
561
|
state.app.delete("/mcp", (req, res) => {
|
|
589
562
|
const sessionId = req.headers["mcp-session-id"];
|
|
590
|
-
if (sessionId === void 0 || !
|
|
563
|
+
if (sessionId === void 0 || !isValidSessionId(sessionId)) {
|
|
564
|
+
res.status(400).send("Invalid or missing session ID");
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const httpTransport = state.transports.get(sessionId);
|
|
568
|
+
if (httpTransport === void 0) {
|
|
591
569
|
res.status(400).send("Invalid or missing session ID");
|
|
592
570
|
return;
|
|
593
571
|
}
|
|
594
|
-
|
|
572
|
+
if (!verifySessionOwner(state, sessionId, req.auth?.sub)) {
|
|
573
|
+
res.status(403).send("Forbidden: session belongs to a different client");
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
logger5.info("Session termination requested", {
|
|
595
577
|
code: "HTTP_SESSION_DELETE",
|
|
596
578
|
sessionId
|
|
597
579
|
});
|
|
598
|
-
const httpTransport = state.transports.get(sessionId);
|
|
599
580
|
if (httpTransport !== void 0) {
|
|
600
581
|
void httpTransport.handleRequest(asIncoming(req), asServerResponse(res));
|
|
601
582
|
}
|
|
602
583
|
});
|
|
603
584
|
}
|
|
585
|
+
var logger6 = createModuleLogger("HTTP");
|
|
586
|
+
var connectionMutex2 = new Mutex();
|
|
604
587
|
function setupLegacySSEEndpoints(state) {
|
|
605
588
|
if (!state.app || !state.mcpServer) return;
|
|
606
589
|
const server = state.mcpServer;
|
|
607
590
|
state.app.get("/sse", (req, res) => {
|
|
608
|
-
|
|
591
|
+
logger6.info("Legacy SSE connection requested", {
|
|
609
592
|
code: "SSE_CONNECT"
|
|
610
593
|
});
|
|
611
594
|
const sseTransport = new SSEServerTransport(
|
|
@@ -615,25 +598,63 @@ function setupLegacySSEEndpoints(state) {
|
|
|
615
598
|
void (async () => {
|
|
616
599
|
try {
|
|
617
600
|
state.sseTransports.set(sseTransport.sessionId, sseTransport);
|
|
601
|
+
state.sessionOwners.set(sseTransport.sessionId, req.auth?.sub);
|
|
618
602
|
sseTransport.onclose = () => {
|
|
619
|
-
|
|
603
|
+
logger6.info("Legacy SSE transport closed", {
|
|
620
604
|
code: "SSE_CLOSE",
|
|
621
605
|
sessionId: sseTransport.sessionId
|
|
622
606
|
});
|
|
623
607
|
state.sseTransports.delete(sseTransport.sessionId);
|
|
608
|
+
state.sessionOwners.delete(sseTransport.sessionId);
|
|
624
609
|
};
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
610
|
+
const origSend = sseTransport.send.bind(sseTransport);
|
|
611
|
+
sseTransport.send = async (message) => {
|
|
612
|
+
logger6.debug("SSE SEND", {
|
|
613
|
+
sessionId: sseTransport.sessionId
|
|
614
|
+
});
|
|
615
|
+
return origSend(message);
|
|
616
|
+
};
|
|
617
|
+
await connectionMutex2.acquire().then(async (release) => {
|
|
618
|
+
try {
|
|
619
|
+
if (server.server.transport) {
|
|
620
|
+
const oldTransport = server.server.transport;
|
|
621
|
+
logger6.info("Captured oldTransport", {
|
|
622
|
+
hasOldTransport: oldTransport !== void 0,
|
|
623
|
+
hasOnclose: oldTransport.onclose !== void 0
|
|
624
|
+
});
|
|
625
|
+
try {
|
|
626
|
+
await Promise.race([
|
|
627
|
+
server.close(),
|
|
628
|
+
new Promise(
|
|
629
|
+
(_, reject) => setTimeout(
|
|
630
|
+
() => reject(new Error("server.close timeout")),
|
|
631
|
+
2e3
|
|
632
|
+
)
|
|
633
|
+
)
|
|
634
|
+
]);
|
|
635
|
+
logger6.info("server.close() succeeded");
|
|
636
|
+
} catch (closeErr) {
|
|
637
|
+
logger6.error("server.close() failed or timed out", {
|
|
638
|
+
error: closeErr instanceof Error ? closeErr : new Error(String(closeErr))
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
if (server.server.transport === oldTransport && oldTransport.onclose !== void 0) {
|
|
642
|
+
logger6.info(
|
|
643
|
+
"Manually invoking oldTransport.onclose() to clear Protocol state"
|
|
644
|
+
);
|
|
645
|
+
oldTransport.onclose();
|
|
646
|
+
}
|
|
647
|
+
delete oldTransport.onclose;
|
|
648
|
+
}
|
|
649
|
+
logger6.info("Attempting server.connect(sseTransport)");
|
|
650
|
+
await server.connect(sseTransport);
|
|
651
|
+
logger6.info("server.connect succeeded");
|
|
652
|
+
} finally {
|
|
653
|
+
release();
|
|
654
|
+
}
|
|
655
|
+
});
|
|
635
656
|
} catch (error) {
|
|
636
|
-
|
|
657
|
+
logger6.error("Error starting SSE transport", {
|
|
637
658
|
code: ERROR_CODES.SERVER.TRANSPORT_ERROR.full,
|
|
638
659
|
error: error instanceof Error ? error : void 0
|
|
639
660
|
});
|
|
@@ -644,6 +665,7 @@ function setupLegacySSEEndpoints(state) {
|
|
|
644
665
|
})();
|
|
645
666
|
req.on("close", () => {
|
|
646
667
|
state.sseTransports.delete(sseTransport.sessionId);
|
|
668
|
+
state.sessionOwners.delete(sseTransport.sessionId);
|
|
647
669
|
});
|
|
648
670
|
});
|
|
649
671
|
state.app.post("/messages", (req, res) => {
|
|
@@ -671,16 +693,33 @@ function setupLegacySSEEndpoints(state) {
|
|
|
671
693
|
});
|
|
672
694
|
return;
|
|
673
695
|
}
|
|
696
|
+
if (!verifySessionOwner(state, sessionId, req.auth?.sub)) {
|
|
697
|
+
res.status(403).json({
|
|
698
|
+
jsonrpc: "2.0",
|
|
699
|
+
error: {
|
|
700
|
+
code: JSONRPC_SERVER_ERROR,
|
|
701
|
+
message: "Forbidden: session belongs to a different client"
|
|
702
|
+
},
|
|
703
|
+
id: null
|
|
704
|
+
});
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
674
707
|
void sseTransport.handlePostMessage(
|
|
675
708
|
asIncoming(req),
|
|
676
709
|
asServerResponse(res),
|
|
677
710
|
req.body
|
|
678
|
-
)
|
|
711
|
+
).then(() => {
|
|
712
|
+
logger6.info("handlePostMessage completed", { sessionId });
|
|
713
|
+
}).catch((e) => {
|
|
714
|
+
logger6.error("handlePostMessage error", {
|
|
715
|
+
error: e instanceof Error ? e : new Error(String(e))
|
|
716
|
+
});
|
|
717
|
+
});
|
|
679
718
|
});
|
|
680
719
|
}
|
|
681
720
|
|
|
682
721
|
// src/auth/oauth-resource-server.ts
|
|
683
|
-
var
|
|
722
|
+
var logger7 = createModuleLogger("AUTH");
|
|
684
723
|
var OAuthResourceServer = class {
|
|
685
724
|
config;
|
|
686
725
|
metadata = null;
|
|
@@ -691,7 +730,7 @@ var OAuthResourceServer = class {
|
|
|
691
730
|
scopesSupported: config.scopesSupported.length > 0 ? config.scopesSupported : [...SUPPORTED_SCOPES],
|
|
692
731
|
bearerMethodsSupported: config.bearerMethodsSupported ?? ["header"]
|
|
693
732
|
};
|
|
694
|
-
|
|
733
|
+
logger7.info(
|
|
695
734
|
`OAuth Resource Server initialized for: ${this.config.resource}`,
|
|
696
735
|
{ code: "AUTH_INIT" }
|
|
697
736
|
);
|
|
@@ -729,7 +768,7 @@ var OAuthResourceServer = class {
|
|
|
729
768
|
res.setHeader("Content-Type", "application/json");
|
|
730
769
|
res.setHeader("Cache-Control", "public, max-age=3600");
|
|
731
770
|
res.json(metadata);
|
|
732
|
-
|
|
771
|
+
logger7.info("Protected Resource Metadata served", {
|
|
733
772
|
code: "AUTH_METADATA_SERVED"
|
|
734
773
|
});
|
|
735
774
|
};
|
|
@@ -747,7 +786,8 @@ var OAuthResourceServer = class {
|
|
|
747
786
|
parts.push(`error="${error}"`);
|
|
748
787
|
}
|
|
749
788
|
if (errorDescription) {
|
|
750
|
-
|
|
789
|
+
const safe = errorDescription.replace(/"/g, "'").substring(0, 200);
|
|
790
|
+
parts.push(`error_description="${safe}"`);
|
|
751
791
|
}
|
|
752
792
|
return parts.join(", ");
|
|
753
793
|
}
|
|
@@ -780,12 +820,6 @@ var OAuthResourceServer = class {
|
|
|
780
820
|
if (this.config.scopesSupported.includes(scope)) {
|
|
781
821
|
return true;
|
|
782
822
|
}
|
|
783
|
-
if (SCOPE_PATTERNS.DATABASE.test(scope)) {
|
|
784
|
-
return true;
|
|
785
|
-
}
|
|
786
|
-
if (SCOPE_PATTERNS.TABLE.test(scope)) {
|
|
787
|
-
return true;
|
|
788
|
-
}
|
|
789
823
|
return false;
|
|
790
824
|
}
|
|
791
825
|
/**
|
|
@@ -803,7 +837,7 @@ var OAuthResourceServer = class {
|
|
|
803
837
|
};
|
|
804
838
|
|
|
805
839
|
// src/auth/authorization-server-discovery.ts
|
|
806
|
-
var
|
|
840
|
+
var logger8 = createModuleLogger("AUTH");
|
|
807
841
|
var AuthorizationServerDiscovery = class {
|
|
808
842
|
authServerUrl;
|
|
809
843
|
cacheTtl;
|
|
@@ -814,7 +848,16 @@ var AuthorizationServerDiscovery = class {
|
|
|
814
848
|
this.authServerUrl = config.authServerUrl.replace(/\/+$/, "");
|
|
815
849
|
this.cacheTtl = config.cacheTtl ?? 3600;
|
|
816
850
|
this.timeout = config.timeout ?? 5e3;
|
|
817
|
-
|
|
851
|
+
if (!this.authServerUrl.startsWith("https://") && process.env["NODE_ENV"] !== "development" && process.env["NODE_ENV"] !== "test") {
|
|
852
|
+
const url = new URL(this.authServerUrl);
|
|
853
|
+
const isLocalDev = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
|
|
854
|
+
if (!isLocalDev) {
|
|
855
|
+
throw new Error(
|
|
856
|
+
`Security: Authorization server URL must use HTTPS in production. Got: ${this.authServerUrl}. Set NODE_ENV=development to allow HTTP for local testing.`
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
logger8.info(
|
|
818
861
|
`Authorization Server Discovery initialized for: ${this.authServerUrl}`,
|
|
819
862
|
{ code: "AUTH_INIT" }
|
|
820
863
|
);
|
|
@@ -830,13 +873,13 @@ var AuthorizationServerDiscovery = class {
|
|
|
830
873
|
*/
|
|
831
874
|
async discover() {
|
|
832
875
|
if (this.cachedMetadata && Date.now() < this.cacheExpiry) {
|
|
833
|
-
|
|
876
|
+
logger8.info("Using cached authorization server metadata", {
|
|
834
877
|
code: "AUTH_CACHE_HIT"
|
|
835
878
|
});
|
|
836
879
|
return this.cachedMetadata;
|
|
837
880
|
}
|
|
838
881
|
const metadataUrl = `${this.authServerUrl}/.well-known/oauth-authorization-server`;
|
|
839
|
-
|
|
882
|
+
logger8.info(`Fetching authorization server metadata from: ${metadataUrl}`, {
|
|
840
883
|
code: "AUTH_DISCOVERY"
|
|
841
884
|
});
|
|
842
885
|
try {
|
|
@@ -861,14 +904,14 @@ var AuthorizationServerDiscovery = class {
|
|
|
861
904
|
this.validateMetadata(metadata);
|
|
862
905
|
this.cachedMetadata = metadata;
|
|
863
906
|
this.cacheExpiry = Date.now() + this.cacheTtl * 1e3;
|
|
864
|
-
|
|
907
|
+
logger8.info(
|
|
865
908
|
`Authorization server metadata cached for ${String(this.cacheTtl)}s`,
|
|
866
909
|
{ code: "AUTH_DISCOVERY_SUCCESS" }
|
|
867
910
|
);
|
|
868
911
|
return metadata;
|
|
869
912
|
} catch (error) {
|
|
870
913
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
871
|
-
|
|
914
|
+
logger8.error(
|
|
872
915
|
`Failed to discover authorization server: ${this.authServerUrl}`,
|
|
873
916
|
{
|
|
874
917
|
code: ERROR_CODES.AUTH.DISCOVERY_FAILED.full,
|
|
@@ -898,11 +941,22 @@ var AuthorizationServerDiscovery = class {
|
|
|
898
941
|
"validation" /* VALIDATION */
|
|
899
942
|
);
|
|
900
943
|
}
|
|
944
|
+
try {
|
|
945
|
+
new URL(metadata.issuer);
|
|
946
|
+
new URL(metadata.token_endpoint);
|
|
947
|
+
} catch {
|
|
948
|
+
throw new DbMcpError(
|
|
949
|
+
"Invalid URL format in metadata fields",
|
|
950
|
+
"AUTH_DISCOVERY_INVALID",
|
|
951
|
+
"validation" /* VALIDATION */
|
|
952
|
+
);
|
|
953
|
+
}
|
|
901
954
|
const expectedIssuer = this.authServerUrl;
|
|
902
955
|
if (metadata.issuer !== expectedIssuer) {
|
|
903
|
-
|
|
904
|
-
`Issuer
|
|
905
|
-
|
|
956
|
+
throw new DbMcpError(
|
|
957
|
+
`Issuer validation failed. Per RFC 8414 \xA73.3, the issuer MUST be identical to the authorization server URL.`,
|
|
958
|
+
"AUTH_ISSUER_MISMATCH",
|
|
959
|
+
"validation" /* VALIDATION */
|
|
906
960
|
);
|
|
907
961
|
}
|
|
908
962
|
}
|
|
@@ -980,7 +1034,7 @@ var AuthorizationServerDiscovery = class {
|
|
|
980
1034
|
clearCache() {
|
|
981
1035
|
this.cachedMetadata = null;
|
|
982
1036
|
this.cacheExpiry = 0;
|
|
983
|
-
|
|
1037
|
+
logger8.info("Authorization server metadata cache cleared", {
|
|
984
1038
|
code: "AUTH_CACHE_CLEARED"
|
|
985
1039
|
});
|
|
986
1040
|
}
|
|
@@ -997,23 +1051,43 @@ var AuthorizationServerDiscovery = class {
|
|
|
997
1051
|
return this.authServerUrl;
|
|
998
1052
|
}
|
|
999
1053
|
};
|
|
1000
|
-
var
|
|
1001
|
-
var TokenValidator = class {
|
|
1054
|
+
var logger9 = createModuleLogger("AUTH");
|
|
1055
|
+
var TokenValidator = class _TokenValidator {
|
|
1056
|
+
/** Default algorithms accepted when none are explicitly configured */
|
|
1057
|
+
static DEFAULT_ALGORITHMS = [
|
|
1058
|
+
"RS256",
|
|
1059
|
+
"RS384",
|
|
1060
|
+
"RS512",
|
|
1061
|
+
"ES256",
|
|
1062
|
+
"ES384",
|
|
1063
|
+
"ES512"
|
|
1064
|
+
];
|
|
1002
1065
|
/** Resolved configuration with all defaults applied */
|
|
1003
1066
|
jwksUri;
|
|
1004
1067
|
issuer;
|
|
1005
1068
|
audience;
|
|
1006
1069
|
clockTolerance;
|
|
1007
1070
|
jwksCacheTtl;
|
|
1071
|
+
algorithms;
|
|
1008
1072
|
jwks = null;
|
|
1009
1073
|
jwksExpiry = 0;
|
|
1010
1074
|
constructor(config) {
|
|
1075
|
+
if (config.jwksUri && !config.jwksUri.startsWith("https://") && process.env["ALLOW_HTTP_JWKS"] !== "true") {
|
|
1076
|
+
const url = new URL(config.jwksUri);
|
|
1077
|
+
const isLocalDev = url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
|
1078
|
+
if (!isLocalDev) {
|
|
1079
|
+
throw new Error(
|
|
1080
|
+
`Security: JWKS URI must use HTTPS in production. Got: ${config.jwksUri}. Set ALLOW_HTTP_JWKS=true to allow HTTP for local testing.`
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1011
1084
|
this.jwksUri = config.jwksUri;
|
|
1012
1085
|
this.issuer = config.issuer;
|
|
1013
1086
|
this.audience = config.audience;
|
|
1014
|
-
this.clockTolerance = config.clockTolerance ??
|
|
1087
|
+
this.clockTolerance = config.clockTolerance ?? 30;
|
|
1015
1088
|
this.jwksCacheTtl = config.jwksCacheTtl ?? 3600;
|
|
1016
|
-
|
|
1089
|
+
this.algorithms = config.algorithms ?? _TokenValidator.DEFAULT_ALGORITHMS;
|
|
1090
|
+
logger9.info(`Token Validator initialized for issuer: ${this.issuer}`, {
|
|
1017
1091
|
code: "AUTH_INIT"
|
|
1018
1092
|
});
|
|
1019
1093
|
}
|
|
@@ -1029,10 +1103,11 @@ var TokenValidator = class {
|
|
|
1029
1103
|
const { payload } = await jose.jwtVerify(token, jwks, {
|
|
1030
1104
|
issuer: this.issuer,
|
|
1031
1105
|
audience: this.audience,
|
|
1032
|
-
clockTolerance: this.clockTolerance
|
|
1106
|
+
clockTolerance: this.clockTolerance,
|
|
1107
|
+
algorithms: this.algorithms
|
|
1033
1108
|
});
|
|
1034
1109
|
const claims = this.extractClaims(payload);
|
|
1035
|
-
|
|
1110
|
+
logger9.info(`Token validated for subject: ${claims.sub}`, {
|
|
1036
1111
|
code: "AUTH_TOKEN_VALID",
|
|
1037
1112
|
sub: claims.sub,
|
|
1038
1113
|
scopes: claims.scopes.length,
|
|
@@ -1053,7 +1128,7 @@ var TokenValidator = class {
|
|
|
1053
1128
|
if (this.jwks && Date.now() < this.jwksExpiry) {
|
|
1054
1129
|
return this.jwks;
|
|
1055
1130
|
}
|
|
1056
|
-
|
|
1131
|
+
logger9.debug(`Fetching JWKS from: ${this.jwksUri}`, {
|
|
1057
1132
|
code: "AUTH_JWKS_FETCH"
|
|
1058
1133
|
});
|
|
1059
1134
|
try {
|
|
@@ -1063,13 +1138,13 @@ var TokenValidator = class {
|
|
|
1063
1138
|
cacheMaxAge: this.jwksCacheTtl * 1e3
|
|
1064
1139
|
});
|
|
1065
1140
|
this.jwksExpiry = Date.now() + this.jwksCacheTtl * 1e3;
|
|
1066
|
-
|
|
1141
|
+
logger9.info(`JWKS cached for ${String(this.jwksCacheTtl)}s`, {
|
|
1067
1142
|
code: "AUTH_JWKS_CACHED"
|
|
1068
1143
|
});
|
|
1069
1144
|
return this.jwks;
|
|
1070
1145
|
} catch (error) {
|
|
1071
1146
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
1072
|
-
|
|
1147
|
+
logger9.error(`Failed to fetch JWKS: ${this.jwksUri}`, {
|
|
1073
1148
|
code: ERROR_CODES.AUTH.JWKS_FETCH_FAILED.full,
|
|
1074
1149
|
error: cause
|
|
1075
1150
|
});
|
|
@@ -1092,18 +1167,25 @@ var TokenValidator = class {
|
|
|
1092
1167
|
(s) => typeof s === "string"
|
|
1093
1168
|
);
|
|
1094
1169
|
}
|
|
1170
|
+
const safePayload = {};
|
|
1171
|
+
for (const key of Object.keys(payload)) {
|
|
1172
|
+
if (key !== "__proto__" && key !== "constructor" && key !== "prototype" && key !== "valueOf" && key !== "toString" && key !== "hasOwnProperty") {
|
|
1173
|
+
safePayload[key] = payload[key];
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1095
1176
|
return {
|
|
1096
|
-
|
|
1177
|
+
// Include all other claims (prototype-polluting keys filtered above)
|
|
1178
|
+
...safePayload,
|
|
1179
|
+
// Explicitly set authoritative fields last to prevent override via safePayload
|
|
1180
|
+
sub: safePayload.sub ?? "unknown",
|
|
1097
1181
|
scopes,
|
|
1098
|
-
exp:
|
|
1099
|
-
iat:
|
|
1100
|
-
iss:
|
|
1101
|
-
aud:
|
|
1102
|
-
nbf:
|
|
1103
|
-
jti:
|
|
1104
|
-
client_id:
|
|
1105
|
-
// Include all other claims
|
|
1106
|
-
...payload
|
|
1182
|
+
exp: safePayload.exp ?? 0,
|
|
1183
|
+
iat: safePayload.iat ?? 0,
|
|
1184
|
+
iss: safePayload.iss,
|
|
1185
|
+
aud: safePayload.aud,
|
|
1186
|
+
nbf: safePayload.nbf ?? void 0,
|
|
1187
|
+
jti: safePayload.jti,
|
|
1188
|
+
client_id: safePayload["client_id"]
|
|
1107
1189
|
};
|
|
1108
1190
|
}
|
|
1109
1191
|
/**
|
|
@@ -1111,7 +1193,7 @@ var TokenValidator = class {
|
|
|
1111
1193
|
*/
|
|
1112
1194
|
handleValidationError(error) {
|
|
1113
1195
|
if (error instanceof jose.errors.JWTExpired) {
|
|
1114
|
-
|
|
1196
|
+
logger9.warning("Token has expired", {
|
|
1115
1197
|
code: ERROR_CODES.AUTH.TOKEN_EXPIRED.full,
|
|
1116
1198
|
error
|
|
1117
1199
|
});
|
|
@@ -1122,18 +1204,18 @@ var TokenValidator = class {
|
|
|
1122
1204
|
};
|
|
1123
1205
|
}
|
|
1124
1206
|
if (error instanceof jose.errors.JWTClaimValidationFailed) {
|
|
1125
|
-
|
|
1207
|
+
logger9.warning(`Token claim validation failed: ${error.message}`, {
|
|
1126
1208
|
code: ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
1127
1209
|
error
|
|
1128
1210
|
});
|
|
1129
1211
|
return {
|
|
1130
1212
|
valid: false,
|
|
1131
|
-
error:
|
|
1213
|
+
error: "Token claim validation failed",
|
|
1132
1214
|
errorCode: ERROR_CODES.AUTH.TOKEN_INVALID.full
|
|
1133
1215
|
};
|
|
1134
1216
|
}
|
|
1135
1217
|
if (error instanceof jose.errors.JWSSignatureVerificationFailed) {
|
|
1136
|
-
|
|
1218
|
+
logger9.warning("Token signature verification failed", {
|
|
1137
1219
|
code: ERROR_CODES.AUTH.SIGNATURE_INVALID.full,
|
|
1138
1220
|
error
|
|
1139
1221
|
});
|
|
@@ -1144,7 +1226,7 @@ var TokenValidator = class {
|
|
|
1144
1226
|
};
|
|
1145
1227
|
}
|
|
1146
1228
|
if (error instanceof jose.errors.JWKSNoMatchingKey) {
|
|
1147
|
-
|
|
1229
|
+
logger9.warning("No matching key found in JWKS", {
|
|
1148
1230
|
code: ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
1149
1231
|
error
|
|
1150
1232
|
});
|
|
@@ -1155,13 +1237,13 @@ var TokenValidator = class {
|
|
|
1155
1237
|
};
|
|
1156
1238
|
}
|
|
1157
1239
|
const message = error instanceof Error ? error.message : String(error);
|
|
1158
|
-
|
|
1240
|
+
logger9.error(`Token validation failed: ${message}`, {
|
|
1159
1241
|
code: ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
1160
1242
|
error: error instanceof Error ? error : void 0
|
|
1161
1243
|
});
|
|
1162
1244
|
return {
|
|
1163
1245
|
valid: false,
|
|
1164
|
-
error:
|
|
1246
|
+
error: "Token validation failed",
|
|
1165
1247
|
errorCode: ERROR_CODES.AUTH.TOKEN_INVALID.full
|
|
1166
1248
|
};
|
|
1167
1249
|
}
|
|
@@ -1172,7 +1254,7 @@ var TokenValidator = class {
|
|
|
1172
1254
|
this.jwks = null;
|
|
1173
1255
|
this.jwksExpiry = 0;
|
|
1174
1256
|
this.getJwks();
|
|
1175
|
-
|
|
1257
|
+
logger9.info("JWKS cache refreshed", { code: "AUTH_JWKS_REFRESHED" });
|
|
1176
1258
|
}
|
|
1177
1259
|
/**
|
|
1178
1260
|
* Clear the JWKS cache
|
|
@@ -1180,7 +1262,7 @@ var TokenValidator = class {
|
|
|
1180
1262
|
clearCache() {
|
|
1181
1263
|
this.jwks = null;
|
|
1182
1264
|
this.jwksExpiry = 0;
|
|
1183
|
-
|
|
1265
|
+
logger9.info("Token validator cache cleared", {
|
|
1184
1266
|
code: "AUTH_CACHE_CLEARED"
|
|
1185
1267
|
});
|
|
1186
1268
|
}
|
|
@@ -1199,8 +1281,15 @@ var TokenValidator = class {
|
|
|
1199
1281
|
};
|
|
1200
1282
|
|
|
1201
1283
|
// src/transports/http/oauth.ts
|
|
1202
|
-
var
|
|
1284
|
+
var logger10 = createModuleLogger("HTTP");
|
|
1203
1285
|
function applyAuthMiddleware(state) {
|
|
1286
|
+
const corsOrigins = state.config.corsOrigins ?? [];
|
|
1287
|
+
const isPubliclyExposed = state.config.oauth.enabled || state.config.noAuthEnforcement;
|
|
1288
|
+
if (corsOrigins.includes("*") && isPubliclyExposed) {
|
|
1289
|
+
throw new Error(
|
|
1290
|
+
"Security: CORS wildcard origin ('*') is forbidden when authentication is enabled or enforcement is explicitly disabled. Configure explicit origins via --cors-origins for production deployments."
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1204
1293
|
if (state.config.oauth.enabled && state.tokenValidator && state.resourceServer && state.app) {
|
|
1205
1294
|
const authMiddleware = createAuthMiddleware({
|
|
1206
1295
|
tokenValidator: state.tokenValidator,
|
|
@@ -1208,56 +1297,148 @@ function applyAuthMiddleware(state) {
|
|
|
1208
1297
|
publicPaths: ["/health", ...state.config.oauth.publicPaths ?? []]
|
|
1209
1298
|
});
|
|
1210
1299
|
state.app.use(authMiddleware);
|
|
1211
|
-
} else if (state.config.authToken && state.app) {
|
|
1212
|
-
state.app.use(createSimpleBearerAuth(state.config.authToken));
|
|
1213
|
-
logger7.info("Simple bearer token authentication enabled", {
|
|
1214
|
-
code: "AUTH_BEARER_ENABLED"
|
|
1215
|
-
});
|
|
1216
1300
|
} else if (state.app) {
|
|
1217
|
-
|
|
1218
|
-
"No authentication configured for HTTP transport. Set --
|
|
1301
|
+
logger10.warning(
|
|
1302
|
+
"No authentication configured for HTTP transport. Set --oauth-enabled for production deployments.",
|
|
1219
1303
|
{ code: "AUTH_NONE" }
|
|
1220
1304
|
);
|
|
1221
1305
|
}
|
|
1222
1306
|
}
|
|
1223
|
-
function
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1307
|
+
function applyScopeEnforcementMiddleware(state) {
|
|
1308
|
+
if (!state.app) return;
|
|
1309
|
+
state.app.use((req, res, next) => {
|
|
1310
|
+
const body = req.body;
|
|
1311
|
+
if (req.method !== "POST") {
|
|
1227
1312
|
next();
|
|
1228
1313
|
return;
|
|
1229
1314
|
}
|
|
1230
|
-
const
|
|
1231
|
-
if (
|
|
1232
|
-
res.status(
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
error: "unauthorized",
|
|
1236
|
-
error_description: "Bearer token required"
|
|
1315
|
+
const contentType = req.headers["content-type"]?.split(";")[0]?.trim();
|
|
1316
|
+
if (contentType !== "application/json") {
|
|
1317
|
+
res.status(400).json({
|
|
1318
|
+
error: "invalid_request",
|
|
1319
|
+
error_description: "Content-Type must be exactly application/json"
|
|
1237
1320
|
});
|
|
1238
1321
|
return;
|
|
1239
1322
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
});
|
|
1245
|
-
res.status(401);
|
|
1246
|
-
res.setHeader(
|
|
1247
|
-
"WWW-Authenticate",
|
|
1248
|
-
'Bearer realm="db-mcp", error="invalid_token"'
|
|
1249
|
-
);
|
|
1250
|
-
res.json({
|
|
1251
|
-
error: "unauthorized",
|
|
1252
|
-
error_description: "Invalid bearer token"
|
|
1323
|
+
if (Array.isArray(body)) {
|
|
1324
|
+
res.status(400).json({
|
|
1325
|
+
error: "invalid_request",
|
|
1326
|
+
error_description: "Batch JSON-RPC requests are not supported"
|
|
1253
1327
|
});
|
|
1254
1328
|
return;
|
|
1255
1329
|
}
|
|
1330
|
+
if (!req.auth) {
|
|
1331
|
+
next();
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
const rpcMethod = body?.method;
|
|
1335
|
+
if (rpcMethod === "tools/list") {
|
|
1336
|
+
const originalJson = res.json;
|
|
1337
|
+
const scopes = req.auth.scopes;
|
|
1338
|
+
const isRecord = (val) => typeof val === "object" && val !== null && !Array.isArray(val);
|
|
1339
|
+
res.json = function(data) {
|
|
1340
|
+
if (isRecord(data) && isRecord(data["result"]) && Array.isArray(data["result"]["tools"])) {
|
|
1341
|
+
data["result"]["tools"] = data["result"]["tools"].filter(
|
|
1342
|
+
(tool) => {
|
|
1343
|
+
if (isRecord(tool) && typeof tool["name"] === "string") {
|
|
1344
|
+
return scopesGrantToolAccess(scopes, tool["name"]);
|
|
1345
|
+
}
|
|
1346
|
+
return false;
|
|
1347
|
+
}
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
return originalJson.call(this, data);
|
|
1351
|
+
};
|
|
1352
|
+
next();
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
if (rpcMethod === "tools/call") {
|
|
1356
|
+
const toolName = body?.params?.name;
|
|
1357
|
+
if (!toolName) {
|
|
1358
|
+
next();
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
const hasAccess = scopesGrantToolAccess(req.auth.scopes, toolName);
|
|
1362
|
+
if (!hasAccess) {
|
|
1363
|
+
const error = new InsufficientScopeError(
|
|
1364
|
+
`Tool access: ${toolName}`,
|
|
1365
|
+
req.auth.scopes
|
|
1366
|
+
);
|
|
1367
|
+
logger10.warning(`Insufficient scope for tool: ${toolName}`, {
|
|
1368
|
+
code: ERROR_CODES.AUTH.SCOPE_DENIED.full,
|
|
1369
|
+
toolName,
|
|
1370
|
+
providedScopes: req.auth.scopes
|
|
1371
|
+
});
|
|
1372
|
+
res.status(error.httpStatus);
|
|
1373
|
+
if (error.wwwAuthenticate) {
|
|
1374
|
+
res.setHeader("WWW-Authenticate", error.wwwAuthenticate);
|
|
1375
|
+
}
|
|
1376
|
+
res.json({
|
|
1377
|
+
error: "insufficient_scope",
|
|
1378
|
+
error_description: `Access to tool '${toolName}' denied`,
|
|
1379
|
+
tool: toolName
|
|
1380
|
+
});
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
} else if (rpcMethod === "resources/read") {
|
|
1384
|
+
const resourceUri = body?.params?.uri ?? "";
|
|
1385
|
+
const requiredScope = resourceUri.startsWith("sqlite://audit") ? "admin" : "read";
|
|
1386
|
+
const hasAccess = requiredScope === "admin" ? hasAdminScope(req.auth.scopes) : hasReadScope(req.auth.scopes);
|
|
1387
|
+
if (!hasAccess) {
|
|
1388
|
+
const error = new InsufficientScopeError(
|
|
1389
|
+
`Resource access: ${resourceUri}`,
|
|
1390
|
+
req.auth.scopes
|
|
1391
|
+
);
|
|
1392
|
+
logger10.warning(`Insufficient scope for resource: ${resourceUri}`, {
|
|
1393
|
+
code: ERROR_CODES.AUTH.SCOPE_DENIED.full,
|
|
1394
|
+
resourceUri,
|
|
1395
|
+
requiredScope,
|
|
1396
|
+
providedScopes: req.auth.scopes
|
|
1397
|
+
});
|
|
1398
|
+
res.status(error.httpStatus);
|
|
1399
|
+
if (error.wwwAuthenticate) {
|
|
1400
|
+
res.setHeader("WWW-Authenticate", error.wwwAuthenticate);
|
|
1401
|
+
}
|
|
1402
|
+
res.json({
|
|
1403
|
+
error: "insufficient_scope",
|
|
1404
|
+
error_description: `Access to resource '${resourceUri}' requires '${requiredScope}' scope`
|
|
1405
|
+
});
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
} else if (rpcMethod === "prompts/get") {
|
|
1409
|
+
const hasAccess = hasReadScope(req.auth.scopes);
|
|
1410
|
+
if (!hasAccess) {
|
|
1411
|
+
const promptName = body?.params?.name ?? "unknown";
|
|
1412
|
+
const error = new InsufficientScopeError(
|
|
1413
|
+
`Prompt access: ${promptName}`,
|
|
1414
|
+
req.auth.scopes
|
|
1415
|
+
);
|
|
1416
|
+
logger10.warning(`Insufficient scope for prompt: ${promptName}`, {
|
|
1417
|
+
code: ERROR_CODES.AUTH.SCOPE_DENIED.full,
|
|
1418
|
+
promptName,
|
|
1419
|
+
providedScopes: req.auth.scopes
|
|
1420
|
+
});
|
|
1421
|
+
res.status(error.httpStatus);
|
|
1422
|
+
if (error.wwwAuthenticate) {
|
|
1423
|
+
res.setHeader("WWW-Authenticate", error.wwwAuthenticate);
|
|
1424
|
+
}
|
|
1425
|
+
res.json({
|
|
1426
|
+
error: "insufficient_scope",
|
|
1427
|
+
error_description: `Access to prompt '${promptName}' requires 'read' scope`
|
|
1428
|
+
});
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1256
1432
|
next();
|
|
1257
|
-
};
|
|
1433
|
+
});
|
|
1258
1434
|
}
|
|
1259
1435
|
async function setupOAuth(state, resourceUri) {
|
|
1260
|
-
|
|
1436
|
+
logger10.info("Setting up OAuth 2.1...", { code: "HTTP_OAUTH_SETUP" });
|
|
1437
|
+
if (state.config.oauth.enabled && !state.config.oauth.audience) {
|
|
1438
|
+
throw new Error(
|
|
1439
|
+
"Security: OAuth audience must be explicitly configured when OAuth is enabled."
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1261
1442
|
state.resourceServer = new OAuthResourceServer({
|
|
1262
1443
|
resource: resourceUri,
|
|
1263
1444
|
authorizationServers: [state.config.oauth.authorizationServerUrl],
|
|
@@ -1278,25 +1459,25 @@ async function setupOAuth(state, resourceUri) {
|
|
|
1278
1459
|
audience: state.config.oauth.audience,
|
|
1279
1460
|
clockTolerance: state.config.oauth.clockTolerance
|
|
1280
1461
|
});
|
|
1281
|
-
|
|
1462
|
+
logger10.info("OAuth 2.1 setup complete", { code: "HTTP_OAUTH_READY" });
|
|
1282
1463
|
} catch (error) {
|
|
1283
|
-
|
|
1464
|
+
logger10.warning(
|
|
1284
1465
|
"Authorization server discovery failed. OAuth validation disabled.",
|
|
1285
1466
|
{
|
|
1286
1467
|
code: ERROR_CODES.AUTH.DISCOVERY_FAILED.full,
|
|
1287
1468
|
error: error instanceof Error ? error : void 0
|
|
1288
1469
|
}
|
|
1289
1470
|
);
|
|
1290
|
-
if (!state.config.oauth.jwksUri) {
|
|
1291
|
-
|
|
1292
|
-
"
|
|
1471
|
+
if (!state.config.oauth.jwksUri || !state.config.oauth.issuer) {
|
|
1472
|
+
logger10.error(
|
|
1473
|
+
"OAuth discovery failed and explicit jwksUri/issuer were not provided. Hard failing to prevent spoofed token acceptance.",
|
|
1293
1474
|
{ code: ERROR_CODES.AUTH.DISCOVERY_FAILED.full }
|
|
1294
1475
|
);
|
|
1295
1476
|
throw error;
|
|
1296
1477
|
}
|
|
1297
1478
|
state.tokenValidator = new TokenValidator({
|
|
1298
1479
|
jwksUri: state.config.oauth.jwksUri,
|
|
1299
|
-
issuer: state.config.oauth.issuer
|
|
1480
|
+
issuer: state.config.oauth.issuer,
|
|
1300
1481
|
audience: state.config.oauth.audience,
|
|
1301
1482
|
clockTolerance: state.config.oauth.clockTolerance
|
|
1302
1483
|
});
|
|
@@ -1304,7 +1485,7 @@ async function setupOAuth(state, resourceUri) {
|
|
|
1304
1485
|
}
|
|
1305
1486
|
|
|
1306
1487
|
// src/transports/http/transport.ts
|
|
1307
|
-
var
|
|
1488
|
+
var logger11 = createModuleLogger("HTTP");
|
|
1308
1489
|
var HttpTransport = class {
|
|
1309
1490
|
/** Internal state shared with session/middleware/oauth modules */
|
|
1310
1491
|
state;
|
|
@@ -1312,7 +1493,7 @@ var HttpTransport = class {
|
|
|
1312
1493
|
this.state = {
|
|
1313
1494
|
config: {
|
|
1314
1495
|
...config,
|
|
1315
|
-
host: config.host ?? "
|
|
1496
|
+
host: config.host ?? "127.0.0.1",
|
|
1316
1497
|
stateless: config.stateless ?? false,
|
|
1317
1498
|
enableHSTS: config.enableHSTS ?? process.env["MCP_ENABLE_HSTS"] === "true"
|
|
1318
1499
|
},
|
|
@@ -1320,13 +1501,12 @@ var HttpTransport = class {
|
|
|
1320
1501
|
httpServer: null,
|
|
1321
1502
|
transports: /* @__PURE__ */ new Map(),
|
|
1322
1503
|
sseTransports: /* @__PURE__ */ new Map(),
|
|
1504
|
+
sessionOwners: /* @__PURE__ */ new Map(),
|
|
1323
1505
|
statelessTransport: null,
|
|
1324
1506
|
resourceServer: null,
|
|
1325
1507
|
authServerDiscovery: null,
|
|
1326
1508
|
tokenValidator: null,
|
|
1327
|
-
mcpServer: null
|
|
1328
|
-
rateLimitMap: /* @__PURE__ */ new Map(),
|
|
1329
|
-
rateLimitCleanupTimer: null
|
|
1509
|
+
mcpServer: null
|
|
1330
1510
|
};
|
|
1331
1511
|
}
|
|
1332
1512
|
/**
|
|
@@ -1338,13 +1518,25 @@ var HttpTransport = class {
|
|
|
1338
1518
|
* @param server - The MCP server instance
|
|
1339
1519
|
*/
|
|
1340
1520
|
async initialize(server) {
|
|
1341
|
-
|
|
1521
|
+
logger11.info("Initializing HTTP transport...", {
|
|
1342
1522
|
code: "HTTP_INIT",
|
|
1343
1523
|
stateless: this.state.config.stateless
|
|
1344
1524
|
});
|
|
1345
1525
|
this.state.mcpServer = server;
|
|
1346
1526
|
this.state.app = express();
|
|
1347
1527
|
this.state.app.use(localhostHostValidation());
|
|
1528
|
+
if (this.state.config.trustedProxyIps !== void 0) {
|
|
1529
|
+
if (Array.isArray(this.state.config.trustedProxyIps) && this.state.config.trustedProxyIps.length === 0) {
|
|
1530
|
+
throw new DbMcpError(
|
|
1531
|
+
"trustedProxyIps cannot be an empty array if specified",
|
|
1532
|
+
"CONFIG_ERROR",
|
|
1533
|
+
"config" /* CONFIGURATION */
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
this.state.app.set("trust proxy", this.state.config.trustedProxyIps);
|
|
1537
|
+
} else {
|
|
1538
|
+
this.state.app.set("trust proxy", false);
|
|
1539
|
+
}
|
|
1348
1540
|
setupSecurityHeaders(this.state);
|
|
1349
1541
|
setupCors(this.state);
|
|
1350
1542
|
setupRateLimiting(this.state);
|
|
@@ -1353,17 +1545,32 @@ var HttpTransport = class {
|
|
|
1353
1545
|
express.json({ limit: maxBodyBytes })
|
|
1354
1546
|
);
|
|
1355
1547
|
const resourceUri = this.state.config.resourceUri ?? `http://localhost:${String(this.state.config.port)}`;
|
|
1548
|
+
if (!this.state.config.oauth.enabled && !this.state.config.noAuthEnforcement) {
|
|
1549
|
+
throw new DbMcpError(
|
|
1550
|
+
"HTTP transport is enabled without authentication. You must configure OAuth (--oauth-enabled) or explicitly bypass this check with --no-auth-enforcement.",
|
|
1551
|
+
"AUTH_REQUIRED",
|
|
1552
|
+
"config" /* CONFIGURATION */
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1356
1555
|
if (this.state.config.oauth.enabled) {
|
|
1556
|
+
if (resourceUri.startsWith("http://") && !resourceUri.includes("localhost") && !resourceUri.includes("127.0.0.1")) {
|
|
1557
|
+
logger11.warning(
|
|
1558
|
+
"Security Warning (F09): OAuth is enabled but resource URI is not using HTTPS. A TLS-terminating reverse proxy is required in production."
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1357
1561
|
await setupOAuth(this.state, resourceUri);
|
|
1358
1562
|
}
|
|
1359
|
-
this.state.app.get("/health", (
|
|
1360
|
-
|
|
1563
|
+
this.state.app.get("/health", (req, res) => {
|
|
1564
|
+
const response = {
|
|
1361
1565
|
status: "healthy",
|
|
1362
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1566
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1567
|
+
};
|
|
1568
|
+
if (req.auth) {
|
|
1569
|
+
response["oauth"] = this.state.config.oauth.enabled;
|
|
1570
|
+
response["mode"] = this.state.config.stateless ? "stateless" : "stateful";
|
|
1571
|
+
response["activeSessions"] = this.state.transports.size;
|
|
1572
|
+
}
|
|
1573
|
+
res.json(response);
|
|
1367
1574
|
});
|
|
1368
1575
|
this.state.app.get("/", (_req, res) => {
|
|
1369
1576
|
res.json({
|
|
@@ -1382,6 +1589,31 @@ var HttpTransport = class {
|
|
|
1382
1589
|
});
|
|
1383
1590
|
});
|
|
1384
1591
|
applyAuthMiddleware(this.state);
|
|
1592
|
+
applyScopeEnforcementMiddleware(this.state);
|
|
1593
|
+
const oauthEnabled = this.state.config.oauth?.enabled ?? false;
|
|
1594
|
+
let lastNoAuthWarning = 0;
|
|
1595
|
+
this.state.app.use((req, _res, next) => {
|
|
1596
|
+
const implicitAdmin = !req.auth && !oauthEnabled;
|
|
1597
|
+
if (implicitAdmin) {
|
|
1598
|
+
const now = Date.now();
|
|
1599
|
+
if (now - lastNoAuthWarning > 6e4) {
|
|
1600
|
+
logger11.warning(
|
|
1601
|
+
"No-auth mode is granting implicit 'admin' scope. This is expected for local dev but dangerous in production.",
|
|
1602
|
+
{ module: "HTTP", ip: req.ip }
|
|
1603
|
+
);
|
|
1604
|
+
lastNoAuthWarning = now;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
const authCtx = {
|
|
1608
|
+
authenticated: !!req.auth || !oauthEnabled,
|
|
1609
|
+
claims: req.auth,
|
|
1610
|
+
scopes: req.auth?.scopes ?? (implicitAdmin ? ["admin"] : []),
|
|
1611
|
+
clientIp: req.ip
|
|
1612
|
+
};
|
|
1613
|
+
runWithAuthContext(authCtx, () => {
|
|
1614
|
+
next();
|
|
1615
|
+
});
|
|
1616
|
+
});
|
|
1385
1617
|
if (this.state.config.stateless) {
|
|
1386
1618
|
await setupStatelessEndpoints(this.state);
|
|
1387
1619
|
} else {
|
|
@@ -1394,7 +1626,7 @@ var HttpTransport = class {
|
|
|
1394
1626
|
this.state.app.use((_req, res) => {
|
|
1395
1627
|
res.status(404).json({ error: "Not found" });
|
|
1396
1628
|
});
|
|
1397
|
-
|
|
1629
|
+
logger11.info("HTTP transport initialized", {
|
|
1398
1630
|
code: "HTTP_INIT_COMPLETE",
|
|
1399
1631
|
port: this.state.config.port,
|
|
1400
1632
|
oauth: this.state.config.oauth.enabled,
|
|
@@ -1417,15 +1649,15 @@ var HttpTransport = class {
|
|
|
1417
1649
|
try {
|
|
1418
1650
|
this.state.httpServer = this.state.app?.listen(
|
|
1419
1651
|
this.state.config.port,
|
|
1420
|
-
this.state.config.host ?? "
|
|
1652
|
+
this.state.config.host ?? "127.0.0.1",
|
|
1421
1653
|
() => {
|
|
1422
1654
|
if (this.state.httpServer) {
|
|
1423
1655
|
this.state.httpServer.setTimeout(HTTP_REQUEST_TIMEOUT_MS);
|
|
1424
1656
|
this.state.httpServer.keepAliveTimeout = HTTP_KEEP_ALIVE_TIMEOUT_MS;
|
|
1425
1657
|
this.state.httpServer.headersTimeout = HTTP_HEADERS_TIMEOUT_MS;
|
|
1426
1658
|
}
|
|
1427
|
-
|
|
1428
|
-
`HTTP server listening on ${this.state.config.host ?? "
|
|
1659
|
+
logger11.info(
|
|
1660
|
+
`HTTP server listening on ${this.state.config.host ?? "127.0.0.1"}:${String(this.state.config.port)}`,
|
|
1429
1661
|
{
|
|
1430
1662
|
code: "HTTP_SERVER_STARTED",
|
|
1431
1663
|
mode: this.state.config.stateless ? "stateless" : "stateful"
|
|
@@ -1435,7 +1667,7 @@ var HttpTransport = class {
|
|
|
1435
1667
|
}
|
|
1436
1668
|
) ?? null;
|
|
1437
1669
|
this.state.httpServer?.on("error", (error) => {
|
|
1438
|
-
|
|
1670
|
+
logger11.error("Failed to start HTTP server", {
|
|
1439
1671
|
code: ERROR_CODES.SERVER.START_FAILED.full,
|
|
1440
1672
|
error
|
|
1441
1673
|
});
|
|
@@ -1450,19 +1682,15 @@ var HttpTransport = class {
|
|
|
1450
1682
|
* Stop the server and close all active sessions
|
|
1451
1683
|
*/
|
|
1452
1684
|
async stop() {
|
|
1453
|
-
if (this.state.rateLimitCleanupTimer) {
|
|
1454
|
-
clearInterval(this.state.rateLimitCleanupTimer);
|
|
1455
|
-
this.state.rateLimitCleanupTimer = null;
|
|
1456
|
-
}
|
|
1457
1685
|
for (const [sessionId, transport] of this.state.transports) {
|
|
1458
1686
|
try {
|
|
1459
|
-
|
|
1687
|
+
logger11.debug("Closing transport", {
|
|
1460
1688
|
code: "HTTP_SESSION_CLEANUP",
|
|
1461
1689
|
sessionId
|
|
1462
1690
|
});
|
|
1463
1691
|
await transport.close();
|
|
1464
1692
|
} catch (error) {
|
|
1465
|
-
|
|
1693
|
+
logger11.error("Error closing transport", {
|
|
1466
1694
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1467
1695
|
sessionId,
|
|
1468
1696
|
error: error instanceof Error ? error : void 0
|
|
@@ -1470,15 +1698,16 @@ var HttpTransport = class {
|
|
|
1470
1698
|
}
|
|
1471
1699
|
}
|
|
1472
1700
|
this.state.transports.clear();
|
|
1701
|
+
this.state.sessionOwners.clear();
|
|
1473
1702
|
for (const [sessionId, transport] of this.state.sseTransports) {
|
|
1474
1703
|
try {
|
|
1475
|
-
|
|
1704
|
+
logger11.debug("Closing SSE transport", {
|
|
1476
1705
|
code: "SSE_SESSION_CLEANUP",
|
|
1477
1706
|
sessionId
|
|
1478
1707
|
});
|
|
1479
1708
|
await transport.close();
|
|
1480
1709
|
} catch (error) {
|
|
1481
|
-
|
|
1710
|
+
logger11.error("Error closing SSE transport", {
|
|
1482
1711
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1483
1712
|
sessionId,
|
|
1484
1713
|
error: error instanceof Error ? error : void 0
|
|
@@ -1490,7 +1719,7 @@ var HttpTransport = class {
|
|
|
1490
1719
|
try {
|
|
1491
1720
|
await this.state.statelessTransport.close();
|
|
1492
1721
|
} catch (error) {
|
|
1493
|
-
|
|
1722
|
+
logger11.error("Error closing stateless transport", {
|
|
1494
1723
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1495
1724
|
error: error instanceof Error ? error : void 0
|
|
1496
1725
|
});
|
|
@@ -1503,13 +1732,13 @@ var HttpTransport = class {
|
|
|
1503
1732
|
}
|
|
1504
1733
|
this.state.httpServer.close((error) => {
|
|
1505
1734
|
if (error) {
|
|
1506
|
-
|
|
1735
|
+
logger11.error("Error stopping HTTP server", {
|
|
1507
1736
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1508
1737
|
error
|
|
1509
1738
|
});
|
|
1510
1739
|
reject(error);
|
|
1511
1740
|
} else {
|
|
1512
|
-
|
|
1741
|
+
logger11.info("HTTP server stopped", { code: "HTTP_SERVER_STOPPED" });
|
|
1513
1742
|
resolve();
|
|
1514
1743
|
}
|
|
1515
1744
|
});
|