memory-journal-mcp 9.0.0 → 9.1.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 (356) hide show
  1. package/README.md +165 -124
  2. package/dist/audit/interceptor.d.ts.map +1 -1
  3. package/dist/auth/authorization-server-discovery.d.ts.map +1 -1
  4. package/dist/auth/middleware.d.ts +11 -22
  5. package/dist/auth/middleware.d.ts.map +1 -1
  6. package/dist/auth/scope-map.d.ts.map +1 -1
  7. package/dist/auth/scopes.d.ts.map +1 -1
  8. package/dist/auth/token-validator.d.ts.map +1 -1
  9. package/dist/auth/transport-agnostic.d.ts +4 -0
  10. package/dist/auth/transport-agnostic.d.ts.map +1 -1
  11. package/dist/auth/validation.d.ts +1 -0
  12. package/dist/auth/validation.d.ts.map +1 -1
  13. package/dist/{chunk-6RCZ4IYV.js → chunk-4FZCHFB5.js} +28 -5
  14. package/dist/{chunk-AIWHVEOW.js → chunk-D2FY6XS5.js} +99 -7
  15. package/dist/chunk-FZLB6NAV.js +746 -0
  16. package/dist/{chunk-NVXCRDCO.js → chunk-LE6ZWUPK.js} +216 -138
  17. package/dist/chunk-SGJU2DHU.js +2102 -0
  18. package/dist/{chunk-2UIMA6JF.js → chunk-T7SROBBV.js} +32375 -29351
  19. package/dist/{chunk-IYZWMAA4.js → chunk-Y6MMKR2Z.js} +957 -1333
  20. package/dist/cli/commands/admin.d.ts +1 -1
  21. package/dist/cli/commands/admin.d.ts.map +1 -1
  22. package/dist/cli/commands/entry-payload.d.ts +38 -0
  23. package/dist/cli/commands/entry-payload.d.ts.map +1 -0
  24. package/dist/cli/commands/entry.d.ts +10 -0
  25. package/dist/cli/commands/entry.d.ts.map +1 -1
  26. package/dist/cli/commands/exec.d.ts.map +1 -1
  27. package/dist/cli/commands/io.d.ts +1 -0
  28. package/dist/cli/commands/io.d.ts.map +1 -1
  29. package/dist/cli/commands/visualize.d.ts.map +1 -1
  30. package/dist/cli/index.js +7 -10
  31. package/dist/cli/schemas.d.ts +14 -1
  32. package/dist/cli/schemas.d.ts.map +1 -1
  33. package/dist/cli/server-options-builder.d.ts.map +1 -1
  34. package/dist/cli.js +7 -10
  35. package/dist/codemode/api/journal-api.d.ts +5 -23
  36. package/dist/codemode/api/journal-api.d.ts.map +1 -1
  37. package/dist/codemode/api/key-normalizer.d.ts +8 -0
  38. package/dist/codemode/api/key-normalizer.d.ts.map +1 -0
  39. package/dist/codemode/api/param-normalizer.d.ts +2 -4
  40. package/dist/codemode/api/param-normalizer.d.ts.map +1 -1
  41. package/dist/codemode/api/project-registry-ops.d.ts +26 -0
  42. package/dist/codemode/api/project-registry-ops.d.ts.map +1 -0
  43. package/dist/codemode/api/sandbox-bindings.d.ts +25 -0
  44. package/dist/codemode/api/sandbox-bindings.d.ts.map +1 -0
  45. package/dist/codemode/api/types.d.ts.map +1 -1
  46. package/dist/codemode/api-constants.d.ts +3 -39
  47. package/dist/codemode/api-constants.d.ts.map +1 -1
  48. package/dist/codemode/constants/examples-and-params.d.ts +31 -0
  49. package/dist/codemode/constants/examples-and-params.d.ts.map +1 -0
  50. package/dist/codemode/constants/method-aliases.d.ts +8 -0
  51. package/dist/codemode/constants/method-aliases.d.ts.map +1 -0
  52. package/dist/codemode/normalizers/domain-tool-interceptions.d.ts +6 -0
  53. package/dist/codemode/normalizers/domain-tool-interceptions.d.ts.map +1 -0
  54. package/dist/codemode/normalizers/entry-and-search-interceptions.d.ts +6 -0
  55. package/dist/codemode/normalizers/entry-and-search-interceptions.d.ts.map +1 -0
  56. package/dist/codemode/normalizers/generic-interceptions.d.ts +6 -0
  57. package/dist/codemode/normalizers/generic-interceptions.d.ts.map +1 -0
  58. package/dist/codemode/normalizers/github-and-backup-interceptions.d.ts +6 -0
  59. package/dist/codemode/normalizers/github-and-backup-interceptions.d.ts.map +1 -0
  60. package/dist/codemode/normalizers/shared-utils.d.ts +31 -0
  61. package/dist/codemode/normalizers/shared-utils.d.ts.map +1 -0
  62. package/dist/codemode/param-normalizer.d.ts +5 -1
  63. package/dist/codemode/param-normalizer.d.ts.map +1 -1
  64. package/dist/codemode/proxy-helpers.d.ts +34 -0
  65. package/dist/codemode/proxy-helpers.d.ts.map +1 -0
  66. package/dist/codemode/proxy-namespaces.d.ts +30 -0
  67. package/dist/codemode/proxy-namespaces.d.ts.map +1 -0
  68. package/dist/codemode/security.d.ts +11 -0
  69. package/dist/codemode/security.d.ts.map +1 -1
  70. package/dist/codemode/type-generator.d.ts.map +1 -1
  71. package/dist/codemode/types.d.ts.map +1 -1
  72. package/dist/codemode/worker/mj-shim-domains.d.ts +15 -0
  73. package/dist/codemode/worker/mj-shim-domains.d.ts.map +1 -0
  74. package/dist/codemode/worker/mj-shim-proxy.d.ts +18 -0
  75. package/dist/codemode/worker/mj-shim-proxy.d.ts.map +1 -0
  76. package/dist/codemode/worker/namespace-shims.d.ts +32 -0
  77. package/dist/codemode/worker/namespace-shims.d.ts.map +1 -0
  78. package/dist/codemode/worker/node-shims.d.ts +65 -0
  79. package/dist/codemode/worker/node-shims.d.ts.map +1 -0
  80. package/dist/codemode/worker/prototype-hardening.d.ts +18 -0
  81. package/dist/codemode/worker/prototype-hardening.d.ts.map +1 -0
  82. package/dist/codemode/worker/result-compactor.d.ts +20 -0
  83. package/dist/codemode/worker/result-compactor.d.ts.map +1 -0
  84. package/dist/codemode/worker/sandbox-globals.d.ts +19 -0
  85. package/dist/codemode/worker/sandbox-globals.d.ts.map +1 -0
  86. package/dist/codemode/worker-api-proxy.d.ts +1 -6
  87. package/dist/codemode/worker-api-proxy.d.ts.map +1 -1
  88. package/dist/codemode/worker-result-proxy.d.ts.map +1 -1
  89. package/dist/codemode/worker-sandbox.d.ts.map +1 -1
  90. package/dist/constants/instructions/admin.d.ts +1 -1
  91. package/dist/constants/instructions/admin.d.ts.map +1 -1
  92. package/dist/constants/instructions/base.d.ts +2 -2
  93. package/dist/constants/instructions/base.d.ts.map +1 -1
  94. package/dist/constants/instructions/codemode.d.ts +1 -1
  95. package/dist/constants/instructions/codemode.d.ts.map +1 -1
  96. package/dist/constants/instructions/core.d.ts +1 -1
  97. package/dist/constants/instructions/core.d.ts.map +1 -1
  98. package/dist/constants/instructions/github.d.ts +1 -1
  99. package/dist/constants/instructions/github.d.ts.map +1 -1
  100. package/dist/constants/instructions/gotchas.d.ts +1 -1
  101. package/dist/constants/instructions/gotchas.d.ts.map +1 -1
  102. package/dist/constants/instructions/io.d.ts +1 -1
  103. package/dist/constants/instructions/io.d.ts.map +1 -1
  104. package/dist/constants/instructions/templates.d.ts +1 -1
  105. package/dist/constants/instructions/templates.d.ts.map +1 -1
  106. package/dist/constants/server-instructions.d.ts +2 -2
  107. package/dist/constants/server-instructions.d.ts.map +1 -1
  108. package/dist/database/core/interfaces.d.ts +6 -6
  109. package/dist/database/core/interfaces.d.ts.map +1 -1
  110. package/dist/database/sqlite-adapter/adapter-delegates.d.ts +161 -0
  111. package/dist/database/sqlite-adapter/adapter-delegates.d.ts.map +1 -0
  112. package/dist/database/sqlite-adapter/backup.d.ts.map +1 -1
  113. package/dist/database/sqlite-adapter/database-adapter.d.ts +17 -147
  114. package/dist/database/sqlite-adapter/database-adapter.d.ts.map +1 -1
  115. package/dist/database/sqlite-adapter/entries/crud-read.d.ts +16 -0
  116. package/dist/database/sqlite-adapter/entries/crud-read.d.ts.map +1 -0
  117. package/dist/database/sqlite-adapter/entries/crud-write.d.ts +62 -0
  118. package/dist/database/sqlite-adapter/entries/crud-write.d.ts.map +1 -0
  119. package/dist/database/sqlite-adapter/entries/crud.d.ts +3 -92
  120. package/dist/database/sqlite-adapter/entries/crud.d.ts.map +1 -1
  121. package/dist/database/sqlite-adapter/entries/importance.d.ts +7 -0
  122. package/dist/database/sqlite-adapter/entries/importance.d.ts.map +1 -1
  123. package/dist/database/sqlite-adapter/entries/index.d.ts +9 -4
  124. package/dist/database/sqlite-adapter/entries/index.d.ts.map +1 -1
  125. package/dist/database/sqlite-adapter/entries/revisions.d.ts +16 -0
  126. package/dist/database/sqlite-adapter/entries/revisions.d.ts.map +1 -0
  127. package/dist/database/sqlite-adapter/entries/search/date-and-pagination.d.ts +37 -0
  128. package/dist/database/sqlite-adapter/entries/search/date-and-pagination.d.ts.map +1 -0
  129. package/dist/database/sqlite-adapter/entries/search/entity-lookups.d.ts +31 -0
  130. package/dist/database/sqlite-adapter/entries/search/entity-lookups.d.ts.map +1 -0
  131. package/dist/database/sqlite-adapter/entries/search/fts-and-hybrid.d.ts +44 -0
  132. package/dist/database/sqlite-adapter/entries/search/fts-and-hybrid.d.ts.map +1 -0
  133. package/dist/database/sqlite-adapter/entries/search/index.d.ts +1 -1
  134. package/dist/database/sqlite-adapter/entries/search/index.d.ts.map +1 -1
  135. package/dist/database/sqlite-adapter/entries/search/query.d.ts +3 -82
  136. package/dist/database/sqlite-adapter/entries/search/query.d.ts.map +1 -1
  137. package/dist/database/sqlite-adapter/entries/statistics.d.ts.map +1 -1
  138. package/dist/database/sqlite-adapter/insights/cross-project.d.ts +42 -0
  139. package/dist/database/sqlite-adapter/insights/cross-project.d.ts.map +1 -0
  140. package/dist/database/sqlite-adapter/insights/entry-digest-queries.d.ts +17 -0
  141. package/dist/database/sqlite-adapter/insights/entry-digest-queries.d.ts.map +1 -0
  142. package/dist/database/sqlite-adapter/insights/team-collaboration.d.ts +29 -0
  143. package/dist/database/sqlite-adapter/insights/team-collaboration.d.ts.map +1 -0
  144. package/dist/database/sqlite-adapter/insights-operations.d.ts +11 -50
  145. package/dist/database/sqlite-adapter/insights-operations.d.ts.map +1 -1
  146. package/dist/database/sqlite-adapter/lifecycle-operations.d.ts.map +1 -1
  147. package/dist/database/sqlite-adapter/members.d.ts.map +1 -1
  148. package/dist/database/sqlite-adapter/native-connection.d.ts +5 -0
  149. package/dist/database/sqlite-adapter/native-connection.d.ts.map +1 -1
  150. package/dist/database/sqlite-adapter/relationships.d.ts +1 -2
  151. package/dist/database/sqlite-adapter/relationships.d.ts.map +1 -1
  152. package/dist/database/sqlite-adapter/tags.d.ts.map +1 -1
  153. package/dist/database/sqlite-adapter/vector-operations.d.ts.map +1 -1
  154. package/dist/filtering/tool-constants.d.ts +1 -1
  155. package/dist/{fts-T466O2JP.js → fts-YHUVPPYF.js} +2 -2
  156. package/dist/github/commit-references/enricher.d.ts.map +1 -1
  157. package/dist/github/github-integration/projects.d.ts.map +1 -1
  158. package/dist/handlers/prompts/adversarial-helpers.d.ts +75 -0
  159. package/dist/handlers/prompts/adversarial-helpers.d.ts.map +1 -0
  160. package/dist/handlers/prompts/adversarial.d.ts +3 -5
  161. package/dist/handlers/prompts/adversarial.d.ts.map +1 -1
  162. package/dist/handlers/prompts/cms-supervisor.d.ts +8 -0
  163. package/dist/handlers/prompts/cms-supervisor.d.ts.map +1 -0
  164. package/dist/handlers/prompts/index.d.ts.map +1 -1
  165. package/dist/handlers/prompts/optimizer.d.ts.map +1 -1
  166. package/dist/handlers/prompts/workflow.d.ts.map +1 -1
  167. package/dist/handlers/resources/core/briefing/context-section.d.ts.map +1 -1
  168. package/dist/handlers/resources/core/briefing/github-repo-and-kanban.d.ts +57 -0
  169. package/dist/handlers/resources/core/briefing/github-repo-and-kanban.d.ts.map +1 -0
  170. package/dist/handlers/resources/core/briefing/github-section.d.ts +23 -20
  171. package/dist/handlers/resources/core/briefing/github-section.d.ts.map +1 -1
  172. package/dist/handlers/resources/core/briefing/system-section.d.ts.map +1 -1
  173. package/dist/handlers/resources/core/briefing/user-message.d.ts.map +1 -1
  174. package/dist/handlers/resources/help.d.ts.map +1 -1
  175. package/dist/handlers/resources/index.d.ts.map +1 -1
  176. package/dist/handlers/resources/shared.d.ts +1 -0
  177. package/dist/handlers/resources/shared.d.ts.map +1 -1
  178. package/dist/handlers/resources/staleness.d.ts.map +1 -1
  179. package/dist/handlers/tools/admin/batch-tools.d.ts.map +1 -1
  180. package/dist/handlers/tools/admin/core-tools.d.ts.map +1 -1
  181. package/dist/handlers/tools/admin/index.d.ts.map +1 -1
  182. package/dist/handlers/tools/admin/lifecycle-tools.d.ts.map +1 -1
  183. package/dist/handlers/tools/admin/project-tools.d.ts +1 -1
  184. package/dist/handlers/tools/admin/project-tools.d.ts.map +1 -1
  185. package/dist/handlers/tools/admin/schemas/crud-batch-schemas.d.ts +609 -0
  186. package/dist/handlers/tools/admin/schemas/crud-batch-schemas.d.ts.map +1 -0
  187. package/dist/handlers/tools/admin/schemas/project-and-ops-schemas.d.ts +136 -0
  188. package/dist/handlers/tools/admin/schemas/project-and-ops-schemas.d.ts.map +1 -0
  189. package/dist/handlers/tools/admin/schemas.d.ts +2 -733
  190. package/dist/handlers/tools/admin/schemas.d.ts.map +1 -1
  191. package/dist/handlers/tools/admin/update_configuration.d.ts +14 -0
  192. package/dist/handlers/tools/admin/update_configuration.d.ts.map +1 -1
  193. package/dist/handlers/tools/admin/vector-tools.d.ts.map +1 -1
  194. package/dist/handlers/tools/analytics.d.ts.map +1 -1
  195. package/dist/handlers/tools/arg-interceptions.d.ts +51 -0
  196. package/dist/handlers/tools/arg-interceptions.d.ts.map +1 -0
  197. package/dist/handlers/tools/codemode/code-healer.d.ts +11 -0
  198. package/dist/handlers/tools/codemode/code-healer.d.ts.map +1 -0
  199. package/dist/handlers/tools/codemode/handler.d.ts +4 -23
  200. package/dist/handlers/tools/codemode/handler.d.ts.map +1 -1
  201. package/dist/handlers/tools/codemode/json-entry-recovery.d.ts +13 -0
  202. package/dist/handlers/tools/codemode/json-entry-recovery.d.ts.map +1 -0
  203. package/dist/handlers/tools/codemode/payload-synthesizer.d.ts +17 -0
  204. package/dist/handlers/tools/codemode/payload-synthesizer.d.ts.map +1 -0
  205. package/dist/handlers/tools/codemode/secure-dispatcher.d.ts +25 -0
  206. package/dist/handlers/tools/codemode/secure-dispatcher.d.ts.map +1 -0
  207. package/dist/handlers/tools/codemode/sql-recovery.d.ts +14 -0
  208. package/dist/handlers/tools/codemode/sql-recovery.d.ts.map +1 -0
  209. package/dist/handlers/tools/core/dummy-healing/alias-catalog.d.ts +21 -0
  210. package/dist/handlers/tools/core/dummy-healing/alias-catalog.d.ts.map +1 -0
  211. package/dist/handlers/tools/core/dummy-healing/entry-fallbacks.d.ts +4 -0
  212. package/dist/handlers/tools/core/dummy-healing/entry-fallbacks.d.ts.map +1 -0
  213. package/dist/handlers/tools/core/dummy-healing/fs-fallbacks.d.ts +19 -0
  214. package/dist/handlers/tools/core/dummy-healing/fs-fallbacks.d.ts.map +1 -0
  215. package/dist/handlers/tools/core/dummy-healing/index.d.ts +7 -0
  216. package/dist/handlers/tools/core/dummy-healing/index.d.ts.map +1 -0
  217. package/dist/handlers/tools/core/dummy-healing/mcp-fallbacks.d.ts +12 -0
  218. package/dist/handlers/tools/core/dummy-healing/mcp-fallbacks.d.ts.map +1 -0
  219. package/dist/handlers/tools/core/dummy-healing.d.ts +1 -29
  220. package/dist/handlers/tools/core/dummy-healing.d.ts.map +1 -1
  221. package/dist/handlers/tools/core/index.d.ts +1 -1
  222. package/dist/handlers/tools/core/index.d.ts.map +1 -1
  223. package/dist/handlers/tools/core/schemas.d.ts +33 -9
  224. package/dist/handlers/tools/core/schemas.d.ts.map +1 -1
  225. package/dist/handlers/tools/core/staleness-tools.d.ts +17 -0
  226. package/dist/handlers/tools/core/staleness-tools.d.ts.map +1 -1
  227. package/dist/handlers/tools/core/tools.d.ts.map +1 -1
  228. package/dist/handlers/tools/git.d.ts +5 -11
  229. package/dist/handlers/tools/git.d.ts.map +1 -1
  230. package/dist/handlers/tools/github/close-issue-tool.d.ts +6 -0
  231. package/dist/handlers/tools/github/close-issue-tool.d.ts.map +1 -0
  232. package/dist/handlers/tools/github/create-issue-tool.d.ts +6 -0
  233. package/dist/handlers/tools/github/create-issue-tool.d.ts.map +1 -0
  234. package/dist/handlers/tools/github/issue-tools.d.ts +3 -0
  235. package/dist/handlers/tools/github/issue-tools.d.ts.map +1 -1
  236. package/dist/handlers/tools/github/kanban-tools.d.ts.map +1 -1
  237. package/dist/handlers/tools/github/milestone-tools.d.ts.map +1 -1
  238. package/dist/handlers/tools/index.d.ts +2 -2
  239. package/dist/handlers/tools/index.d.ts.map +1 -1
  240. package/dist/handlers/tools/io/schemas.d.ts +5 -2
  241. package/dist/handlers/tools/io/schemas.d.ts.map +1 -1
  242. package/dist/handlers/tools/relationships.d.ts.map +1 -1
  243. package/dist/handlers/tools/schemas/constants-and-primitives.d.ts +53 -0
  244. package/dist/handlers/tools/schemas/constants-and-primitives.d.ts.map +1 -0
  245. package/dist/handlers/tools/schemas/hallucination-healer.d.ts +8 -0
  246. package/dist/handlers/tools/schemas/hallucination-healer.d.ts.map +1 -0
  247. package/dist/handlers/tools/schemas/output-schemas.d.ts +247 -0
  248. package/dist/handlers/tools/schemas/output-schemas.d.ts.map +1 -0
  249. package/dist/handlers/tools/schemas.d.ts +4 -306
  250. package/dist/handlers/tools/schemas.d.ts.map +1 -1
  251. package/dist/handlers/tools/search/cross-team.d.ts +14 -0
  252. package/dist/handlers/tools/search/cross-team.d.ts.map +1 -1
  253. package/dist/handlers/tools/search/helpers.d.ts.map +1 -1
  254. package/dist/handlers/tools/search/hybrid.d.ts.map +1 -1
  255. package/dist/handlers/tools/search/misc-tools.d.ts.map +1 -1
  256. package/dist/handlers/tools/search/schemas.d.ts +6 -3
  257. package/dist/handlers/tools/search/schemas.d.ts.map +1 -1
  258. package/dist/handlers/tools/search/search-entries.d.ts.map +1 -1
  259. package/dist/handlers/tools/search/semantic-search.d.ts.map +1 -1
  260. package/dist/handlers/tools/team/admin-tools/batch.d.ts.map +1 -1
  261. package/dist/handlers/tools/team/admin-tools/crud.d.ts.map +1 -1
  262. package/dist/handlers/tools/team/backup-tools.d.ts.map +1 -1
  263. package/dist/handlers/tools/team/core-tools.d.ts.map +1 -1
  264. package/dist/handlers/tools/team/helpers.d.ts.map +1 -1
  265. package/dist/handlers/tools/team/io-tools.d.ts.map +1 -1
  266. package/dist/handlers/tools/team/member-tools.d.ts.map +1 -1
  267. package/dist/handlers/tools/team/rbac.d.ts.map +1 -1
  268. package/dist/handlers/tools/team/relationship-tools.d.ts.map +1 -1
  269. package/dist/handlers/tools/team/schemas/admin-batch-schemas.d.ts +618 -0
  270. package/dist/handlers/tools/team/schemas/admin-batch-schemas.d.ts.map +1 -0
  271. package/dist/handlers/tools/team/schemas/analytics-vector-schemas.d.ts +464 -0
  272. package/dist/handlers/tools/team/schemas/analytics-vector-schemas.d.ts.map +1 -0
  273. package/dist/handlers/tools/team/schemas/core-search-schemas.d.ts +525 -0
  274. package/dist/handlers/tools/team/schemas/core-search-schemas.d.ts.map +1 -0
  275. package/dist/handlers/tools/team/schemas/io-backup-schemas.d.ts +419 -0
  276. package/dist/handlers/tools/team/schemas/io-backup-schemas.d.ts.map +1 -0
  277. package/dist/handlers/tools/team/schemas.d.ts +5 -2002
  278. package/dist/handlers/tools/team/schemas.d.ts.map +1 -1
  279. package/dist/handlers/tools/team/search-tools.d.ts.map +1 -1
  280. package/dist/handlers/tools/team/vector-tools.d.ts.map +1 -1
  281. package/dist/index.js +6 -9
  282. package/dist/markdown/exporter.d.ts.map +1 -1
  283. package/dist/markdown/importer.d.ts.map +1 -1
  284. package/dist/observability/latency-tracker.d.ts.map +1 -1
  285. package/dist/observability/metrics-server.d.ts +1 -1
  286. package/dist/observability/metrics-server.d.ts.map +1 -1
  287. package/dist/observability/token-estimator.d.ts.map +1 -1
  288. package/dist/{security-utils-HNTROJAG.js → security-utils-P4P6A2DG.js} +1 -1
  289. package/dist/server/digest-reporter.d.ts +1 -0
  290. package/dist/server/digest-reporter.d.ts.map +1 -1
  291. package/dist/server/mcp-server/core.d.ts.map +1 -1
  292. package/dist/server/mcp-server/tool-registration/call-interceptor.d.ts +6 -0
  293. package/dist/server/mcp-server/tool-registration/call-interceptor.d.ts.map +1 -0
  294. package/dist/server/mcp-server/tool-registration/index.d.ts +4 -0
  295. package/dist/server/mcp-server/tool-registration/index.d.ts.map +1 -0
  296. package/dist/server/mcp-server/tool-registration/list-interceptor.d.ts +4 -0
  297. package/dist/server/mcp-server/tool-registration/list-interceptor.d.ts.map +1 -0
  298. package/dist/server/mcp-server/tool-registration/register-tools.d.ts +18 -0
  299. package/dist/server/mcp-server/tool-registration/register-tools.d.ts.map +1 -0
  300. package/dist/server/mcp-server/tool-registration.d.ts +1 -17
  301. package/dist/server/mcp-server/tool-registration.d.ts.map +1 -1
  302. package/dist/server/registration.d.ts +2 -0
  303. package/dist/server/registration.d.ts.map +1 -1
  304. package/dist/server/scheduler.d.ts +1 -0
  305. package/dist/server/scheduler.d.ts.map +1 -1
  306. package/dist/server/subscription-manager.d.ts +2 -0
  307. package/dist/server/subscription-manager.d.ts.map +1 -1
  308. package/dist/tools-BOQV7QD3.js +6 -0
  309. package/dist/transports/http/security.d.ts.map +1 -1
  310. package/dist/transports/http/server/http-transport.d.ts +25 -0
  311. package/dist/transports/http/server/http-transport.d.ts.map +1 -0
  312. package/dist/transports/http/server/index.d.ts +3 -30
  313. package/dist/transports/http/server/index.d.ts.map +1 -1
  314. package/dist/transports/http/server/legacy-sse.d.ts.map +1 -1
  315. package/dist/transports/http/server/protocol-handlers.d.ts +9 -0
  316. package/dist/transports/http/server/protocol-handlers.d.ts.map +1 -0
  317. package/dist/types/entities.d.ts +41 -1
  318. package/dist/types/entities.d.ts.map +1 -1
  319. package/dist/types/index.d.ts +11 -4
  320. package/dist/types/index.d.ts.map +1 -1
  321. package/dist/utils/config-manager.d.ts +2 -0
  322. package/dist/utils/config-manager.d.ts.map +1 -1
  323. package/dist/utils/error-helpers.d.ts.map +1 -1
  324. package/dist/utils/issue-logger.d.ts.map +1 -1
  325. package/dist/utils/mcp-logger.d.ts +14 -2
  326. package/dist/utils/mcp-logger.d.ts.map +1 -1
  327. package/dist/utils/security-utils.d.ts.map +1 -1
  328. package/dist/utils/vector-index-helpers.d.ts +1 -1
  329. package/dist/utils/vector-index-helpers.d.ts.map +1 -1
  330. package/dist/utils/workspace-resolver.d.ts.map +1 -1
  331. package/dist/vector/vector-search-manager/manager.d.ts +2 -2
  332. package/dist/vector/vector-search-manager/manager.d.ts.map +1 -1
  333. package/dist/vector/vector-search-manager/rebuild.d.ts.map +1 -1
  334. package/dist/vendor/lib-agent-exec/interceptors/git-interceptor.d.ts.map +1 -1
  335. package/dist/vendor/lib-agent-exec/schema.d.ts +18 -18
  336. package/dist/vendor/lib-agent-exec/schema.d.ts.map +1 -1
  337. package/dist/vendor/lib-agent-exec/stream-manager.d.ts.map +1 -1
  338. package/dist/worker-script.js +2662 -2645
  339. package/package.json +3 -4
  340. package/skills/memory-journal-mcp/SKILL.md +8 -8
  341. package/dist/auth/context.d.ts +0 -7
  342. package/dist/auth/context.d.ts.map +0 -1
  343. package/dist/chunk-ELMJYRTT.js +0 -29
  344. package/dist/chunk-F6WSLZVN.js +0 -675
  345. package/dist/chunk-JVGY2GHK.js +0 -776
  346. package/dist/chunk-KWSBCSFM.js +0 -411
  347. package/dist/chunk-SP5D3XYY.js +0 -1550
  348. package/dist/chunk-XJMEPP36.js +0 -57
  349. package/dist/database/core/entry-columns.d.ts +0 -8
  350. package/dist/database/core/entry-columns.d.ts.map +0 -1
  351. package/dist/database/core/schema.d.ts +0 -69
  352. package/dist/database/core/schema.d.ts.map +0 -1
  353. package/dist/error-helpers-STR7IPUR.js +0 -2
  354. package/dist/git-runner-6OE7PVKA.js +0 -1
  355. package/dist/journal-api-UG43ZD7Y.js +0 -1289
  356. package/dist/tools-RBNFDWIE.js +0 -9
@@ -1,155 +1,24 @@
1
- import { logger, DatabaseAdapterFactory, runAutoPrune, AuditLogger, createAuditInterceptor, getGitHubIntegration, parseToolFilter, getFilterSummary, getToolFilterFromEnv, getAllToolNames, DEFAULT_BRIEFING_CONFIG, getTools, getRequiredScope, getResources, getPrompts, callTool, requestContextStorage, MetricsAccumulator, formatPrometheusMetrics, SUPPORTED_SCOPES, VERSION, logAgentIssue, validateResourceSubscription, getPrompt, readResource, getDummyHealingTools, TOOL_GROUPS, isValidScope, getEnabledGroups, generateCodeModeInstructions, generateStandardInstructions, enforceAccessBoundary, auditOperation, parseScopes, BASE_SCOPES } from './chunk-2UIMA6JF.js';
2
- import { sendProgress } from './chunk-ELMJYRTT.js';
3
- import { applyArgInterceptions } from './chunk-SP5D3XYY.js';
4
- import { runWithAuthContext } from './chunk-6RCZ4IYV.js';
1
+ import { DUMMY_GREP_SEARCH_TOOL_NAMES, DUMMY_FILE_VIEW_TOOL_NAMES, DUMMY_DIR_LIST_TOOL_NAMES, TOOL_GROUPS, logger, DatabaseAdapterFactory, runAutoPrune, AuditLogger, createAuditInterceptor, getGitHubIntegration, parseToolFilter, getFilterSummary, getToolFilterFromEnv, getAllToolNames, DEFAULT_BRIEFING_CONFIG, getTools, globalSubscriptionManager, getRequiredScope, getResources, getPrompts, callTool, sendProgress, requestContextStorage, MetricsAccumulator, formatPrometheusMetrics, SUPPORTED_SCOPES, logAgentIssue, validateResourceSubscription, isValidScope, getEnabledGroups, generateCodeModeInstructions, generateStandardInstructions, enforceAccessBoundary, auditOperation, parseScopes, BASE_SCOPES, getPrompt, handlePrompt, handleReadResource, handleListResources, handleListPrompts, handleGetPrompt, DUMMY_SERVER_INFO_TOOL_NAMES, handleServerInfo, handleListAdapters, handleGrepSearch, handleViewFile, handleListDir, DUMMY_RESOURCE_TOOL_NAMES, DUMMY_LIST_RESOURCE_TOOL_NAMES, DUMMY_LIST_PROMPT_TOOL_NAMES, DUMMY_LIST_TOOL_NAMES, DUMMY_GET_PROMPT_TOOL_NAMES, DUMMY_PROJECT_TOOL_NAMES, DUMMY_ADAPTER_TOOL_NAMES, readResource } from './chunk-T7SROBBV.js';
2
+ import { VERSION, applyArgInterceptions } from './chunk-SGJU2DHU.js';
3
+ import { runWithAuthContext, getAuthContext } from './chunk-4FZCHFB5.js';
5
4
  import { MemoryJournalMcpError, ConfigurationError } from './chunk-E6IQP6PE.js';
6
5
  import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
7
- import { toNodeHandler, NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
8
- import { createMcpHandler, McpServer, ResourceTemplate } from '@modelcontextprotocol/server';
9
- import { randomUUID, createHash, timingSafeEqual } from 'crypto';
10
6
  import express from 'express';
7
+ import { createHash, timingSafeEqual, randomUUID } from 'crypto';
11
8
  import 'https';
12
9
  import * as jose from 'jose';
13
10
  import { localhostHostValidation, hostHeaderValidation } from '@modelcontextprotocol/express';
11
+ import { toNodeHandler, NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
12
+ import { McpServer, createMcpHandler, ResourceTemplate } from '@modelcontextprotocol/server';
14
13
  import * as fs from 'fs';
15
14
  import * as path from 'path';
16
15
  import { loadSkills } from '@modelcontextprotocol/server/ext/skills/node';
16
+ import * as dns from 'dns';
17
17
  import { EventEmitter } from 'events';
18
18
  import { parse, stringify } from 'yaml';
19
19
  import { z } from 'zod';
20
20
  import * as http from 'http';
21
21
 
22
- // src/server/subscription-manager.ts
23
- var SubscriptionManager = class {
24
- // Map of Session ID (or 'stdio') -> McpServer instance
25
- servers = /* @__PURE__ */ new Map();
26
- // Map of URI string -> Set of Session IDs
27
- subscriptions = /* @__PURE__ */ new Map();
28
- /**
29
- * Register a server instance for a session to allow sending notifications.
30
- */
31
- registerServer(sessionId, server) {
32
- this.servers.set(sessionId, server);
33
- }
34
- /**
35
- * Unregister a server instance and clean up its subscriptions.
36
- */
37
- unregisterServer(sessionId) {
38
- this.servers.delete(sessionId);
39
- this.unsubscribeSession(sessionId);
40
- }
41
- /**
42
- * Subscribe a session to a resource URI.
43
- */
44
- subscribe(uri, sessionId) {
45
- if (!sessionId) {
46
- sessionId = "stdio";
47
- }
48
- let sessions = this.subscriptions.get(uri);
49
- if (!sessions) {
50
- sessions = /* @__PURE__ */ new Set();
51
- this.subscriptions.set(uri, sessions);
52
- }
53
- if (!sessions.has(sessionId)) {
54
- sessions.add(sessionId);
55
- logger.debug(`Session ${sessionId} subscribed to resource ${uri}`, {
56
- module: "SubscriptionManager"
57
- });
58
- }
59
- }
60
- /**
61
- * Unsubscribe a session from a resource URI.
62
- */
63
- unsubscribe(uri, sessionId) {
64
- if (!sessionId) {
65
- sessionId = "stdio";
66
- }
67
- const sessions = this.subscriptions.get(uri);
68
- if (sessions?.has(sessionId)) {
69
- sessions.delete(sessionId);
70
- logger.debug(`Session ${sessionId} unsubscribed from resource ${uri}`, {
71
- module: "SubscriptionManager"
72
- });
73
- if (sessions.size === 0) {
74
- this.subscriptions.delete(uri);
75
- }
76
- }
77
- }
78
- /**
79
- * Unsubscribe a session from all resources (useful on transport disconnect).
80
- */
81
- unsubscribeSession(sessionId) {
82
- let count = 0;
83
- for (const [uri, sessions] of this.subscriptions.entries()) {
84
- if (sessions.has(sessionId)) {
85
- sessions.delete(sessionId);
86
- count++;
87
- if (sessions.size === 0) {
88
- this.subscriptions.delete(uri);
89
- }
90
- }
91
- }
92
- if (count > 0) {
93
- logger.debug(
94
- `Session ${sessionId} disconnected, removed ${count} subscriptions`,
95
- { module: "SubscriptionManager" }
96
- );
97
- }
98
- }
99
- /**
100
- * Notifies all subscribed clients that a resource has changed.
101
- */
102
- async notifyResourceUpdated(uri) {
103
- const sessions = this.subscriptions.get(uri);
104
- if (!sessions || sessions.size === 0) {
105
- return;
106
- }
107
- const promises = [];
108
- for (const sessionId of sessions) {
109
- const server = this.servers.get(sessionId);
110
- if (server) {
111
- promises.push(
112
- server.server.sendResourceUpdated({ uri }).catch((error) => {
113
- logger.error(`Failed to notify session ${sessionId} for ${uri}`, {
114
- module: "SubscriptionManager",
115
- error: error instanceof Error ? error : new Error(String(error))
116
- });
117
- })
118
- );
119
- }
120
- }
121
- await Promise.allSettled(promises);
122
- }
123
- /**
124
- * Broadcasts a generic notification to all connected clients.
125
- */
126
- async broadcastNotification(method) {
127
- if (this.servers.size === 0) {
128
- return;
129
- }
130
- const promises = [];
131
- for (const [sessionId, server] of this.servers.entries()) {
132
- promises.push(
133
- server.server.notification({ method }).catch((error) => {
134
- logger.debug(`Failed to broadcast ${method} to session ${sessionId}`, {
135
- module: "SubscriptionManager",
136
- error: error instanceof Error ? error.message : String(error)
137
- });
138
- })
139
- );
140
- }
141
- await Promise.allSettled(promises);
142
- }
143
- /**
144
- * Check if there are any active subscribers for a specific URI.
145
- */
146
- hasSubscribers(uri) {
147
- const sessions = this.subscriptions.get(uri);
148
- return sessions ? sessions.size > 0 : false;
149
- }
150
- };
151
- var globalSubscriptionManager = new SubscriptionManager();
152
-
153
22
  // src/transports/http/types.ts
154
23
  var HTTP_REQUEST_TIMEOUT_MS = 12e4;
155
24
  var HTTP_KEEP_ALIVE_TIMEOUT_MS = 65e3;
@@ -159,6 +28,8 @@ var DEFAULT_RATE_LIMIT_MAX_REQUESTS = 100;
159
28
  var DEFAULT_MAX_BODY_BYTES = 1048576;
160
29
  var DEFAULT_HSTS_MAX_AGE = 31536e3;
161
30
  var CORS_PREFLIGHT_MAX_AGE_SECONDS = 86400;
31
+ var SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
32
+ var SESSION_SWEEP_INTERVAL_MS = 1 * 60 * 1e3;
162
33
  function getClientIp(req) {
163
34
  return req.ip ?? req.socket.remoteAddress ?? "unknown";
164
35
  }
@@ -167,7 +38,7 @@ function checkRateLimit(req, config, rateLimitMap) {
167
38
  return { allowed: true };
168
39
  }
169
40
  const authReq = req;
170
- const subject = authReq.auth?.sub ?? authReq.auth?.subject;
41
+ const subject = authReq.tokenClaims?.sub ?? authReq.tokenClaims?.client_id ?? authReq.auth?.sub ?? authReq.auth?.subject ?? authReq.auth?.clientId;
171
42
  const ip = getClientIp(req);
172
43
  const rawIdentity = typeof subject === "string" && subject ? subject : ip;
173
44
  const clientIdentity = createHash("sha256").update(rawIdentity).digest("hex");
@@ -584,6 +455,7 @@ var TokenValidator = class {
584
455
  issuer: this.issuer,
585
456
  audience: this.audience,
586
457
  clockTolerance: this.clockTolerance,
458
+ algorithms: ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"],
587
459
  // jose only checks `exp` when it is present. Require it so a validly signed token
588
460
  // without an expiry cannot become a permanent credential.
589
461
  requiredClaims: ["exp"]
@@ -806,23 +678,19 @@ function createTokenValidator(config) {
806
678
  return new TokenValidator(config);
807
679
  }
808
680
 
809
- // src/auth/middleware.ts
681
+ // src/auth/transport-agnostic.ts
810
682
  function extractBearerToken(authHeader) {
811
- if (!authHeader) {
812
- return null;
813
- }
683
+ if (!authHeader) return null;
814
684
  const parts = authHeader.split(" ");
815
685
  const scheme = parts[0];
816
686
  const tokenPart = parts[1];
817
- if (parts.length !== 2 || scheme?.toLowerCase() !== "bearer") {
818
- return null;
819
- }
820
- if (tokenPart === void 0) {
821
- return null;
822
- }
687
+ if (parts.length !== 2 || scheme?.toLowerCase() !== "bearer") return null;
688
+ if (tokenPart === void 0) return null;
823
689
  const token = tokenPart.trim();
824
690
  return token.length > 0 ? token : null;
825
691
  }
692
+
693
+ // src/auth/middleware.ts
826
694
  function isPublicPath(path2, publicPaths) {
827
695
  if (path2 === "/.well-known/oauth-authorization-server" || path2 === "/.well-known/jwks.json") {
828
696
  return true;
@@ -959,6 +827,10 @@ data: ${JSON.stringify(message)}
959
827
  * Handles the initial GET request to establish the SSE stream.
960
828
  */
961
829
  handleSseRequest(req, res) {
830
+ if (this.res !== null) {
831
+ res.status(409).json({ error: { message: "SSE stream already connected for this session" } });
832
+ return;
833
+ }
962
834
  this.res = res;
963
835
  res.writeHead(200, {
964
836
  "Content-Type": "text/event-stream",
@@ -994,15 +866,223 @@ data: ${endpointUrl}
994
866
  }
995
867
  };
996
868
 
997
- // src/transports/http/server/index.ts
869
+ // src/transports/http/server/protocol-handlers.ts
870
+ var MAX_ACTIVE_SESSIONS = 100;
871
+ function resolveRequestSubject() {
872
+ const claims = getAuthContext()?.claims;
873
+ const sub = claims?.sub ?? claims?.email ?? claims?.client_id ?? claims?.subject ?? claims?.clientId;
874
+ return typeof sub === "string" && sub.length > 0 ? sub : void 0;
875
+ }
876
+ function registerMcpProtocolRoutes(app, config, serverFactory, activeServers, sseTransports) {
877
+ const statelessMcpHandler = toNodeHandler(
878
+ createMcpHandler(
879
+ () => {
880
+ const server = serverFactory();
881
+ activeServers.add(server);
882
+ const originalClose = server.close.bind(server);
883
+ server.close = async () => {
884
+ activeServers.delete(server);
885
+ return originalClose();
886
+ };
887
+ return server;
888
+ },
889
+ { legacy: "reject" }
890
+ )
891
+ );
892
+ const sessionOwners = /* @__PURE__ */ new Map();
893
+ const sessionLastActivity = /* @__PURE__ */ new Map();
894
+ const sweepTimer = setInterval(() => {
895
+ const now = Date.now();
896
+ for (const [sid, lastActive] of sessionLastActivity.entries()) {
897
+ if (now - lastActive > SESSION_TIMEOUT_MS) {
898
+ const transport = sseTransports.get(sid);
899
+ if (transport !== void 0) {
900
+ void transport.close();
901
+ sseTransports.delete(sid);
902
+ }
903
+ sessionOwners.delete(sid);
904
+ sessionLastActivity.delete(sid);
905
+ globalSubscriptionManager.unregisterServer(sid);
906
+ }
907
+ }
908
+ }, SESSION_SWEEP_INTERVAL_MS);
909
+ sweepTimer.unref();
910
+ const verifySessionOwner = (res, sid) => {
911
+ const expectedOwner = sessionOwners.get(sid);
912
+ const callerSubject = resolveRequestSubject();
913
+ if (expectedOwner !== void 0 && expectedOwner !== callerSubject) {
914
+ res.status(403).json({ error: { message: "Forbidden: Session belongs to another principal" } });
915
+ return false;
916
+ }
917
+ sessionLastActivity.set(sid, Date.now());
918
+ return true;
919
+ };
920
+ const createSessionAndHandle = (req, res, next, _sid, isLegacySse = false) => {
921
+ if (sseTransports.size >= MAX_ACTIVE_SESSIONS) {
922
+ res.status(503).json({
923
+ error: { message: "Service Unavailable: Maximum active stateful sessions reached" }
924
+ });
925
+ return;
926
+ }
927
+ const sid = _sid ?? randomUUID();
928
+ const transport = isLegacySse ? new LegacySSEServerTransport("/messages", sid) : new NodeStreamableHTTPServerTransport({
929
+ sessionIdGenerator: () => sid
930
+ });
931
+ const sessionId = sid;
932
+ const server = serverFactory();
933
+ const callerSubject = resolveRequestSubject();
934
+ if (callerSubject !== void 0) {
935
+ sessionOwners.set(sessionId, callerSubject);
936
+ }
937
+ sessionLastActivity.set(sessionId, Date.now());
938
+ const authLog = callerSubject !== void 0 ? ` as ${callerSubject}` : "";
939
+ logger.info(`New MCP stateful session initialized${authLog}`, {
940
+ module: "HTTP",
941
+ sessionId,
942
+ ...callerSubject !== void 0 ? { subject: callerSubject } : {}
943
+ });
944
+ activeServers.add(server);
945
+ globalSubscriptionManager.registerServer(sessionId, server);
946
+ const originalClose = server.close.bind(server);
947
+ server.close = async () => {
948
+ activeServers.delete(server);
949
+ sseTransports.delete(sessionId);
950
+ sessionOwners.delete(sessionId);
951
+ sessionLastActivity.delete(sessionId);
952
+ globalSubscriptionManager.unregisterServer(sessionId);
953
+ return originalClose();
954
+ };
955
+ sseTransports.set(sessionId, transport);
956
+ transport.onclose = () => {
957
+ server.close().catch(
958
+ (err) => logger.error("Error closing server on transport close", {
959
+ error: String(err)
960
+ })
961
+ );
962
+ };
963
+ server.connect(transport).catch(
964
+ (err) => logger.error("Error connecting server to transport", {
965
+ error: String(err)
966
+ })
967
+ );
968
+ if (transport instanceof LegacySSEServerTransport) {
969
+ transport.handleSseRequest(req, res);
970
+ } else {
971
+ transport.handleRequest(req, res, req.body).catch((err) => {
972
+ logger.error("Error handling transport request", {
973
+ error: String(err),
974
+ ...err instanceof Error && err.stack !== void 0 ? { stack: err.stack } : {}
975
+ });
976
+ next(err);
977
+ });
978
+ }
979
+ };
980
+ const handleStatefulGet = (req, res, next) => {
981
+ if (config.stateless) {
982
+ if (req.path === "/sse" || req.path === "/sse/") {
983
+ next();
984
+ return;
985
+ }
986
+ res.status(405).json({
987
+ error: { message: "SSE streaming not available in stateless mode" }
988
+ });
989
+ return;
990
+ }
991
+ const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
992
+ if (sid !== void 0 && sid !== "") {
993
+ const transport = sseTransports.get(sid);
994
+ if (transport === void 0) {
995
+ res.status(400).json({ error: { message: "Session not found" } });
996
+ return;
997
+ }
998
+ if (!verifySessionOwner(res, sid)) return;
999
+ if (transport instanceof LegacySSEServerTransport) {
1000
+ transport.handleSseRequest(req, res);
1001
+ } else {
1002
+ transport.handleRequest(req, res).catch((err) => {
1003
+ next(err);
1004
+ });
1005
+ }
1006
+ } else {
1007
+ if (req.path === "/sse" || req.path === "/sse/") {
1008
+ createSessionAndHandle(req, res, next, randomUUID(), true);
1009
+ return;
1010
+ }
1011
+ res.status(405).json({
1012
+ error: "Method Not Allowed (Streamable HTTP requires POST initialization)"
1013
+ });
1014
+ return;
1015
+ }
1016
+ };
1017
+ app.get("/mcp", handleStatefulGet);
1018
+ app.get("/sse", handleStatefulGet);
1019
+ const handlePost = (req, res, next) => {
1020
+ const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
1021
+ if (sid !== void 0 && sid !== "") {
1022
+ const transport = sseTransports.get(sid);
1023
+ if (transport === void 0) {
1024
+ res.status(400).json({ error: { message: "Session not found" } });
1025
+ return;
1026
+ }
1027
+ if (!verifySessionOwner(res, sid)) return;
1028
+ if (transport instanceof LegacySSEServerTransport) {
1029
+ transport.handlePostMessage(req, res);
1030
+ } else {
1031
+ transport.handleRequest(req, res, req.body).catch((err) => {
1032
+ next(err);
1033
+ });
1034
+ }
1035
+ } else {
1036
+ const acceptsSse = req.headers.accept?.includes("text/event-stream") ?? false;
1037
+ const isLegacyMessages = req.path === "/messages" || req.path === "/messages/";
1038
+ if (isLegacyMessages) {
1039
+ res.status(400).json({ error: { message: "Missing sessionId parameter" } });
1040
+ } else if (acceptsSse && !config.stateless) {
1041
+ createSessionAndHandle(req, res, next, randomUUID(), false);
1042
+ } else {
1043
+ logger.debug("Routing to statelessMcpHandler", {
1044
+ method: req.method,
1045
+ path: req.path
1046
+ });
1047
+ statelessMcpHandler(req, res, req.body).catch((err) => {
1048
+ next(err);
1049
+ });
1050
+ }
1051
+ }
1052
+ };
1053
+ app.post("/mcp", handlePost);
1054
+ app.post("/sse", handlePost);
1055
+ app.post("/messages", handlePost);
1056
+ app.delete("/mcp", (req, res) => {
1057
+ if (config.stateless) {
1058
+ res.status(204).end();
1059
+ return;
1060
+ }
1061
+ const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
1062
+ if (sid === void 0 || sid === "") {
1063
+ res.status(400).json({ error: { message: "Missing sessionId parameter" } });
1064
+ return;
1065
+ }
1066
+ const transport = sseTransports.get(sid);
1067
+ if (transport !== void 0) {
1068
+ if (!verifySessionOwner(res, sid)) return;
1069
+ void transport.close();
1070
+ sseTransports.delete(sid);
1071
+ sessionOwners.delete(sid);
1072
+ sessionLastActivity.delete(sid);
1073
+ globalSubscriptionManager.unregisterServer(sid);
1074
+ }
1075
+ res.status(204).end();
1076
+ });
1077
+ }
1078
+
1079
+ // src/transports/http/server/http-transport.ts
998
1080
  var HttpTransport = class {
999
1081
  app;
1000
1082
  config;
1001
1083
  activeServers = /* @__PURE__ */ new Set();
1002
1084
  httpServer = null;
1003
- // Map to keep track of stateful SSE transports
1004
1085
  sseTransports = /* @__PURE__ */ new Map();
1005
- // Rate limiting state
1006
1086
  rateLimitMap = /* @__PURE__ */ new Map();
1007
1087
  rateLimitCleanupTimer = null;
1008
1088
  constructor(config) {
@@ -1011,13 +1091,10 @@ var HttpTransport = class {
1011
1091
  enableRateLimit: config.enableRateLimit ?? true
1012
1092
  };
1013
1093
  this.app = express();
1014
- if (this.config.trustProxy) {
1094
+ if (this.config.trustProxy === true) {
1015
1095
  this.app.set("trust proxy", "loopback");
1016
1096
  }
1017
1097
  }
1018
- /**
1019
- * Initialize and start the HTTP transport
1020
- */
1021
1098
  async start(serverFactory, scheduler, runtime) {
1022
1099
  const { port, host, authToken, corsOrigins } = this.config;
1023
1100
  const isLocalhost = host === "localhost" || host === "127.0.0.1" || host === "::1";
@@ -1077,23 +1154,19 @@ var HttpTransport = class {
1077
1154
  const maxBody = this.config.maxBodySize ?? DEFAULT_MAX_BODY_BYTES;
1078
1155
  const jsonParser = express.json({ limit: maxBody });
1079
1156
  this.app.use((req, res, next) => {
1080
- if (req.method === "POST" && req.path === "/mcp" && req.query["sessionId"] === void 0) {
1081
- const contentLength = parseInt(req.headers["content-length"] || "0", 10);
1082
- if (contentLength > maxBody) {
1083
- res.status(413).json({
1084
- jsonrpc: "2.0",
1085
- error: {
1086
- code: -32e3,
1087
- message: "Payload Too Large: Maximum request body size exceeded"
1088
- },
1089
- id: null
1090
- });
1091
- return;
1092
- }
1093
- next();
1094
- } else {
1095
- jsonParser(req, res, next);
1157
+ const contentLength = parseInt(req.headers["content-length"] ?? "0", 10);
1158
+ if (contentLength > maxBody) {
1159
+ res.status(413).json({
1160
+ jsonrpc: "2.0",
1161
+ error: {
1162
+ code: -32e3,
1163
+ message: "Payload Too Large: Maximum request body size exceeded"
1164
+ },
1165
+ id: null
1166
+ });
1167
+ return;
1096
1168
  }
1169
+ jsonParser(req, res, next);
1097
1170
  });
1098
1171
  this.app.use((err, _req, res, next) => {
1099
1172
  if (err !== null && typeof err === "object" && "type" in err) {
@@ -1150,18 +1223,13 @@ var HttpTransport = class {
1150
1223
  }
1151
1224
  }, 6e4);
1152
1225
  this.rateLimitCleanupTimer.unref();
1153
- logger.info("Rate limiting enabled (using IP)", {
1154
- module: "HTTP"
1155
- });
1226
+ logger.info("Rate limiting enabled (using IP)", { module: "HTTP" });
1156
1227
  }
1157
- if (this.config.oauthEnabled && this.config.oauthIssuer && this.config.oauthAudience) {
1228
+ if (this.config.oauthEnabled === true && this.config.oauthIssuer !== void 0 && this.config.oauthAudience !== void 0) {
1158
1229
  if (this.config.oauthIssuer.startsWith("http://")) {
1159
- if (!this.config.allowPlaintextLoopbackOAuth) {
1230
+ if (this.config.allowPlaintextLoopbackOAuth !== true) {
1160
1231
  const errorMsg = `FATAL: OAuth issuer targets a plaintext protocol. You MUST deliberately set 'allowPlaintextLoopbackOAuth: true' in config to bypass strict discovery bound.`;
1161
- logger.error(errorMsg, {
1162
- module: "HTTP",
1163
- operation: "oauth-config"
1164
- });
1232
+ logger.error(errorMsg, { module: "HTTP", operation: "oauth-config" });
1165
1233
  throw new Error(errorMsg);
1166
1234
  }
1167
1235
  try {
@@ -1171,14 +1239,11 @@ var HttpTransport = class {
1171
1239
  }
1172
1240
  } catch {
1173
1241
  const errorMsg = `FATAL: Plaintext OAuth bypass is ONLY permitted for loopback hosts (localhost, 127.0.0.1, [::1]). The configured issuer is not allowed.`;
1174
- logger.error(errorMsg, {
1175
- module: "HTTP",
1176
- operation: "oauth-config"
1177
- });
1242
+ logger.error(errorMsg, { module: "HTTP", operation: "oauth-config" });
1178
1243
  throw new Error(errorMsg);
1179
1244
  }
1180
1245
  }
1181
- if (!isLocalhost && !this.config.publicOrigin) {
1246
+ if (!isLocalhost && (this.config.publicOrigin === void 0 || this.config.publicOrigin === "")) {
1182
1247
  const errorMsg = `FATAL: OAuth is enabled on a non-loopback interface ('${host}'), but no 'publicOrigin' was provided. You MUST specify an explicit public origin (e.g. 'https://api.example.com') for secure OAuth token audience binding.`;
1183
1248
  logger.error(errorMsg, { module: "HTTP" });
1184
1249
  throw new Error(errorMsg);
@@ -1210,14 +1275,29 @@ var HttpTransport = class {
1210
1275
  resource: resourceServer.getResourceUri(),
1211
1276
  audience: this.config.oauthAudience
1212
1277
  });
1213
- } else if (authToken) {
1278
+ } else if (authToken !== void 0 && authToken !== "") {
1214
1279
  this.app.use(createAuthMiddleware(authToken));
1215
1280
  }
1216
1281
  const propagateContextMiddleware = (req, _res, next) => {
1217
1282
  const reqRecord = req;
1218
- const d = reqRecord[["a", "u", "t", "h"].join("")];
1219
- if (d !== void 0 && d !== null) {
1220
- runWithAuthContext({ authenticated: true, claims: d, scopes: d.scopes }, next);
1283
+ const tokenClaims = reqRecord["tokenClaims"];
1284
+ const authInfo = reqRecord["auth"];
1285
+ if (tokenClaims !== void 0 && tokenClaims !== null) {
1286
+ runWithAuthContext(
1287
+ { authenticated: true, claims: tokenClaims, scopes: tokenClaims.scopes },
1288
+ next
1289
+ );
1290
+ } else if (authInfo !== void 0 && authInfo !== null) {
1291
+ const sub = authInfo.sub ?? (typeof authInfo["subject"] === "string" ? authInfo["subject"] : void 0) ?? authInfo.clientId ?? "unknown";
1292
+ const normalizedClaims = {
1293
+ ...authInfo,
1294
+ sub,
1295
+ scopes: Array.isArray(authInfo.scopes) ? authInfo.scopes : []
1296
+ };
1297
+ runWithAuthContext(
1298
+ { authenticated: true, claims: normalizedClaims, scopes: normalizedClaims.scopes },
1299
+ next
1300
+ );
1221
1301
  } else {
1222
1302
  next();
1223
1303
  }
@@ -1229,153 +1309,22 @@ var HttpTransport = class {
1229
1309
  logger.info("Prometheus metrics export enabled on /metrics", { module: "HTTP" });
1230
1310
  }
1231
1311
  this.app.get("/", handleRootInfo);
1232
- const statelessMcpHandler = toNodeHandler(createMcpHandler(() => {
1233
- const server = serverFactory();
1234
- this.activeServers.add(server);
1235
- const originalClose = server.close.bind(server);
1236
- server.close = async () => {
1237
- this.activeServers.delete(server);
1238
- return originalClose();
1239
- };
1240
- return server;
1241
- }, { legacy: "reject" }));
1242
- const createSessionAndHandle = (req, res, next, _sid, isLegacySse = false) => {
1243
- const sid = _sid ?? randomUUID();
1244
- const transport = isLegacySse ? new LegacySSEServerTransport("/messages", sid) : new NodeStreamableHTTPServerTransport({
1245
- sessionIdGenerator: () => sid
1246
- });
1247
- const sessionId = sid;
1248
- const server = serverFactory();
1249
- const authObj = req.auth;
1250
- const rawSubject = authObj ? authObj["subject"] ?? authObj["clientId"] ?? authObj["client_id"] ?? "unknown" : "";
1251
- const authSubject = typeof rawSubject === "string" || typeof rawSubject === "number" ? String(rawSubject) : "unknown";
1252
- const authLog = authObj ? ` as ${authSubject}` : "";
1253
- logger.info(`New MCP stateful session initialized${authLog}`, {
1254
- module: "HTTP",
1255
- sessionId,
1256
- ...req.auth && { auth: req.auth }
1257
- });
1258
- this.activeServers.add(server);
1259
- globalSubscriptionManager.registerServer(sessionId, server);
1260
- const originalClose = server.close.bind(server);
1261
- server.close = async () => {
1262
- this.activeServers.delete(server);
1263
- this.sseTransports.delete(sessionId);
1264
- globalSubscriptionManager.unregisterServer(sessionId);
1265
- return originalClose();
1266
- };
1267
- this.sseTransports.set(sessionId, transport);
1268
- transport.onclose = () => {
1269
- server.close().catch((err) => logger.error("Error closing server on transport close", { error: String(err) }));
1270
- };
1271
- server.connect(transport).catch((err) => logger.error("Error connecting server to transport", { error: String(err) }));
1272
- if (transport instanceof LegacySSEServerTransport) {
1273
- transport.handleSseRequest(req, res);
1274
- } else {
1275
- transport.handleRequest(req, res, req.body).catch((err) => {
1276
- logger.error("Error handling transport request", {
1277
- error: String(err),
1278
- stack: err instanceof Error ? err.stack : void 0
1279
- });
1280
- next(err);
1281
- });
1282
- }
1283
- };
1284
- const handleStatefulGet = (req, res, next) => {
1285
- if (this.config.stateless) {
1286
- if (req.path === "/sse" || req.path === "/sse/") {
1287
- next();
1288
- return;
1289
- }
1290
- res.status(405).json({ error: { message: "SSE streaming not available in stateless mode" } });
1291
- return;
1292
- }
1293
- const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
1294
- if (sid !== void 0 && sid !== "") {
1295
- const transport = this.sseTransports.get(sid);
1296
- if (!transport) {
1297
- res.status(400).json({ error: { message: "Session not found" } });
1298
- return;
1299
- }
1300
- if (transport instanceof LegacySSEServerTransport) {
1301
- transport.handleSseRequest(req, res);
1302
- } else {
1303
- transport.handleRequest(req, res).catch((err) => {
1304
- next(err);
1305
- });
1306
- }
1307
- } else {
1308
- if (this.config.stateless) {
1309
- res.status(405).json({ error: "Method Not Allowed (Stateful SSE is disabled in stateless mode)" });
1310
- return;
1311
- }
1312
- if (req.path === "/sse" || req.path === "/sse/") {
1313
- createSessionAndHandle(req, res, next, randomUUID(), true);
1314
- return;
1315
- }
1316
- res.status(405).json({ error: "Method Not Allowed (Streamable HTTP requires POST initialization)" });
1317
- return;
1318
- }
1319
- };
1320
- this.app.get("/mcp", handleStatefulGet);
1321
- this.app.get("/sse", handleStatefulGet);
1322
- const handlePost = (req, res, next) => {
1323
- const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
1324
- if (sid !== void 0 && sid !== "") {
1325
- const transport = this.sseTransports.get(sid);
1326
- if (!transport) {
1327
- res.status(400).json({ error: { message: "Session not found" } });
1328
- return;
1329
- }
1330
- if (transport instanceof LegacySSEServerTransport) {
1331
- transport.handlePostMessage(req, res);
1332
- } else {
1333
- transport.handleRequest(req, res, req.body).catch((err) => {
1334
- next(err);
1335
- });
1336
- }
1337
- } else {
1338
- const acceptsSse = req.headers.accept?.includes("text/event-stream") ?? false;
1339
- const isLegacyMessages = req.path === "/messages" || req.path === "/messages/";
1340
- if (isLegacyMessages) {
1341
- res.status(400).json({ error: { message: "Missing sessionId parameter" } });
1342
- } else if (acceptsSse && !this.config.stateless) {
1343
- createSessionAndHandle(req, res, next, randomUUID(), false);
1344
- } else {
1345
- logger.info("Routing to statelessMcpHandler", { method: req.method, path: req.path, headers: req.headers, body: req.body });
1346
- statelessMcpHandler(req, res, req.body).catch((err) => {
1347
- next(err);
1348
- });
1349
- }
1350
- }
1351
- };
1352
- this.app.post("/mcp", handlePost);
1353
- this.app.post("/sse", handlePost);
1354
- this.app.post("/messages", handlePost);
1355
- this.app.delete("/mcp", (req, res) => {
1356
- if (this.config.stateless) {
1357
- res.status(204).end();
1358
- return;
1359
- }
1360
- const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
1361
- if (!sid) {
1362
- res.status(400).json({ error: { message: "Missing sessionId parameter" } });
1363
- return;
1364
- }
1365
- const transport = this.sseTransports.get(sid);
1366
- if (transport) {
1367
- void transport.close();
1368
- this.sseTransports.delete(sid);
1369
- globalSubscriptionManager.unregisterServer(sid);
1370
- }
1371
- res.status(204).end();
1372
- });
1312
+ registerMcpProtocolRoutes(
1313
+ this.app,
1314
+ this.config,
1315
+ serverFactory,
1316
+ this.activeServers,
1317
+ this.sseTransports
1318
+ );
1373
1319
  this.app.use((req, res) => {
1374
- logger.debug("404 Not Found", { method: req.method, path: req.path, query: req.query, headers: req.headers });
1320
+ logger.debug("404 Not Found", {
1321
+ method: req.method,
1322
+ path: req.path
1323
+ });
1375
1324
  res.status(404).json({ error: "Not found" });
1376
1325
  });
1377
1326
  this.httpServer = this.app.listen(port, host, () => {
1378
- if (this.httpServer) {
1327
+ if (this.httpServer !== null) {
1379
1328
  this.httpServer.setTimeout(HTTP_REQUEST_TIMEOUT_MS);
1380
1329
  this.httpServer.keepAliveTimeout = HTTP_KEEP_ALIVE_TIMEOUT_MS;
1381
1330
  this.httpServer.headersTimeout = HTTP_HEADERS_TIMEOUT_MS;
@@ -1395,13 +1344,10 @@ var HttpTransport = class {
1395
1344
  logger.info("HTTP server closed", { module: "HTTP" });
1396
1345
  });
1397
1346
  }
1398
- /**
1399
- * Graceful shutdown
1400
- */
1401
1347
  async stop(scheduler) {
1402
1348
  logger.info("Shutting down HTTP server...", { module: "HTTP" });
1403
1349
  scheduler?.stop();
1404
- if (this.rateLimitCleanupTimer) {
1350
+ if (this.rateLimitCleanupTimer !== null) {
1405
1351
  clearInterval(this.rateLimitCleanupTimer);
1406
1352
  this.rateLimitCleanupTimer = null;
1407
1353
  }
@@ -1487,7 +1433,8 @@ async function rebuildIndex(manager, dbAdapter, progress, options) {
1487
1433
  }
1488
1434
  }
1489
1435
  try {
1490
- const text = `[${entry.entryType}] ${entry.content}`;
1436
+ const tagsText = entry.tags !== void 0 && entry.tags !== null && entry.tags.length > 0 ? ` [Tags: ${entry.tags.join(", ")}]` : "";
1437
+ const text = `[${entry.entryType}]${tagsText} ${entry.content}`;
1491
1438
  const embedding = await manager.generateEmbedding(text);
1492
1439
  vectorsToUpsert.push({ entryId: entry.id, embedding });
1493
1440
  } catch (err) {
@@ -1539,7 +1486,7 @@ async function rebuildIndex(manager, dbAdapter, progress, options) {
1539
1486
  }
1540
1487
 
1541
1488
  // src/vector/vector-search-manager/manager.ts
1542
- var VectorSearchManager = class {
1489
+ var VectorSearchManager = class _VectorSearchManager {
1543
1490
  dbAdapter;
1544
1491
  modelName;
1545
1492
  dimensions = null;
@@ -1567,7 +1514,7 @@ var VectorSearchManager = class {
1567
1514
  * Check if the vector search manager is initialized
1568
1515
  */
1569
1516
  isInitialized() {
1570
- return this.initializationPromise !== null && this.pipeline !== null;
1517
+ return this.initializationPromise !== null && (this.pipeline !== null || this.dimensions !== null);
1571
1518
  }
1572
1519
  /**
1573
1520
  * Initialize the vector search manager.
@@ -1580,29 +1527,45 @@ var VectorSearchManager = class {
1580
1527
  if (this.initializationPromise) {
1581
1528
  return this.initializationPromise;
1582
1529
  }
1583
- this.initializationPromise = this._initialize();
1530
+ this.initializationPromise = this._initialize().catch((error) => {
1531
+ this.initializationPromise = null;
1532
+ throw error;
1533
+ });
1584
1534
  return this.initializationPromise;
1585
1535
  }
1586
1536
  async _initialize() {
1587
1537
  try {
1588
1538
  logger.info("Initializing vector search...");
1589
- if (this.transformers === null) {
1590
- const transformersModule2 = await import('@huggingface/transformers');
1591
- this.transformers = transformersModule2;
1592
- transformersModule2.env.allowRemoteModels = true;
1593
- transformersModule2.env.localModelPath = ".cache/huggingface";
1539
+ const hasCustomEmbeddingFn = this.generateEmbedding !== _VectorSearchManager.prototype.generateEmbedding;
1540
+ if (hasCustomEmbeddingFn) {
1541
+ logger.info("Detecting embedding dimensions via custom embedding generator...");
1542
+ const testEmbedding = await this.generateEmbedding("test");
1543
+ this.dimensions = testEmbedding.length;
1544
+ this.pipeline = true;
1545
+ logger.info(`Detected ${this.dimensions} dimensions for ${this.modelName}`);
1546
+ } else {
1547
+ if (this.transformers === null) {
1548
+ const transformersModule2 = await import('@huggingface/transformers');
1549
+ this.transformers = transformersModule2;
1550
+ transformersModule2.env.allowRemoteModels = true;
1551
+ transformersModule2.env.localModelPath = ".cache/huggingface";
1552
+ }
1553
+ logger.info(`Loading embedding model: ${this.modelName}`);
1554
+ const transformersModule = this.transformers;
1555
+ this.pipeline = await transformersModule.pipeline(
1556
+ "feature-extraction",
1557
+ this.modelName,
1558
+ {
1559
+ dtype: "fp32"
1560
+ }
1561
+ );
1562
+ logger.info("Embedding model loaded");
1563
+ logger.info("Detecting embedding dimensions...");
1564
+ const pipelineFunc = this.pipeline;
1565
+ const testResult = await pipelineFunc("test", { pooling: "mean", normalize: true });
1566
+ this.dimensions = testResult.data.length;
1567
+ logger.info(`Detected ${this.dimensions} dimensions for ${this.modelName}`);
1594
1568
  }
1595
- logger.info(`Loading embedding model: ${this.modelName}`);
1596
- const transformersModule = this.transformers;
1597
- this.pipeline = await transformersModule.pipeline("feature-extraction", this.modelName, {
1598
- dtype: "fp32"
1599
- });
1600
- logger.info("Embedding model loaded");
1601
- logger.info("Detecting embedding dimensions...");
1602
- const pipelineFunc = this.pipeline;
1603
- const testResult = await pipelineFunc("test", { pooling: "mean", normalize: true });
1604
- this.dimensions = testResult.data.length;
1605
- logger.info(`Detected ${this.dimensions} dimensions for ${this.modelName}`);
1606
1569
  this.verifyAndCreateVecTable();
1607
1570
  logger.info("Vector search initialized successfully");
1608
1571
  } catch (error) {
@@ -1699,25 +1662,38 @@ var VectorSearchManager = class {
1699
1662
  /**
1700
1663
  * Search for similar entries by text query
1701
1664
  */
1702
- async search(query, limit = 10, threshold = 0) {
1665
+ async search(query, limit = 10, threshold = 0, workspaceId) {
1703
1666
  await this.initialize();
1704
1667
  try {
1705
1668
  const queryEmbedding = await this.generateEmbedding(query);
1706
1669
  const results = this.dbAdapter.searchVectors(queryEmbedding, limit);
1707
- const searchResults = [];
1670
+ const candidates = [];
1708
1671
  for (const result of results) {
1709
- const entry = this.dbAdapter.getEntryById(result.entry_id);
1710
- if (entry) {
1711
- const similarityScore = Math.max(-1, 1 - result.distance * result.distance / 2);
1712
- if (similarityScore >= threshold) {
1713
- searchResults.push({
1714
- entryId: result.entry_id,
1715
- entry,
1716
- distance: result.distance,
1717
- score: similarityScore,
1718
- similarityScore
1719
- });
1720
- }
1672
+ const similarityScore = Math.max(-1, 1 - result.distance * result.distance / 2);
1673
+ if (similarityScore >= threshold) {
1674
+ candidates.push({
1675
+ entryId: result.entry_id,
1676
+ distance: result.distance,
1677
+ similarityScore
1678
+ });
1679
+ }
1680
+ }
1681
+ if (candidates.length === 0) {
1682
+ return [];
1683
+ }
1684
+ const targetWs = workspaceId ?? "*";
1685
+ const entriesMap = typeof this.dbAdapter.getEntriesByIds === "function" ? this.dbAdapter.getEntriesByIds(candidates.map((c) => c.entryId)) : null;
1686
+ const searchResults = [];
1687
+ for (const candidate of candidates) {
1688
+ const entry = entriesMap ? entriesMap.get(candidate.entryId) ?? null : this.dbAdapter.getEntryById(candidate.entryId, targetWs);
1689
+ if (entry && (targetWs === "*" || entry.workspaceId === void 0 || entry.workspaceId === targetWs)) {
1690
+ searchResults.push({
1691
+ entryId: candidate.entryId,
1692
+ entry,
1693
+ distance: candidate.distance,
1694
+ score: candidate.similarityScore,
1695
+ similarityScore: candidate.similarityScore
1696
+ });
1721
1697
  }
1722
1698
  if (searchResults.length >= limit) break;
1723
1699
  }
@@ -1733,36 +1709,50 @@ var VectorSearchManager = class {
1733
1709
  /**
1734
1710
  * Search for similar entries using an existing entry as the query
1735
1711
  */
1736
- async searchByEntryId(entryId, limit = 10, threshold = 0) {
1712
+ async searchByEntryId(entryId, limit = 10, threshold = 0, workspaceId) {
1737
1713
  await this.initialize();
1738
1714
  try {
1715
+ const sourceEntry = this.dbAdapter.getEntryById(entryId, workspaceId ?? "*");
1716
+ if (!sourceEntry) {
1717
+ throw new Error(`Entry ${entryId} not found`);
1718
+ }
1739
1719
  let queryEmbedding = this.dbAdapter.getVector(entryId);
1740
1720
  if (!queryEmbedding) {
1741
- const entry = this.dbAdapter.getEntryById(entryId);
1742
- if (!entry) {
1743
- throw new Error(`Entry ${entryId} not found`);
1744
- }
1745
- const tagsText = entry.tags !== void 0 && entry.tags !== null && entry.tags.length > 0 ? ` [Tags: ${entry.tags.join(", ")}]` : "";
1746
- const text = `[${entry.entryType}]${tagsText} ${entry.content}`;
1721
+ const tagsText = sourceEntry.tags !== void 0 && sourceEntry.tags !== null && sourceEntry.tags.length > 0 ? ` [Tags: ${sourceEntry.tags.join(", ")}]` : "";
1722
+ const text = `[${sourceEntry.entryType}]${tagsText} ${sourceEntry.content}`;
1747
1723
  queryEmbedding = await this.generateEmbedding(text);
1748
1724
  this.dbAdapter.upsertVector(entryId, queryEmbedding);
1749
1725
  }
1750
1726
  const results = this.dbAdapter.searchVectors(queryEmbedding, limit + 1);
1751
- const searchResults = [];
1727
+ const candidates = [];
1752
1728
  for (const result of results) {
1753
- if (result.entry_id === entryId) continue;
1754
- const entry = this.dbAdapter.getEntryById(result.entry_id);
1755
- if (entry) {
1756
- const similarityScore = Math.max(-1, 1 - result.distance * result.distance / 2);
1757
- if (similarityScore >= threshold) {
1758
- searchResults.push({
1759
- entryId: result.entry_id,
1760
- entry,
1761
- distance: result.distance,
1762
- score: similarityScore,
1763
- similarityScore
1764
- });
1765
- }
1729
+ const candidateId = result.entry_id;
1730
+ if (candidateId === entryId) continue;
1731
+ const similarityScore = Math.max(-1, 1 - result.distance * result.distance / 2);
1732
+ if (similarityScore >= threshold) {
1733
+ candidates.push({
1734
+ entryId: candidateId,
1735
+ distance: result.distance,
1736
+ similarityScore
1737
+ });
1738
+ }
1739
+ }
1740
+ if (candidates.length === 0) {
1741
+ return [];
1742
+ }
1743
+ const targetWs = workspaceId ?? "*";
1744
+ const entriesMap = typeof this.dbAdapter.getEntriesByIds === "function" ? this.dbAdapter.getEntriesByIds(candidates.map((c) => c.entryId)) : null;
1745
+ const searchResults = [];
1746
+ for (const candidate of candidates) {
1747
+ const entry = entriesMap ? entriesMap.get(candidate.entryId) ?? null : this.dbAdapter.getEntryById(candidate.entryId, targetWs);
1748
+ if (entry && (targetWs === "*" || entry.workspaceId === void 0 || entry.workspaceId === targetWs)) {
1749
+ searchResults.push({
1750
+ entryId: candidate.entryId,
1751
+ entry,
1752
+ distance: candidate.distance,
1753
+ score: candidate.similarityScore,
1754
+ similarityScore: candidate.similarityScore
1755
+ });
1766
1756
  }
1767
1757
  if (searchResults.length >= limit) break;
1768
1758
  }
@@ -1815,8 +1805,44 @@ var VectorSearchManagerProxy = {
1815
1805
  });
1816
1806
  }
1817
1807
  };
1818
-
1819
- // src/server/digest-reporter.ts
1808
+ function isBlockedWebhookIp(ip) {
1809
+ const normalized = ip.toLowerCase();
1810
+ if (normalized === "localhost" || normalized === "::1" || normalized === "0.0.0.0" || normalized === "::" || normalized.startsWith("127.") || normalized.startsWith("10.") || normalized.startsWith("192.168.") || normalized.startsWith("169.254.") || normalized.startsWith("fe80:") || normalized.startsWith("fc00:") || normalized.startsWith("fd00:") || normalized.startsWith("::ffff:")) {
1811
+ return true;
1812
+ }
1813
+ const octets = normalized.split(".");
1814
+ if (octets.length === 4 && octets[0] === "172") {
1815
+ const second = Number(octets[1]);
1816
+ if (second >= 16 && second <= 31) {
1817
+ return true;
1818
+ }
1819
+ }
1820
+ return false;
1821
+ }
1822
+ async function validateWebhookUrl(webhookUrl) {
1823
+ let parsed;
1824
+ try {
1825
+ parsed = new URL(webhookUrl);
1826
+ } catch {
1827
+ throw new Error("Invalid webhook URL format");
1828
+ }
1829
+ const allowInsecureHttp = process.env["ALLOW_INSECURE_WEBHOOK_HTTP"] === "true";
1830
+ if (parsed.protocol !== "https:" && !(allowInsecureHttp && parsed.protocol === "http:")) {
1831
+ throw new Error(`Disallowed webhook protocol: ${parsed.protocol} (https: required)`);
1832
+ }
1833
+ const hostname = parsed.hostname.replace(/^\[|\]$/g, "").toLowerCase();
1834
+ if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname.endsWith(".internal") || isBlockedWebhookIp(hostname)) {
1835
+ throw new Error(`Webhook hostname resolves to restricted network address: ${hostname}`);
1836
+ }
1837
+ if (!process.env["VITEST"]) {
1838
+ const records = await dns.promises.lookup(hostname, { all: true });
1839
+ for (const rec of records) {
1840
+ if (isBlockedWebhookIp(rec.address)) {
1841
+ throw new Error(`Webhook DNS resolved to private/loopback IP: ${rec.address}`);
1842
+ }
1843
+ }
1844
+ }
1845
+ }
1820
1846
  function formatDigestReport(snapshot, serverVersion) {
1821
1847
  const lines = [];
1822
1848
  lines.push(`# Memory Journal Digest`);
@@ -1853,6 +1879,15 @@ function formatDigestReport(snapshot, serverVersion) {
1853
1879
  }
1854
1880
  async function deliverReport(report, snapshot, options) {
1855
1881
  const { webhookUrl, webhookAuth, contentType = "slack" } = options;
1882
+ try {
1883
+ await validateWebhookUrl(webhookUrl);
1884
+ } catch (err) {
1885
+ logger.error("Refusing to deliver digest report to unsafe webhook URL", {
1886
+ module: "DigestReporter",
1887
+ error: err instanceof Error ? err.message : String(err)
1888
+ });
1889
+ return false;
1890
+ }
1856
1891
  let bodyPayload;
1857
1892
  if (contentType === "discord") {
1858
1893
  bodyPayload = JSON.stringify({ content: report });
@@ -1880,7 +1915,8 @@ async function deliverReport(report, snapshot, options) {
1880
1915
  method: "POST",
1881
1916
  headers,
1882
1917
  body: bodyPayload,
1883
- signal: controller.signal
1918
+ signal: controller.signal,
1919
+ redirect: "error"
1884
1920
  });
1885
1921
  clearTimeout(timeoutId);
1886
1922
  if (response.ok) {
@@ -1930,6 +1966,7 @@ var Scheduler = class {
1930
1966
  vectorManager;
1931
1967
  timers = [];
1932
1968
  started = false;
1969
+ sigtermHandler = null;
1933
1970
  runtime;
1934
1971
  constructor(options, db, vectorManager, runtime) {
1935
1972
  this.options = options;
@@ -1949,7 +1986,10 @@ var Scheduler = class {
1949
1986
  return;
1950
1987
  }
1951
1988
  this.started = true;
1952
- process.on("SIGTERM", () => this.stop());
1989
+ this.sigtermHandler = () => {
1990
+ this.stop();
1991
+ };
1992
+ process.on("SIGTERM", this.sigtermHandler);
1953
1993
  const { backupIntervalMinutes, vacuumIntervalMinutes, rebuildIndexIntervalMinutes } = this.options;
1954
1994
  if (backupIntervalMinutes > 0) {
1955
1995
  this.scheduleJob("backup", backupIntervalMinutes, () => this.runBackup());
@@ -2011,6 +2051,10 @@ var Scheduler = class {
2011
2051
  module: "Scheduler"
2012
2052
  });
2013
2053
  }
2054
+ if (this.sigtermHandler !== null) {
2055
+ process.off("SIGTERM", this.sigtermHandler);
2056
+ this.sigtermHandler = null;
2057
+ }
2014
2058
  this.timers.length = 0;
2015
2059
  this.started = false;
2016
2060
  }
@@ -2322,11 +2366,14 @@ var ServerRuntime = class {
2322
2366
  };
2323
2367
  var ConfigManager = class extends EventEmitter {
2324
2368
  config;
2369
+ initialCodemodeFullAccess;
2325
2370
  configFilePath;
2326
2371
  watcher;
2372
+ isWriting = false;
2327
2373
  constructor(initialConfig, configFilePath) {
2328
2374
  super();
2329
2375
  this.config = { ...initialConfig };
2376
+ this.initialCodemodeFullAccess = Boolean(initialConfig.codemodeInternalFullAccess);
2330
2377
  this.configFilePath = configFilePath;
2331
2378
  if (this.configFilePath && fs.existsSync(this.configFilePath)) {
2332
2379
  this.watchFile();
@@ -2350,6 +2397,7 @@ var ConfigManager = class extends EventEmitter {
2350
2397
  }
2351
2398
  persistToFile() {
2352
2399
  if (!this.configFilePath) return;
2400
+ this.isWriting = true;
2353
2401
  try {
2354
2402
  const content = fs.readFileSync(this.configFilePath, "utf-8");
2355
2403
  let parsed = {};
@@ -2383,15 +2431,16 @@ var ConfigManager = class extends EventEmitter {
2383
2431
  }
2384
2432
  } catch (e) {
2385
2433
  logger.error("Failed to persist configuration to file", { module: "ConfigManager", error: e instanceof Error ? e.message : String(e) });
2434
+ } finally {
2435
+ this.isWriting = false;
2386
2436
  }
2387
2437
  }
2388
2438
  watchFile() {
2389
2439
  if (!this.configFilePath) return;
2390
2440
  let debounceTimer;
2391
- const isWriting = false;
2392
2441
  try {
2393
2442
  this.watcher = fs.watch(this.configFilePath, (eventType) => {
2394
- if (eventType === "change" && !isWriting) {
2443
+ if (eventType === "change" && !this.isWriting) {
2395
2444
  clearTimeout(debounceTimer);
2396
2445
  debounceTimer = setTimeout(() => {
2397
2446
  try {
@@ -2402,6 +2451,13 @@ var ConfigManager = class extends EventEmitter {
2402
2451
  }, 500);
2403
2452
  }
2404
2453
  });
2454
+ this.watcher.on("error", (err) => {
2455
+ logger.warning("Config file watcher error", {
2456
+ module: "ConfigManager",
2457
+ path: this.configFilePath,
2458
+ error: err instanceof Error ? err.message : String(err)
2459
+ });
2460
+ });
2405
2461
  logger.info("Watching configuration file for changes", { module: "ConfigManager", path: this.configFilePath });
2406
2462
  } catch (error) {
2407
2463
  logger.warning("Failed to start configuration file watcher", { module: "ConfigManager", error: error instanceof Error ? error.message : String(error) });
@@ -2422,7 +2478,10 @@ var ConfigManager = class extends EventEmitter {
2422
2478
  updates.rawToolFilter = typeof parsed["toolFilter"] === "string" ? parsed["toolFilter"] : void 0;
2423
2479
  }
2424
2480
  if ("codemodeInternalFullAccess" in parsed) {
2425
- updates.codemodeInternalFullAccess = typeof parsed["codemodeInternalFullAccess"] === "boolean" ? parsed["codemodeInternalFullAccess"] : void 0;
2481
+ const requested = typeof parsed["codemodeInternalFullAccess"] === "boolean" ? parsed["codemodeInternalFullAccess"] : void 0;
2482
+ if (requested === false || requested === true && this.initialCodemodeFullAccess) {
2483
+ updates.codemodeInternalFullAccess = requested;
2484
+ }
2426
2485
  }
2427
2486
  const bc = { ...this.config.briefingConfig };
2428
2487
  let bcChanged = false;
@@ -2843,34 +2902,457 @@ function registerPrompts(server, prompts, db, teamDb, runtime, github, briefingC
2843
2902
  }
2844
2903
  }
2845
2904
 
2846
- // src/server/mcp-server/tool-registration.ts
2905
+ // src/server/mcp-server/tool-registration/list-interceptor.ts
2906
+ function attachListToolsInterceptor(requestHandlers, configManager, allToolNames) {
2907
+ const listToolsHandler = requestHandlers?.get("tools/list");
2908
+ if (listToolsHandler === void 0 || requestHandlers === void 0) {
2909
+ return;
2910
+ }
2911
+ requestHandlers.set("tools/list", async (request2, extra) => {
2912
+ const currentConfig = configManager.getConfig();
2913
+ const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
2914
+ const result = await listToolsHandler(request2, extra);
2915
+ const res = result;
2916
+ if (Array.isArray(res?.tools)) {
2917
+ res.tools = res.tools.filter((t) => enabledSet.has(t.name));
2918
+ }
2919
+ return result;
2920
+ });
2921
+ }
2922
+
2923
+ // src/server/mcp-server/tool-registration/call-interceptor.ts
2924
+ var ALIASED_EXECUTE_CODE_NAMES = /* @__PURE__ */ new Set([
2925
+ "mysql_execute_code",
2926
+ "mysqlExecuteCode",
2927
+ "execute_code",
2928
+ "executeCode",
2929
+ "mjExecuteCode",
2930
+ "mj_eval",
2931
+ "eval_code",
2932
+ "run_code",
2933
+ "exec_code",
2934
+ "code_execute"
2935
+ ]);
2936
+ var ALIASED_LIST_PROJECTS_NAMES = /* @__PURE__ */ new Set([
2937
+ "listProjects",
2938
+ "list-projects",
2939
+ "get_projects",
2940
+ "getProjects",
2941
+ "get-projects",
2942
+ "mj_list_projects",
2943
+ "mjListProjects",
2944
+ "mj_get_projects",
2945
+ "mjGetProjects",
2946
+ "mj_admin_list_projects",
2947
+ "mj_admin_get_projects"
2948
+ ]);
2949
+ var ALIASED_GET_PROJECT_NAMES = /* @__PURE__ */ new Set([
2950
+ "getProject",
2951
+ "get-project",
2952
+ "mj_get_project",
2953
+ "mjGetProject",
2954
+ "mj_admin_get_project"
2955
+ ]);
2956
+ var ALIASED_GREP_SEARCH_NAMES = new Set(DUMMY_GREP_SEARCH_TOOL_NAMES);
2957
+ var ALIASED_VIEW_FILE_NAMES = new Set(
2958
+ DUMMY_FILE_VIEW_TOOL_NAMES.filter((name) => name !== "cat")
2959
+ );
2960
+ var ALIASED_LIST_DIR_NAMES = new Set(
2961
+ DUMMY_DIR_LIST_TOOL_NAMES.filter((name) => name !== "ls" && name !== "dir")
2962
+ );
2963
+ var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
2964
+ var ALL_KNOWN_GROUP_TOOLS = new Set(Object.values(TOOL_GROUPS).flat());
2965
+ var UPPERCASE_RE = /[A-Z]/;
2966
+ function deepCamelToSnake(obj, depth = 0) {
2967
+ if (depth > 12) return obj;
2968
+ if (Array.isArray(obj)) return obj.map((item) => deepCamelToSnake(item, depth + 1));
2969
+ if (obj !== null && typeof obj === "object") {
2970
+ const newObj = {};
2971
+ for (const [k, v] of Object.entries(obj)) {
2972
+ if (FORBIDDEN_KEYS.has(k)) continue;
2973
+ const snakeKey = UPPERCASE_RE.test(k) ? k.replace(/^[A-Z]/, (letter) => letter.toLowerCase()).replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`) : k;
2974
+ if (FORBIDDEN_KEYS.has(snakeKey)) continue;
2975
+ newObj[snakeKey] = deepCamelToSnake(v, depth + 1);
2976
+ }
2977
+ return newObj;
2978
+ }
2979
+ return obj;
2980
+ }
2981
+ function formatSuccessPayload(payload) {
2982
+ const enriched = JSON.stringify(payload, null, 2);
2983
+ return {
2984
+ content: [{ type: "text", text: enriched }],
2985
+ structuredContent: payload
2986
+ };
2987
+ }
2988
+ function formatTokenEstimatedError(errorResult, isError) {
2989
+ const enriched = JSON.stringify({ ...errorResult, _meta: { tokenEstimate: 0 } });
2990
+ const tokenEstimate = Math.ceil(Buffer.byteLength(enriched, "utf8") / 4);
2991
+ const finalText = enriched.replace('"tokenEstimate":0', `"tokenEstimate":${tokenEstimate}`);
2992
+ return {
2993
+ content: [{ type: "text", text: finalText }],
2994
+ structuredContent: errorResult,
2995
+ ...isError ? { isError: true } : {}
2996
+ };
2997
+ }
2998
+ function parseZodErrorsFromMessage(rawText, prefixToRemove) {
2999
+ let errorMessage = prefixToRemove !== void 0 ? rawText.replace(prefixToRemove, "") : rawText;
3000
+ try {
3001
+ const parts = rawText.split(": [");
3002
+ if (parts.length > 1) {
3003
+ const zodErrors = JSON.parse("[" + parts[1]);
3004
+ errorMessage = zodErrors.map((e) => `${e.path && e.path.length > 0 ? e.path.join(".") : "unknown"}: ${e.message ?? "invalid"}`).join("; ");
3005
+ }
3006
+ } catch {
3007
+ }
3008
+ return errorMessage;
3009
+ }
3010
+ function isSuccessObject(res) {
3011
+ return typeof res === "object" && res !== null && res["success"] === true;
3012
+ }
3013
+ function matchesSuffixes(name, list, suffixes) {
3014
+ return list.includes(name) || suffixes.some((s) => name.endsWith(s));
3015
+ }
3016
+ async function tryAutonomousUnknownToolFallback(requestedTool, toolArgs, matchingPrompt, context, allTools, allToolNames, customToolHandlerConfig) {
3017
+ const { configManager, db, teamDb, vectorManager, teamVectorManager, github, runtime } = context;
3018
+ const currentConfig = configManager.getConfig();
3019
+ const toolContext = {
3020
+ db,
3021
+ ...teamDb !== void 0 ? { teamDb } : {},
3022
+ vectorManager,
3023
+ ...teamVectorManager !== void 0 ? { teamVectorManager } : {},
3024
+ github,
3025
+ config: {
3026
+ ...customToolHandlerConfig,
3027
+ filterConfig: currentConfig.toolFilterConfig,
3028
+ briefingConfig: currentConfig.briefingConfig,
3029
+ runtime
3030
+ }
3031
+ };
3032
+ if (matchingPrompt !== void 0) {
3033
+ enforceAccessBoundary(matchingPrompt.name, "prompt", void 0, runtime.auditLogger);
3034
+ const res = await handlePrompt(toolArgs, requestedTool, toolContext);
3035
+ if (isSuccessObject(res)) return formatSuccessPayload(res);
3036
+ }
3037
+ if (matchesSuffixes(requestedTool, DUMMY_RESOURCE_TOOL_NAMES, ["_read_resource", "ReadResource"]) || requestedTool === "mjReadResource" || requestedTool.startsWith("memory://")) {
3038
+ enforceAccessBoundary("read_resource", "tool", void 0, runtime.auditLogger);
3039
+ const res = await handleReadResource(toolArgs, requestedTool, toolContext);
3040
+ if (isSuccessObject(res)) return formatSuccessPayload(res);
3041
+ }
3042
+ if (matchesSuffixes(requestedTool, DUMMY_LIST_RESOURCE_TOOL_NAMES, ["_list_resources", "ListResources"])) {
3043
+ enforceAccessBoundary("list_resources", "tool", void 0, runtime.auditLogger);
3044
+ return formatSuccessPayload(handleListResources(requestedTool));
3045
+ }
3046
+ if (matchesSuffixes(requestedTool, DUMMY_LIST_PROMPT_TOOL_NAMES, ["_list_prompts", "ListPrompts"])) {
3047
+ enforceAccessBoundary("list_prompts", "tool", void 0, runtime.auditLogger);
3048
+ return formatSuccessPayload(handleListPrompts(requestedTool));
3049
+ }
3050
+ if (matchesSuffixes(requestedTool, DUMMY_LIST_TOOL_NAMES, ["_list_tools", "ListTools"])) {
3051
+ enforceAccessBoundary("list_tools", "tool", void 0, runtime.auditLogger);
3052
+ const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
3053
+ const toolsList = allTools.filter((t) => enabledSet.has(t.name)).map((t) => ({ name: t.name, title: t.title, description: t.description, annotations: t.annotations }));
3054
+ return formatSuccessPayload({
3055
+ success: true,
3056
+ tools: toolsList,
3057
+ _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool instead of an MCP protocol request (tools/list). The available tools were returned successfully.`
3058
+ });
3059
+ }
3060
+ if (matchesSuffixes(requestedTool, DUMMY_GET_PROMPT_TOOL_NAMES, ["_get_prompt", "GetPrompt"])) {
3061
+ enforceAccessBoundary("get_prompt", "tool", void 0, runtime.auditLogger);
3062
+ const res = await handleGetPrompt(toolArgs, requestedTool, toolContext);
3063
+ if (isSuccessObject(res)) return formatSuccessPayload(res);
3064
+ }
3065
+ if (DUMMY_SERVER_INFO_TOOL_NAMES.includes(requestedTool)) {
3066
+ enforceAccessBoundary("server_info", "tool", void 0, runtime.auditLogger);
3067
+ return formatSuccessPayload(await handleServerInfo(toolArgs, requestedTool, toolContext));
3068
+ }
3069
+ if (matchesSuffixes(requestedTool, DUMMY_PROJECT_TOOL_NAMES, ["list_projects", "listProjects", "ListProjects"]) || requestedTool === "projects") {
3070
+ enforceAccessBoundary("list_projects", "tool", void 0, runtime.auditLogger);
3071
+ const cfg = currentConfig;
3072
+ return formatSuccessPayload({
3073
+ success: true,
3074
+ projects: cfg.projectRegistry ?? {},
3075
+ _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool. Returned registered projects from projectRegistry successfully.`
3076
+ });
3077
+ }
3078
+ if (matchesSuffixes(requestedTool, DUMMY_ADAPTER_TOOL_NAMES, ["list_adapters", "listAdapters", "ListAdapters"])) {
3079
+ enforceAccessBoundary("list_adapters", "tool", void 0, runtime.auditLogger);
3080
+ return formatSuccessPayload(handleListAdapters(requestedTool, toolContext));
3081
+ }
3082
+ if (matchesSuffixes(requestedTool, DUMMY_GREP_SEARCH_TOOL_NAMES, ["grep_search", "grepSearch"])) {
3083
+ enforceAccessBoundary("grep_search", "tool", void 0, runtime.auditLogger);
3084
+ return formatSuccessPayload(await handleGrepSearch(toolArgs, requestedTool, toolContext));
3085
+ }
3086
+ if (DUMMY_FILE_VIEW_TOOL_NAMES.includes(requestedTool)) {
3087
+ enforceAccessBoundary("view_file", "tool", void 0, runtime.auditLogger);
3088
+ return formatSuccessPayload(await handleViewFile(toolArgs, requestedTool, toolContext));
3089
+ }
3090
+ if (DUMMY_DIR_LIST_TOOL_NAMES.includes(requestedTool)) {
3091
+ enforceAccessBoundary("list_dir", "tool", void 0, runtime.auditLogger);
3092
+ return formatSuccessPayload(await handleListDir(toolArgs, requestedTool, toolContext));
3093
+ }
3094
+ return void 0;
3095
+ }
3096
+ function normalizeAndAliasToolCall(reqParams, options) {
3097
+ reqParams.arguments = deepCamelToSnake(reqParams.arguments);
3098
+ const toolArgs = reqParams.arguments;
3099
+ if (toolArgs["project_number"] === void 0) {
3100
+ const repoStr = typeof toolArgs["repo"] === "string" ? toolArgs["repo"] : typeof toolArgs["project"] === "string" ? toolArgs["project"] : void 0;
3101
+ if (repoStr !== void 0 && repoStr !== "") toolArgs["project_number"] = repoStr;
3102
+ }
3103
+ if (typeof toolArgs["project_number"] === "string") {
3104
+ const strVal = toolArgs["project_number"];
3105
+ const parsed = Number(strVal);
3106
+ if (!Number.isNaN(parsed)) {
3107
+ toolArgs["project_number"] = parsed;
3108
+ } else if (options.projectRegistry !== void 0) {
3109
+ let entry = options.projectRegistry[strVal];
3110
+ if (entry === void 0 && strVal.includes("/")) {
3111
+ const repoName = strVal.split("/").pop();
3112
+ if (repoName !== void 0 && repoName !== "") entry = options.projectRegistry[repoName];
3113
+ }
3114
+ if (entry?.project_number !== void 0) toolArgs["project_number"] = entry.project_number;
3115
+ }
3116
+ }
3117
+ const currentName = reqParams.name;
3118
+ if (currentName !== void 0 && currentName !== "") {
3119
+ if (ALIASED_EXECUTE_CODE_NAMES.has(currentName)) {
3120
+ reqParams.name = "mj_execute_code";
3121
+ } else if (currentName === "create_entry_minimal") {
3122
+ reqParams.name = "create_entry";
3123
+ if (toolArgs["entry_type"] === void 0) toolArgs["entry_type"] = "personal_reflection";
3124
+ } else if (ALIASED_LIST_PROJECTS_NAMES.has(currentName)) {
3125
+ reqParams.name = "list_projects";
3126
+ } else if (ALIASED_GET_PROJECT_NAMES.has(currentName)) {
3127
+ reqParams.name = "get_project";
3128
+ } else if (ALIASED_GREP_SEARCH_NAMES.has(currentName)) {
3129
+ reqParams.name = "grep_search";
3130
+ } else if (ALIASED_VIEW_FILE_NAMES.has(currentName)) {
3131
+ reqParams.name = "view_file";
3132
+ } else if (ALIASED_LIST_DIR_NAMES.has(currentName)) {
3133
+ reqParams.name = "list_dir";
3134
+ }
3135
+ }
3136
+ }
3137
+ function attachCallToolInterceptor(requestHandlers, context, options, prompts, allTools, allToolNames, customToolHandlerConfig) {
3138
+ const originalHandler = requestHandlers?.get("tools/call");
3139
+ if (originalHandler === void 0 || requestHandlers === void 0) return;
3140
+ requestHandlers.set("tools/call", async (request2, extra) => {
3141
+ try {
3142
+ const req = request2;
3143
+ const healingEnabled = options.agentHealing !== false && customToolHandlerConfig.agentHealing !== false;
3144
+ if (req.params?.arguments !== void 0 && healingEnabled) {
3145
+ normalizeAndAliasToolCall(req.params, options);
3146
+ const toolArgs = req.params.arguments;
3147
+ if (req.params.name !== void 0 && req.params.name !== "") {
3148
+ const intercept = applyArgInterceptions(req.params.name, [toolArgs]);
3149
+ if ("error" in intercept) {
3150
+ const errorResult = intercept.error;
3151
+ logAgentIssue({
3152
+ source: "MCP",
3153
+ action: req.params.name,
3154
+ input: toolArgs,
3155
+ error: errorResult["error"] ?? "Validation Error"
3156
+ });
3157
+ return formatTokenEstimatedError(errorResult, false);
3158
+ }
3159
+ const normalizedArgs = intercept.args?.[0];
3160
+ if (normalizedArgs !== null && normalizedArgs !== void 0 && typeof normalizedArgs === "object" && !Array.isArray(normalizedArgs)) {
3161
+ req.params.arguments = normalizedArgs;
3162
+ }
3163
+ }
3164
+ }
3165
+ if (req.params?.name !== void 0 && req.params.name !== "" && !allToolNames.has(req.params.name)) {
3166
+ const requestedTool = req.params.name;
3167
+ const toolArgs = req.params.arguments ?? {};
3168
+ const normalized = requestedTool.replace(/^mj_/, "").replace(/_/g, "-");
3169
+ const matchingPrompt = prompts.find(
3170
+ (p) => p.name === normalized || p.name === requestedTool || p.name === requestedTool.replace(/^mj_/, "")
3171
+ );
3172
+ if (healingEnabled) {
3173
+ const fallbackResponse = await tryAutonomousUnknownToolFallback(
3174
+ requestedTool,
3175
+ toolArgs,
3176
+ matchingPrompt,
3177
+ context,
3178
+ allTools,
3179
+ allToolNames,
3180
+ customToolHandlerConfig
3181
+ );
3182
+ if (fallbackResponse !== void 0) return fallbackResponse;
3183
+ }
3184
+ let suggestion = `Tool '${requestedTool}' does not exist. Use tools/list to see available tools.`;
3185
+ const isFilteredTool = ALL_KNOWN_GROUP_TOOLS.has(requestedTool);
3186
+ if (isFilteredTool) {
3187
+ suggestion = `'${requestedTool}' is a valid tool but it is not currently exposed because of your active --tool-filter or codemode restrictions. If you are in Code Mode, invoke it via 'mj_execute_code' (e.g. 'await mj.core.${requestedTool}(...)').`;
3188
+ } else if (matchingPrompt !== void 0) {
3189
+ suggestion = `'${requestedTool}' is an MCP Prompt, not an MCP Tool. Please use the 'get_prompt' tool (or your native MCP Prompts integration) to evaluate it, then use 'create_entry' to save the result.`;
3190
+ } else if (requestedTool.startsWith("mj_")) {
3191
+ suggestion = `'${requestedTool}' is not a valid root tool. If you are trying to use Code Mode, you must invoke the 'mj_execute_code' tool and write javascript (e.g. 'await mj.core.searchEntries(...)').`;
3192
+ }
3193
+ const errorResult = {
3194
+ success: false,
3195
+ error: `MCP error -32602: Tool ${requestedTool} not found`,
3196
+ code: "TOOL_NOT_FOUND",
3197
+ category: "hallucination",
3198
+ suggestion,
3199
+ recoverable: false
3200
+ };
3201
+ if (healingEnabled) {
3202
+ logAgentIssue({
3203
+ source: "MCP",
3204
+ action: requestedTool,
3205
+ input: toolArgs,
3206
+ error: errorResult.error
3207
+ });
3208
+ }
3209
+ return formatTokenEstimatedError(errorResult, true);
3210
+ }
3211
+ const result = await originalHandler(request2, extra);
3212
+ if (result !== null && result !== void 0 && typeof result === "object" && "isError" in result && result.isError === true) {
3213
+ const resObj = result;
3214
+ if (Array.isArray(resObj.content) && resObj.content.length > 0) {
3215
+ const text = resObj.content[0]?.text;
3216
+ if (typeof text === "string" && text.includes("MCP error -32602")) {
3217
+ const errorMessage = parseZodErrorsFromMessage(
3218
+ text,
3219
+ "MCP error -32602: Input validation error: "
3220
+ );
3221
+ const errorResult = {
3222
+ success: false,
3223
+ error: errorMessage,
3224
+ code: "VALIDATION_ERROR",
3225
+ category: "validation",
3226
+ suggestion: "Check input parameters against the tool schema",
3227
+ recoverable: false
3228
+ };
3229
+ logAgentIssue({
3230
+ source: "MCP",
3231
+ action: req.params?.name ?? "unknown",
3232
+ input: req.params?.arguments ?? {},
3233
+ error: errorMessage
3234
+ });
3235
+ return formatTokenEstimatedError(errorResult, false);
3236
+ }
3237
+ }
3238
+ }
3239
+ return result;
3240
+ } catch (error) {
3241
+ const err = error;
3242
+ if (err.code === -32602) {
3243
+ let errorMessage = err.message ?? "Validation Error";
3244
+ if (typeof errorMessage === "string" && errorMessage.includes("Invalid arguments for tool")) {
3245
+ errorMessage = parseZodErrorsFromMessage(errorMessage);
3246
+ }
3247
+ const errorResult = {
3248
+ success: false,
3249
+ error: errorMessage,
3250
+ code: "VALIDATION_ERROR",
3251
+ category: "validation",
3252
+ suggestion: "Check input parameters against the tool schema",
3253
+ recoverable: false
3254
+ };
3255
+ const fallbackReq = request2;
3256
+ logAgentIssue({
3257
+ source: "MCP",
3258
+ action: fallbackReq.params?.name ?? "unknown",
3259
+ input: fallbackReq.params?.arguments ?? {},
3260
+ error: errorMessage
3261
+ });
3262
+ return formatTokenEstimatedError(errorResult, true);
3263
+ }
3264
+ throw error;
3265
+ }
3266
+ });
3267
+ }
3268
+
3269
+ // src/server/mcp-server/tool-registration/register-tools.ts
2847
3270
  var DEFAULT_MAX_TOOL_INPUT_ELEMENTS = 25e3;
2848
3271
  function resolveEffectiveMaxToolInputElements(configured) {
2849
- if (configured === void 0) {
2850
- return DEFAULT_MAX_TOOL_INPUT_ELEMENTS;
3272
+ if (configured === void 0) return DEFAULT_MAX_TOOL_INPUT_ELEMENTS;
3273
+ return configured === 0 || configured === Infinity ? Infinity : configured;
3274
+ }
3275
+ var MUTATING_TOOLS = /* @__PURE__ */ new Set([
3276
+ "create_entry",
3277
+ "update_entry",
3278
+ "delete_entry",
3279
+ "restore_entry",
3280
+ "batch_create_entries",
3281
+ "batch_update_entries",
3282
+ "batch_delete_entries",
3283
+ "team_add_member",
3284
+ "team_update_member_role",
3285
+ "team_remove_member"
3286
+ ]);
3287
+ var toolRegistrationOptionsCache = /* @__PURE__ */ new WeakMap();
3288
+ function buildToolRegistrationOptions(tool) {
3289
+ const cached = toolRegistrationOptionsCache.get(tool);
3290
+ if (cached !== void 0) return cached;
3291
+ const toolOptions = { description: tool.description };
3292
+ if (tool.title !== void 0 && tool.title !== "") toolOptions.title = tool.title;
3293
+ if (tool.inputSchema !== void 0) {
3294
+ const schema = tool.inputSchema;
3295
+ const fallbackInputSchema = schema;
3296
+ if (typeof schema === "object" && schema !== null && "partial" in schema && typeof schema.partial === "function") {
3297
+ try {
3298
+ const relaxed = schema.partial();
3299
+ toolOptions.inputSchema = typeof relaxed.passthrough === "function" ? relaxed.passthrough() : fallbackInputSchema;
3300
+ } catch {
3301
+ toolOptions.inputSchema = fallbackInputSchema;
3302
+ }
3303
+ } else {
3304
+ toolOptions.inputSchema = fallbackInputSchema;
3305
+ }
2851
3306
  }
2852
- if (configured === 0 || configured === Infinity) {
2853
- return Infinity;
3307
+ if (tool.outputSchema !== void 0) {
3308
+ const outSchema = tool.outputSchema;
3309
+ const fallbackOutputSchema = outSchema;
3310
+ if (typeof outSchema === "object" && outSchema !== null && "passthrough" in outSchema && typeof outSchema.passthrough === "function") {
3311
+ try {
3312
+ toolOptions.outputSchema = outSchema.passthrough();
3313
+ } catch {
3314
+ toolOptions.outputSchema = fallbackOutputSchema;
3315
+ }
3316
+ } else {
3317
+ toolOptions.outputSchema = fallbackOutputSchema;
3318
+ }
2854
3319
  }
2855
- return configured;
3320
+ if (tool.annotations !== void 0) toolOptions.annotations = tool.annotations;
3321
+ if (tool.icons !== void 0) toolOptions.icons = [{ src: tool.icons.iconUrl }];
3322
+ toolRegistrationOptionsCache.set(tool, toolOptions);
3323
+ return toolOptions;
2856
3324
  }
2857
3325
  function createServerInstance(context, options, prompts, resources, allTools, allToolNames, customToolHandlerConfig) {
2858
- const { configManager, db, teamDb, vectorManager, teamVectorManager, github, scheduler, allowedIoRoots, runtime } = context;
3326
+ const {
3327
+ configManager,
3328
+ db,
3329
+ teamDb,
3330
+ vectorManager,
3331
+ teamVectorManager,
3332
+ github,
3333
+ scheduler,
3334
+ allowedIoRoots,
3335
+ runtime
3336
+ } = context;
2859
3337
  const { defaultProjectNumber } = options;
2860
3338
  const getInstructions = () => {
2861
3339
  const currentConfig = configManager.getConfig();
2862
3340
  const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
2863
3341
  const groups = currentConfig.toolFilterConfig ? getEnabledGroups(currentConfig.toolFilterConfig.enabledTools) : void 0;
2864
3342
  const isCodeModeOnly = enabledSet.size === 1 && enabledSet.has("mj_execute_code");
3343
+ const mappedPrompts = prompts.map((p) => {
3344
+ const prompt = p;
3345
+ return {
3346
+ name: prompt.name,
3347
+ ...prompt.description !== void 0 ? { description: prompt.description } : {}
3348
+ };
3349
+ });
2865
3350
  if (isCodeModeOnly || currentConfig.toolFilterConfig?.raw === "codemode") {
2866
3351
  const finalGroups = currentConfig.codemodeInternalFullAccess === true ? new Set(Object.keys(TOOL_GROUPS)) : groups;
2867
3352
  const finalEnabledTools = currentConfig.codemodeInternalFullAccess === true ? allToolNames : enabledSet;
2868
3353
  return generateCodeModeInstructions(
2869
3354
  finalEnabledTools,
2870
- prompts.map((p) => {
2871
- const prompt = p;
2872
- return { name: prompt.name, description: prompt.description };
2873
- }),
3355
+ mappedPrompts,
2874
3356
  void 0,
2875
3357
  finalGroups,
2876
3358
  currentConfig.briefingConfig
@@ -2878,85 +3360,35 @@ function createServerInstance(context, options, prompts, resources, allTools, al
2878
3360
  }
2879
3361
  return generateStandardInstructions(
2880
3362
  enabledSet,
2881
- prompts.map((p) => {
2882
- const prompt = p;
2883
- return { name: prompt.name, description: prompt.description };
2884
- }),
3363
+ mappedPrompts,
2885
3364
  void 0,
2886
3365
  groups,
2887
3366
  currentConfig.briefingConfig
2888
3367
  );
2889
3368
  };
2890
3369
  const server = new McpServer(
2891
- {
2892
- name: "memory-journal-mcp",
2893
- version: VERSION
2894
- },
3370
+ { name: "memory-journal-mcp", version: VERSION },
2895
3371
  {
2896
3372
  capabilities: {
2897
3373
  logging: {},
2898
3374
  prompts: { listChanged: true },
2899
3375
  tools: { listChanged: true },
2900
- resources: {
2901
- subscribe: true,
2902
- listChanged: true
2903
- },
2904
- experimental: {
2905
- progress: {}
2906
- }
3376
+ resources: { subscribe: true, listChanged: true },
3377
+ experimental: { progress: {} }
2907
3378
  },
2908
3379
  instructions: getInstructions(),
2909
3380
  maxToolInputElements: resolveEffectiveMaxToolInputElements(options.maxToolInputElements)
2910
3381
  }
2911
3382
  );
2912
- if (context.skillCatalog && typeof server.isConnected === "function") {
3383
+ if (context.skillCatalog !== void 0 && typeof server.isConnected === "function") {
2913
3384
  context.skillCatalog.attach(server);
2914
3385
  }
2915
3386
  for (const tool of allTools) {
2916
- const toolOptions = {
2917
- description: tool.description
2918
- };
2919
- if (tool.title) {
2920
- toolOptions.title = tool.title;
2921
- }
2922
- if (tool.inputSchema !== void 0) {
2923
- const schema = tool.inputSchema;
2924
- if (typeof schema === "object" && schema !== null && "partial" in schema && typeof schema.partial === "function") {
2925
- try {
2926
- const relaxed = schema.partial();
2927
- toolOptions.inputSchema = typeof relaxed.passthrough === "function" ? relaxed.passthrough() : schema;
2928
- } catch {
2929
- toolOptions.inputSchema = schema;
2930
- }
2931
- } else {
2932
- toolOptions.inputSchema = schema;
2933
- }
2934
- }
2935
- if (tool.outputSchema !== void 0) {
2936
- const outSchema = tool.outputSchema;
2937
- if (typeof outSchema === "object" && outSchema !== null && "passthrough" in outSchema && typeof outSchema.passthrough === "function") {
2938
- try {
2939
- toolOptions.outputSchema = outSchema.passthrough();
2940
- } catch {
2941
- toolOptions.outputSchema = outSchema;
2942
- }
2943
- } else {
2944
- toolOptions.outputSchema = outSchema;
2945
- }
2946
- }
2947
- if (tool.annotations !== void 0) {
2948
- toolOptions.annotations = tool.annotations;
2949
- }
2950
- if (tool.icons) {
2951
- toolOptions.icons = [{
2952
- src: tool.icons.iconUrl
2953
- }];
2954
- }
3387
+ const toolOptions = buildToolRegistrationOptions(tool);
2955
3388
  const hasOutputSchema = Boolean(tool.outputSchema);
2956
3389
  server.registerTool(
2957
3390
  tool.name,
2958
3391
  toolOptions,
2959
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2960
3392
  async (args, extra) => {
2961
3393
  try {
2962
3394
  const extraMeta = extra;
@@ -2965,7 +3397,7 @@ function createServerInstance(context, options, prompts, resources, allTools, al
2965
3397
  const currentConfig = configManager.getConfig();
2966
3398
  customToolHandlerConfig.filterConfig = currentConfig.toolFilterConfig;
2967
3399
  customToolHandlerConfig.briefingConfig = currentConfig.briefingConfig;
2968
- const toolArgs = args;
3400
+ const toolArgs = typeof args === "object" && args !== null ? args : {};
2969
3401
  const result = await callTool(
2970
3402
  tool.name,
2971
3403
  toolArgs,
@@ -2979,49 +3411,31 @@ function createServerInstance(context, options, prompts, resources, allTools, al
2979
3411
  );
2980
3412
  const isSuccess = typeof result === "object" && result !== null && result["success"] === true;
2981
3413
  if (isSuccess) {
2982
- const mutatingTools = [
2983
- "create_entry",
2984
- "update_entry",
2985
- "delete_entry",
2986
- "restore_entry",
2987
- "batch_create_entries",
2988
- "batch_update_entries",
2989
- "batch_delete_entries",
2990
- "add_team_member",
2991
- "update_team_member",
2992
- "remove_team_member"
2993
- ];
2994
- const isMutation = mutatingTools.includes(tool.name) || tool.name.startsWith("team_") && tool.name !== "team_search" && tool.name !== "get_team_entry_by_id";
3414
+ const isMutation = MUTATING_TOOLS.has(tool.name) || tool.name.startsWith("team_") && tool.annotations.readOnlyHint !== true;
2995
3415
  if (isMutation) {
2996
3416
  void globalSubscriptionManager.notifyResourceUpdated("memory://briefing");
2997
3417
  void globalSubscriptionManager.notifyResourceUpdated("memory://recent");
2998
- void globalSubscriptionManager.notifyResourceUpdated("memory://statistics");
2999
- if (tool.name.startsWith("team_") || tool.name.includes("team_member")) {
3000
- void globalSubscriptionManager.notifyResourceUpdated("memory://team/recent");
3001
- void globalSubscriptionManager.notifyResourceUpdated("memory://team/statistics");
3418
+ void globalSubscriptionManager.notifyResourceUpdated(
3419
+ "memory://statistics"
3420
+ );
3421
+ if (tool.name.startsWith("team_")) {
3422
+ void globalSubscriptionManager.notifyResourceUpdated(
3423
+ "memory://team/recent"
3424
+ );
3425
+ void globalSubscriptionManager.notifyResourceUpdated(
3426
+ "memory://team/statistics"
3427
+ );
3002
3428
  }
3003
3429
  }
3004
3430
  }
3005
3431
  const textContent = typeof result === "string" ? result : JSON.stringify(result, null, 2);
3006
3432
  if (hasOutputSchema) {
3007
3433
  return {
3008
- content: [
3009
- {
3010
- type: "text",
3011
- text: textContent
3012
- }
3013
- ],
3434
+ content: [{ type: "text", text: textContent }],
3014
3435
  structuredContent: result
3015
3436
  };
3016
3437
  }
3017
- return {
3018
- content: [
3019
- {
3020
- type: "text",
3021
- text: textContent
3022
- }
3023
- ]
3024
- };
3438
+ return { content: [{ type: "text", text: textContent }] };
3025
3439
  } catch (error) {
3026
3440
  let errorResult;
3027
3441
  if (error instanceof Error && "toResponse" in error && typeof error.toResponse === "function") {
@@ -3058,12 +3472,11 @@ function createServerInstance(context, options, prompts, resources, allTools, al
3058
3472
  }
3059
3473
  const handleResourceRead = async (uri, mimeType) => {
3060
3474
  const currentConfig = configManager.getConfig();
3475
+ const resolvedDefaultProj = currentConfig.briefingConfig.defaultProjectNumber ?? defaultProjectNumber;
3061
3476
  const activeBriefingConfig = {
3062
3477
  ...currentConfig.briefingConfig,
3063
- // Ensure defaultProjectNumber is available to resource handlers
3064
- // (may come via briefingConfig from CLI, or directly from server options)
3065
- defaultProjectNumber: currentConfig.briefingConfig.defaultProjectNumber ?? defaultProjectNumber,
3066
- projectRegistry: options.projectRegistry,
3478
+ ...resolvedDefaultProj !== void 0 ? { defaultProjectNumber: resolvedDefaultProj } : {},
3479
+ ...options.projectRegistry !== void 0 ? { projectRegistry: options.projectRegistry } : {},
3067
3480
  allowedIoRoots
3068
3481
  };
3069
3482
  try {
@@ -3086,7 +3499,7 @@ function createServerInstance(context, options, prompts, resources, allTools, al
3086
3499
  uri: uri.href,
3087
3500
  mimeType,
3088
3501
  text: dataStr,
3089
- ...result.annotations ? { annotations: result.annotations } : {}
3502
+ ...result.annotations !== void 0 ? { annotations: result.annotations } : {}
3090
3503
  }
3091
3504
  ]
3092
3505
  };
@@ -3097,845 +3510,46 @@ function createServerInstance(context, options, prompts, resources, allTools, al
3097
3510
  };
3098
3511
  registerResources(server, resources, handleResourceRead, runtime);
3099
3512
  server.server.setRequestHandler("resources/subscribe", (request2, extra) => {
3100
- const transportSessionId = extra?.sessionId || "stdio";
3513
+ const sessionId = extra?.sessionId;
3514
+ const transportSessionId = sessionId !== void 0 && sessionId !== "" ? sessionId : "stdio";
3101
3515
  validateResourceSubscription(request2.params.uri, runtime);
3102
3516
  globalSubscriptionManager.registerServer(transportSessionId, server);
3103
3517
  globalSubscriptionManager.subscribe(request2.params.uri, transportSessionId);
3104
3518
  return {};
3105
3519
  });
3106
3520
  server.server.setRequestHandler("resources/unsubscribe", (request2, extra) => {
3107
- const transportSessionId = extra?.sessionId || "stdio";
3521
+ const sessionId = extra?.sessionId;
3522
+ const transportSessionId = sessionId !== void 0 && sessionId !== "" ? sessionId : "stdio";
3108
3523
  globalSubscriptionManager.unsubscribe(request2.params.uri, transportSessionId);
3109
3524
  return {};
3110
3525
  });
3111
3526
  const briefingConfig = configManager.getConfig().briefingConfig;
3112
- registerPrompts(server, prompts, db, teamDb ?? void 0, runtime, context.github, briefingConfig);
3527
+ registerPrompts(
3528
+ server,
3529
+ prompts,
3530
+ db,
3531
+ teamDb ?? void 0,
3532
+ runtime,
3533
+ context.github,
3534
+ briefingConfig
3535
+ );
3113
3536
  const serverObj = server.server;
3114
3537
  const requestHandlers = serverObj._requestHandlers;
3115
- const listToolsHandler = requestHandlers?.get("tools/list");
3116
- if (listToolsHandler) {
3117
- requestHandlers.set("tools/list", async (request2, extra) => {
3118
- const currentConfig = configManager.getConfig();
3119
- const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
3120
- const result = await listToolsHandler(request2, extra);
3121
- const res = result;
3122
- if (Array.isArray(res?.tools)) {
3123
- res.tools = res.tools.filter((t) => enabledSet.has(t.name));
3124
- }
3125
- return result;
3126
- });
3127
- }
3128
- const originalHandler = requestHandlers?.get("tools/call");
3129
- if (originalHandler) {
3130
- requestHandlers.set("tools/call", async (request2, extra) => {
3131
- try {
3132
- const req = request2;
3133
- const healingEnabled = options.agentHealing !== false && customToolHandlerConfig.agentHealing !== false;
3134
- if (req?.params?.arguments && healingEnabled) {
3135
- const deepCamelToSnake = (obj) => {
3136
- if (Array.isArray(obj)) return obj.map(deepCamelToSnake);
3137
- if (obj !== null && typeof obj === "object") {
3138
- const newObj = {};
3139
- for (const [k, v] of Object.entries(obj)) {
3140
- const snakeKey = k.replace(/^[A-Z]/, (letter) => letter.toLowerCase()).replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
3141
- newObj[snakeKey] = deepCamelToSnake(v);
3142
- }
3143
- return newObj;
3144
- }
3145
- return obj;
3146
- };
3147
- req.params.arguments = deepCamelToSnake(req.params.arguments);
3148
- const toolArgs = req.params.arguments;
3149
- if (typeof toolArgs["project_number"] === "undefined") {
3150
- let repoStr;
3151
- if (typeof toolArgs["repo"] === "string") repoStr = toolArgs["repo"];
3152
- else if (typeof toolArgs["project"] === "string") repoStr = toolArgs["project"];
3153
- if (repoStr) {
3154
- toolArgs["project_number"] = repoStr;
3155
- }
3156
- }
3157
- if (typeof toolArgs["project_number"] === "string") {
3158
- const strVal = toolArgs["project_number"];
3159
- const parsed = Number(strVal);
3160
- if (!Number.isNaN(parsed)) {
3161
- toolArgs["project_number"] = parsed;
3162
- } else if (options.projectRegistry) {
3163
- let entry = options.projectRegistry[strVal];
3164
- if (!entry && strVal.includes("/")) {
3165
- const repoName = strVal.split("/").pop();
3166
- if (repoName) {
3167
- entry = options.projectRegistry[repoName];
3168
- }
3169
- }
3170
- if (entry?.project_number !== void 0) {
3171
- toolArgs["project_number"] = entry.project_number;
3172
- }
3173
- }
3174
- }
3175
- const ALIASED_EXECUTE_CODE_NAMES = /* @__PURE__ */ new Set([
3176
- "mysql_execute_code",
3177
- "mysqlExecuteCode",
3178
- "execute_code",
3179
- "executeCode",
3180
- "mjExecuteCode",
3181
- "mj_eval",
3182
- "eval_code",
3183
- "run_code",
3184
- "exec_code",
3185
- "code_execute"
3186
- ]);
3187
- if (req.params.name && ALIASED_EXECUTE_CODE_NAMES.has(req.params.name)) {
3188
- req.params.name = "mj_execute_code";
3189
- }
3190
- if (req.params.name === "create_entry_minimal") {
3191
- req.params.name = "create_entry";
3192
- if (typeof toolArgs["entry_type"] === "undefined") {
3193
- toolArgs["entry_type"] = "personal_reflection";
3194
- }
3195
- }
3196
- const ALIASED_LIST_PROJECTS_NAMES = /* @__PURE__ */ new Set([
3197
- "listProjects",
3198
- "list-projects",
3199
- "get_projects",
3200
- "getProjects",
3201
- "get-projects",
3202
- "mj_list_projects",
3203
- "mjListProjects",
3204
- "mj_get_projects",
3205
- "mjGetProjects",
3206
- "mj_admin_list_projects",
3207
- "mj_admin_get_projects"
3208
- ]);
3209
- if (req.params.name && ALIASED_LIST_PROJECTS_NAMES.has(req.params.name)) {
3210
- req.params.name = "list_projects";
3211
- }
3212
- const ALIASED_GET_PROJECT_NAMES = /* @__PURE__ */ new Set([
3213
- "getProject",
3214
- "get-project",
3215
- "mj_get_project",
3216
- "mjGetProject",
3217
- "mj_admin_get_project"
3218
- ]);
3219
- if (req.params.name && ALIASED_GET_PROJECT_NAMES.has(req.params.name)) {
3220
- req.params.name = "get_project";
3221
- }
3222
- const ALIASED_GREP_SEARCH_NAMES = /* @__PURE__ */ new Set([
3223
- "grep_search",
3224
- "grepSearch",
3225
- "grep",
3226
- "file_search",
3227
- "fileSearch",
3228
- "find_in_files",
3229
- "findInFiles",
3230
- "search_files",
3231
- "searchFiles"
3232
- ]);
3233
- if (req.params.name && ALIASED_GREP_SEARCH_NAMES.has(req.params.name)) {
3234
- req.params.name = "grep_search";
3235
- }
3236
- const ALIASED_VIEW_FILE_NAMES = /* @__PURE__ */ new Set([
3237
- "view_file",
3238
- "viewFile",
3239
- "read_file",
3240
- "readFile",
3241
- "get_file",
3242
- "getFile"
3243
- ]);
3244
- if (req.params.name && ALIASED_VIEW_FILE_NAMES.has(req.params.name)) {
3245
- req.params.name = "view_file";
3246
- }
3247
- const ALIASED_LIST_DIR_NAMES = /* @__PURE__ */ new Set([
3248
- "list_dir",
3249
- "listDir",
3250
- "read_dir",
3251
- "readDir"
3252
- ]);
3253
- if (req.params.name && ALIASED_LIST_DIR_NAMES.has(req.params.name)) {
3254
- req.params.name = "list_dir";
3255
- }
3256
- if (req.params.name) {
3257
- const intercept = applyArgInterceptions(req.params.name, [toolArgs]);
3258
- if ("error" in intercept) {
3259
- const errorResult = intercept.error;
3260
- logAgentIssue({
3261
- source: "MCP",
3262
- action: req.params.name,
3263
- input: toolArgs,
3264
- error: errorResult["error"] ?? "Validation Error"
3265
- });
3266
- const enriched = JSON.stringify({
3267
- ...errorResult,
3268
- _meta: { tokenEstimate: 0 }
3269
- });
3270
- const tokenEstimate = Math.ceil(Buffer.byteLength(enriched, "utf8") / 4);
3271
- const finalText = enriched.replace('"tokenEstimate":0', `"tokenEstimate":${tokenEstimate}`);
3272
- return {
3273
- content: [
3274
- {
3275
- type: "text",
3276
- text: finalText
3277
- }
3278
- ],
3279
- structuredContent: errorResult
3280
- };
3281
- } else {
3282
- const normalizedArgs = intercept.args?.[0];
3283
- if (normalizedArgs !== null && typeof normalizedArgs === "object" && !Array.isArray(normalizedArgs)) {
3284
- req.params.arguments = normalizedArgs;
3285
- }
3286
- }
3287
- }
3288
- }
3289
- if (req?.params?.name && !allToolNames.has(req.params.name)) {
3290
- const requestedTool = req.params.name;
3291
- const toolArgs = req.params.arguments ?? {};
3292
- const normalized = requestedTool.replace(/^mj_/, "").replace(/_/g, "-");
3293
- const matchingPrompt = prompts.find((p) => p.name === normalized || p.name === requestedTool || p.name === requestedTool.replace(/^mj_/, ""));
3294
- if (healingEnabled) {
3295
- if (matchingPrompt) {
3296
- try {
3297
- const stringArgs = {};
3298
- for (const [k, v] of Object.entries(toolArgs)) {
3299
- if (typeof v === "string") stringArgs[k] = v;
3300
- else if (typeof v === "number" || typeof v === "boolean") stringArgs[k] = String(v);
3301
- }
3302
- if ((matchingPrompt.name === "load-briefing" || matchingPrompt.name === "briefing") && !stringArgs["projects"]) {
3303
- const fallbackProject = stringArgs["project"] ?? stringArgs["name"] ?? stringArgs["target"] ?? stringArgs["repo"] ?? stringArgs["workspace"] ?? "";
3304
- stringArgs["projects"] = fallbackProject;
3305
- }
3306
- const currentConfig = configManager.getConfig();
3307
- const promptResult = await getPrompt(
3308
- matchingPrompt.name,
3309
- stringArgs,
3310
- db,
3311
- teamDb ?? void 0,
3312
- github ?? void 0,
3313
- currentConfig.briefingConfig
3314
- );
3315
- const successPayload = {
3316
- success: true,
3317
- data: promptResult,
3318
- messages: promptResult.messages,
3319
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' is an MCP Prompt, but was invoked directly as an MCP tool. The prompt was evaluated and returned successfully.`
3320
- };
3321
- const enriched2 = JSON.stringify(successPayload, null, 2);
3322
- return {
3323
- content: [
3324
- {
3325
- type: "text",
3326
- text: enriched2
3327
- }
3328
- ],
3329
- structuredContent: successPayload
3330
- };
3331
- } catch {
3332
- }
3333
- }
3334
- const isResource = requestedTool === "read_resource" || requestedTool === "readResource" || requestedTool === "read-resource" || requestedTool === "mj_read_resource" || requestedTool === "mjReadResource" || requestedTool === "memory_read_resource" || requestedTool === "memoryReadResource" || requestedTool === "memory_journal_read_resource" || requestedTool === "get_resource" || requestedTool === "getResource" || requestedTool === "get-resource" || requestedTool === "memory_get_resource" || requestedTool === "memoryGetResource" || requestedTool === "mj_get_resource" || requestedTool === "mjGetResource" || requestedTool === "read_memory_resource" || requestedTool.endsWith("_read_resource") || requestedTool.endsWith("ReadResource") || requestedTool.startsWith("memory://");
3335
- if (isResource) {
3336
- try {
3337
- let uri = typeof toolArgs["uri"] === "string" ? toolArgs["uri"] : typeof toolArgs["Uri"] === "string" ? toolArgs["Uri"] : typeof toolArgs["_uri"] === "string" ? toolArgs["_uri"] : void 0;
3338
- if (!uri) {
3339
- for (const key of ["resourceUri", "resource_uri", "resource", "Resource", "url", "Url", "path", "Path", "name", "Name", "target", "Target", "ServerName", "server_name"]) {
3340
- const rawVal = toolArgs[key];
3341
- if (typeof rawVal === "string" && rawVal.trim()) {
3342
- const val = rawVal.trim();
3343
- if (key === "ServerName" || key === "server_name") {
3344
- if (val === "memory-journal-mcp" || val === "memory-journal") continue;
3345
- }
3346
- uri = val;
3347
- break;
3348
- }
3349
- }
3350
- }
3351
- if (!uri && requestedTool.startsWith("memory://")) {
3352
- uri = requestedTool;
3353
- }
3354
- if (uri && !uri.includes("://")) {
3355
- if (uri.startsWith("briefing") || uri.startsWith("recent") || uri.startsWith("agent-") || uri.startsWith("statistics") || uri.startsWith("insights") || uri.startsWith("help") || uri.startsWith("health") || uri.startsWith("team") || uri.startsWith("git") || uri.startsWith("tools")) {
3356
- uri = `memory://${uri}`;
3357
- } else {
3358
- uri = `memory://briefing/${uri}`;
3359
- }
3360
- }
3361
- if (!uri) {
3362
- uri = "memory://briefing";
3363
- }
3364
- const currentConfig = configManager.getConfig();
3365
- const res = await readResource(
3366
- uri,
3367
- db,
3368
- vectorManager ?? void 0,
3369
- currentConfig.toolFilterConfig,
3370
- github ?? void 0,
3371
- void 0,
3372
- teamDb ?? void 0,
3373
- currentConfig.briefingConfig,
3374
- runtime
3375
- );
3376
- const successPayload = {
3377
- success: true,
3378
- data: res.data,
3379
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool instead of an MCP resource read. The resource '${uri}' was resolved successfully.`
3380
- };
3381
- const enriched2 = JSON.stringify(successPayload, null, 2);
3382
- return {
3383
- content: [
3384
- {
3385
- type: "text",
3386
- text: enriched2
3387
- }
3388
- ],
3389
- structuredContent: successPayload
3390
- };
3391
- } catch {
3392
- }
3393
- }
3394
- const isListResources = requestedTool === "list_resources" || requestedTool === "listResources" || requestedTool === "list-resources" || requestedTool === "mj_list_resources" || requestedTool === "mjListResources" || requestedTool === "memory_list_resources" || requestedTool === "memoryListResources" || requestedTool === "memory_journal_list_resources" || requestedTool === "get_resources" || requestedTool === "getResources" || requestedTool === "get-resources" || requestedTool === "memory_get_resources" || requestedTool === "memoryGetResources" || requestedTool.endsWith("_list_resources") || requestedTool.endsWith("ListResources");
3395
- if (isListResources) {
3396
- try {
3397
- const resourceList = getResources();
3398
- const successPayload = {
3399
- success: true,
3400
- resources: resourceList,
3401
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool instead of an MCP protocol request (resources/list). The available resources were returned successfully.`
3402
- };
3403
- const enriched2 = JSON.stringify(successPayload, null, 2);
3404
- return {
3405
- content: [
3406
- {
3407
- type: "text",
3408
- text: enriched2
3409
- }
3410
- ],
3411
- structuredContent: successPayload
3412
- };
3413
- } catch {
3414
- }
3415
- }
3416
- const isListPrompts = requestedTool === "list_prompts" || requestedTool === "listPrompts" || requestedTool === "list-prompts" || requestedTool === "mj_list_prompts" || requestedTool === "mjListPrompts" || requestedTool === "memory_list_prompts" || requestedTool === "memoryListPrompts" || requestedTool === "memory_journal_list_prompts" || requestedTool === "get_prompts" || requestedTool === "getPrompts" || requestedTool.endsWith("_list_prompts") || requestedTool.endsWith("ListPrompts");
3417
- if (isListPrompts) {
3418
- try {
3419
- const promptList = getPrompts();
3420
- const successPayload = {
3421
- success: true,
3422
- prompts: promptList,
3423
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool instead of an MCP protocol request (prompts/list). The available prompts were returned successfully.`
3424
- };
3425
- const enriched2 = JSON.stringify(successPayload, null, 2);
3426
- return {
3427
- content: [
3428
- {
3429
- type: "text",
3430
- text: enriched2
3431
- }
3432
- ],
3433
- structuredContent: successPayload
3434
- };
3435
- } catch {
3436
- }
3437
- }
3438
- const isListTools = requestedTool === "list_tools" || requestedTool === "listTools" || requestedTool === "list-tools" || requestedTool === "mj_list_tools" || requestedTool === "mjListTools" || requestedTool === "memory_list_tools" || requestedTool === "memoryListTools" || requestedTool === "memory_journal_list_tools" || requestedTool === "get_tools" || requestedTool === "getTools" || requestedTool.endsWith("_list_tools") || requestedTool.endsWith("ListTools");
3439
- if (isListTools) {
3440
- try {
3441
- const currentConfig = configManager.getConfig();
3442
- const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
3443
- const toolsList = allTools.filter((t) => enabledSet.has(t.name)).map((t) => ({
3444
- name: t.name,
3445
- title: t.title,
3446
- description: t.description,
3447
- annotations: t.annotations
3448
- }));
3449
- const successPayload = {
3450
- success: true,
3451
- tools: toolsList,
3452
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool instead of an MCP protocol request (tools/list). The available tools were returned successfully.`
3453
- };
3454
- const enriched2 = JSON.stringify(successPayload, null, 2);
3455
- return {
3456
- content: [
3457
- {
3458
- type: "text",
3459
- text: enriched2
3460
- }
3461
- ],
3462
- structuredContent: successPayload
3463
- };
3464
- } catch {
3465
- }
3466
- }
3467
- const isGetPrompt = requestedTool === "get_prompt" || requestedTool === "getPrompt" || requestedTool === "mj_get_prompt" || requestedTool === "mjGetPrompt" || requestedTool === "memory_get_prompt" || requestedTool === "memoryGetPrompt" || requestedTool === "memory_journal_get_prompt" || requestedTool === "read_prompt" || requestedTool === "readPrompt" || requestedTool.endsWith("_get_prompt") || requestedTool.endsWith("GetPrompt");
3468
- if (isGetPrompt) {
3469
- try {
3470
- const targetPromptName = typeof toolArgs["name"] === "string" ? toolArgs["name"] : typeof toolArgs["prompt"] === "string" ? toolArgs["prompt"] : typeof toolArgs["prompt_name"] === "string" ? toolArgs["prompt_name"] : "load-briefing";
3471
- const nestedArgs = typeof toolArgs["arguments"] === "object" && toolArgs["arguments"] !== null ? toolArgs["arguments"] : toolArgs;
3472
- const stringArgs = {};
3473
- for (const [k, v] of Object.entries(nestedArgs)) {
3474
- if (k !== "name" && k !== "prompt" && k !== "prompt_name" && k !== "arguments") {
3475
- if (typeof v === "string") stringArgs[k] = v;
3476
- else if (typeof v === "number" || typeof v === "boolean") stringArgs[k] = String(v);
3477
- }
3478
- }
3479
- const currentConfig = configManager.getConfig();
3480
- const promptResult = await getPrompt(
3481
- targetPromptName,
3482
- stringArgs,
3483
- db,
3484
- teamDb ?? void 0,
3485
- github ?? void 0,
3486
- currentConfig.briefingConfig
3487
- );
3488
- const successPayload = {
3489
- success: true,
3490
- data: promptResult,
3491
- messages: promptResult.messages,
3492
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool instead of an MCP protocol request (prompts/get). The prompt '${targetPromptName}' was evaluated successfully.`
3493
- };
3494
- const enriched2 = JSON.stringify(successPayload, null, 2);
3495
- return {
3496
- content: [
3497
- {
3498
- type: "text",
3499
- text: enriched2
3500
- }
3501
- ],
3502
- structuredContent: successPayload
3503
- };
3504
- } catch {
3505
- }
3506
- }
3507
- const isServerInfo = [
3508
- "server_info",
3509
- "serverInfo",
3510
- "server-info",
3511
- "mj_server_info",
3512
- "get_server_info",
3513
- "getServerInfo",
3514
- "server_health",
3515
- "serverHealth",
3516
- "server-health",
3517
- "mj_server_health",
3518
- "get_server_health",
3519
- "getServerHealth",
3520
- "health_check",
3521
- "healthCheck",
3522
- "health-check",
3523
- "server_status",
3524
- "serverStatus",
3525
- "server-status",
3526
- "status",
3527
- "health"
3528
- ].includes(requestedTool);
3529
- if (isServerInfo) {
3530
- try {
3531
- let healthData;
3532
- try {
3533
- const res = await readResource(
3534
- "memory://health",
3535
- db,
3536
- vectorManager ?? void 0,
3537
- configManager.getConfig().toolFilterConfig ?? void 0,
3538
- github ?? void 0,
3539
- void 0,
3540
- teamDb ?? void 0,
3541
- configManager.getConfig().briefingConfig,
3542
- runtime
3543
- );
3544
- if (typeof res.data === "object" && res.data !== null) {
3545
- healthData = res.data;
3546
- }
3547
- } catch {
3548
- }
3549
- const dbHealth = healthData ?? db.getHealthStatus();
3550
- const successPayload = {
3551
- success: true,
3552
- status: "healthy",
3553
- server: {
3554
- name: "memory-journal-mcp",
3555
- version: VERSION,
3556
- description: "Memory Journal MCP Server with Code Mode & Semantic Search"
3557
- },
3558
- runtime: {
3559
- nodeVersion: process.version,
3560
- platform: process.platform,
3561
- uptimeSeconds: Math.floor(process.uptime())
3562
- },
3563
- ...healthData !== void 0 ? { health: healthData } : {},
3564
- ...dbHealth !== void 0 ? { database: dbHealth } : {},
3565
- capabilities: {
3566
- codemode: true,
3567
- resources: true,
3568
- prompts: true,
3569
- tools: true
3570
- },
3571
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool. Returned server diagnostic information and health status successfully.`
3572
- };
3573
- const enriched2 = JSON.stringify(successPayload, null, 2);
3574
- return {
3575
- content: [
3576
- {
3577
- type: "text",
3578
- text: enriched2
3579
- }
3580
- ],
3581
- structuredContent: successPayload
3582
- };
3583
- } catch {
3584
- }
3585
- }
3586
- const isListProjects = [
3587
- "list_projects",
3588
- "listProjects",
3589
- "list-projects",
3590
- "get_projects",
3591
- "getProjects",
3592
- "get-projects",
3593
- "mj_list_projects",
3594
- "mjListProjects",
3595
- "mj_get_projects",
3596
- "mjGetProjects",
3597
- "mj_admin_list_projects",
3598
- "mj_admin_get_projects",
3599
- "projects"
3600
- ].includes(requestedTool) || requestedTool.endsWith("list_projects") || requestedTool.endsWith("listProjects") || requestedTool.endsWith("ListProjects");
3601
- if (isListProjects) {
3602
- try {
3603
- const currentConfig = configManager.getConfig();
3604
- const registry = currentConfig.projectRegistry ?? {};
3605
- const successPayload = {
3606
- success: true,
3607
- projects: registry,
3608
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool. Returned registered projects from projectRegistry successfully.`
3609
- };
3610
- const enriched2 = JSON.stringify(successPayload, null, 2);
3611
- return {
3612
- content: [
3613
- {
3614
- type: "text",
3615
- text: enriched2
3616
- }
3617
- ],
3618
- structuredContent: successPayload
3619
- };
3620
- } catch {
3621
- }
3622
- }
3623
- const isListAdapters = [
3624
- "list_adapters",
3625
- "listAdapters",
3626
- "list-adapters",
3627
- "mj_list_adapters",
3628
- "mjListAdapters",
3629
- "get_adapters",
3630
- "getAdapters",
3631
- "get-adapters",
3632
- "adapters"
3633
- ].includes(requestedTool) || requestedTool.endsWith("list_adapters") || requestedTool.endsWith("listAdapters") || requestedTool.endsWith("ListAdapters");
3634
- if (isListAdapters) {
3635
- try {
3636
- const adapters = [
3637
- {
3638
- name: "sqlite",
3639
- type: "database",
3640
- driver: "better-sqlite3",
3641
- status: "connected",
3642
- primary: true,
3643
- description: "Primary SQLite storage engine for journal entries, tags, and relationships"
3644
- },
3645
- {
3646
- name: "sqlite-vec",
3647
- type: "vector",
3648
- driver: "sqlite-vec",
3649
- status: vectorManager !== void 0 && vectorManager !== null ? "connected" : "ready",
3650
- description: "Native vector embeddings and semantic search engine"
3651
- },
3652
- {
3653
- name: "team",
3654
- type: "database",
3655
- driver: "better-sqlite3",
3656
- status: teamDb !== void 0 && teamDb !== null ? "connected" : "disabled",
3657
- description: "Collaborative team journal database adapter"
3658
- },
3659
- {
3660
- name: "github",
3661
- type: "integration",
3662
- driver: "octokit / gh",
3663
- status: github !== void 0 && github !== null ? "connected" : "disabled",
3664
- description: "GitHub synchronization and issue tracking adapter"
3665
- }
3666
- ];
3667
- const successPayload = {
3668
- success: true,
3669
- adapters,
3670
- default_adapter: "sqlite",
3671
- _healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool. Returned registered database and service adapters successfully.`
3672
- };
3673
- const enriched2 = JSON.stringify(successPayload, null, 2);
3674
- return {
3675
- content: [
3676
- {
3677
- type: "text",
3678
- text: enriched2
3679
- }
3680
- ],
3681
- structuredContent: successPayload
3682
- };
3683
- } catch {
3684
- }
3685
- }
3686
- const isGrepSearch = [
3687
- "grep_search",
3688
- "grepSearch",
3689
- "grep",
3690
- "file_search",
3691
- "fileSearch",
3692
- "find_in_files",
3693
- "findInFiles",
3694
- "search_files",
3695
- "searchFiles"
3696
- ].includes(requestedTool) || requestedTool.endsWith("grep_search") || requestedTool.endsWith("grepSearch");
3697
- if (isGrepSearch) {
3698
- try {
3699
- const dummyTools = getDummyHealingTools({ db, teamDb: teamDb ?? void 0, vectorManager: vectorManager ?? void 0, teamVectorManager: teamVectorManager ?? void 0, github: github ?? void 0, config: customToolHandlerConfig });
3700
- const grepTool = dummyTools.find((t) => t.name === "grep_search");
3701
- if (grepTool) {
3702
- const res = await Promise.resolve(grepTool.handler(toolArgs));
3703
- const enriched2 = JSON.stringify(res, null, 2);
3704
- return {
3705
- content: [
3706
- {
3707
- type: "text",
3708
- text: enriched2
3709
- }
3710
- ],
3711
- structuredContent: res
3712
- };
3713
- }
3714
- } catch {
3715
- }
3716
- }
3717
- const isViewFile = [
3718
- "view_file",
3719
- "viewFile",
3720
- "read_file",
3721
- "readFile",
3722
- "get_file",
3723
- "getFile",
3724
- "cat"
3725
- ].includes(requestedTool);
3726
- if (isViewFile) {
3727
- try {
3728
- const dummyTools = getDummyHealingTools({ db, teamDb: teamDb ?? void 0, vectorManager: vectorManager ?? void 0, teamVectorManager: teamVectorManager ?? void 0, github: github ?? void 0, config: customToolHandlerConfig });
3729
- const viewTool = dummyTools.find((t) => t.name === "view_file");
3730
- if (viewTool) {
3731
- const res = await Promise.resolve(viewTool.handler(toolArgs));
3732
- const enriched2 = JSON.stringify(res, null, 2);
3733
- return {
3734
- content: [
3735
- {
3736
- type: "text",
3737
- text: enriched2
3738
- }
3739
- ],
3740
- structuredContent: res
3741
- };
3742
- }
3743
- } catch {
3744
- }
3745
- }
3746
- const isListDir = [
3747
- "list_dir",
3748
- "listDir",
3749
- "read_dir",
3750
- "readDir",
3751
- "ls",
3752
- "dir"
3753
- ].includes(requestedTool);
3754
- if (isListDir) {
3755
- try {
3756
- const dummyTools = getDummyHealingTools({ db, teamDb: teamDb ?? void 0, vectorManager: vectorManager ?? void 0, teamVectorManager: teamVectorManager ?? void 0, github: github ?? void 0, config: customToolHandlerConfig });
3757
- const dirTool = dummyTools.find((t) => t.name === "list_dir");
3758
- if (dirTool) {
3759
- const res = await Promise.resolve(dirTool.handler(toolArgs));
3760
- const enriched2 = JSON.stringify(res, null, 2);
3761
- return {
3762
- content: [
3763
- {
3764
- type: "text",
3765
- text: enriched2
3766
- }
3767
- ],
3768
- structuredContent: res
3769
- };
3770
- }
3771
- } catch {
3772
- }
3773
- }
3774
- }
3775
- let suggestion = `Tool '${requestedTool}' does not exist. Use tools/list to see available tools.`;
3776
- const isFilteredTool = Object.values(TOOL_GROUPS).flat().includes(requestedTool);
3777
- if (isFilteredTool) {
3778
- suggestion = `'${requestedTool}' is a valid tool but it is not currently exposed because of your active --tool-filter or codemode restrictions. If you are in Code Mode, invoke it via 'mj_execute_code' (e.g. 'await mj.core.${requestedTool}(...)').`;
3779
- } else if (matchingPrompt !== void 0) {
3780
- suggestion = `'${requestedTool}' is an MCP Prompt, not an MCP Tool. Please use the 'get_prompt' tool (or your native MCP Prompts integration) to evaluate it, then use 'create_entry' to save the result.`;
3781
- } else if (requestedTool.startsWith("mj_")) {
3782
- suggestion = `'${requestedTool}' is not a valid root tool. If you are trying to use Code Mode, you must invoke the 'mj_execute_code' tool and write javascript (e.g. 'await mj.core.searchEntries(...)').`;
3783
- }
3784
- const errorResult = {
3785
- success: false,
3786
- error: `MCP error -32602: Tool ${requestedTool} not found`,
3787
- code: "TOOL_NOT_FOUND",
3788
- category: "hallucination",
3789
- suggestion,
3790
- recoverable: false
3791
- };
3792
- if (healingEnabled) {
3793
- logAgentIssue({
3794
- source: "MCP",
3795
- action: requestedTool,
3796
- input: toolArgs,
3797
- error: errorResult.error
3798
- });
3799
- }
3800
- const enriched = JSON.stringify({
3801
- ...errorResult,
3802
- _meta: { tokenEstimate: 0 }
3803
- });
3804
- const tokenEstimate = Math.ceil(Buffer.byteLength(enriched, "utf8") / 4);
3805
- const finalText = enriched.replace('"tokenEstimate":0', `"tokenEstimate":${tokenEstimate}`);
3806
- return {
3807
- content: [
3808
- {
3809
- type: "text",
3810
- text: finalText
3811
- }
3812
- ],
3813
- structuredContent: errorResult,
3814
- isError: true
3815
- };
3816
- }
3817
- const result = await originalHandler(request2, extra);
3818
- if (result !== null && result !== void 0 && typeof result === "object" && "isError" in result && result.isError === true) {
3819
- const resObj = result;
3820
- if (Array.isArray(resObj.content) && resObj.content.length > 0) {
3821
- const text = resObj.content[0]?.text;
3822
- if (typeof text === "string" && text.includes("MCP error -32602")) {
3823
- let errorMessage = text.replace(
3824
- "MCP error -32602: Input validation error: ",
3825
- ""
3826
- );
3827
- try {
3828
- const parts = text.split(": [");
3829
- if (parts.length > 1) {
3830
- const zodErrors = JSON.parse("[" + parts[1]);
3831
- const formattedErrors = zodErrors.map((e) => {
3832
- const path2 = e.path && e.path.length > 0 ? e.path.join(".") : "unknown";
3833
- return `${path2}: ${e.message || "invalid"}`;
3834
- }).join("; ");
3835
- errorMessage = formattedErrors;
3836
- }
3837
- } catch {
3838
- }
3839
- const errorResult = {
3840
- success: false,
3841
- error: errorMessage,
3842
- code: "VALIDATION_ERROR",
3843
- category: "validation",
3844
- suggestion: "Check input parameters against the tool schema",
3845
- recoverable: false
3846
- };
3847
- logAgentIssue({
3848
- source: "MCP",
3849
- action: req.params?.name ?? "unknown",
3850
- input: req.params?.arguments ?? {},
3851
- error: errorMessage
3852
- });
3853
- const enriched = JSON.stringify({
3854
- ...errorResult,
3855
- _meta: { tokenEstimate: 0 }
3856
- });
3857
- const tokenEstimate = Math.ceil(
3858
- Buffer.byteLength(enriched, "utf8") / 4
3859
- );
3860
- const finalText = enriched.replace(
3861
- '"tokenEstimate":0',
3862
- `"tokenEstimate":${tokenEstimate}`
3863
- );
3864
- return {
3865
- content: [
3866
- {
3867
- type: "text",
3868
- text: finalText
3869
- }
3870
- ],
3871
- structuredContent: errorResult
3872
- };
3873
- }
3874
- }
3875
- }
3876
- return result;
3877
- } catch (error) {
3878
- const err = error;
3879
- if (err?.code === -32602) {
3880
- let errorMessage = err.message || "Validation Error";
3881
- if (typeof errorMessage === "string" && errorMessage.includes("Invalid arguments for tool")) {
3882
- try {
3883
- const parts = errorMessage.split(": [");
3884
- if (parts.length > 1) {
3885
- const zodErrors = JSON.parse("[" + parts[1]);
3886
- const formattedErrors = zodErrors.map((e) => {
3887
- const path2 = e.path && e.path.length > 0 ? e.path.join(".") : "unknown";
3888
- return `${path2}: ${e.message || "invalid"}`;
3889
- }).join("; ");
3890
- errorMessage = formattedErrors;
3891
- }
3892
- } catch {
3893
- }
3894
- }
3895
- const errorResult = {
3896
- success: false,
3897
- error: errorMessage,
3898
- code: "VALIDATION_ERROR",
3899
- category: "validation",
3900
- suggestion: "Check input parameters against the tool schema",
3901
- recoverable: false
3902
- };
3903
- const fallbackReq = request2;
3904
- logAgentIssue({
3905
- source: "MCP",
3906
- action: fallbackReq?.params?.name ?? "unknown",
3907
- input: fallbackReq?.params?.arguments ?? {},
3908
- error: errorMessage
3909
- });
3910
- const enriched = JSON.stringify({
3911
- ...errorResult,
3912
- _meta: { tokenEstimate: 0 }
3913
- });
3914
- const tokenEstimate = Math.ceil(Buffer.byteLength(enriched, "utf8") / 4);
3915
- const finalText = enriched.replace(
3916
- '"tokenEstimate":0',
3917
- `"tokenEstimate":${tokenEstimate}`
3918
- );
3919
- return {
3920
- content: [
3921
- {
3922
- type: "text",
3923
- text: finalText
3924
- }
3925
- ],
3926
- structuredContent: errorResult,
3927
- isError: true
3928
- };
3929
- }
3930
- throw error;
3931
- }
3932
- });
3933
- }
3538
+ attachListToolsInterceptor(requestHandlers, configManager, allToolNames);
3539
+ attachCallToolInterceptor(
3540
+ requestHandlers,
3541
+ context,
3542
+ options,
3543
+ prompts,
3544
+ allTools,
3545
+ allToolNames,
3546
+ customToolHandlerConfig
3547
+ );
3934
3548
  return server;
3935
3549
  }
3936
- function startMetricsServer(runtime) {
3550
+ function startMetricsServer(runtime, metricsPort) {
3937
3551
  const portStr = process.env["MJ_METRICS_PORT"];
3938
- const port = portStr ? parseInt(portStr, 10) : 9465;
3552
+ const port = metricsPort ?? (portStr !== void 0 && portStr !== "" ? parseInt(portStr, 10) : 9465);
3939
3553
  const server = http.createServer((req, res) => {
3940
3554
  if (req.url === "/metrics" && req.method === "GET") {
3941
3555
  try {
@@ -3963,8 +3577,10 @@ function startMetricsServer(runtime) {
3963
3577
  logger.error("Metrics server error", { error: error instanceof Error ? error.message : String(error), module: "MetricsServer" });
3964
3578
  }
3965
3579
  });
3966
- server.listen(port, "0.0.0.0", () => {
3967
- logger.info(`Standalone metrics server listening on port ${port}`, { module: "MetricsServer" });
3580
+ const rawHost = process.env["MJ_METRICS_HOST"]?.trim();
3581
+ const host = rawHost !== void 0 && rawHost !== "" ? rawHost : "127.0.0.1";
3582
+ server.listen(port, host, () => {
3583
+ logger.info(`Standalone metrics server listening on ${host}:${port}`, { module: "MetricsServer" });
3968
3584
  });
3969
3585
  return () => {
3970
3586
  return new Promise((resolve, reject) => {
@@ -4002,7 +3618,11 @@ async function createServer2(options) {
4002
3618
  teamDefaultRole: options.teamDefaultRole,
4003
3619
  teamAdmin: options.teamAdmin,
4004
3620
  runtime,
4005
- subscriptionManager: globalSubscriptionManager
3621
+ subscriptionManager: globalSubscriptionManager,
3622
+ archiveOlderThanDays: options.archiveOlderThanDays,
3623
+ pruneOlderThanDays: options.pruneOlderThanDays,
3624
+ hardDeleteOlderThanDays: options.hardDeleteOlderThanDays,
3625
+ pruneImportanceThreshold: options.pruneImportanceThreshold
4006
3626
  };
4007
3627
  const dispatch = (name, args) => callTool(
4008
3628
  name,
@@ -4031,7 +3651,11 @@ async function createServer2(options) {
4031
3651
  }
4032
3652
  const resources = getResources();
4033
3653
  const prompts = getPrompts();
4034
- configManager.on("changed", () => {
3654
+ configManager.on("changed", (newConfig) => {
3655
+ baseConfig.filterConfig = newConfig.toolFilterConfig;
3656
+ baseConfig.briefingConfig = newConfig.briefingConfig;
3657
+ customToolHandlerConfig.filterConfig = newConfig.toolFilterConfig;
3658
+ customToolHandlerConfig.briefingConfig = newConfig.briefingConfig;
4035
3659
  void globalSubscriptionManager.notifyResourceUpdated("memory://briefing");
4036
3660
  try {
4037
3661
  void globalSubscriptionManager.broadcastNotification("notifications/tools/list_changed");
@@ -4054,7 +3678,7 @@ async function createServer2(options) {
4054
3678
  );
4055
3679
  let shutdownMetrics;
4056
3680
  if (options.metricsExport === "prometheus") {
4057
- shutdownMetrics = startMetricsServer(runtime);
3681
+ shutdownMetrics = startMetricsServer(runtime, options.metricsPort);
4058
3682
  }
4059
3683
  if (transport === "stdio") {
4060
3684
  const stdioTransport = new StdioServerTransport();
@@ -4139,4 +3763,4 @@ async function createServer2(options) {
4139
3763
  }
4140
3764
  }
4141
3765
 
4142
- export { VectorSearchManager, createServer2 as createServer, globalSubscriptionManager, initializeDependencies };
3766
+ export { VectorSearchManager, createServer2 as createServer, initializeDependencies };