@happyvertical/smrt-core 0.30.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 (631) hide show
  1. package/AGENTS.md +124 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +265 -0
  5. package/bin/smrt-prebuild.js +26 -0
  6. package/dist/__tests__/fixtures/advisor-test-classes.d.ts +28 -0
  7. package/dist/__tests__/fixtures/advisor-test-classes.d.ts.map +1 -0
  8. package/dist/__tests__/fixtures/collection-coverage-fixtures.d.ts +12 -0
  9. package/dist/__tests__/fixtures/collection-coverage-fixtures.d.ts.map +1 -0
  10. package/dist/__tests__/fixtures/inheritance-resolver-fixtures.d.ts +28 -0
  11. package/dist/__tests__/fixtures/inheritance-resolver-fixtures.d.ts.map +1 -0
  12. package/dist/__tests__/fixtures/inheritance-test-classes.d.ts +43 -0
  13. package/dist/__tests__/fixtures/inheritance-test-classes.d.ts.map +1 -0
  14. package/dist/__tests__/fixtures/mcp-integration-test-classes.d.ts +18 -0
  15. package/dist/__tests__/fixtures/mcp-integration-test-classes.d.ts.map +1 -0
  16. package/dist/__tests__/fixtures/object-ai-memory-fixtures.d.ts +15 -0
  17. package/dist/__tests__/fixtures/object-ai-memory-fixtures.d.ts.map +1 -0
  18. package/dist/__tests__/fixtures/object-spec-test-classes.d.ts +13 -0
  19. package/dist/__tests__/fixtures/object-spec-test-classes.d.ts.map +1 -0
  20. package/dist/__tests__/fixtures/registry-test-classes.d.ts +23 -0
  21. package/dist/__tests__/fixtures/registry-test-classes.d.ts.map +1 -0
  22. package/dist/adapters/ai-usage.d.ts +23 -0
  23. package/dist/adapters/ai-usage.d.ts.map +1 -0
  24. package/dist/adapters/ai-usage.js +105 -0
  25. package/dist/adapters/ai-usage.js.map +1 -0
  26. package/dist/adapters/cost-rates.d.ts +20 -0
  27. package/dist/adapters/cost-rates.d.ts.map +1 -0
  28. package/dist/adapters/cost-rates.js +40 -0
  29. package/dist/adapters/cost-rates.js.map +1 -0
  30. package/dist/adapters/index.d.ts +19 -0
  31. package/dist/adapters/index.d.ts.map +1 -0
  32. package/dist/adapters/metrics.d.ts +111 -0
  33. package/dist/adapters/metrics.d.ts.map +1 -0
  34. package/dist/adapters/metrics.js +169 -0
  35. package/dist/adapters/metrics.js.map +1 -0
  36. package/dist/adapters/pubsub.d.ts +124 -0
  37. package/dist/adapters/pubsub.d.ts.map +1 -0
  38. package/dist/adapters/pubsub.js +121 -0
  39. package/dist/adapters/pubsub.js.map +1 -0
  40. package/dist/browser.d.ts +32 -0
  41. package/dist/browser.d.ts.map +1 -0
  42. package/dist/browser.js +68 -0
  43. package/dist/browser.js.map +1 -0
  44. package/dist/child-accessors.d.ts +27 -0
  45. package/dist/child-accessors.d.ts.map +1 -0
  46. package/dist/child-accessors.js +35 -0
  47. package/dist/child-accessors.js.map +1 -0
  48. package/dist/class.d.ts +313 -0
  49. package/dist/class.d.ts.map +1 -0
  50. package/dist/class.js +896 -0
  51. package/dist/class.js.map +1 -0
  52. package/dist/collection-cache.d.ts +110 -0
  53. package/dist/collection-cache.d.ts.map +1 -0
  54. package/dist/collection-cache.js +187 -0
  55. package/dist/collection-cache.js.map +1 -0
  56. package/dist/collection.d.ts +894 -0
  57. package/dist/collection.d.ts.map +1 -0
  58. package/dist/collection.js +1987 -0
  59. package/dist/collection.js.map +1 -0
  60. package/dist/config/global-config.d.ts +3 -0
  61. package/dist/config/global-config.d.ts.map +1 -0
  62. package/dist/config/global-config.js +19 -0
  63. package/dist/config/global-config.js.map +1 -0
  64. package/dist/config.d.ts +145 -0
  65. package/dist/config.d.ts.map +1 -0
  66. package/dist/config.js +57 -0
  67. package/dist/config.js.map +1 -0
  68. package/dist/consumer-plugin/index.d.ts +22 -0
  69. package/dist/consumer-plugin/index.d.ts.map +1 -0
  70. package/dist/consumer-plugin/index.js +452 -0
  71. package/dist/consumer-plugin/index.js.map +1 -0
  72. package/dist/consumer-plugin.d.ts +8 -0
  73. package/dist/consumer-plugin.d.ts.map +1 -0
  74. package/dist/consumer-plugin.js +5 -0
  75. package/dist/consumer-plugin.js.map +1 -0
  76. package/dist/database.d.ts +95 -0
  77. package/dist/database.d.ts.map +1 -0
  78. package/dist/database.js +32 -0
  79. package/dist/database.js.map +1 -0
  80. package/dist/decorators/compatibility.d.ts +14 -0
  81. package/dist/decorators/compatibility.d.ts.map +1 -0
  82. package/dist/decorators/compatibility.js +111 -0
  83. package/dist/decorators/compatibility.js.map +1 -0
  84. package/dist/decorators/index.d.ts +381 -0
  85. package/dist/decorators/index.d.ts.map +1 -0
  86. package/dist/decorators/index.js +104 -0
  87. package/dist/decorators/index.js.map +1 -0
  88. package/dist/dispatch/bus.d.ts +306 -0
  89. package/dist/dispatch/bus.d.ts.map +1 -0
  90. package/dist/dispatch/bus.js +583 -0
  91. package/dist/dispatch/bus.js.map +1 -0
  92. package/dist/dispatch/collections/DispatchSubscriptions.d.ts +79 -0
  93. package/dist/dispatch/collections/DispatchSubscriptions.d.ts.map +1 -0
  94. package/dist/dispatch/collections/DispatchSubscriptions.js +243 -0
  95. package/dist/dispatch/collections/DispatchSubscriptions.js.map +1 -0
  96. package/dist/dispatch/collections/Dispatches.d.ts +98 -0
  97. package/dist/dispatch/collections/Dispatches.d.ts.map +1 -0
  98. package/dist/dispatch/collections/Dispatches.js +358 -0
  99. package/dist/dispatch/collections/Dispatches.js.map +1 -0
  100. package/dist/dispatch/index.d.ts +47 -0
  101. package/dist/dispatch/index.d.ts.map +1 -0
  102. package/dist/dispatch/models/Dispatch.d.ts +101 -0
  103. package/dist/dispatch/models/Dispatch.d.ts.map +1 -0
  104. package/dist/dispatch/models/Dispatch.js +162 -0
  105. package/dist/dispatch/models/Dispatch.js.map +1 -0
  106. package/dist/dispatch/models/DispatchSubscription.d.ts +83 -0
  107. package/dist/dispatch/models/DispatchSubscription.d.ts.map +1 -0
  108. package/dist/dispatch/models/DispatchSubscription.js +112 -0
  109. package/dist/dispatch/models/DispatchSubscription.js.map +1 -0
  110. package/dist/dispatch/tenant-resolver.d.ts +98 -0
  111. package/dist/dispatch/tenant-resolver.d.ts.map +1 -0
  112. package/dist/dispatch/tenant-resolver.js +32 -0
  113. package/dist/dispatch/tenant-resolver.js.map +1 -0
  114. package/dist/dispatch/types.d.ts +149 -0
  115. package/dist/dispatch/types.d.ts.map +1 -0
  116. package/dist/embeddings/hash.d.ts +33 -0
  117. package/dist/embeddings/hash.d.ts.map +1 -0
  118. package/dist/embeddings/hash.js +37 -0
  119. package/dist/embeddings/hash.js.map +1 -0
  120. package/dist/embeddings/index.d.ts +36 -0
  121. package/dist/embeddings/index.d.ts.map +1 -0
  122. package/dist/embeddings/provider.d.ts +75 -0
  123. package/dist/embeddings/provider.d.ts.map +1 -0
  124. package/dist/embeddings/provider.js +170 -0
  125. package/dist/embeddings/provider.js.map +1 -0
  126. package/dist/embeddings/similarity.d.ts +47 -0
  127. package/dist/embeddings/similarity.d.ts.map +1 -0
  128. package/dist/embeddings/similarity.js +64 -0
  129. package/dist/embeddings/similarity.js.map +1 -0
  130. package/dist/embeddings/storage.d.ts +125 -0
  131. package/dist/embeddings/storage.d.ts.map +1 -0
  132. package/dist/embeddings/storage.js +283 -0
  133. package/dist/embeddings/storage.js.map +1 -0
  134. package/dist/embeddings/types.d.ts +250 -0
  135. package/dist/embeddings/types.d.ts.map +1 -0
  136. package/dist/errors.d.ts +363 -0
  137. package/dist/errors.d.ts.map +1 -0
  138. package/dist/errors.js +669 -0
  139. package/dist/errors.js.map +1 -0
  140. package/dist/generators/cli.d.ts +162 -0
  141. package/dist/generators/cli.d.ts.map +1 -0
  142. package/dist/generators/cli.js +462 -0
  143. package/dist/generators/cli.js.map +1 -0
  144. package/dist/generators/index.d.ts +13 -0
  145. package/dist/generators/index.d.ts.map +1 -0
  146. package/dist/generators/mcp-runtime-template.d.ts +60 -0
  147. package/dist/generators/mcp-runtime-template.d.ts.map +1 -0
  148. package/dist/generators/mcp-runtime-template.js +509 -0
  149. package/dist/generators/mcp-runtime-template.js.map +1 -0
  150. package/dist/generators/mcp.d.ts +231 -0
  151. package/dist/generators/mcp.d.ts.map +1 -0
  152. package/dist/generators/mcp.js +1220 -0
  153. package/dist/generators/mcp.js.map +1 -0
  154. package/dist/generators/rest.d.ts +171 -0
  155. package/dist/generators/rest.d.ts.map +1 -0
  156. package/dist/generators/rest.js +591 -0
  157. package/dist/generators/rest.js.map +1 -0
  158. package/dist/generators/swagger.d.ts +21 -0
  159. package/dist/generators/swagger.d.ts.map +1 -0
  160. package/dist/generators/swagger.js +307 -0
  161. package/dist/generators/swagger.js.map +1 -0
  162. package/dist/generators/tenant-gate.d.ts +74 -0
  163. package/dist/generators/tenant-gate.d.ts.map +1 -0
  164. package/dist/generators/tenant-gate.js +15 -0
  165. package/dist/generators/tenant-gate.js.map +1 -0
  166. package/dist/generators.d.ts +8 -0
  167. package/dist/generators.d.ts.map +1 -0
  168. package/dist/generators.js +19 -0
  169. package/dist/generators.js.map +1 -0
  170. package/dist/hierarchical.d.ts +103 -0
  171. package/dist/hierarchical.d.ts.map +1 -0
  172. package/dist/hierarchical.js +184 -0
  173. package/dist/hierarchical.js.map +1 -0
  174. package/dist/index.d.ts +57 -0
  175. package/dist/index.d.ts.map +1 -0
  176. package/dist/index.js +202 -0
  177. package/dist/index.js.map +1 -0
  178. package/dist/interceptors.d.ts +251 -0
  179. package/dist/interceptors.d.ts.map +1 -0
  180. package/dist/interceptors.js +259 -0
  181. package/dist/interceptors.js.map +1 -0
  182. package/dist/junction.d.ts +99 -0
  183. package/dist/junction.d.ts.map +1 -0
  184. package/dist/junction.js +136 -0
  185. package/dist/junction.js.map +1 -0
  186. package/dist/knowledge.d.ts +11 -0
  187. package/dist/knowledge.d.ts.map +1 -0
  188. package/dist/knowledge.js +310 -0
  189. package/dist/knowledge.js.map +1 -0
  190. package/dist/lazy-config.d.ts +160 -0
  191. package/dist/lazy-config.d.ts.map +1 -0
  192. package/dist/lazy-config.js +146 -0
  193. package/dist/lazy-config.js.map +1 -0
  194. package/dist/manifest/discover-base-classes.d.ts +78 -0
  195. package/dist/manifest/discover-base-classes.d.ts.map +1 -0
  196. package/dist/manifest/discover-base-classes.js +85 -0
  197. package/dist/manifest/discover-base-classes.js.map +1 -0
  198. package/dist/manifest/discover-smrt-packages.d.ts +48 -0
  199. package/dist/manifest/discover-smrt-packages.d.ts.map +1 -0
  200. package/dist/manifest/discover-smrt-packages.js +361 -0
  201. package/dist/manifest/discover-smrt-packages.js.map +1 -0
  202. package/dist/manifest/generator.d.ts +93 -0
  203. package/dist/manifest/generator.d.ts.map +1 -0
  204. package/dist/manifest/generator.js +380 -0
  205. package/dist/manifest/generator.js.map +1 -0
  206. package/dist/manifest/index.d.ts +16 -0
  207. package/dist/manifest/index.d.ts.map +1 -0
  208. package/dist/manifest/index.js +51 -0
  209. package/dist/manifest/index.js.map +1 -0
  210. package/dist/manifest/manager.d.ts +51 -0
  211. package/dist/manifest/manager.d.ts.map +1 -0
  212. package/dist/manifest/manager.js +89 -0
  213. package/dist/manifest/manager.js.map +1 -0
  214. package/dist/manifest/manifest-loader.d.ts +187 -0
  215. package/dist/manifest/manifest-loader.d.ts.map +1 -0
  216. package/dist/manifest/manifest-loader.js +847 -0
  217. package/dist/manifest/manifest-loader.js.map +1 -0
  218. package/dist/manifest/sources/composite.d.ts +22 -0
  219. package/dist/manifest/sources/composite.d.ts.map +1 -0
  220. package/dist/manifest/sources/composite.js +60 -0
  221. package/dist/manifest/sources/composite.js.map +1 -0
  222. package/dist/manifest/sources/embedded.d.ts +7 -0
  223. package/dist/manifest/sources/embedded.d.ts.map +1 -0
  224. package/dist/manifest/sources/embedded.js +30 -0
  225. package/dist/manifest/sources/embedded.js.map +1 -0
  226. package/dist/manifest/sources/explicit-paths.d.ts +17 -0
  227. package/dist/manifest/sources/explicit-paths.d.ts.map +1 -0
  228. package/dist/manifest/sources/explicit-paths.js +35 -0
  229. package/dist/manifest/sources/explicit-paths.js.map +1 -0
  230. package/dist/manifest/sources/fallback.d.ts +25 -0
  231. package/dist/manifest/sources/fallback.d.ts.map +1 -0
  232. package/dist/manifest/sources/fallback.js +63 -0
  233. package/dist/manifest/sources/fallback.js.map +1 -0
  234. package/dist/manifest/sources/index.d.ts +17 -0
  235. package/dist/manifest/sources/index.d.ts.map +1 -0
  236. package/dist/manifest/sources/local-test.d.ts +7 -0
  237. package/dist/manifest/sources/local-test.d.ts.map +1 -0
  238. package/dist/manifest/sources/local-test.js +21 -0
  239. package/dist/manifest/sources/local-test.js.map +1 -0
  240. package/dist/manifest/sources/static.d.ts +7 -0
  241. package/dist/manifest/sources/static.d.ts.map +1 -0
  242. package/dist/manifest/sources/static.js +19 -0
  243. package/dist/manifest/sources/static.js.map +1 -0
  244. package/dist/manifest/sources/test.d.ts +7 -0
  245. package/dist/manifest/sources/test.d.ts.map +1 -0
  246. package/dist/manifest/sources/test.js +21 -0
  247. package/dist/manifest/sources/test.js.map +1 -0
  248. package/dist/manifest/sources/types.d.ts +79 -0
  249. package/dist/manifest/sources/types.d.ts.map +1 -0
  250. package/dist/manifest/sources/types.js +61 -0
  251. package/dist/manifest/sources/types.js.map +1 -0
  252. package/dist/manifest/static-manifest.d.ts +4 -0
  253. package/dist/manifest/static-manifest.d.ts.map +1 -0
  254. package/dist/manifest/static-manifest.js +1535 -0
  255. package/dist/manifest/static-manifest.js.map +1 -0
  256. package/dist/manifest/store.d.ts +111 -0
  257. package/dist/manifest/store.d.ts.map +1 -0
  258. package/dist/manifest/store.js +431 -0
  259. package/dist/manifest/store.js.map +1 -0
  260. package/dist/manifest/test-manifest-loader.d.ts +3 -0
  261. package/dist/manifest/test-manifest-loader.d.ts.map +1 -0
  262. package/dist/manifest/test-manifest-stub.d.ts +4 -0
  263. package/dist/manifest/test-manifest-stub.d.ts.map +1 -0
  264. package/dist/manifest/test-manifest-stub.js +80013 -0
  265. package/dist/manifest/test-manifest-stub.js.map +1 -0
  266. package/dist/manifest.d.ts +8 -0
  267. package/dist/manifest.d.ts.map +1 -0
  268. package/dist/manifest.js +20 -0
  269. package/dist/manifest.js.map +1 -0
  270. package/dist/manifest.json +1489 -0
  271. package/dist/mcp-advisor/index.d.ts +499 -0
  272. package/dist/mcp-advisor/index.d.ts.map +1 -0
  273. package/dist/mcp-advisor/tools/add-ai-methods.d.ts +6 -0
  274. package/dist/mcp-advisor/tools/add-ai-methods.d.ts.map +1 -0
  275. package/dist/mcp-advisor/tools/configure-decorators.d.ts +6 -0
  276. package/dist/mcp-advisor/tools/configure-decorators.d.ts.map +1 -0
  277. package/dist/mcp-advisor/tools/generate-collection.d.ts +6 -0
  278. package/dist/mcp-advisor/tools/generate-collection.d.ts.map +1 -0
  279. package/dist/mcp-advisor/tools/generate-field-definitions.d.ts +6 -0
  280. package/dist/mcp-advisor/tools/generate-field-definitions.d.ts.map +1 -0
  281. package/dist/mcp-advisor/tools/generate-smrt-class.d.ts +6 -0
  282. package/dist/mcp-advisor/tools/generate-smrt-class.d.ts.map +1 -0
  283. package/dist/mcp-advisor/tools/get-object-config.d.ts +6 -0
  284. package/dist/mcp-advisor/tools/get-object-config.d.ts.map +1 -0
  285. package/dist/mcp-advisor/tools/get-object-schema.d.ts +10 -0
  286. package/dist/mcp-advisor/tools/get-object-schema.d.ts.map +1 -0
  287. package/dist/mcp-advisor/tools/list-registered-objects.d.ts +9 -0
  288. package/dist/mcp-advisor/tools/list-registered-objects.d.ts.map +1 -0
  289. package/dist/mcp-advisor/tools/preview-api-endpoints.d.ts +9 -0
  290. package/dist/mcp-advisor/tools/preview-api-endpoints.d.ts.map +1 -0
  291. package/dist/mcp-advisor/tools/preview-mcp-tools.d.ts +9 -0
  292. package/dist/mcp-advisor/tools/preview-mcp-tools.d.ts.map +1 -0
  293. package/dist/mcp-advisor/tools/validate-smrt-object.d.ts +6 -0
  294. package/dist/mcp-advisor/tools/validate-smrt-object.d.ts.map +1 -0
  295. package/dist/mcp-advisor/types.d.ts +209 -0
  296. package/dist/mcp-advisor/types.d.ts.map +1 -0
  297. package/dist/migrations/backfill-tracker.d.ts +84 -0
  298. package/dist/migrations/backfill-tracker.d.ts.map +1 -0
  299. package/dist/migrations/backfill-tracker.js +118 -0
  300. package/dist/migrations/backfill-tracker.js.map +1 -0
  301. package/dist/migrations/checksum.d.ts +43 -0
  302. package/dist/migrations/checksum.d.ts.map +1 -0
  303. package/dist/migrations/checksum.js +32 -0
  304. package/dist/migrations/checksum.js.map +1 -0
  305. package/dist/migrations/differ.d.ts +186 -0
  306. package/dist/migrations/differ.d.ts.map +1 -0
  307. package/dist/migrations/differ.js +601 -0
  308. package/dist/migrations/differ.js.map +1 -0
  309. package/dist/migrations/generator.d.ts +133 -0
  310. package/dist/migrations/generator.d.ts.map +1 -0
  311. package/dist/migrations/generator.js +328 -0
  312. package/dist/migrations/generator.js.map +1 -0
  313. package/dist/migrations/index.d.ts +20 -0
  314. package/dist/migrations/index.d.ts.map +1 -0
  315. package/dist/migrations/orchestrate.d.ts +148 -0
  316. package/dist/migrations/orchestrate.d.ts.map +1 -0
  317. package/dist/migrations/orchestrate.js +118 -0
  318. package/dist/migrations/orchestrate.js.map +1 -0
  319. package/dist/migrations/tracker.d.ts +134 -0
  320. package/dist/migrations/tracker.d.ts.map +1 -0
  321. package/dist/migrations/tracker.js +624 -0
  322. package/dist/migrations/tracker.js.map +1 -0
  323. package/dist/migrations/types.d.ts +221 -0
  324. package/dist/migrations/types.d.ts.map +1 -0
  325. package/dist/migrations.d.ts +7 -0
  326. package/dist/migrations.d.ts.map +1 -0
  327. package/dist/migrations.js +26 -0
  328. package/dist/migrations.js.map +1 -0
  329. package/dist/node_modules/.pnpm/balanced-match@4.0.4/node_modules/balanced-match/dist/esm/index.js +56 -0
  330. package/dist/node_modules/.pnpm/balanced-match@4.0.4/node_modules/balanced-match/dist/esm/index.js.map +1 -0
  331. package/dist/node_modules/.pnpm/brace-expansion@5.0.5/node_modules/brace-expansion/dist/esm/index.js +163 -0
  332. package/dist/node_modules/.pnpm/brace-expansion@5.0.5/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
  333. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/assert-valid-pattern.js +13 -0
  334. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -0
  335. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js +654 -0
  336. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js.map +1 -0
  337. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/brace-expressions.js +111 -0
  338. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -0
  339. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/escape.js +10 -0
  340. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/escape.js.map +1 -0
  341. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js +824 -0
  342. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js.map +1 -0
  343. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js +10 -0
  344. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js.map +1 -0
  345. package/dist/object.d.ts +1202 -0
  346. package/dist/object.d.ts.map +1 -0
  347. package/dist/object.js +2731 -0
  348. package/dist/object.js.map +1 -0
  349. package/dist/polymorphic-association.d.ts +69 -0
  350. package/dist/polymorphic-association.d.ts.map +1 -0
  351. package/dist/polymorphic-association.js +96 -0
  352. package/dist/polymorphic-association.js.map +1 -0
  353. package/dist/prebuild/cli.d.ts +7 -0
  354. package/dist/prebuild/cli.d.ts.map +1 -0
  355. package/dist/prebuild/cli.js +29 -0
  356. package/dist/prebuild/cli.js.map +1 -0
  357. package/dist/prebuild/index.d.ts +22 -0
  358. package/dist/prebuild/index.d.ts.map +1 -0
  359. package/dist/prebuild/index.js +239 -0
  360. package/dist/prebuild/index.js.map +1 -0
  361. package/dist/prebuild.d.ts +8 -0
  362. package/dist/prebuild.d.ts.map +1 -0
  363. package/dist/prebuild.js +6 -0
  364. package/dist/prebuild.js.map +1 -0
  365. package/dist/registry/cache-config.d.ts +13 -0
  366. package/dist/registry/cache-config.d.ts.map +1 -0
  367. package/dist/registry/cache-config.js +17 -0
  368. package/dist/registry/cache-config.js.map +1 -0
  369. package/dist/registry/class-registration.d.ts +31 -0
  370. package/dist/registry/class-registration.d.ts.map +1 -0
  371. package/dist/registry/class-registration.js +1074 -0
  372. package/dist/registry/class-registration.js.map +1 -0
  373. package/dist/registry/collection-resolution.d.ts +45 -0
  374. package/dist/registry/collection-resolution.d.ts.map +1 -0
  375. package/dist/registry/collection-resolution.js +121 -0
  376. package/dist/registry/collection-resolution.js.map +1 -0
  377. package/dist/registry/collision-policy.d.ts +179 -0
  378. package/dist/registry/collision-policy.d.ts.map +1 -0
  379. package/dist/registry/collision-policy.js +153 -0
  380. package/dist/registry/collision-policy.js.map +1 -0
  381. package/dist/registry/diagnostics.d.ts +58 -0
  382. package/dist/registry/diagnostics.d.ts.map +1 -0
  383. package/dist/registry/diagnostics.js +54 -0
  384. package/dist/registry/diagnostics.js.map +1 -0
  385. package/dist/registry/embedding-manager.d.ts +23 -0
  386. package/dist/registry/embedding-manager.d.ts.map +1 -0
  387. package/dist/registry/embedding-manager.js +62 -0
  388. package/dist/registry/embedding-manager.js.map +1 -0
  389. package/dist/registry/index.d.ts +13 -0
  390. package/dist/registry/index.d.ts.map +1 -0
  391. package/dist/registry/inheritance-resolver.d.ts +13 -0
  392. package/dist/registry/inheritance-resolver.d.ts.map +1 -0
  393. package/dist/registry/inheritance-resolver.js +244 -0
  394. package/dist/registry/inheritance-resolver.js.map +1 -0
  395. package/dist/registry/manifest-field-merge.d.ts +4 -0
  396. package/dist/registry/manifest-field-merge.d.ts.map +1 -0
  397. package/dist/registry/manifest-field-merge.js +82 -0
  398. package/dist/registry/manifest-field-merge.js.map +1 -0
  399. package/dist/registry/name-resolver.d.ts +102 -0
  400. package/dist/registry/name-resolver.d.ts.map +1 -0
  401. package/dist/registry/name-resolver.js +241 -0
  402. package/dist/registry/name-resolver.js.map +1 -0
  403. package/dist/registry/relationship-graph.d.ts +16 -0
  404. package/dist/registry/relationship-graph.d.ts.map +1 -0
  405. package/dist/registry/relationship-graph.js +79 -0
  406. package/dist/registry/relationship-graph.js.map +1 -0
  407. package/dist/registry/schema-builder.d.ts +113 -0
  408. package/dist/registry/schema-builder.d.ts.map +1 -0
  409. package/dist/registry/schema-builder.js +474 -0
  410. package/dist/registry/schema-builder.js.map +1 -0
  411. package/dist/registry/shared-state.d.ts +62 -0
  412. package/dist/registry/shared-state.d.ts.map +1 -0
  413. package/dist/registry/shared-state.js +135 -0
  414. package/dist/registry/shared-state.js.map +1 -0
  415. package/dist/registry/types.d.ts +667 -0
  416. package/dist/registry/types.d.ts.map +1 -0
  417. package/dist/registry/validator.d.ts +13 -0
  418. package/dist/registry/validator.d.ts.map +1 -0
  419. package/dist/registry/validator.js +138 -0
  420. package/dist/registry/validator.js.map +1 -0
  421. package/dist/registry.d.ts +1358 -0
  422. package/dist/registry.d.ts.map +1 -0
  423. package/dist/registry.js +2301 -0
  424. package/dist/registry.js.map +1 -0
  425. package/dist/runtime/client.d.ts +34 -0
  426. package/dist/runtime/client.d.ts.map +1 -0
  427. package/dist/runtime/client.js +104 -0
  428. package/dist/runtime/client.js.map +1 -0
  429. package/dist/runtime/index.d.ts +10 -0
  430. package/dist/runtime/index.d.ts.map +1 -0
  431. package/dist/runtime/mcp.d.ts +47 -0
  432. package/dist/runtime/mcp.d.ts.map +1 -0
  433. package/dist/runtime/mcp.js +72 -0
  434. package/dist/runtime/mcp.js.map +1 -0
  435. package/dist/runtime/server.d.ts +92 -0
  436. package/dist/runtime/server.d.ts.map +1 -0
  437. package/dist/runtime/server.js +390 -0
  438. package/dist/runtime/server.js.map +1 -0
  439. package/dist/runtime/types.d.ts +58 -0
  440. package/dist/runtime/types.d.ts.map +1 -0
  441. package/dist/runtime.d.ts +8 -0
  442. package/dist/runtime.d.ts.map +1 -0
  443. package/dist/runtime.js +10 -0
  444. package/dist/runtime.js.map +1 -0
  445. package/dist/scanner/import-scanner.d.ts +7 -0
  446. package/dist/scanner/import-scanner.d.ts.map +1 -0
  447. package/dist/scanner/index.d.ts +12 -0
  448. package/dist/scanner/index.d.ts.map +1 -0
  449. package/dist/scanner/manifest-generator.d.ts +304 -0
  450. package/dist/scanner/manifest-generator.d.ts.map +1 -0
  451. package/dist/scanner/manifest-generator.js +1707 -0
  452. package/dist/scanner/manifest-generator.js.map +1 -0
  453. package/dist/scanner/test-file-patterns.d.ts +18 -0
  454. package/dist/scanner/test-file-patterns.d.ts.map +1 -0
  455. package/dist/scanner/test-file-patterns.js +16 -0
  456. package/dist/scanner/test-file-patterns.js.map +1 -0
  457. package/dist/scanner/types.d.ts +313 -0
  458. package/dist/scanner/types.d.ts.map +1 -0
  459. package/dist/scanner/types.js +2 -0
  460. package/dist/scanner/types.js.map +1 -0
  461. package/dist/scanner.d.ts +6 -0
  462. package/dist/scanner.d.ts.map +1 -0
  463. package/dist/scanner.js +6 -0
  464. package/dist/scanner.js.map +1 -0
  465. package/dist/schema/code-generator.d.ts +53 -0
  466. package/dist/schema/code-generator.d.ts.map +1 -0
  467. package/dist/schema/ddl/base-strategy.d.ts +80 -0
  468. package/dist/schema/ddl/base-strategy.d.ts.map +1 -0
  469. package/dist/schema/ddl/base-strategy.js +240 -0
  470. package/dist/schema/ddl/base-strategy.js.map +1 -0
  471. package/dist/schema/ddl/duckdb-strategy.d.ts +33 -0
  472. package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -0
  473. package/dist/schema/ddl/duckdb-strategy.js +74 -0
  474. package/dist/schema/ddl/duckdb-strategy.js.map +1 -0
  475. package/dist/schema/ddl/index.d.ts +53 -0
  476. package/dist/schema/ddl/index.d.ts.map +1 -0
  477. package/dist/schema/ddl/index.js +80 -0
  478. package/dist/schema/ddl/index.js.map +1 -0
  479. package/dist/schema/ddl/json-duckdb-strategy.d.ts +8 -0
  480. package/dist/schema/ddl/json-duckdb-strategy.d.ts.map +1 -0
  481. package/dist/schema/ddl/json-duckdb-strategy.js +14 -0
  482. package/dist/schema/ddl/json-duckdb-strategy.js.map +1 -0
  483. package/dist/schema/ddl/postgres-strategy.d.ts +29 -0
  484. package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -0
  485. package/dist/schema/ddl/postgres-strategy.js +102 -0
  486. package/dist/schema/ddl/postgres-strategy.js.map +1 -0
  487. package/dist/schema/ddl/sqlite-strategy.d.ts +38 -0
  488. package/dist/schema/ddl/sqlite-strategy.d.ts.map +1 -0
  489. package/dist/schema/ddl/sqlite-strategy.js +74 -0
  490. package/dist/schema/ddl/sqlite-strategy.js.map +1 -0
  491. package/dist/schema/ddl/types.d.ts +114 -0
  492. package/dist/schema/ddl/types.d.ts.map +1 -0
  493. package/dist/schema/generator.d.ts +176 -0
  494. package/dist/schema/generator.d.ts.map +1 -0
  495. package/dist/schema/generator.js +1076 -0
  496. package/dist/schema/generator.js.map +1 -0
  497. package/dist/schema/index-utils.d.ts +19 -0
  498. package/dist/schema/index-utils.d.ts.map +1 -0
  499. package/dist/schema/index-utils.js +32 -0
  500. package/dist/schema/index-utils.js.map +1 -0
  501. package/dist/schema/index.d.ts +13 -0
  502. package/dist/schema/index.d.ts.map +1 -0
  503. package/dist/schema/override-system.d.ts +43 -0
  504. package/dist/schema/override-system.d.ts.map +1 -0
  505. package/dist/schema/schema-aggregator.d.ts +112 -0
  506. package/dist/schema/schema-aggregator.d.ts.map +1 -0
  507. package/dist/schema/schema-manager.d.ts +95 -0
  508. package/dist/schema/schema-manager.d.ts.map +1 -0
  509. package/dist/schema/schema-manager.js +283 -0
  510. package/dist/schema/schema-manager.js.map +1 -0
  511. package/dist/schema/sql-identifiers.d.ts +107 -0
  512. package/dist/schema/sql-identifiers.d.ts.map +1 -0
  513. package/dist/schema/sql-identifiers.js +190 -0
  514. package/dist/schema/sql-identifiers.js.map +1 -0
  515. package/dist/schema/table-verifier.d.ts +10 -0
  516. package/dist/schema/table-verifier.d.ts.map +1 -0
  517. package/dist/schema/table-verifier.js +37 -0
  518. package/dist/schema/table-verifier.js.map +1 -0
  519. package/dist/schema/types.d.ts +241 -0
  520. package/dist/schema/types.d.ts.map +1 -0
  521. package/dist/schema/utils.d.ts +32 -0
  522. package/dist/schema/utils.d.ts.map +1 -0
  523. package/dist/schema/utils.js +134 -0
  524. package/dist/schema/utils.js.map +1 -0
  525. package/dist/scripts/create-wrappers.js +89 -0
  526. package/dist/scripts/generate-manifest.js +155 -0
  527. package/dist/scripts/generate-test-manifest.js +77 -0
  528. package/dist/scripts/migrate-datetime-to-timestamp.ts +310 -0
  529. package/dist/scripts/prepack.js +49 -0
  530. package/dist/signals/bus.d.ts +64 -0
  531. package/dist/signals/bus.d.ts.map +1 -0
  532. package/dist/signals/bus.js +102 -0
  533. package/dist/signals/bus.js.map +1 -0
  534. package/dist/signals/index.d.ts +11 -0
  535. package/dist/signals/index.d.ts.map +1 -0
  536. package/dist/signals/sanitizer.d.ts +54 -0
  537. package/dist/signals/sanitizer.d.ts.map +1 -0
  538. package/dist/signals/sanitizer.js +111 -0
  539. package/dist/signals/sanitizer.js.map +1 -0
  540. package/dist/smrt-knowledge.json +335 -0
  541. package/dist/system/compatibility.d.ts +8 -0
  542. package/dist/system/compatibility.d.ts.map +1 -0
  543. package/dist/system/compatibility.js +409 -0
  544. package/dist/system/compatibility.js.map +1 -0
  545. package/dist/system/index.d.ts +9 -0
  546. package/dist/system/index.d.ts.map +1 -0
  547. package/dist/system/schema.d.ts +69 -0
  548. package/dist/system/schema.d.ts.map +1 -0
  549. package/dist/system/schema.js +271 -0
  550. package/dist/system/schema.js.map +1 -0
  551. package/dist/system/types.d.ts +135 -0
  552. package/dist/system/types.d.ts.map +1 -0
  553. package/dist/system-fields.d.ts +44 -0
  554. package/dist/system-fields.d.ts.map +1 -0
  555. package/dist/system-fields.js +55 -0
  556. package/dist/system-fields.js.map +1 -0
  557. package/dist/table-cache.d.ts +28 -0
  558. package/dist/table-cache.d.ts.map +1 -0
  559. package/dist/table-cache.js +21 -0
  560. package/dist/table-cache.js.map +1 -0
  561. package/dist/test-utils.d.ts +140 -0
  562. package/dist/test-utils.d.ts.map +1 -0
  563. package/dist/testing/database.d.ts +73 -0
  564. package/dist/testing/database.d.ts.map +1 -0
  565. package/dist/testing/database.js +204 -0
  566. package/dist/testing/database.js.map +1 -0
  567. package/dist/testing/index.d.ts +21 -0
  568. package/dist/testing/index.d.ts.map +1 -0
  569. package/dist/testing.d.ts +6 -0
  570. package/dist/testing.d.ts.map +1 -0
  571. package/dist/testing.js +5 -0
  572. package/dist/testing.js.map +1 -0
  573. package/dist/tools/index.d.ts +8 -0
  574. package/dist/tools/index.d.ts.map +1 -0
  575. package/dist/tools/tool-executor.d.ts +101 -0
  576. package/dist/tools/tool-executor.d.ts.map +1 -0
  577. package/dist/tools/tool-executor.js +142 -0
  578. package/dist/tools/tool-executor.js.map +1 -0
  579. package/dist/tools/tool-generator.d.ts +54 -0
  580. package/dist/tools/tool-generator.d.ts.map +1 -0
  581. package/dist/tools/tool-generator.js +121 -0
  582. package/dist/tools/tool-generator.js.map +1 -0
  583. package/dist/utils/chunk.d.ts +32 -0
  584. package/dist/utils/chunk.d.ts.map +1 -0
  585. package/dist/utils/chunk.js +14 -0
  586. package/dist/utils/chunk.js.map +1 -0
  587. package/dist/utils/import-workspace-module.d.ts +8 -0
  588. package/dist/utils/import-workspace-module.d.ts.map +1 -0
  589. package/dist/utils/import-workspace-module.js +81 -0
  590. package/dist/utils/import-workspace-module.js.map +1 -0
  591. package/dist/utils/json.d.ts +102 -0
  592. package/dist/utils/json.d.ts.map +1 -0
  593. package/dist/utils/json.js +43 -0
  594. package/dist/utils/json.js.map +1 -0
  595. package/dist/utils/lru-cache.d.ts +69 -0
  596. package/dist/utils/lru-cache.d.ts.map +1 -0
  597. package/dist/utils/lru-cache.js +100 -0
  598. package/dist/utils/lru-cache.js.map +1 -0
  599. package/dist/utils/naming.d.ts +16 -0
  600. package/dist/utils/naming.d.ts.map +1 -0
  601. package/dist/utils/naming.js +23 -0
  602. package/dist/utils/naming.js.map +1 -0
  603. package/dist/utils/qualified-names.d.ts +122 -0
  604. package/dist/utils/qualified-names.d.ts.map +1 -0
  605. package/dist/utils/qualified-names.js +82 -0
  606. package/dist/utils/qualified-names.js.map +1 -0
  607. package/dist/utils/scanner-module.d.ts +37 -0
  608. package/dist/utils/scanner-module.d.ts.map +1 -0
  609. package/dist/utils.d.ts +177 -0
  610. package/dist/utils.d.ts.map +1 -0
  611. package/dist/utils.js +185 -0
  612. package/dist/utils.js.map +1 -0
  613. package/dist/vite-plugin/import-build-aware.d.ts +68 -0
  614. package/dist/vite-plugin/import-build-aware.d.ts.map +1 -0
  615. package/dist/vite-plugin/import-build-aware.js +72 -0
  616. package/dist/vite-plugin/import-build-aware.js.map +1 -0
  617. package/dist/vite-plugin/index.d.ts +59 -0
  618. package/dist/vite-plugin/index.d.ts.map +1 -0
  619. package/dist/vite-plugin/index.js +1400 -0
  620. package/dist/vite-plugin/index.js.map +1 -0
  621. package/dist/vite-plugin/sveltekit-generator.d.ts +66 -0
  622. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -0
  623. package/dist/vite-plugin/sveltekit-generator.js +1375 -0
  624. package/dist/vite-plugin/sveltekit-generator.js.map +1 -0
  625. package/dist/vite-plugin/templates/default-ui.ts +432 -0
  626. package/dist/vite-plugin/templates/default.html +206 -0
  627. package/dist/vite-plugin.d.ts +8 -0
  628. package/dist/vite-plugin.d.ts.map +1 -0
  629. package/dist/vite-plugin.js +11 -0
  630. package/dist/vite-plugin.js.map +1 -0
  631. package/package.json +208 -0
@@ -0,0 +1,1220 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { resolve, dirname } from "node:path";
3
+ import { SmrtCollection } from "../collection.js";
4
+ import { ObjectRegistry } from "../registry.js";
5
+ import { generateRuntimeBootstrap, generateClaudeConfig, generateMCPDocumentation, generateMCPScript } from "./mcp-runtime-template.js";
6
+ import { runWithTenantGate } from "./tenant-gate.js";
7
+ class MCPGenerator {
8
+ config;
9
+ context;
10
+ collections = /* @__PURE__ */ new Map();
11
+ constructor(config = {}, context = {}) {
12
+ this.config = {
13
+ name: "smrt-mcp-server",
14
+ version: "1.0.0",
15
+ description: "Auto-generated MCP server from smrt objects",
16
+ server: {
17
+ name: "smrt-mcp",
18
+ version: "1.0.0"
19
+ },
20
+ ...config
21
+ };
22
+ this.context = context;
23
+ }
24
+ /**
25
+ * Get server name
26
+ */
27
+ get name() {
28
+ return this.config.name;
29
+ }
30
+ /**
31
+ * Get server version
32
+ */
33
+ get version() {
34
+ return this.config.version;
35
+ }
36
+ /**
37
+ * Generate all available tools from registered objects
38
+ */
39
+ async generateTools() {
40
+ const tools = [];
41
+ const registeredClasses = ObjectRegistry.getAllClasses();
42
+ for (const [key, classInfo] of registeredClasses) {
43
+ const simpleName = classInfo.name || key;
44
+ const config = ObjectRegistry.getConfig(simpleName);
45
+ const mcpConfig = config.mcp;
46
+ if (mcpConfig === false) {
47
+ continue;
48
+ }
49
+ const excluded = typeof mcpConfig === "object" && mcpConfig?.exclude ? mcpConfig.exclude : [];
50
+ const included = typeof mcpConfig === "object" ? mcpConfig?.include : void 0;
51
+ const shouldInclude = (endpoint) => {
52
+ if (included && !included.includes(endpoint)) return false;
53
+ if (excluded.includes(endpoint)) return false;
54
+ return true;
55
+ };
56
+ const objectTools = await this.generateObjectTools(
57
+ simpleName,
58
+ shouldInclude
59
+ );
60
+ tools.push(...objectTools);
61
+ }
62
+ return tools;
63
+ }
64
+ /**
65
+ * Generate tools for a specific object
66
+ */
67
+ async generateObjectTools(objectName, shouldInclude) {
68
+ const tools = [];
69
+ const fields = ObjectRegistry.getFields(objectName);
70
+ const lowerName = objectName.toLowerCase();
71
+ const classInfo = ObjectRegistry.getClass(objectName);
72
+ if (shouldInclude("list")) {
73
+ tools.push({
74
+ name: `${lowerName}_list`,
75
+ description: `List ${objectName} objects with optional filtering`,
76
+ inputSchema: {
77
+ type: "object",
78
+ properties: {
79
+ limit: {
80
+ type: "integer",
81
+ description: "Maximum number of items to return",
82
+ default: 50,
83
+ minimum: 1,
84
+ maximum: 1e3
85
+ },
86
+ offset: {
87
+ type: "integer",
88
+ description: "Number of items to skip",
89
+ default: 0,
90
+ minimum: 0
91
+ },
92
+ orderBy: {
93
+ type: "string",
94
+ description: 'Field to order by (e.g., "created_at DESC")'
95
+ },
96
+ where: {
97
+ type: "object",
98
+ description: "Filter conditions as key-value pairs",
99
+ additionalProperties: true
100
+ }
101
+ }
102
+ }
103
+ });
104
+ }
105
+ if (shouldInclude("get")) {
106
+ tools.push({
107
+ name: `${lowerName}_get`,
108
+ description: `Get a specific ${objectName} by ID or slug`,
109
+ inputSchema: {
110
+ type: "object",
111
+ properties: {
112
+ id: {
113
+ type: "string",
114
+ description: "Unique identifier of the object"
115
+ },
116
+ slug: {
117
+ type: "string",
118
+ description: "URL-friendly identifier of the object"
119
+ }
120
+ },
121
+ required: ["id"]
122
+ }
123
+ });
124
+ }
125
+ if (shouldInclude("create")) {
126
+ const properties = {};
127
+ const required = [];
128
+ for (const [fieldName, field] of fields) {
129
+ properties[fieldName] = this.fieldToMCPSchema(field);
130
+ if (field._meta?.required) {
131
+ required.push(fieldName);
132
+ }
133
+ }
134
+ tools.push({
135
+ name: `${lowerName}_create`,
136
+ description: `Create a new ${objectName}`,
137
+ inputSchema: {
138
+ type: "object",
139
+ properties,
140
+ required
141
+ }
142
+ });
143
+ }
144
+ if (shouldInclude("update")) {
145
+ const properties = {
146
+ id: {
147
+ type: "string",
148
+ description: "ID of the object to update"
149
+ }
150
+ };
151
+ for (const [fieldName, field] of fields) {
152
+ properties[fieldName] = this.fieldToMCPSchema(field);
153
+ }
154
+ tools.push({
155
+ name: `${lowerName}_update`,
156
+ description: `Update an existing ${objectName}`,
157
+ inputSchema: {
158
+ type: "object",
159
+ properties,
160
+ required: ["id"]
161
+ }
162
+ });
163
+ }
164
+ if (shouldInclude("delete")) {
165
+ tools.push({
166
+ name: `${lowerName}_delete`,
167
+ description: `Delete a ${objectName} by ID`,
168
+ inputSchema: {
169
+ type: "object",
170
+ properties: {
171
+ id: {
172
+ type: "string",
173
+ description: "ID of the object to delete"
174
+ }
175
+ },
176
+ required: ["id"]
177
+ }
178
+ });
179
+ }
180
+ if (classInfo) {
181
+ const config = ObjectRegistry.getConfig(objectName);
182
+ const mcpConfig = config.mcp;
183
+ const included = typeof mcpConfig === "object" ? mcpConfig?.include : void 0;
184
+ const excluded = typeof mcpConfig === "object" && mcpConfig?.exclude ? mcpConfig.exclude : [];
185
+ const crudOperations = ["list", "get", "create", "update", "delete"];
186
+ const customMethodsInInclude = included?.filter((item) => !crudOperations.includes(item)) || [];
187
+ const hasIncludeList = included !== void 0;
188
+ const methods = await ObjectRegistry.getAllMethods(objectName);
189
+ const methodNames = new Set(Array.from(methods.keys()));
190
+ if (hasIncludeList) {
191
+ for (const methodName of customMethodsInInclude) {
192
+ if (excluded.includes(methodName)) continue;
193
+ const existsInManifest = methodNames.has(methodName);
194
+ const existsOnClass = this.validateCustomMethod(
195
+ classInfo.constructor,
196
+ methodName
197
+ );
198
+ if (!existsInManifest && !existsOnClass) {
199
+ console.warn(
200
+ `Warning: Custom action '${methodName}' specified in MCP config for ${objectName}, but method ${methodName}() not found on class`
201
+ );
202
+ continue;
203
+ }
204
+ const methodDef = methods.get(methodName);
205
+ if (methodDef && !methodDef.isPublic) continue;
206
+ const toolName = `${lowerName}_${methodName}`.toLowerCase();
207
+ tools.push({
208
+ name: toolName,
209
+ description: `Execute ${methodName} action on ${objectName}`,
210
+ inputSchema: {
211
+ type: "object",
212
+ properties: {
213
+ id: {
214
+ type: "string",
215
+ description: "ID of the object to execute action on"
216
+ },
217
+ options: {
218
+ type: "object",
219
+ description: "Additional options for the custom action",
220
+ additionalProperties: true
221
+ }
222
+ },
223
+ required: ["id"]
224
+ }
225
+ });
226
+ }
227
+ } else {
228
+ for (const [methodName, methodDef] of methods) {
229
+ if (!methodDef.isPublic) continue;
230
+ if (excluded.includes(methodName)) continue;
231
+ const toolName = `${lowerName}_${methodName}`.toLowerCase();
232
+ tools.push({
233
+ name: toolName,
234
+ description: `Execute ${methodName} action on ${objectName}`,
235
+ inputSchema: {
236
+ type: "object",
237
+ properties: {
238
+ id: {
239
+ type: "string",
240
+ description: "ID of the object to execute action on"
241
+ },
242
+ options: {
243
+ type: "object",
244
+ description: "Additional options for the custom action",
245
+ additionalProperties: true
246
+ }
247
+ },
248
+ required: ["id"]
249
+ }
250
+ });
251
+ }
252
+ }
253
+ }
254
+ return tools;
255
+ }
256
+ /**
257
+ * Validate that a custom method exists on a class
258
+ */
259
+ validateCustomMethod(classConstructor, methodName) {
260
+ try {
261
+ const prototype = classConstructor.prototype;
262
+ if (typeof prototype[methodName] === "function") {
263
+ return true;
264
+ }
265
+ if (typeof classConstructor[methodName] === "function") {
266
+ return true;
267
+ }
268
+ return false;
269
+ } catch (error) {
270
+ console.warn(
271
+ `Error validating method ${methodName} on class ${classConstructor.name}:`,
272
+ error
273
+ );
274
+ return false;
275
+ }
276
+ }
277
+ /**
278
+ * Convert field definition to MCP schema
279
+ */
280
+ fieldToMCPSchema(field) {
281
+ const schema = {
282
+ description: field._meta?.description || `${field.type} field`
283
+ };
284
+ switch (field.type) {
285
+ case "text":
286
+ schema.type = "string";
287
+ if (field._meta?.maxLength) schema.maxLength = field._meta.maxLength;
288
+ if (field._meta?.minLength) schema.minLength = field._meta.minLength;
289
+ break;
290
+ case "integer":
291
+ schema.type = "integer";
292
+ if (field._meta?.min !== void 0) schema.minimum = field._meta.min;
293
+ if (field._meta?.max !== void 0) schema.maximum = field._meta.max;
294
+ break;
295
+ case "decimal":
296
+ schema.type = "number";
297
+ if (field._meta?.min !== void 0) schema.minimum = field._meta.min;
298
+ if (field._meta?.max !== void 0) schema.maximum = field._meta.max;
299
+ break;
300
+ case "boolean":
301
+ schema.type = "boolean";
302
+ break;
303
+ case "datetime":
304
+ schema.type = "string";
305
+ schema.format = "date-time";
306
+ break;
307
+ case "json":
308
+ schema.type = "object";
309
+ break;
310
+ case "foreignKey":
311
+ schema.type = "string";
312
+ schema.description = `ID of related ${field.related || "object"}`;
313
+ break;
314
+ default:
315
+ schema.type = "string";
316
+ }
317
+ if (field._meta?.default !== void 0) {
318
+ schema.default = field._meta.default;
319
+ }
320
+ return schema;
321
+ }
322
+ /**
323
+ * Handle MCP tool calls
324
+ */
325
+ async handleToolCall(request) {
326
+ const { name, arguments: args } = request.params;
327
+ try {
328
+ const availableTools = await this.generateTools();
329
+ const toolExists = availableTools.some((t) => t.name === name);
330
+ if (!toolExists) {
331
+ throw new Error(`Unknown tool: ${name}`);
332
+ }
333
+ const firstUnderscore = name.indexOf("_");
334
+ const objectName = firstUnderscore === -1 ? "" : name.slice(0, firstUnderscore);
335
+ const action = firstUnderscore === -1 ? "" : name.slice(firstUnderscore + 1);
336
+ if (!objectName || !action) {
337
+ throw new Error(`Invalid tool name format: ${name}`);
338
+ }
339
+ const registeredClasses = ObjectRegistry.getAllClasses();
340
+ let classInfo = null;
341
+ let actualObjectName = "";
342
+ for (const [_key, info] of registeredClasses) {
343
+ const simpleName = info.name || _key;
344
+ if (simpleName.toLowerCase() === objectName.toLowerCase()) {
345
+ classInfo = info;
346
+ actualObjectName = simpleName;
347
+ break;
348
+ }
349
+ }
350
+ if (!classInfo) {
351
+ throw new Error(`Object type '${objectName}' not found`);
352
+ }
353
+ const collection = await this.getCollection(actualObjectName, classInfo);
354
+ const result = await this.executeAction(
355
+ collection,
356
+ action,
357
+ args,
358
+ actualObjectName
359
+ );
360
+ return {
361
+ content: [
362
+ {
363
+ type: "text",
364
+ text: JSON.stringify(result, null, 2)
365
+ }
366
+ ]
367
+ };
368
+ } catch (error) {
369
+ return {
370
+ content: [
371
+ {
372
+ type: "text",
373
+ text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`
374
+ }
375
+ ]
376
+ };
377
+ }
378
+ }
379
+ /**
380
+ * Get or create collection for an object
381
+ */
382
+ async getCollection(objectName, classInfo) {
383
+ if (!this.collections.has(objectName)) {
384
+ if (!classInfo.collectionConstructor || typeof classInfo.collectionConstructor !== "function") {
385
+ throw new Error(
386
+ `No valid collection constructor found for ${objectName}`
387
+ );
388
+ }
389
+ const collection2 = new classInfo.collectionConstructor({
390
+ ai: this.context.ai,
391
+ db: this.context.db
392
+ });
393
+ if (!(collection2 instanceof SmrtCollection)) {
394
+ throw new Error(
395
+ `Collection for ${objectName} must extend SmrtCollection`
396
+ );
397
+ }
398
+ await collection2.initialize();
399
+ this.collections.set(objectName, collection2);
400
+ }
401
+ const collection = this.collections.get(objectName);
402
+ if (!collection) {
403
+ throw new Error(`Collection for ${objectName} not found`);
404
+ }
405
+ return collection;
406
+ }
407
+ /**
408
+ * Serialize a tool-response payload, excluding sensitive fields (#1540).
409
+ * Recurses through arrays and plain objects so a SmrtObject nested inside a
410
+ * custom-action result (e.g. `{ item }`) is also stripped — `JSON.stringify`
411
+ * would otherwise call its `toJSON()`. Non-plain instances (Date, etc.) and
412
+ * primitives pass through unchanged; a cycle guard prevents infinite loops.
413
+ */
414
+ toPublicData(value, seen = /* @__PURE__ */ new WeakSet()) {
415
+ if (value === null || typeof value !== "object") return value;
416
+ if (typeof value.toPublicJSON === "function") return value.toPublicJSON();
417
+ if (Array.isArray(value)) {
418
+ if (seen.has(value)) return value;
419
+ seen.add(value);
420
+ return value.map((entry) => this.toPublicData(entry, seen));
421
+ }
422
+ const proto = Object.getPrototypeOf(value);
423
+ if (proto !== Object.prototype && proto !== null) return value;
424
+ if (seen.has(value)) return value;
425
+ seen.add(value);
426
+ const out = {};
427
+ for (const [key, entry] of Object.entries(value)) {
428
+ out[key] = this.toPublicData(entry, seen);
429
+ }
430
+ return out;
431
+ }
432
+ /**
433
+ * Mass-assignment guard (#1540): strip framework/server-managed and
434
+ * `@field({ readonly: true })` fields from a create/update body, and — when an
435
+ * `@smrt({ api: { writable: [...] } })` allowlist is set — intersect with it.
436
+ */
437
+ applyWritablePolicy(objectName, data) {
438
+ if (!data || typeof data !== "object") {
439
+ return {};
440
+ }
441
+ const serverManaged = /* @__PURE__ */ new Set([
442
+ "id",
443
+ "tenantId",
444
+ "tenant_id",
445
+ "createdAt",
446
+ "created_at",
447
+ "updatedAt",
448
+ "updated_at"
449
+ ]);
450
+ const readonly = /* @__PURE__ */ new Set();
451
+ let writable = null;
452
+ if (objectName) {
453
+ const apiConfig = ObjectRegistry.getConfig(objectName)?.api;
454
+ if (apiConfig && typeof apiConfig === "object" && Array.isArray(apiConfig.writable)) {
455
+ writable = apiConfig.writable;
456
+ }
457
+ for (const [name, def] of ObjectRegistry.getFields(objectName)) {
458
+ if (def && (def.readonly === true || def._meta?.readonly === true)) {
459
+ readonly.add(name);
460
+ }
461
+ }
462
+ }
463
+ const result = {};
464
+ for (const [key, value] of Object.entries(data)) {
465
+ if (key.startsWith("_")) continue;
466
+ if (serverManaged.has(key)) continue;
467
+ if (readonly.has(key)) continue;
468
+ if (writable && !writable.includes(key)) continue;
469
+ result[key] = value;
470
+ }
471
+ return result;
472
+ }
473
+ /**
474
+ * Execute action on collection
475
+ */
476
+ /**
477
+ * Fail-closed authorization for tool calls (#1540). Mutating tools
478
+ * (create/update/delete + custom actions) require an authenticated principal
479
+ * (`context.user`) unless the object opts out via `@smrt({ api: { public } })`.
480
+ * Reads are allowed when `public` is `true` or `'read'`.
481
+ */
482
+ requireToolAuth(objectName, mutating) {
483
+ const apiConfig = objectName ? ObjectRegistry.getConfig(objectName)?.api : void 0;
484
+ const publicAccess = apiConfig && typeof apiConfig === "object" ? apiConfig.public : void 0;
485
+ if (publicAccess === true) return;
486
+ if (publicAccess === "read" && !mutating) return;
487
+ if (!this.context.user) {
488
+ throw new Error("Authentication required");
489
+ }
490
+ }
491
+ async executeAction(collection, action, args, objectName) {
492
+ const mutating = action !== "list" && action !== "get";
493
+ this.requireToolAuth(objectName, mutating);
494
+ return runWithTenantGate(
495
+ {
496
+ className: objectName,
497
+ tenantId: this.context.tenantId,
498
+ allowCrossTenant: this.context.allowCrossTenant,
499
+ surface: "MCP"
500
+ },
501
+ () => this.runAction(collection, action, args, objectName)
502
+ );
503
+ }
504
+ /**
505
+ * Derive the set of tenant-scoped object names (lowercased simple names) from
506
+ * a generated tool list, for the emitted runtime template's tenant gate
507
+ * (#1554). Tool names are `objectname_action`.
508
+ *
509
+ * Detection uses ONLY tenancy's `isTenantScopedClass` (the authoritative
510
+ * source the interceptor uses; covers `@TenantScoped`), consulted via an
511
+ * optional dynamic import. We deliberately do NOT fall back to core's
512
+ * `ObjectRegistry.isTenantScoped`: a `@smrt({ tenantScoped })` model can exist
513
+ * in an app that has NOT installed `@happyvertical/smrt-tenancy`, and emitting
514
+ * the static `import { runTenantScopedEntryPoint } from '@happyvertical/smrt-tenancy'`
515
+ * gate for it would crash the generated server at import time. When tenancy is
516
+ * absent there is also nothing to enforce, so emitting no gate is correct.
517
+ */
518
+ async tenantScopedObjectNames(tools) {
519
+ let isTenantScopedClass;
520
+ try {
521
+ const tenancySpecifier = "@happyvertical/smrt-tenancy";
522
+ const tenancy = await import(
523
+ /* @vite-ignore */
524
+ tenancySpecifier
525
+ );
526
+ isTenantScopedClass = tenancy.isTenantScopedClass;
527
+ } catch {
528
+ isTenantScopedClass = void 0;
529
+ }
530
+ if (typeof isTenantScopedClass !== "function") return [];
531
+ const scoped = /* @__PURE__ */ new Set();
532
+ for (const tool of tools) {
533
+ const [objectName] = tool.name.split("_");
534
+ if (!objectName) continue;
535
+ for (const [key, info] of ObjectRegistry.getAllClasses()) {
536
+ const simpleName = info.name || key;
537
+ if (simpleName.toLowerCase() === objectName.toLowerCase()) {
538
+ if (isTenantScopedClass(simpleName)) {
539
+ scoped.add(simpleName.toLowerCase());
540
+ }
541
+ break;
542
+ }
543
+ }
544
+ }
545
+ return Array.from(scoped);
546
+ }
547
+ /**
548
+ * Execute a resolved MCP action (CRUD or custom) against a collection. Always
549
+ * invoked inside the tenant gate established by {@link executeAction}.
550
+ */
551
+ async runAction(collection, action, args, objectName) {
552
+ switch (action) {
553
+ case "list": {
554
+ const listOptions = {
555
+ limit: Math.min(args.limit || 50, 1e3),
556
+ offset: args.offset || 0
557
+ };
558
+ if (args.where) {
559
+ listOptions.where = args.where;
560
+ }
561
+ if (args.orderBy) {
562
+ listOptions.orderBy = args.orderBy;
563
+ }
564
+ const results = await collection.list(listOptions);
565
+ const total = await collection.count({ where: args.where || {} });
566
+ return {
567
+ data: results.map((result) => this.toPublicData(result)),
568
+ meta: {
569
+ total,
570
+ limit: listOptions.limit,
571
+ offset: listOptions.offset,
572
+ count: results.length
573
+ }
574
+ };
575
+ }
576
+ case "get": {
577
+ if (!args.id && !args.slug) {
578
+ throw new Error("Either id or slug is required");
579
+ }
580
+ const filter = args.id ? args.id : args.slug;
581
+ const item = await collection.get(filter);
582
+ if (!item) {
583
+ throw new Error("Object not found");
584
+ }
585
+ return this.toPublicData(item);
586
+ }
587
+ case "create": {
588
+ const createData = this.applyWritablePolicy(
589
+ objectName,
590
+ args
591
+ );
592
+ if (this.context.user) {
593
+ createData.created_by = this.context.user.id;
594
+ createData.owner_id = this.context.user.id;
595
+ }
596
+ const newItem = await collection.create(createData);
597
+ await newItem.save();
598
+ return this.toPublicData(newItem);
599
+ }
600
+ case "update": {
601
+ const { id } = args;
602
+ if (!id) {
603
+ throw new Error("ID is required for update");
604
+ }
605
+ const existing = await collection.get(id);
606
+ if (!existing) {
607
+ throw new Error("Object not found");
608
+ }
609
+ const updateData = this.applyWritablePolicy(objectName, args);
610
+ Object.assign(existing, updateData);
611
+ if (this.context.user) {
612
+ existing.updated_by = this.context.user.id;
613
+ }
614
+ await existing.save();
615
+ return this.toPublicData(existing);
616
+ }
617
+ case "delete": {
618
+ if (!args.id) {
619
+ throw new Error("ID is required for delete");
620
+ }
621
+ const toDelete = await collection.get(args.id);
622
+ if (!toDelete) {
623
+ throw new Error("Object not found");
624
+ }
625
+ await toDelete.delete();
626
+ return { success: true, message: "Object deleted successfully" };
627
+ }
628
+ default: {
629
+ const result = await this.executeCustomAction(collection, action, args);
630
+ return this.toPublicData(result);
631
+ }
632
+ }
633
+ }
634
+ /**
635
+ * Execute a custom action on a collection/object
636
+ */
637
+ async executeCustomAction(collection, action, args) {
638
+ const { id, options = {}, ...directArgs } = args;
639
+ try {
640
+ if (id) {
641
+ const object = await collection.get(id);
642
+ if (!object) {
643
+ throw new Error("Object not found");
644
+ }
645
+ const objectWithMethods = object;
646
+ if (typeof objectWithMethods[action] === "function") {
647
+ const methodArgs = Object.keys(options).length > 0 ? options : directArgs;
648
+ const result = await objectWithMethods[action](methodArgs);
649
+ return result;
650
+ } else {
651
+ throw new Error(`Method '${action}' not found on object instance`);
652
+ }
653
+ } else {
654
+ if (typeof collection[action] === "function") {
655
+ const methodArgs = Object.keys(options).length > 0 ? options : directArgs;
656
+ const result = await collection[action](methodArgs);
657
+ return result;
658
+ } else {
659
+ throw new Error(
660
+ `Method '${action}' not found on collection. For object-specific actions, provide an 'id' parameter.`
661
+ );
662
+ }
663
+ }
664
+ } catch (error) {
665
+ throw new Error(
666
+ `Failed to execute custom action '${action}': ${error instanceof Error ? error.message : "Unknown error"}`
667
+ );
668
+ }
669
+ }
670
+ /**
671
+ * Generate MCP server info
672
+ */
673
+ getServerInfo() {
674
+ return {
675
+ name: this.config.server?.name,
676
+ version: this.config.server?.version,
677
+ description: this.config.description
678
+ };
679
+ }
680
+ /**
681
+ * Generate complete MCP server with stdio transport
682
+ *
683
+ * Creates a runnable Node.js script that exposes SMRT objects as MCP tools.
684
+ * The generated server includes:
685
+ * - Stdio transport integration
686
+ * - Tool registration from ObjectRegistry
687
+ * - Error handling and logging
688
+ * - Graceful shutdown
689
+ *
690
+ * @param options - Server generation options
691
+ * @returns Promise that resolves when all files are written
692
+ *
693
+ * @example
694
+ * ```typescript
695
+ * const generator = new MCPGenerator({
696
+ * name: 'my-app',
697
+ * version: '1.0.0'
698
+ * });
699
+ *
700
+ * await generator.generateServer({
701
+ * outputPath: '.smrt/mcp-server/index.js',
702
+ * serverName: 'my-app-mcp',
703
+ * debug: true
704
+ * });
705
+ * ```
706
+ */
707
+ async generateServer(options = {}) {
708
+ const {
709
+ outputPath = ".smrt/mcp-server/index.js",
710
+ serverName = this.config.name || "smrt-mcp-server",
711
+ serverVersion = this.config.version || "1.0.0",
712
+ debug = false,
713
+ generateClaudeConfigFile = false,
714
+ generateReadme = false,
715
+ modular = false
716
+ } = options;
717
+ const resolvedPath = resolve(process.cwd(), outputPath);
718
+ const outputDir = dirname(resolvedPath);
719
+ await mkdir(outputDir, { recursive: true });
720
+ if (modular) {
721
+ await this.generateModularServer(
722
+ outputDir,
723
+ serverName,
724
+ serverVersion,
725
+ debug
726
+ );
727
+ } else {
728
+ const tools = await this.generateTools();
729
+ const runtimeOptions = {
730
+ name: serverName,
731
+ version: serverVersion,
732
+ description: this.config.description,
733
+ config: this.config,
734
+ context: this.context,
735
+ debug,
736
+ tools,
737
+ tenantScopedObjects: await this.tenantScopedObjectNames(tools)
738
+ };
739
+ const serverCode = generateRuntimeBootstrap(runtimeOptions);
740
+ await writeFile(resolvedPath, serverCode, "utf-8");
741
+ console.log(`✅ Generated MCP server: ${resolvedPath}`);
742
+ }
743
+ if (generateClaudeConfigFile) {
744
+ const claudeConfig = generateClaudeConfig(serverName, resolvedPath);
745
+ const claudeConfigPath = resolve(outputDir, "claude-config.example.json");
746
+ await writeFile(
747
+ claudeConfigPath,
748
+ JSON.stringify(claudeConfig, null, 2),
749
+ "utf-8"
750
+ );
751
+ console.log(`✅ Generated Claude config example: ${claudeConfigPath}`);
752
+ }
753
+ if (generateReadme) {
754
+ const readme = generateMCPDocumentation(serverName, outputPath);
755
+ const readmePath = resolve(outputDir, "MCP-README.md");
756
+ await writeFile(readmePath, readme, "utf-8");
757
+ console.log(`✅ Generated MCP documentation: ${readmePath}`);
758
+ }
759
+ const mcpScript = generateMCPScript(outputPath);
760
+ console.log(`
761
+ 📝 Add this to your package.json scripts:`);
762
+ console.log(` "mcp": "${mcpScript}"
763
+ `);
764
+ }
765
+ /**
766
+ * Generate modular MCP server structure
767
+ *
768
+ * Creates separate files for tools, handlers, configuration, and main entry point.
769
+ * This makes the generated server easier to customize and extend.
770
+ *
771
+ * @param outputDir - Directory to generate files in
772
+ * @param serverName - Server name
773
+ * @param serverVersion - Server version
774
+ * @param debug - Enable debug logging
775
+ */
776
+ async generateModularServer(outputDir, serverName, serverVersion, debug) {
777
+ const toolsDir = resolve(outputDir, "tools");
778
+ const handlersDir = resolve(outputDir, "handlers");
779
+ await mkdir(toolsDir, { recursive: true });
780
+ await mkdir(handlersDir, { recursive: true });
781
+ const configPath = resolve(outputDir, "config.ts");
782
+ const configCode = this.generateConfigFile(
783
+ serverName,
784
+ serverVersion,
785
+ debug
786
+ );
787
+ await writeFile(configPath, configCode, "utf-8");
788
+ console.log(`✅ Generated config: ${configPath}`);
789
+ const toolsPath = resolve(toolsDir, "index.ts");
790
+ const toolsCode = await this.generateToolsFile();
791
+ await writeFile(toolsPath, toolsCode, "utf-8");
792
+ console.log(`✅ Generated tools: ${toolsPath}`);
793
+ const handlersPath = resolve(handlersDir, "index.ts");
794
+ const tenantScopedObjects = await this.tenantScopedObjectNames(
795
+ await this.generateTools()
796
+ );
797
+ const handlersCode = await this.generateHandlersFile(tenantScopedObjects);
798
+ await writeFile(handlersPath, handlersCode, "utf-8");
799
+ console.log(`✅ Generated handlers: ${handlersPath}`);
800
+ const indexPath = resolve(outputDir, "index.js");
801
+ const indexCode = this.generateModularIndex();
802
+ await writeFile(indexPath, indexCode, "utf-8");
803
+ console.log(`✅ Generated MCP server: ${indexPath}`);
804
+ }
805
+ /**
806
+ * Generate configuration file for modular server
807
+ */
808
+ generateConfigFile(serverName, serverVersion, debug) {
809
+ return `/**
810
+ * MCP Server Configuration
811
+ * Auto-generated by @happyvertical/smrt-core
812
+ */
813
+
814
+ export const SERVER_NAME = ${JSON.stringify(serverName)};
815
+ export const SERVER_VERSION = ${JSON.stringify(serverVersion)};
816
+ export const SERVER_DESCRIPTION = ${JSON.stringify(this.config.description)};
817
+ export const DEBUG = ${debug};
818
+ `;
819
+ }
820
+ /**
821
+ * Generate tools definitions file for modular server
822
+ */
823
+ async generateToolsFile() {
824
+ const tools = await this.generateTools();
825
+ return `/**
826
+ * MCP Tools Definitions
827
+ * Auto-generated from SMRT objects
828
+ */
829
+
830
+ export const tools: Array<{
831
+ name: string;
832
+ description: string;
833
+ inputSchema: any;
834
+ }> = ${JSON.stringify(tools, null, 2)};
835
+ `;
836
+ }
837
+ /**
838
+ * Generate switch cases for tool execution
839
+ */
840
+ async generateToolSwitchCases(indent = " ") {
841
+ const tools = await this.generateTools();
842
+ const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
843
+ const switchCases = tools.map((tool) => {
844
+ const [objectName, action] = tool.name.split("_");
845
+ switch (action) {
846
+ case "list":
847
+ return `${indent}case '${tool.name}': {
848
+ ${indent} const limit = args.limit ?? 50;
849
+ ${indent} const offset = args.offset ?? 0;
850
+ ${indent} const where = args.where ?? {};
851
+
852
+ ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
853
+ ${indent} persistence: { type: 'sql', url: process.env.DATABASE_URL || ':memory:' },
854
+ ${indent} ai: aiConfig
855
+ ${indent} });
856
+
857
+ ${indent} const items = await collection.list({ where, limit, offset });
858
+ ${indent} const itemsPublic = items.map((item) => item.toPublicJSON());
859
+ ${indent} return { content: [{ type: 'text', text: JSON.stringify(itemsPublic) }] };
860
+ ${indent}}`;
861
+ case "get":
862
+ return `${indent}case '${tool.name}': {
863
+ ${indent} if (!args.id && !args.slug) {
864
+ ${indent} throw new Error('Either id or slug is required');
865
+ ${indent} }
866
+
867
+ ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
868
+ ${indent} persistence: { type: 'sql', url: process.env.DATABASE_URL || ':memory:' },
869
+ ${indent} ai: aiConfig
870
+ ${indent} });
871
+
872
+ ${indent} const filter = args.id || args.slug;
873
+ ${indent} const item = await collection.get(filter);
874
+
875
+ ${indent} if (!item) {
876
+ ${indent} throw new Error('Object not found');
877
+ ${indent} }
878
+
879
+ ${indent} return { content: [{ type: 'text', text: JSON.stringify(item.toPublicJSON()) }] };
880
+ ${indent}}`;
881
+ case "create":
882
+ return `${indent}case '${tool.name}': {
883
+ ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
884
+ ${indent} persistence: { type: 'sql', url: process.env.DATABASE_URL || ':memory:' },
885
+ ${indent} ai: aiConfig
886
+ ${indent} });
887
+
888
+ ${indent} const newItem = await collection.create(applyWritablePolicy('${capitalize(objectName)}', args));
889
+ ${indent} await newItem.save();
890
+
891
+ ${indent} return { content: [{ type: 'text', text: JSON.stringify(newItem.toPublicJSON()) }] };
892
+ ${indent}}`;
893
+ case "update":
894
+ return `${indent}case '${tool.name}': {
895
+ ${indent} const { id, ...updateData } = args;
896
+ ${indent} if (!id) {
897
+ ${indent} throw new Error('ID is required for update');
898
+ ${indent} }
899
+
900
+ ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
901
+ ${indent} persistence: { type: 'sql', url: process.env.DATABASE_URL || ':memory:' },
902
+ ${indent} ai: aiConfig
903
+ ${indent} });
904
+
905
+ ${indent} const existing = await collection.get(id);
906
+ ${indent} if (!existing) {
907
+ ${indent} throw new Error('Object not found');
908
+ ${indent} }
909
+
910
+ ${indent} Object.assign(existing, applyWritablePolicy('${capitalize(objectName)}', updateData));
911
+ ${indent} await existing.save();
912
+
913
+ ${indent} return { content: [{ type: 'text', text: JSON.stringify(existing.toPublicJSON()) }] };
914
+ ${indent}}`;
915
+ case "delete":
916
+ return `${indent}case '${tool.name}': {
917
+ ${indent} if (!args.id) {
918
+ ${indent} throw new Error('ID is required for delete');
919
+ ${indent} }
920
+
921
+ ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
922
+ ${indent} persistence: { type: 'sql', url: process.env.DATABASE_URL || ':memory:' },
923
+ ${indent} ai: aiConfig
924
+ ${indent} });
925
+
926
+ ${indent} const toDelete = await collection.get(args.id);
927
+ ${indent} if (!toDelete) {
928
+ ${indent} throw new Error('Object not found');
929
+ ${indent} }
930
+
931
+ ${indent} await toDelete.delete();
932
+
933
+ ${indent} return { content: [{ type: 'text', text: JSON.stringify({ success: true, message: 'Object deleted successfully' }) }] };
934
+ ${indent}}`;
935
+ default:
936
+ return `${indent}case '${tool.name}': {
937
+ ${indent} const { id, options = {}, ...directArgs } = args;
938
+
939
+ ${indent} if (!id) {
940
+ ${indent} throw new Error('ID is required for custom action ${action}');
941
+ ${indent} }
942
+
943
+ ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
944
+ ${indent} persistence: { type: 'sql', url: process.env.DATABASE_URL || ':memory:' },
945
+ ${indent} ai: aiConfig
946
+ ${indent} });
947
+
948
+ ${indent} const object = await collection.get(id);
949
+ ${indent} if (!object) {
950
+ ${indent} throw new Error('Object not found');
951
+ ${indent} }
952
+
953
+ ${indent} if (typeof object['${action}'] !== 'function') {
954
+ ${indent} throw new Error('Method ${action} not found on object');
955
+ ${indent} }
956
+
957
+ ${indent} const methodArgs = Object.keys(options).length > 0 ? options : directArgs;
958
+ ${indent} const result = await object['${action}'](methodArgs);
959
+
960
+ ${indent} return { content: [{ type: 'text', text: JSON.stringify(toPublicResult(result)) }] };
961
+ ${indent}}`;
962
+ }
963
+ }).join("\n\n");
964
+ return switchCases;
965
+ }
966
+ /**
967
+ * Generate handlers file for modular server
968
+ */
969
+ async generateHandlersFile(tenantScopedObjects = []) {
970
+ const switchCases = await this.generateToolSwitchCases(" ");
971
+ const tenantScopedSet = Array.from(
972
+ new Set(tenantScopedObjects.map((n) => n.toLowerCase()))
973
+ );
974
+ const hasTenantScoped = tenantScopedSet.length > 0;
975
+ return `/**
976
+ * MCP Tool Call Handlers
977
+ * Auto-generated from SMRT objects
978
+ *
979
+ * SECURITY (#1540): responses exclude @field({ sensitive }) fields and
980
+ * create/update bodies are mass-assignment guarded. This handler has no
981
+ * per-call authentication principal — the generated stdio MCP server's trust
982
+ * boundary is the host process / MCP client. Run it only in a trusted context
983
+ * or behind an authenticated gateway.
984
+ *
985
+ * SECURITY (#1554): tenant-scoped tools run inside a fail-closed tenant gate;
986
+ * the tenant is taken from SMRT_MCP_TENANT_ID (this server has no auth
987
+ * principal) and tenancy is enabled so the interceptor enforces filtering.
988
+ */
989
+
990
+ import { ObjectRegistry } from '@happyvertical/smrt-core';
991
+ ${hasTenantScoped ? "import { enableTenancy, runTenantScopedEntryPoint } from '@happyvertical/smrt-tenancy';\n" : ""}${hasTenantScoped ? `
992
+ // Install the tenancy interceptor so tenant-scoped tools are filtered and the
993
+ // gate fail-closes when no tenant is supplied (#1554).
994
+ enableTenancy();
995
+ const TENANT_SCOPED = new Set(${JSON.stringify(tenantScopedSet)});
996
+ const MCP_TENANT_ID = process.env.SMRT_MCP_TENANT_ID || undefined;
997
+ const MCP_ALLOW_CROSS_TENANT = process.env.SMRT_MCP_ALLOW_CROSS_TENANT === 'true';
998
+ ` : ""}
999
+
1000
+ /**
1001
+ * Mass-assignment guard (#1540): strip framework/server-managed and
1002
+ * \`@field({ readonly: true })\` fields from create/update bodies, intersecting
1003
+ * with the optional \`@smrt({ api: { writable: [...] } })\` allowlist.
1004
+ */
1005
+ function applyWritablePolicy(objectName: string, data: any): Record<string, any> {
1006
+ if (!data || typeof data !== 'object') return {};
1007
+ const serverManaged = new Set<string>([
1008
+ 'id', 'tenantId', 'tenant_id',
1009
+ 'createdAt', 'created_at', 'updatedAt', 'updated_at',
1010
+ ]);
1011
+ const readonly = new Set<string>();
1012
+ let writable: string[] | null = null;
1013
+ const apiConfig = ObjectRegistry.getConfig(objectName)?.api as any;
1014
+ if (apiConfig && typeof apiConfig === 'object' && Array.isArray(apiConfig.writable)) {
1015
+ writable = apiConfig.writable;
1016
+ }
1017
+ for (const [name, def] of ObjectRegistry.getFields(objectName)) {
1018
+ if (def && ((def as any).readonly === true || (def as any)._meta?.readonly === true)) {
1019
+ readonly.add(name);
1020
+ }
1021
+ }
1022
+ const result: Record<string, any> = {};
1023
+ for (const [key, value] of Object.entries(data as Record<string, any>)) {
1024
+ if (key.startsWith('_')) continue;
1025
+ if (serverManaged.has(key)) continue;
1026
+ if (readonly.has(key)) continue;
1027
+ if (writable && !writable.includes(key)) continue;
1028
+ result[key] = value;
1029
+ }
1030
+ return result;
1031
+ }
1032
+
1033
+ /**
1034
+ * Sensitive-field-safe serialization for custom-action results (#1540).
1035
+ * Recurses through arrays and plain objects so nested SmrtObjects are stripped
1036
+ * too; non-plain instances (Date, etc.) and primitives pass through. Cycle-safe.
1037
+ */
1038
+ function toPublicResult(value: any, seen: WeakSet<object> = new WeakSet()): any {
1039
+ if (value === null || typeof value !== 'object') return value;
1040
+ if (typeof value.toPublicJSON === 'function') return value.toPublicJSON();
1041
+ if (Array.isArray(value)) {
1042
+ if (seen.has(value)) return value;
1043
+ seen.add(value);
1044
+ return value.map((entry: any) => toPublicResult(entry, seen));
1045
+ }
1046
+ const proto = Object.getPrototypeOf(value);
1047
+ if (proto !== Object.prototype && proto !== null) return value;
1048
+ if (seen.has(value)) return value;
1049
+ seen.add(value);
1050
+ const out: Record<string, any> = {};
1051
+ for (const [key, entry] of Object.entries(value as Record<string, any>)) {
1052
+ out[key] = toPublicResult(entry, seen);
1053
+ }
1054
+ return out;
1055
+ }
1056
+
1057
+ /**
1058
+ * Handle tool call request
1059
+ */
1060
+ export async function handleToolCall(
1061
+ name: string,
1062
+ arguments: any = {},
1063
+ aiConfig: any = {}
1064
+ ) {
1065
+ try {
1066
+ const args = arguments;
1067
+
1068
+ const runToolBody = async () => {
1069
+ switch (name) {
1070
+ ${switchCases}
1071
+
1072
+ default:
1073
+ throw new Error(\`Unknown tool: \${name}\`);
1074
+ }
1075
+ };
1076
+ ${hasTenantScoped ? `
1077
+ // Fail-closed tenant context for tenant-scoped tools (#1554).
1078
+ const [toolObject] = name.split('_');
1079
+ const result =
1080
+ toolObject && TENANT_SCOPED.has(toolObject.toLowerCase())
1081
+ ? await runTenantScopedEntryPoint(
1082
+ { tenantScoped: true, tenantId: MCP_TENANT_ID, allowCrossTenant: MCP_ALLOW_CROSS_TENANT, surface: 'MCP' },
1083
+ runToolBody,
1084
+ )
1085
+ : await runToolBody();` : `
1086
+ const result = await runToolBody();`}
1087
+
1088
+ return result;
1089
+ } catch (error) {
1090
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
1091
+
1092
+ return {
1093
+ content: [
1094
+ {
1095
+ type: 'text',
1096
+ text: \`Error executing tool \${name}: \${errorMessage}\`,
1097
+ },
1098
+ ],
1099
+ isError: true,
1100
+ };
1101
+ }
1102
+ }
1103
+ `;
1104
+ }
1105
+ /**
1106
+ * Generate modular index file (main entry point)
1107
+ */
1108
+ generateModularIndex() {
1109
+ return `#!/usr/bin/env node
1110
+ /**
1111
+ * Auto-generated MCP Server
1112
+ * Generated by @happyvertical/smrt-core MCPGenerator
1113
+ *
1114
+ * This server exposes SMRT objects as MCP tools for AI integration.
1115
+ */
1116
+
1117
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
1118
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
1119
+ import {
1120
+ CallToolRequestSchema,
1121
+ ListToolsRequestSchema,
1122
+ } from '@modelcontextprotocol/sdk/types.js';
1123
+ import { config } from '@happyvertical/smrt-config';
1124
+ import { getDatabase } from '@happyvertical/sql';
1125
+ import { getAI } from '@happyvertical/ai';
1126
+
1127
+ import { SERVER_NAME, SERVER_VERSION, DEBUG } from './config.js';
1128
+ import { tools } from './tools/index.js';
1129
+ import { handleToolCall } from './handlers/index.js';
1130
+
1131
+ /**
1132
+ * Main server startup function
1133
+ */
1134
+ async function main() {
1135
+ try {
1136
+ if (DEBUG) {
1137
+ console.error(\`[MCP] Starting server: \${SERVER_NAME} v\${SERVER_VERSION}\`);
1138
+ console.error(\`[MCP] Available tools:\`, tools.map(t => t.name).join(', '));
1139
+ }
1140
+
1141
+ // Load configuration from environment and .smrt.config files
1142
+ const appConfig = await config.load();
1143
+ const aiConfig = appConfig?.ai || {};
1144
+
1145
+ // Create MCP server
1146
+ const server = new Server(
1147
+ {
1148
+ name: SERVER_NAME,
1149
+ version: SERVER_VERSION,
1150
+ },
1151
+ {
1152
+ capabilities: {
1153
+ tools: {},
1154
+ },
1155
+ }
1156
+ );
1157
+
1158
+ // Register ListTools handler
1159
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
1160
+ if (DEBUG) {
1161
+ console.error(\`[MCP] ListTools request received\`);
1162
+ }
1163
+
1164
+ return {
1165
+ tools: tools.map(tool => ({
1166
+ name: tool.name,
1167
+ description: tool.description,
1168
+ inputSchema: tool.inputSchema,
1169
+ })),
1170
+ };
1171
+ });
1172
+
1173
+ // Register CallTool handler
1174
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1175
+ const { name, arguments: args = {} } = request.params;
1176
+
1177
+ if (DEBUG) {
1178
+ console.error(\`[MCP] CallTool request: \${name}\`);
1179
+ console.error(\`[MCP] Arguments:\`, JSON.stringify(args, null, 2));
1180
+ }
1181
+
1182
+ return await handleToolCall(name, args, aiConfig);
1183
+ });
1184
+
1185
+ // Setup stdio transport
1186
+ const transport = new StdioServerTransport();
1187
+ await server.connect(transport);
1188
+
1189
+ if (DEBUG) {
1190
+ console.error(\`[MCP] Server connected and ready\`);
1191
+ }
1192
+
1193
+ // Handle graceful shutdown
1194
+ const shutdown = async () => {
1195
+ if (DEBUG) {
1196
+ console.error(\`[MCP] Shutting down gracefully\`);
1197
+ }
1198
+ await server.close();
1199
+ process.exit(0);
1200
+ };
1201
+
1202
+ process.on('SIGINT', shutdown);
1203
+ process.on('SIGTERM', shutdown);
1204
+ } catch (error) {
1205
+ console.error('[MCP] Fatal error during server startup:', error);
1206
+ process.exit(1);
1207
+ }
1208
+ }
1209
+
1210
+ main().catch((error) => {
1211
+ console.error('[MCP] Unhandled error:', error);
1212
+ process.exit(1);
1213
+ });
1214
+ `;
1215
+ }
1216
+ }
1217
+ export {
1218
+ MCPGenerator
1219
+ };
1220
+ //# sourceMappingURL=mcp.js.map