db-mcp 1.1.1 → 3.0.0

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