db-mcp 2.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -91
- 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-WBER5YY4.js → chunk-37G4DLL6.js} +1010 -409
- package/dist/chunk-E5IESRTK.js +489 -0
- package/dist/{chunk-645ZEFLA.js → chunk-L552U3QS.js} +887 -309
- package/dist/{chunk-5Y42NPBP.js → chunk-NV34JSQM.js} +4656 -1829
- package/dist/{chunk-Z7C2TM4L.js → chunk-W5WQVNVX.js} +169 -57
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +47 -26
- 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-6KF4ULDI.js → http-HWTUVFIA.js} +498 -391
- package/dist/index.d.ts +9 -1065
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -6
- 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-U5KSYQXK.js → sqlite-TB56Z7G3.js} +61 -17
- package/dist/{sqlite-native-JXMCFQBA.js → sqlite-native-IF75BB3O.js} +459 -254
- 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 +26 -13
- package/.gitattributes +0 -2
- package/.gitleaks.toml +0 -9
- package/.trivyignore +0 -8
- package/dist/chunk-OKOVZ5QE.js +0 -28
- package/dist/chunk-SFJQCNG7.js +0 -131
- package/dist/chunk-VIDSICEL.js +0 -85
- package/dist/chunk-X3MUUOWM.js +0 -152
- package/dist/worker-script.d.ts +0 -2
- package/dist/worker-script.js +0 -150
- package/logs/.gitkeep +0 -1
- package/mcp-config-example.json +0 -83
- package/playwright.config.ts +0 -101
- package/scripts/generate-server-instructions.ts +0 -111
- package/scripts/update-badges.ts +0 -99
- package/server.json +0 -54
- package/test-server/README.md +0 -115
- package/test-server/code-map.md +0 -421
- package/test-server/fixtures/sample.csv +0 -6
- package/test-server/reset-database.ps1 +0 -415
- package/test-server/sample.csv +0 -11
- package/test-server/scripts/README.md +0 -27
- package/test-server/scripts/test-help-resources.mjs +0 -245
- package/test-server/scripts/test-prompts.mjs +0 -251
- package/test-server/scripts/test-tool-annotations.mjs +0 -162
- package/test-server/test-advanced/README.md +0 -70
- package/test-server/test-advanced/test-codemode-advanced-admin.md +0 -174
- package/test-server/test-advanced/test-codemode-advanced-core.md +0 -193
- package/test-server/test-advanced/test-codemode-advanced-geo.md +0 -157
- package/test-server/test-advanced/test-codemode-advanced-introspection.md +0 -171
- package/test-server/test-advanced/test-codemode-advanced-json.md +0 -169
- package/test-server/test-advanced/test-codemode-advanced-migration.md +0 -160
- package/test-server/test-advanced/test-codemode-advanced-stats.md +0 -185
- package/test-server/test-advanced/test-codemode-advanced-text.md +0 -183
- package/test-server/test-advanced/test-codemode-advanced-transactions.md +0 -136
- package/test-server/test-advanced/test-codemode-advanced-vector.md +0 -141
- package/test-server/test-codemode/README.md +0 -121
- package/test-server/test-codemode/test-codemode-admin.md +0 -223
- package/test-server/test-codemode/test-codemode-core.md +0 -286
- package/test-server/test-codemode/test-codemode-geo.md +0 -177
- package/test-server/test-codemode/test-codemode-introspection.md +0 -190
- package/test-server/test-codemode/test-codemode-json.md +0 -237
- package/test-server/test-codemode/test-codemode-migration.md +0 -278
- package/test-server/test-codemode/test-codemode-sandbox.md +0 -413
- package/test-server/test-codemode/test-codemode-stats.md +0 -232
- package/test-server/test-codemode/test-codemode-text.md +0 -237
- package/test-server/test-codemode/test-codemode-transactions.md +0 -236
- package/test-server/test-codemode/test-codemode-vector.md +0 -244
- package/test-server/test-codemode/test-codemode-wasm-degradation.md +0 -394
- package/test-server/test-database.sql +0 -424
- package/test-server/test-preflight.md +0 -53
- package/test-server/test-prompts.md +0 -354
- package/test-server/test-resources.md +0 -272
- package/test-server/test-tool-groups/README.md +0 -100
- package/test-server/test-tool-groups/test-admin-core.md +0 -165
- package/test-server/test-tool-groups/test-admin-extensions.md +0 -133
- package/test-server/test-tool-groups/test-core-data.md +0 -262
- package/test-server/test-tool-groups/test-core-schema.md +0 -240
- package/test-server/test-tool-groups/test-geo-haversine.md +0 -130
- package/test-server/test-tool-groups/test-geo-spatialite.md +0 -110
- package/test-server/test-tool-groups/test-introspection-diagnostics.md +0 -123
- package/test-server/test-tool-groups/test-introspection-schema.md +0 -133
- package/test-server/test-tool-groups/test-json-read.md +0 -219
- package/test-server/test-tool-groups/test-json-write.md +0 -157
- package/test-server/test-tool-groups/test-migration.md +0 -193
- package/test-server/test-tool-groups/test-stats-advanced.md +0 -118
- package/test-server/test-tool-groups/test-stats-basic.md +0 -156
- package/test-server/test-tool-groups/test-text-advanced.md +0 -169
- package/test-server/test-tool-groups/test-text-basic.md +0 -177
- package/test-server/test-tool-groups/test-transactions.md +0 -179
- package/test-server/test-tool-groups/test-vector-read.md +0 -130
- package/test-server/test-tool-groups/test-vector-write.md +0 -115
- package/test-server/tool-reference.md +0 -257
- package/tsconfig.build.json +0 -6
- package/tsconfig.test.json +0 -9
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { runWithAuthContext, SUPPORTED_SCOPES, scopesGrantToolAccess, BASE_SCOPES,
|
|
2
|
-
import './chunk-X3MUUOWM.js';
|
|
3
|
-
import { createModuleLogger, DbMcpError, ERROR_CODES } from './chunk-645ZEFLA.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';
|
|
4
2
|
import express from 'express';
|
|
5
3
|
import { localhostHostValidation } from '@modelcontextprotocol/sdk/server/middleware/hostHeaderValidation.js';
|
|
6
4
|
import cors from 'cors';
|
|
7
|
-
import
|
|
5
|
+
import rateLimit from 'express-rate-limit';
|
|
6
|
+
import RedisStore from 'rate-limit-redis';
|
|
7
|
+
import { createClient } from 'redis';
|
|
8
8
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
9
|
-
import {
|
|
9
|
+
import { randomUUID } from 'crypto';
|
|
10
10
|
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
11
12
|
import * as jose from 'jose';
|
|
12
13
|
|
|
13
14
|
// src/auth/middleware/extraction.ts
|
|
@@ -28,115 +29,8 @@ function extractBearerToken(authHeader) {
|
|
|
28
29
|
return token.length > 0 ? token : null;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
// src/auth/errors.ts
|
|
32
|
-
var OAuthError = class extends DbMcpError {
|
|
33
|
-
/** HTTP status code for this error */
|
|
34
|
-
httpStatus;
|
|
35
|
-
/** WWW-Authenticate header value */
|
|
36
|
-
wwwAuthenticate;
|
|
37
|
-
constructor(message, code, httpStatus, details, wwwAuthenticate) {
|
|
38
|
-
super(message, code, "authentication" /* AUTHENTICATION */, { details });
|
|
39
|
-
this.name = "OAuthError";
|
|
40
|
-
this.httpStatus = httpStatus;
|
|
41
|
-
this.wwwAuthenticate = wwwAuthenticate;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
var TokenMissingError = class extends OAuthError {
|
|
45
|
-
constructor(realm = "db-mcp") {
|
|
46
|
-
super(
|
|
47
|
-
"No access token provided",
|
|
48
|
-
ERROR_CODES.AUTH.TOKEN_MISSING.full,
|
|
49
|
-
401,
|
|
50
|
-
void 0,
|
|
51
|
-
`Bearer realm="${realm}"`
|
|
52
|
-
);
|
|
53
|
-
this.name = "TokenMissingError";
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
var InvalidTokenError = class extends OAuthError {
|
|
57
|
-
constructor(message = "Invalid access token", details) {
|
|
58
|
-
super(
|
|
59
|
-
message,
|
|
60
|
-
ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
61
|
-
401,
|
|
62
|
-
details,
|
|
63
|
-
'Bearer error="invalid_token"'
|
|
64
|
-
);
|
|
65
|
-
this.name = "InvalidTokenError";
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
var TokenExpiredError = class extends OAuthError {
|
|
69
|
-
constructor(expiredAt) {
|
|
70
|
-
super(
|
|
71
|
-
"Access token has expired",
|
|
72
|
-
ERROR_CODES.AUTH.TOKEN_EXPIRED.full,
|
|
73
|
-
401,
|
|
74
|
-
expiredAt ? { expiredAt: expiredAt.toISOString() } : void 0,
|
|
75
|
-
'Bearer error="invalid_token", error_description="Token has expired"'
|
|
76
|
-
);
|
|
77
|
-
this.name = "TokenExpiredError";
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
var InvalidSignatureError = class extends OAuthError {
|
|
81
|
-
constructor(message = "Token signature verification failed") {
|
|
82
|
-
super(
|
|
83
|
-
message,
|
|
84
|
-
ERROR_CODES.AUTH.SIGNATURE_INVALID.full,
|
|
85
|
-
401,
|
|
86
|
-
void 0,
|
|
87
|
-
'Bearer error="invalid_token", error_description="Signature verification failed"'
|
|
88
|
-
);
|
|
89
|
-
this.name = "InvalidSignatureError";
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
var InsufficientScopeError = class extends OAuthError {
|
|
93
|
-
constructor(requiredScope, providedScopes) {
|
|
94
|
-
const required = Array.isArray(requiredScope) ? requiredScope : [requiredScope];
|
|
95
|
-
const scopeValue = required.join(" ");
|
|
96
|
-
super(
|
|
97
|
-
`Insufficient scope. Required: ${scopeValue}`,
|
|
98
|
-
ERROR_CODES.AUTH.SCOPE_DENIED.full,
|
|
99
|
-
403,
|
|
100
|
-
{ requiredScope: required, providedScopes },
|
|
101
|
-
`Bearer error="insufficient_scope", scope="${scopeValue}"`
|
|
102
|
-
);
|
|
103
|
-
this.name = "InsufficientScopeError";
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
var AuthServerDiscoveryError = class extends OAuthError {
|
|
107
|
-
constructor(serverUrl, cause) {
|
|
108
|
-
super(
|
|
109
|
-
`Failed to discover authorization server metadata: ${serverUrl}`,
|
|
110
|
-
ERROR_CODES.AUTH.DISCOVERY_FAILED.full,
|
|
111
|
-
500,
|
|
112
|
-
{
|
|
113
|
-
serverUrl,
|
|
114
|
-
cause: cause?.message
|
|
115
|
-
}
|
|
116
|
-
);
|
|
117
|
-
this.name = "AuthServerDiscoveryError";
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
var JwksFetchError = class extends OAuthError {
|
|
121
|
-
constructor(jwksUri, cause) {
|
|
122
|
-
super(
|
|
123
|
-
`Failed to fetch JWKS: ${jwksUri}`,
|
|
124
|
-
ERROR_CODES.AUTH.JWKS_FETCH_FAILED.full,
|
|
125
|
-
500,
|
|
126
|
-
{
|
|
127
|
-
jwksUri,
|
|
128
|
-
cause: cause?.message
|
|
129
|
-
}
|
|
130
|
-
);
|
|
131
|
-
this.name = "JwksFetchError";
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
function isOAuthError(error) {
|
|
135
|
-
return error instanceof OAuthError;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
32
|
// src/auth/middleware/express-auth.ts
|
|
139
|
-
var
|
|
33
|
+
var logger2 = createModuleLogger("AUTH");
|
|
140
34
|
function isPublicPath(path, publicPaths) {
|
|
141
35
|
if (path.startsWith("/.well-known/")) {
|
|
142
36
|
return true;
|
|
@@ -159,8 +53,9 @@ function createAuthMiddleware(config) {
|
|
|
159
53
|
return async (req, res, next) => {
|
|
160
54
|
const requestId = crypto.randomUUID();
|
|
161
55
|
req.requestId = requestId;
|
|
56
|
+
res.setHeader("X-Request-ID", requestId);
|
|
162
57
|
if (isPublicPath(req.path, publicPaths)) {
|
|
163
|
-
|
|
58
|
+
logger2.info(`Public path accessed: ${req.path}`, {
|
|
164
59
|
code: "AUTH_PUBLIC_PATH",
|
|
165
60
|
requestId,
|
|
166
61
|
path: req.path
|
|
@@ -171,7 +66,7 @@ function createAuthMiddleware(config) {
|
|
|
171
66
|
const token = extractBearerToken(req.headers.authorization);
|
|
172
67
|
if (!token) {
|
|
173
68
|
const error = new TokenMissingError(resourceServer.getResourceUri());
|
|
174
|
-
|
|
69
|
+
logger2.warning("No access token provided", {
|
|
175
70
|
code: ERROR_CODES.AUTH.TOKEN_MISSING.full,
|
|
176
71
|
requestId,
|
|
177
72
|
path: req.path
|
|
@@ -186,7 +81,7 @@ function createAuthMiddleware(config) {
|
|
|
186
81
|
}
|
|
187
82
|
const result = await tokenValidator.validate(token);
|
|
188
83
|
if (!result.valid) {
|
|
189
|
-
|
|
84
|
+
logger2.warning(
|
|
190
85
|
`Token validation failed: ${result.error ?? "Unknown error"}`,
|
|
191
86
|
{
|
|
192
87
|
code: result.errorCode ?? ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
@@ -197,11 +92,14 @@ function createAuthMiddleware(config) {
|
|
|
197
92
|
res.status(401);
|
|
198
93
|
res.setHeader(
|
|
199
94
|
"WWW-Authenticate",
|
|
200
|
-
resourceServer.getWWWAuthenticateHeader(
|
|
95
|
+
resourceServer.getWWWAuthenticateHeader(
|
|
96
|
+
"invalid_token",
|
|
97
|
+
"Token validation failed"
|
|
98
|
+
)
|
|
201
99
|
);
|
|
202
100
|
res.json({
|
|
203
101
|
error: "invalid_token",
|
|
204
|
-
error_description:
|
|
102
|
+
error_description: "Token validation failed"
|
|
205
103
|
});
|
|
206
104
|
return;
|
|
207
105
|
}
|
|
@@ -212,7 +110,7 @@ function createAuthMiddleware(config) {
|
|
|
212
110
|
}
|
|
213
111
|
req.auth = claims;
|
|
214
112
|
req.accessToken = token;
|
|
215
|
-
|
|
113
|
+
logger2.info(`Request authenticated: ${claims.sub}`, {
|
|
216
114
|
code: "AUTH_SUCCESS",
|
|
217
115
|
requestId,
|
|
218
116
|
sub: claims.sub,
|
|
@@ -250,18 +148,9 @@ var JSONRPC_INTERNAL_ERROR = -32603;
|
|
|
250
148
|
var HTTP_REQUEST_TIMEOUT_MS = 12e4;
|
|
251
149
|
var HTTP_KEEP_ALIVE_TIMEOUT_MS = 65e3;
|
|
252
150
|
var HTTP_HEADERS_TIMEOUT_MS = 66e3;
|
|
253
|
-
function getClientIp(req, trustProxy) {
|
|
254
|
-
if (trustProxy) {
|
|
255
|
-
const forwarded = req.headers["x-forwarded-for"];
|
|
256
|
-
if (typeof forwarded === "string") {
|
|
257
|
-
const firstIp = forwarded.split(",")[0]?.trim();
|
|
258
|
-
if (firstIp) return firstIp;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return req.ip ?? req.socket.remoteAddress ?? "unknown";
|
|
262
|
-
}
|
|
263
151
|
function setupSecurityHeaders(state) {
|
|
264
152
|
if (!state.app) return;
|
|
153
|
+
state.app.disable("x-powered-by");
|
|
265
154
|
state.app.use((_req, res, next) => {
|
|
266
155
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
267
156
|
res.setHeader("X-Frame-Options", "DENY");
|
|
@@ -275,8 +164,12 @@ function setupSecurityHeaders(state) {
|
|
|
275
164
|
"camera=(), microphone=(), geolocation=()"
|
|
276
165
|
);
|
|
277
166
|
res.setHeader("Referrer-Policy", "no-referrer");
|
|
167
|
+
res.setHeader("X-Permitted-Cross-Domain-Policies", "none");
|
|
278
168
|
if (state.config.enableHSTS) {
|
|
279
|
-
const maxAge =
|
|
169
|
+
const maxAge = Math.max(
|
|
170
|
+
state.config.hstsMaxAge ?? DEFAULT_HSTS_MAX_AGE,
|
|
171
|
+
31536e3
|
|
172
|
+
);
|
|
280
173
|
res.setHeader(
|
|
281
174
|
"Strict-Transport-Security",
|
|
282
175
|
`max-age=${String(maxAge)}; includeSubDomains`
|
|
@@ -289,13 +182,15 @@ function matchesCorsOrigin(origin, pattern) {
|
|
|
289
182
|
if (pattern === "*") return true;
|
|
290
183
|
if (pattern.startsWith("*.")) {
|
|
291
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;
|
|
292
187
|
return origin.endsWith(domain) && origin.length > domain.length;
|
|
293
188
|
}
|
|
294
189
|
return origin === pattern;
|
|
295
190
|
}
|
|
296
191
|
function setupCors(state) {
|
|
297
192
|
if (!state.app) return;
|
|
298
|
-
const corsOrigins = state.config.corsOrigins ?? [
|
|
193
|
+
const corsOrigins = state.config.corsOrigins ?? [];
|
|
299
194
|
const isWildcard = corsOrigins.includes("*");
|
|
300
195
|
state.app.use((req, res, next) => {
|
|
301
196
|
const origin = req.headers.origin;
|
|
@@ -326,41 +221,41 @@ function setupCors(state) {
|
|
|
326
221
|
function setupRateLimiting(state) {
|
|
327
222
|
if (!state.app) return;
|
|
328
223
|
const windowMs = DEFAULT_RATE_LIMIT_WINDOW_MS;
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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"
|
|
359
255
|
});
|
|
360
|
-
return;
|
|
361
256
|
}
|
|
362
|
-
next();
|
|
363
257
|
});
|
|
258
|
+
state.app.use(limiter);
|
|
364
259
|
}
|
|
365
260
|
|
|
366
261
|
// src/transports/http/type-adapters.ts
|
|
@@ -371,32 +266,8 @@ function asServerResponse(res) {
|
|
|
371
266
|
return res;
|
|
372
267
|
}
|
|
373
268
|
|
|
374
|
-
// src/transports/http/
|
|
375
|
-
var
|
|
376
|
-
var Mutex = class {
|
|
377
|
-
queue = [];
|
|
378
|
-
locked = false;
|
|
379
|
-
async acquire() {
|
|
380
|
-
return new Promise((resolve) => {
|
|
381
|
-
const lock = () => {
|
|
382
|
-
this.locked = true;
|
|
383
|
-
resolve(() => {
|
|
384
|
-
this.locked = false;
|
|
385
|
-
if (this.queue.length > 0) {
|
|
386
|
-
const next = this.queue.shift();
|
|
387
|
-
next?.();
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
};
|
|
391
|
-
if (this.locked) {
|
|
392
|
-
this.queue.push(lock);
|
|
393
|
-
} else {
|
|
394
|
-
lock();
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
var connectionMutex = new Mutex();
|
|
269
|
+
// src/transports/http/sessions/stateless.ts
|
|
270
|
+
var logger4 = createModuleLogger("HTTP");
|
|
400
271
|
async function setupStatelessEndpoints(state) {
|
|
401
272
|
if (!state.app || !state.mcpServer) {
|
|
402
273
|
throw new DbMcpError(
|
|
@@ -409,14 +280,14 @@ async function setupStatelessEndpoints(state) {
|
|
|
409
280
|
enableJsonResponse: true
|
|
410
281
|
});
|
|
411
282
|
state.statelessTransport.onclose ??= () => {
|
|
412
|
-
|
|
283
|
+
logger4.debug("Stateless transport closed", {
|
|
413
284
|
code: "HTTP_STATELESS_CLOSE"
|
|
414
285
|
});
|
|
415
286
|
};
|
|
416
287
|
await state.mcpServer.connect(
|
|
417
288
|
state.statelessTransport
|
|
418
289
|
);
|
|
419
|
-
|
|
290
|
+
logger4.info("Stateless transport connected", { code: "HTTP_STATELESS" });
|
|
420
291
|
state.app.post("/mcp", (req, res) => {
|
|
421
292
|
if (!state.statelessTransport) {
|
|
422
293
|
res.status(500).json({ error: "Transport not initialized" });
|
|
@@ -442,6 +313,47 @@ async function setupStatelessEndpoints(state) {
|
|
|
442
313
|
res.status(204).end();
|
|
443
314
|
});
|
|
444
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
|
+
}
|
|
445
357
|
function setupStatefulEndpoints(state) {
|
|
446
358
|
if (!state.app || !state.mcpServer) {
|
|
447
359
|
throw new DbMcpError(
|
|
@@ -453,6 +365,17 @@ function setupStatefulEndpoints(state) {
|
|
|
453
365
|
const server = state.mcpServer;
|
|
454
366
|
state.app.post("/mcp", (req, res) => {
|
|
455
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
|
+
}
|
|
456
379
|
if (sessionId && state.sseTransports.has(sessionId)) {
|
|
457
380
|
res.status(400).json({
|
|
458
381
|
jsonrpc: "2.0",
|
|
@@ -476,34 +399,60 @@ function setupStatefulEndpoints(state) {
|
|
|
476
399
|
void (async () => {
|
|
477
400
|
try {
|
|
478
401
|
let httpTransport;
|
|
479
|
-
|
|
480
|
-
|
|
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;
|
|
481
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
|
+
}
|
|
482
429
|
const newTransport = new StreamableHTTPServerTransport({
|
|
483
430
|
sessionIdGenerator: () => randomUUID(),
|
|
484
431
|
onsessioninitialized: (sid) => {
|
|
485
|
-
|
|
432
|
+
logger5.info("HTTP session initialized", {
|
|
486
433
|
code: "HTTP_SESSION_INIT",
|
|
487
434
|
sessionId: sid
|
|
488
435
|
});
|
|
489
436
|
state.transports.set(sid, newTransport);
|
|
437
|
+
state.sessionOwners.set(sid, req.auth?.sub);
|
|
490
438
|
}
|
|
491
439
|
});
|
|
492
440
|
newTransport.onclose = () => {
|
|
493
441
|
const sid = newTransport.sessionId;
|
|
494
442
|
if (sid !== void 0 && state.transports.has(sid)) {
|
|
495
|
-
|
|
443
|
+
logger5.info("HTTP transport closed", {
|
|
496
444
|
code: "HTTP_SESSION_CLOSE",
|
|
497
445
|
sessionId: sid
|
|
498
446
|
});
|
|
499
447
|
state.transports.delete(sid);
|
|
448
|
+
state.sessionOwners.delete(sid);
|
|
500
449
|
}
|
|
501
450
|
};
|
|
502
451
|
await connectionMutex.acquire().then(async (release) => {
|
|
503
452
|
try {
|
|
504
453
|
if (server.server.transport) {
|
|
505
454
|
const oldTransport = server.server.transport;
|
|
506
|
-
|
|
455
|
+
logger5.info("Captured oldTransport in /mcp", {
|
|
507
456
|
hasOldTransport: oldTransport !== void 0,
|
|
508
457
|
hasOnclose: oldTransport.onclose !== void 0
|
|
509
458
|
});
|
|
@@ -517,25 +466,25 @@ function setupStatefulEndpoints(state) {
|
|
|
517
466
|
)
|
|
518
467
|
)
|
|
519
468
|
]);
|
|
520
|
-
|
|
469
|
+
logger5.info("server.close() succeeded in /mcp");
|
|
521
470
|
} catch (closeErr) {
|
|
522
|
-
|
|
471
|
+
logger5.error("server.close() failed or timed out in /mcp", {
|
|
523
472
|
error: closeErr instanceof Error ? closeErr : new Error(String(closeErr))
|
|
524
473
|
});
|
|
525
474
|
}
|
|
526
475
|
if (server.server.transport === oldTransport && oldTransport.onclose !== void 0) {
|
|
527
|
-
|
|
476
|
+
logger5.info(
|
|
528
477
|
"Manually invoking oldTransport.onclose() to clear Protocol state in /mcp"
|
|
529
478
|
);
|
|
530
479
|
oldTransport.onclose();
|
|
531
480
|
}
|
|
532
481
|
delete oldTransport.onclose;
|
|
533
482
|
}
|
|
534
|
-
|
|
483
|
+
logger5.info("Attempting server.connect(newTransport)");
|
|
535
484
|
await server.connect(
|
|
536
485
|
newTransport
|
|
537
486
|
);
|
|
538
|
-
|
|
487
|
+
logger5.info("server.connect succeeded in /mcp");
|
|
539
488
|
} finally {
|
|
540
489
|
release();
|
|
541
490
|
}
|
|
@@ -565,7 +514,7 @@ function setupStatefulEndpoints(state) {
|
|
|
565
514
|
);
|
|
566
515
|
}
|
|
567
516
|
} catch (error) {
|
|
568
|
-
|
|
517
|
+
logger5.error("Error handling MCP request", {
|
|
569
518
|
code: ERROR_CODES.SERVER.TRANSPORT_ERROR.full,
|
|
570
519
|
error: error instanceof Error ? error : void 0
|
|
571
520
|
});
|
|
@@ -584,44 +533,62 @@ function setupStatefulEndpoints(state) {
|
|
|
584
533
|
});
|
|
585
534
|
state.app.get("/mcp", (req, res) => {
|
|
586
535
|
const sessionId = req.headers["mcp-session-id"];
|
|
587
|
-
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) {
|
|
588
542
|
res.status(400).send("Invalid or missing session ID");
|
|
589
543
|
return;
|
|
590
544
|
}
|
|
545
|
+
if (!verifySessionOwner(state, sessionId, req.auth?.sub)) {
|
|
546
|
+
res.status(403).send("Forbidden: session belongs to a different client");
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
591
549
|
const lastEventId = req.headers["last-event-id"];
|
|
592
550
|
if (lastEventId !== void 0) {
|
|
593
|
-
|
|
551
|
+
logger5.debug("Client reconnecting with Last-Event-ID", {
|
|
594
552
|
code: "HTTP_SSE_RECONNECT",
|
|
595
553
|
sessionId,
|
|
596
554
|
lastEventId
|
|
597
555
|
});
|
|
598
556
|
}
|
|
599
|
-
const httpTransport = state.transports.get(sessionId);
|
|
600
557
|
if (httpTransport !== void 0) {
|
|
601
558
|
void httpTransport.handleRequest(asIncoming(req), asServerResponse(res));
|
|
602
559
|
}
|
|
603
560
|
});
|
|
604
561
|
state.app.delete("/mcp", (req, res) => {
|
|
605
562
|
const sessionId = req.headers["mcp-session-id"];
|
|
606
|
-
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) {
|
|
607
569
|
res.status(400).send("Invalid or missing session ID");
|
|
608
570
|
return;
|
|
609
571
|
}
|
|
610
|
-
|
|
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", {
|
|
611
577
|
code: "HTTP_SESSION_DELETE",
|
|
612
578
|
sessionId
|
|
613
579
|
});
|
|
614
|
-
const httpTransport = state.transports.get(sessionId);
|
|
615
580
|
if (httpTransport !== void 0) {
|
|
616
581
|
void httpTransport.handleRequest(asIncoming(req), asServerResponse(res));
|
|
617
582
|
}
|
|
618
583
|
});
|
|
619
584
|
}
|
|
585
|
+
var logger6 = createModuleLogger("HTTP");
|
|
586
|
+
var connectionMutex2 = new Mutex();
|
|
620
587
|
function setupLegacySSEEndpoints(state) {
|
|
621
588
|
if (!state.app || !state.mcpServer) return;
|
|
622
589
|
const server = state.mcpServer;
|
|
623
590
|
state.app.get("/sse", (req, res) => {
|
|
624
|
-
|
|
591
|
+
logger6.info("Legacy SSE connection requested", {
|
|
625
592
|
code: "SSE_CONNECT"
|
|
626
593
|
});
|
|
627
594
|
const sseTransport = new SSEServerTransport(
|
|
@@ -631,32 +598,27 @@ function setupLegacySSEEndpoints(state) {
|
|
|
631
598
|
void (async () => {
|
|
632
599
|
try {
|
|
633
600
|
state.sseTransports.set(sseTransport.sessionId, sseTransport);
|
|
601
|
+
state.sessionOwners.set(sseTransport.sessionId, req.auth?.sub);
|
|
634
602
|
sseTransport.onclose = () => {
|
|
635
|
-
|
|
603
|
+
logger6.info("Legacy SSE transport closed", {
|
|
636
604
|
code: "SSE_CLOSE",
|
|
637
605
|
sessionId: sseTransport.sessionId
|
|
638
606
|
});
|
|
639
607
|
state.sseTransports.delete(sseTransport.sessionId);
|
|
608
|
+
state.sessionOwners.delete(sseTransport.sessionId);
|
|
640
609
|
};
|
|
641
610
|
const origSend = sseTransport.send.bind(sseTransport);
|
|
642
611
|
sseTransport.send = async (message) => {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
msg: JSON.stringify(message).substring(0, 1e3)
|
|
647
|
-
});
|
|
648
|
-
} catch (e) {
|
|
649
|
-
logger3.error("SSE SEND Stringify Error", {
|
|
650
|
-
error: e instanceof Error ? e : new Error(String(e))
|
|
651
|
-
});
|
|
652
|
-
}
|
|
612
|
+
logger6.debug("SSE SEND", {
|
|
613
|
+
sessionId: sseTransport.sessionId
|
|
614
|
+
});
|
|
653
615
|
return origSend(message);
|
|
654
616
|
};
|
|
655
|
-
await
|
|
617
|
+
await connectionMutex2.acquire().then(async (release) => {
|
|
656
618
|
try {
|
|
657
619
|
if (server.server.transport) {
|
|
658
620
|
const oldTransport = server.server.transport;
|
|
659
|
-
|
|
621
|
+
logger6.info("Captured oldTransport", {
|
|
660
622
|
hasOldTransport: oldTransport !== void 0,
|
|
661
623
|
hasOnclose: oldTransport.onclose !== void 0
|
|
662
624
|
});
|
|
@@ -670,29 +632,29 @@ function setupLegacySSEEndpoints(state) {
|
|
|
670
632
|
)
|
|
671
633
|
)
|
|
672
634
|
]);
|
|
673
|
-
|
|
635
|
+
logger6.info("server.close() succeeded");
|
|
674
636
|
} catch (closeErr) {
|
|
675
|
-
|
|
637
|
+
logger6.error("server.close() failed or timed out", {
|
|
676
638
|
error: closeErr instanceof Error ? closeErr : new Error(String(closeErr))
|
|
677
639
|
});
|
|
678
640
|
}
|
|
679
641
|
if (server.server.transport === oldTransport && oldTransport.onclose !== void 0) {
|
|
680
|
-
|
|
642
|
+
logger6.info(
|
|
681
643
|
"Manually invoking oldTransport.onclose() to clear Protocol state"
|
|
682
644
|
);
|
|
683
645
|
oldTransport.onclose();
|
|
684
646
|
}
|
|
685
647
|
delete oldTransport.onclose;
|
|
686
648
|
}
|
|
687
|
-
|
|
649
|
+
logger6.info("Attempting server.connect(sseTransport)");
|
|
688
650
|
await server.connect(sseTransport);
|
|
689
|
-
|
|
651
|
+
logger6.info("server.connect succeeded");
|
|
690
652
|
} finally {
|
|
691
653
|
release();
|
|
692
654
|
}
|
|
693
655
|
});
|
|
694
656
|
} catch (error) {
|
|
695
|
-
|
|
657
|
+
logger6.error("Error starting SSE transport", {
|
|
696
658
|
code: ERROR_CODES.SERVER.TRANSPORT_ERROR.full,
|
|
697
659
|
error: error instanceof Error ? error : void 0
|
|
698
660
|
});
|
|
@@ -703,6 +665,7 @@ function setupLegacySSEEndpoints(state) {
|
|
|
703
665
|
})();
|
|
704
666
|
req.on("close", () => {
|
|
705
667
|
state.sseTransports.delete(sseTransport.sessionId);
|
|
668
|
+
state.sessionOwners.delete(sseTransport.sessionId);
|
|
706
669
|
});
|
|
707
670
|
});
|
|
708
671
|
state.app.post("/messages", (req, res) => {
|
|
@@ -730,14 +693,25 @@ function setupLegacySSEEndpoints(state) {
|
|
|
730
693
|
});
|
|
731
694
|
return;
|
|
732
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
|
+
}
|
|
733
707
|
void sseTransport.handlePostMessage(
|
|
734
708
|
asIncoming(req),
|
|
735
709
|
asServerResponse(res),
|
|
736
710
|
req.body
|
|
737
711
|
).then(() => {
|
|
738
|
-
|
|
712
|
+
logger6.info("handlePostMessage completed", { sessionId });
|
|
739
713
|
}).catch((e) => {
|
|
740
|
-
|
|
714
|
+
logger6.error("handlePostMessage error", {
|
|
741
715
|
error: e instanceof Error ? e : new Error(String(e))
|
|
742
716
|
});
|
|
743
717
|
});
|
|
@@ -745,7 +719,7 @@ function setupLegacySSEEndpoints(state) {
|
|
|
745
719
|
}
|
|
746
720
|
|
|
747
721
|
// src/auth/oauth-resource-server.ts
|
|
748
|
-
var
|
|
722
|
+
var logger7 = createModuleLogger("AUTH");
|
|
749
723
|
var OAuthResourceServer = class {
|
|
750
724
|
config;
|
|
751
725
|
metadata = null;
|
|
@@ -756,7 +730,7 @@ var OAuthResourceServer = class {
|
|
|
756
730
|
scopesSupported: config.scopesSupported.length > 0 ? config.scopesSupported : [...SUPPORTED_SCOPES],
|
|
757
731
|
bearerMethodsSupported: config.bearerMethodsSupported ?? ["header"]
|
|
758
732
|
};
|
|
759
|
-
|
|
733
|
+
logger7.info(
|
|
760
734
|
`OAuth Resource Server initialized for: ${this.config.resource}`,
|
|
761
735
|
{ code: "AUTH_INIT" }
|
|
762
736
|
);
|
|
@@ -794,7 +768,7 @@ var OAuthResourceServer = class {
|
|
|
794
768
|
res.setHeader("Content-Type", "application/json");
|
|
795
769
|
res.setHeader("Cache-Control", "public, max-age=3600");
|
|
796
770
|
res.json(metadata);
|
|
797
|
-
|
|
771
|
+
logger7.info("Protected Resource Metadata served", {
|
|
798
772
|
code: "AUTH_METADATA_SERVED"
|
|
799
773
|
});
|
|
800
774
|
};
|
|
@@ -812,7 +786,8 @@ var OAuthResourceServer = class {
|
|
|
812
786
|
parts.push(`error="${error}"`);
|
|
813
787
|
}
|
|
814
788
|
if (errorDescription) {
|
|
815
|
-
|
|
789
|
+
const safe = errorDescription.replace(/"/g, "'").substring(0, 200);
|
|
790
|
+
parts.push(`error_description="${safe}"`);
|
|
816
791
|
}
|
|
817
792
|
return parts.join(", ");
|
|
818
793
|
}
|
|
@@ -845,12 +820,6 @@ var OAuthResourceServer = class {
|
|
|
845
820
|
if (this.config.scopesSupported.includes(scope)) {
|
|
846
821
|
return true;
|
|
847
822
|
}
|
|
848
|
-
if (SCOPE_PATTERNS.DATABASE.test(scope)) {
|
|
849
|
-
return true;
|
|
850
|
-
}
|
|
851
|
-
if (SCOPE_PATTERNS.TABLE.test(scope)) {
|
|
852
|
-
return true;
|
|
853
|
-
}
|
|
854
823
|
return false;
|
|
855
824
|
}
|
|
856
825
|
/**
|
|
@@ -868,7 +837,7 @@ var OAuthResourceServer = class {
|
|
|
868
837
|
};
|
|
869
838
|
|
|
870
839
|
// src/auth/authorization-server-discovery.ts
|
|
871
|
-
var
|
|
840
|
+
var logger8 = createModuleLogger("AUTH");
|
|
872
841
|
var AuthorizationServerDiscovery = class {
|
|
873
842
|
authServerUrl;
|
|
874
843
|
cacheTtl;
|
|
@@ -879,7 +848,16 @@ var AuthorizationServerDiscovery = class {
|
|
|
879
848
|
this.authServerUrl = config.authServerUrl.replace(/\/+$/, "");
|
|
880
849
|
this.cacheTtl = config.cacheTtl ?? 3600;
|
|
881
850
|
this.timeout = config.timeout ?? 5e3;
|
|
882
|
-
|
|
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(
|
|
883
861
|
`Authorization Server Discovery initialized for: ${this.authServerUrl}`,
|
|
884
862
|
{ code: "AUTH_INIT" }
|
|
885
863
|
);
|
|
@@ -895,13 +873,13 @@ var AuthorizationServerDiscovery = class {
|
|
|
895
873
|
*/
|
|
896
874
|
async discover() {
|
|
897
875
|
if (this.cachedMetadata && Date.now() < this.cacheExpiry) {
|
|
898
|
-
|
|
876
|
+
logger8.info("Using cached authorization server metadata", {
|
|
899
877
|
code: "AUTH_CACHE_HIT"
|
|
900
878
|
});
|
|
901
879
|
return this.cachedMetadata;
|
|
902
880
|
}
|
|
903
881
|
const metadataUrl = `${this.authServerUrl}/.well-known/oauth-authorization-server`;
|
|
904
|
-
|
|
882
|
+
logger8.info(`Fetching authorization server metadata from: ${metadataUrl}`, {
|
|
905
883
|
code: "AUTH_DISCOVERY"
|
|
906
884
|
});
|
|
907
885
|
try {
|
|
@@ -926,14 +904,14 @@ var AuthorizationServerDiscovery = class {
|
|
|
926
904
|
this.validateMetadata(metadata);
|
|
927
905
|
this.cachedMetadata = metadata;
|
|
928
906
|
this.cacheExpiry = Date.now() + this.cacheTtl * 1e3;
|
|
929
|
-
|
|
907
|
+
logger8.info(
|
|
930
908
|
`Authorization server metadata cached for ${String(this.cacheTtl)}s`,
|
|
931
909
|
{ code: "AUTH_DISCOVERY_SUCCESS" }
|
|
932
910
|
);
|
|
933
911
|
return metadata;
|
|
934
912
|
} catch (error) {
|
|
935
913
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
936
|
-
|
|
914
|
+
logger8.error(
|
|
937
915
|
`Failed to discover authorization server: ${this.authServerUrl}`,
|
|
938
916
|
{
|
|
939
917
|
code: ERROR_CODES.AUTH.DISCOVERY_FAILED.full,
|
|
@@ -963,11 +941,22 @@ var AuthorizationServerDiscovery = class {
|
|
|
963
941
|
"validation" /* VALIDATION */
|
|
964
942
|
);
|
|
965
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
|
+
}
|
|
966
954
|
const expectedIssuer = this.authServerUrl;
|
|
967
955
|
if (metadata.issuer !== expectedIssuer) {
|
|
968
|
-
|
|
969
|
-
`Issuer
|
|
970
|
-
|
|
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 */
|
|
971
960
|
);
|
|
972
961
|
}
|
|
973
962
|
}
|
|
@@ -1045,7 +1034,7 @@ var AuthorizationServerDiscovery = class {
|
|
|
1045
1034
|
clearCache() {
|
|
1046
1035
|
this.cachedMetadata = null;
|
|
1047
1036
|
this.cacheExpiry = 0;
|
|
1048
|
-
|
|
1037
|
+
logger8.info("Authorization server metadata cache cleared", {
|
|
1049
1038
|
code: "AUTH_CACHE_CLEARED"
|
|
1050
1039
|
});
|
|
1051
1040
|
}
|
|
@@ -1062,23 +1051,43 @@ var AuthorizationServerDiscovery = class {
|
|
|
1062
1051
|
return this.authServerUrl;
|
|
1063
1052
|
}
|
|
1064
1053
|
};
|
|
1065
|
-
var
|
|
1066
|
-
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
|
+
];
|
|
1067
1065
|
/** Resolved configuration with all defaults applied */
|
|
1068
1066
|
jwksUri;
|
|
1069
1067
|
issuer;
|
|
1070
1068
|
audience;
|
|
1071
1069
|
clockTolerance;
|
|
1072
1070
|
jwksCacheTtl;
|
|
1071
|
+
algorithms;
|
|
1073
1072
|
jwks = null;
|
|
1074
1073
|
jwksExpiry = 0;
|
|
1075
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
|
+
}
|
|
1076
1084
|
this.jwksUri = config.jwksUri;
|
|
1077
1085
|
this.issuer = config.issuer;
|
|
1078
1086
|
this.audience = config.audience;
|
|
1079
|
-
this.clockTolerance = config.clockTolerance ??
|
|
1087
|
+
this.clockTolerance = config.clockTolerance ?? 30;
|
|
1080
1088
|
this.jwksCacheTtl = config.jwksCacheTtl ?? 3600;
|
|
1081
|
-
|
|
1089
|
+
this.algorithms = config.algorithms ?? _TokenValidator.DEFAULT_ALGORITHMS;
|
|
1090
|
+
logger9.info(`Token Validator initialized for issuer: ${this.issuer}`, {
|
|
1082
1091
|
code: "AUTH_INIT"
|
|
1083
1092
|
});
|
|
1084
1093
|
}
|
|
@@ -1094,10 +1103,11 @@ var TokenValidator = class {
|
|
|
1094
1103
|
const { payload } = await jose.jwtVerify(token, jwks, {
|
|
1095
1104
|
issuer: this.issuer,
|
|
1096
1105
|
audience: this.audience,
|
|
1097
|
-
clockTolerance: this.clockTolerance
|
|
1106
|
+
clockTolerance: this.clockTolerance,
|
|
1107
|
+
algorithms: this.algorithms
|
|
1098
1108
|
});
|
|
1099
1109
|
const claims = this.extractClaims(payload);
|
|
1100
|
-
|
|
1110
|
+
logger9.info(`Token validated for subject: ${claims.sub}`, {
|
|
1101
1111
|
code: "AUTH_TOKEN_VALID",
|
|
1102
1112
|
sub: claims.sub,
|
|
1103
1113
|
scopes: claims.scopes.length,
|
|
@@ -1118,7 +1128,7 @@ var TokenValidator = class {
|
|
|
1118
1128
|
if (this.jwks && Date.now() < this.jwksExpiry) {
|
|
1119
1129
|
return this.jwks;
|
|
1120
1130
|
}
|
|
1121
|
-
|
|
1131
|
+
logger9.debug(`Fetching JWKS from: ${this.jwksUri}`, {
|
|
1122
1132
|
code: "AUTH_JWKS_FETCH"
|
|
1123
1133
|
});
|
|
1124
1134
|
try {
|
|
@@ -1128,13 +1138,13 @@ var TokenValidator = class {
|
|
|
1128
1138
|
cacheMaxAge: this.jwksCacheTtl * 1e3
|
|
1129
1139
|
});
|
|
1130
1140
|
this.jwksExpiry = Date.now() + this.jwksCacheTtl * 1e3;
|
|
1131
|
-
|
|
1141
|
+
logger9.info(`JWKS cached for ${String(this.jwksCacheTtl)}s`, {
|
|
1132
1142
|
code: "AUTH_JWKS_CACHED"
|
|
1133
1143
|
});
|
|
1134
1144
|
return this.jwks;
|
|
1135
1145
|
} catch (error) {
|
|
1136
1146
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
1137
|
-
|
|
1147
|
+
logger9.error(`Failed to fetch JWKS: ${this.jwksUri}`, {
|
|
1138
1148
|
code: ERROR_CODES.AUTH.JWKS_FETCH_FAILED.full,
|
|
1139
1149
|
error: cause
|
|
1140
1150
|
});
|
|
@@ -1157,18 +1167,25 @@ var TokenValidator = class {
|
|
|
1157
1167
|
(s) => typeof s === "string"
|
|
1158
1168
|
);
|
|
1159
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
|
+
}
|
|
1160
1176
|
return {
|
|
1161
|
-
|
|
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",
|
|
1162
1181
|
scopes,
|
|
1163
|
-
exp:
|
|
1164
|
-
iat:
|
|
1165
|
-
iss:
|
|
1166
|
-
aud:
|
|
1167
|
-
nbf:
|
|
1168
|
-
jti:
|
|
1169
|
-
client_id:
|
|
1170
|
-
// Include all other claims
|
|
1171
|
-
...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"]
|
|
1172
1189
|
};
|
|
1173
1190
|
}
|
|
1174
1191
|
/**
|
|
@@ -1176,7 +1193,7 @@ var TokenValidator = class {
|
|
|
1176
1193
|
*/
|
|
1177
1194
|
handleValidationError(error) {
|
|
1178
1195
|
if (error instanceof jose.errors.JWTExpired) {
|
|
1179
|
-
|
|
1196
|
+
logger9.warning("Token has expired", {
|
|
1180
1197
|
code: ERROR_CODES.AUTH.TOKEN_EXPIRED.full,
|
|
1181
1198
|
error
|
|
1182
1199
|
});
|
|
@@ -1187,18 +1204,18 @@ var TokenValidator = class {
|
|
|
1187
1204
|
};
|
|
1188
1205
|
}
|
|
1189
1206
|
if (error instanceof jose.errors.JWTClaimValidationFailed) {
|
|
1190
|
-
|
|
1207
|
+
logger9.warning(`Token claim validation failed: ${error.message}`, {
|
|
1191
1208
|
code: ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
1192
1209
|
error
|
|
1193
1210
|
});
|
|
1194
1211
|
return {
|
|
1195
1212
|
valid: false,
|
|
1196
|
-
error:
|
|
1213
|
+
error: "Token claim validation failed",
|
|
1197
1214
|
errorCode: ERROR_CODES.AUTH.TOKEN_INVALID.full
|
|
1198
1215
|
};
|
|
1199
1216
|
}
|
|
1200
1217
|
if (error instanceof jose.errors.JWSSignatureVerificationFailed) {
|
|
1201
|
-
|
|
1218
|
+
logger9.warning("Token signature verification failed", {
|
|
1202
1219
|
code: ERROR_CODES.AUTH.SIGNATURE_INVALID.full,
|
|
1203
1220
|
error
|
|
1204
1221
|
});
|
|
@@ -1209,7 +1226,7 @@ var TokenValidator = class {
|
|
|
1209
1226
|
};
|
|
1210
1227
|
}
|
|
1211
1228
|
if (error instanceof jose.errors.JWKSNoMatchingKey) {
|
|
1212
|
-
|
|
1229
|
+
logger9.warning("No matching key found in JWKS", {
|
|
1213
1230
|
code: ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
1214
1231
|
error
|
|
1215
1232
|
});
|
|
@@ -1220,13 +1237,13 @@ var TokenValidator = class {
|
|
|
1220
1237
|
};
|
|
1221
1238
|
}
|
|
1222
1239
|
const message = error instanceof Error ? error.message : String(error);
|
|
1223
|
-
|
|
1240
|
+
logger9.error(`Token validation failed: ${message}`, {
|
|
1224
1241
|
code: ERROR_CODES.AUTH.TOKEN_INVALID.full,
|
|
1225
1242
|
error: error instanceof Error ? error : void 0
|
|
1226
1243
|
});
|
|
1227
1244
|
return {
|
|
1228
1245
|
valid: false,
|
|
1229
|
-
error:
|
|
1246
|
+
error: "Token validation failed",
|
|
1230
1247
|
errorCode: ERROR_CODES.AUTH.TOKEN_INVALID.full
|
|
1231
1248
|
};
|
|
1232
1249
|
}
|
|
@@ -1237,7 +1254,7 @@ var TokenValidator = class {
|
|
|
1237
1254
|
this.jwks = null;
|
|
1238
1255
|
this.jwksExpiry = 0;
|
|
1239
1256
|
this.getJwks();
|
|
1240
|
-
|
|
1257
|
+
logger9.info("JWKS cache refreshed", { code: "AUTH_JWKS_REFRESHED" });
|
|
1241
1258
|
}
|
|
1242
1259
|
/**
|
|
1243
1260
|
* Clear the JWKS cache
|
|
@@ -1245,7 +1262,7 @@ var TokenValidator = class {
|
|
|
1245
1262
|
clearCache() {
|
|
1246
1263
|
this.jwks = null;
|
|
1247
1264
|
this.jwksExpiry = 0;
|
|
1248
|
-
|
|
1265
|
+
logger9.info("Token validator cache cleared", {
|
|
1249
1266
|
code: "AUTH_CACHE_CLEARED"
|
|
1250
1267
|
});
|
|
1251
1268
|
}
|
|
@@ -1264,8 +1281,15 @@ var TokenValidator = class {
|
|
|
1264
1281
|
};
|
|
1265
1282
|
|
|
1266
1283
|
// src/transports/http/oauth.ts
|
|
1267
|
-
var
|
|
1284
|
+
var logger10 = createModuleLogger("HTTP");
|
|
1268
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
|
+
}
|
|
1269
1293
|
if (state.config.oauth.enabled && state.tokenValidator && state.resourceServer && state.app) {
|
|
1270
1294
|
const authMiddleware = createAuthMiddleware({
|
|
1271
1295
|
tokenValidator: state.tokenValidator,
|
|
@@ -1273,98 +1297,148 @@ function applyAuthMiddleware(state) {
|
|
|
1273
1297
|
publicPaths: ["/health", ...state.config.oauth.publicPaths ?? []]
|
|
1274
1298
|
});
|
|
1275
1299
|
state.app.use(authMiddleware);
|
|
1276
|
-
} else if (state.config.authToken && state.app) {
|
|
1277
|
-
state.app.use(createSimpleBearerAuth(state.config.authToken));
|
|
1278
|
-
logger7.info("Simple bearer token authentication enabled", {
|
|
1279
|
-
code: "AUTH_BEARER_ENABLED"
|
|
1280
|
-
});
|
|
1281
1300
|
} else if (state.app) {
|
|
1282
|
-
|
|
1283
|
-
"No authentication configured for HTTP transport. Set --
|
|
1301
|
+
logger10.warning(
|
|
1302
|
+
"No authentication configured for HTTP transport. Set --oauth-enabled for production deployments.",
|
|
1284
1303
|
{ code: "AUTH_NONE" }
|
|
1285
1304
|
);
|
|
1286
1305
|
}
|
|
1287
1306
|
}
|
|
1288
|
-
function
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
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") {
|
|
1292
1312
|
next();
|
|
1293
1313
|
return;
|
|
1294
1314
|
}
|
|
1295
|
-
const
|
|
1296
|
-
if (
|
|
1297
|
-
res.status(
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
error: "unauthorized",
|
|
1301
|
-
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"
|
|
1302
1320
|
});
|
|
1303
1321
|
return;
|
|
1304
1322
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
});
|
|
1310
|
-
res.status(401);
|
|
1311
|
-
res.setHeader(
|
|
1312
|
-
"WWW-Authenticate",
|
|
1313
|
-
'Bearer realm="db-mcp", error="invalid_token"'
|
|
1314
|
-
);
|
|
1315
|
-
res.json({
|
|
1316
|
-
error: "unauthorized",
|
|
1317
|
-
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"
|
|
1318
1327
|
});
|
|
1319
1328
|
return;
|
|
1320
1329
|
}
|
|
1321
|
-
|
|
1322
|
-
};
|
|
1323
|
-
}
|
|
1324
|
-
function applyScopeEnforcementMiddleware(state) {
|
|
1325
|
-
if (!state.app) return;
|
|
1326
|
-
state.app.use((req, res, next) => {
|
|
1327
|
-
const body = req.body;
|
|
1328
|
-
if (req.method !== "POST" || body?.method !== "tools/call") {
|
|
1329
|
-
next();
|
|
1330
|
-
return;
|
|
1331
|
-
}
|
|
1332
|
-
const toolName = body.params?.name;
|
|
1333
|
-
if (!toolName) {
|
|
1330
|
+
if (!req.auth) {
|
|
1334
1331
|
next();
|
|
1335
1332
|
return;
|
|
1336
1333
|
}
|
|
1337
|
-
|
|
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
|
+
};
|
|
1338
1352
|
next();
|
|
1339
1353
|
return;
|
|
1340
1354
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
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;
|
|
1355
1430
|
}
|
|
1356
|
-
res.json({
|
|
1357
|
-
error: "insufficient_scope",
|
|
1358
|
-
error_description: `Access to tool '${toolName}' denied`,
|
|
1359
|
-
tool: toolName
|
|
1360
|
-
});
|
|
1361
|
-
return;
|
|
1362
1431
|
}
|
|
1363
1432
|
next();
|
|
1364
1433
|
});
|
|
1365
1434
|
}
|
|
1366
1435
|
async function setupOAuth(state, resourceUri) {
|
|
1367
|
-
|
|
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
|
+
}
|
|
1368
1442
|
state.resourceServer = new OAuthResourceServer({
|
|
1369
1443
|
resource: resourceUri,
|
|
1370
1444
|
authorizationServers: [state.config.oauth.authorizationServerUrl],
|
|
@@ -1385,25 +1459,25 @@ async function setupOAuth(state, resourceUri) {
|
|
|
1385
1459
|
audience: state.config.oauth.audience,
|
|
1386
1460
|
clockTolerance: state.config.oauth.clockTolerance
|
|
1387
1461
|
});
|
|
1388
|
-
|
|
1462
|
+
logger10.info("OAuth 2.1 setup complete", { code: "HTTP_OAUTH_READY" });
|
|
1389
1463
|
} catch (error) {
|
|
1390
|
-
|
|
1464
|
+
logger10.warning(
|
|
1391
1465
|
"Authorization server discovery failed. OAuth validation disabled.",
|
|
1392
1466
|
{
|
|
1393
1467
|
code: ERROR_CODES.AUTH.DISCOVERY_FAILED.full,
|
|
1394
1468
|
error: error instanceof Error ? error : void 0
|
|
1395
1469
|
}
|
|
1396
1470
|
);
|
|
1397
|
-
if (!state.config.oauth.jwksUri) {
|
|
1398
|
-
|
|
1399
|
-
"
|
|
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.",
|
|
1400
1474
|
{ code: ERROR_CODES.AUTH.DISCOVERY_FAILED.full }
|
|
1401
1475
|
);
|
|
1402
1476
|
throw error;
|
|
1403
1477
|
}
|
|
1404
1478
|
state.tokenValidator = new TokenValidator({
|
|
1405
1479
|
jwksUri: state.config.oauth.jwksUri,
|
|
1406
|
-
issuer: state.config.oauth.issuer
|
|
1480
|
+
issuer: state.config.oauth.issuer,
|
|
1407
1481
|
audience: state.config.oauth.audience,
|
|
1408
1482
|
clockTolerance: state.config.oauth.clockTolerance
|
|
1409
1483
|
});
|
|
@@ -1411,7 +1485,7 @@ async function setupOAuth(state, resourceUri) {
|
|
|
1411
1485
|
}
|
|
1412
1486
|
|
|
1413
1487
|
// src/transports/http/transport.ts
|
|
1414
|
-
var
|
|
1488
|
+
var logger11 = createModuleLogger("HTTP");
|
|
1415
1489
|
var HttpTransport = class {
|
|
1416
1490
|
/** Internal state shared with session/middleware/oauth modules */
|
|
1417
1491
|
state;
|
|
@@ -1419,7 +1493,7 @@ var HttpTransport = class {
|
|
|
1419
1493
|
this.state = {
|
|
1420
1494
|
config: {
|
|
1421
1495
|
...config,
|
|
1422
|
-
host: config.host ?? "
|
|
1496
|
+
host: config.host ?? "127.0.0.1",
|
|
1423
1497
|
stateless: config.stateless ?? false,
|
|
1424
1498
|
enableHSTS: config.enableHSTS ?? process.env["MCP_ENABLE_HSTS"] === "true"
|
|
1425
1499
|
},
|
|
@@ -1427,13 +1501,12 @@ var HttpTransport = class {
|
|
|
1427
1501
|
httpServer: null,
|
|
1428
1502
|
transports: /* @__PURE__ */ new Map(),
|
|
1429
1503
|
sseTransports: /* @__PURE__ */ new Map(),
|
|
1504
|
+
sessionOwners: /* @__PURE__ */ new Map(),
|
|
1430
1505
|
statelessTransport: null,
|
|
1431
1506
|
resourceServer: null,
|
|
1432
1507
|
authServerDiscovery: null,
|
|
1433
1508
|
tokenValidator: null,
|
|
1434
|
-
mcpServer: null
|
|
1435
|
-
rateLimitMap: /* @__PURE__ */ new Map(),
|
|
1436
|
-
rateLimitCleanupTimer: null
|
|
1509
|
+
mcpServer: null
|
|
1437
1510
|
};
|
|
1438
1511
|
}
|
|
1439
1512
|
/**
|
|
@@ -1445,13 +1518,25 @@ var HttpTransport = class {
|
|
|
1445
1518
|
* @param server - The MCP server instance
|
|
1446
1519
|
*/
|
|
1447
1520
|
async initialize(server) {
|
|
1448
|
-
|
|
1521
|
+
logger11.info("Initializing HTTP transport...", {
|
|
1449
1522
|
code: "HTTP_INIT",
|
|
1450
1523
|
stateless: this.state.config.stateless
|
|
1451
1524
|
});
|
|
1452
1525
|
this.state.mcpServer = server;
|
|
1453
1526
|
this.state.app = express();
|
|
1454
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
|
+
}
|
|
1455
1540
|
setupSecurityHeaders(this.state);
|
|
1456
1541
|
setupCors(this.state);
|
|
1457
1542
|
setupRateLimiting(this.state);
|
|
@@ -1460,17 +1545,32 @@ var HttpTransport = class {
|
|
|
1460
1545
|
express.json({ limit: maxBodyBytes })
|
|
1461
1546
|
);
|
|
1462
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
|
+
}
|
|
1463
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
|
+
}
|
|
1464
1561
|
await setupOAuth(this.state, resourceUri);
|
|
1465
1562
|
}
|
|
1466
|
-
this.state.app.get("/health", (
|
|
1467
|
-
|
|
1563
|
+
this.state.app.get("/health", (req, res) => {
|
|
1564
|
+
const response = {
|
|
1468
1565
|
status: "healthy",
|
|
1469
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
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);
|
|
1474
1574
|
});
|
|
1475
1575
|
this.state.app.get("/", (_req, res) => {
|
|
1476
1576
|
res.json({
|
|
@@ -1490,19 +1590,29 @@ var HttpTransport = class {
|
|
|
1490
1590
|
});
|
|
1491
1591
|
applyAuthMiddleware(this.state);
|
|
1492
1592
|
applyScopeEnforcementMiddleware(this.state);
|
|
1593
|
+
const oauthEnabled = this.state.config.oauth?.enabled ?? false;
|
|
1594
|
+
let lastNoAuthWarning = 0;
|
|
1493
1595
|
this.state.app.use((req, _res, next) => {
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
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
|
+
}
|
|
1505
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
|
+
});
|
|
1506
1616
|
});
|
|
1507
1617
|
if (this.state.config.stateless) {
|
|
1508
1618
|
await setupStatelessEndpoints(this.state);
|
|
@@ -1516,7 +1626,7 @@ var HttpTransport = class {
|
|
|
1516
1626
|
this.state.app.use((_req, res) => {
|
|
1517
1627
|
res.status(404).json({ error: "Not found" });
|
|
1518
1628
|
});
|
|
1519
|
-
|
|
1629
|
+
logger11.info("HTTP transport initialized", {
|
|
1520
1630
|
code: "HTTP_INIT_COMPLETE",
|
|
1521
1631
|
port: this.state.config.port,
|
|
1522
1632
|
oauth: this.state.config.oauth.enabled,
|
|
@@ -1539,15 +1649,15 @@ var HttpTransport = class {
|
|
|
1539
1649
|
try {
|
|
1540
1650
|
this.state.httpServer = this.state.app?.listen(
|
|
1541
1651
|
this.state.config.port,
|
|
1542
|
-
this.state.config.host ?? "
|
|
1652
|
+
this.state.config.host ?? "127.0.0.1",
|
|
1543
1653
|
() => {
|
|
1544
1654
|
if (this.state.httpServer) {
|
|
1545
1655
|
this.state.httpServer.setTimeout(HTTP_REQUEST_TIMEOUT_MS);
|
|
1546
1656
|
this.state.httpServer.keepAliveTimeout = HTTP_KEEP_ALIVE_TIMEOUT_MS;
|
|
1547
1657
|
this.state.httpServer.headersTimeout = HTTP_HEADERS_TIMEOUT_MS;
|
|
1548
1658
|
}
|
|
1549
|
-
|
|
1550
|
-
`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)}`,
|
|
1551
1661
|
{
|
|
1552
1662
|
code: "HTTP_SERVER_STARTED",
|
|
1553
1663
|
mode: this.state.config.stateless ? "stateless" : "stateful"
|
|
@@ -1557,7 +1667,7 @@ var HttpTransport = class {
|
|
|
1557
1667
|
}
|
|
1558
1668
|
) ?? null;
|
|
1559
1669
|
this.state.httpServer?.on("error", (error) => {
|
|
1560
|
-
|
|
1670
|
+
logger11.error("Failed to start HTTP server", {
|
|
1561
1671
|
code: ERROR_CODES.SERVER.START_FAILED.full,
|
|
1562
1672
|
error
|
|
1563
1673
|
});
|
|
@@ -1572,19 +1682,15 @@ var HttpTransport = class {
|
|
|
1572
1682
|
* Stop the server and close all active sessions
|
|
1573
1683
|
*/
|
|
1574
1684
|
async stop() {
|
|
1575
|
-
if (this.state.rateLimitCleanupTimer) {
|
|
1576
|
-
clearInterval(this.state.rateLimitCleanupTimer);
|
|
1577
|
-
this.state.rateLimitCleanupTimer = null;
|
|
1578
|
-
}
|
|
1579
1685
|
for (const [sessionId, transport] of this.state.transports) {
|
|
1580
1686
|
try {
|
|
1581
|
-
|
|
1687
|
+
logger11.debug("Closing transport", {
|
|
1582
1688
|
code: "HTTP_SESSION_CLEANUP",
|
|
1583
1689
|
sessionId
|
|
1584
1690
|
});
|
|
1585
1691
|
await transport.close();
|
|
1586
1692
|
} catch (error) {
|
|
1587
|
-
|
|
1693
|
+
logger11.error("Error closing transport", {
|
|
1588
1694
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1589
1695
|
sessionId,
|
|
1590
1696
|
error: error instanceof Error ? error : void 0
|
|
@@ -1592,15 +1698,16 @@ var HttpTransport = class {
|
|
|
1592
1698
|
}
|
|
1593
1699
|
}
|
|
1594
1700
|
this.state.transports.clear();
|
|
1701
|
+
this.state.sessionOwners.clear();
|
|
1595
1702
|
for (const [sessionId, transport] of this.state.sseTransports) {
|
|
1596
1703
|
try {
|
|
1597
|
-
|
|
1704
|
+
logger11.debug("Closing SSE transport", {
|
|
1598
1705
|
code: "SSE_SESSION_CLEANUP",
|
|
1599
1706
|
sessionId
|
|
1600
1707
|
});
|
|
1601
1708
|
await transport.close();
|
|
1602
1709
|
} catch (error) {
|
|
1603
|
-
|
|
1710
|
+
logger11.error("Error closing SSE transport", {
|
|
1604
1711
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1605
1712
|
sessionId,
|
|
1606
1713
|
error: error instanceof Error ? error : void 0
|
|
@@ -1612,7 +1719,7 @@ var HttpTransport = class {
|
|
|
1612
1719
|
try {
|
|
1613
1720
|
await this.state.statelessTransport.close();
|
|
1614
1721
|
} catch (error) {
|
|
1615
|
-
|
|
1722
|
+
logger11.error("Error closing stateless transport", {
|
|
1616
1723
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1617
1724
|
error: error instanceof Error ? error : void 0
|
|
1618
1725
|
});
|
|
@@ -1625,13 +1732,13 @@ var HttpTransport = class {
|
|
|
1625
1732
|
}
|
|
1626
1733
|
this.state.httpServer.close((error) => {
|
|
1627
1734
|
if (error) {
|
|
1628
|
-
|
|
1735
|
+
logger11.error("Error stopping HTTP server", {
|
|
1629
1736
|
code: ERROR_CODES.SERVER.SHUTDOWN_FAILED.full,
|
|
1630
1737
|
error
|
|
1631
1738
|
});
|
|
1632
1739
|
reject(error);
|
|
1633
1740
|
} else {
|
|
1634
|
-
|
|
1741
|
+
logger11.info("HTTP server stopped", { code: "HTTP_SERVER_STOPPED" });
|
|
1635
1742
|
resolve();
|
|
1636
1743
|
}
|
|
1637
1744
|
});
|