akanjs 3.0.0-alpha.2 → 3.0.0-alpha.21

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 (388) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/base/symbols.ts +4 -0
  4. package/client/clientRuntime.ts +8 -0
  5. package/client/cn.ts +7 -0
  6. package/client/csrTypes.ts +2 -0
  7. package/client/frameDebug.ts +3 -2
  8. package/common/Logger.ts +4 -0
  9. package/common/deepObjectify.ts +21 -7
  10. package/common/index.ts +14 -0
  11. package/common/mcpExposure.ts +99 -0
  12. package/common/pathSet.ts +17 -5
  13. package/common/routeConvention.ts +30 -0
  14. package/constant/crystalize.ts +3 -1
  15. package/constant/fieldInfo.ts +6 -0
  16. package/constant/getDefault.ts +37 -9
  17. package/constant/immerify.ts +1 -1
  18. package/constant/index.ts +2 -0
  19. package/constant/labelOf.ts +17 -0
  20. package/constant/mask.ts +60 -0
  21. package/constant/purify.ts +17 -11
  22. package/constant/types.ts +14 -12
  23. package/dictionary/DictionaryLookup.ts +30 -0
  24. package/dictionary/agent.dictionary.ts +31 -0
  25. package/dictionary/agentTurn.dictionary.ts +29 -0
  26. package/dictionary/base.dictionary.ts +8 -0
  27. package/dictionary/dictInfo.ts +8 -0
  28. package/dictionary/dictionary.ts +9 -3
  29. package/dictionary/index.ts +1 -0
  30. package/document/database.ts +21 -0
  31. package/document/filterMeta.ts +7 -0
  32. package/document/index.ts +1 -0
  33. package/document/into.ts +7 -1
  34. package/document/noDocumentError.ts +12 -0
  35. package/fetch/agentTurn.ts +19 -0
  36. package/fetch/client/fetchClient.ts +71 -13
  37. package/fetch/client/wsClient.ts +17 -2
  38. package/fetch/fetchType/endpointFetch.type.ts +10 -4
  39. package/fetch/index.ts +1 -0
  40. package/local/apps/serverLifecycle/serverLifecycle-local.db +0 -0
  41. package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
  42. package/local/apps/serverLifecycle/serverLifecycle-local.db-wal +0 -0
  43. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db +0 -0
  44. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
  45. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-wal +0 -0
  46. package/package.json +11 -9
  47. package/server/akanApp.ts +30 -34
  48. package/server/akanOption.ts +65 -7
  49. package/server/akanServer.ts +172 -7
  50. package/server/animatedImage.ts +83 -0
  51. package/server/artifact/routeClientCache.ts +14 -0
  52. package/server/assetEncoding.ts +47 -0
  53. package/server/devtools/signalSerializer.ts +2 -2
  54. package/server/devtools/types.ts +2 -2
  55. package/server/di/diLifecycle.ts +31 -3
  56. package/server/di/predefinedAdaptor.ts +6 -0
  57. package/server/imageOptimizer.ts +33 -46
  58. package/server/index.ts +1 -2
  59. package/server/mcp/McpAuth.ts +177 -0
  60. package/server/mcp/McpDispatcher.ts +245 -0
  61. package/server/mcp/McpEventStream.ts +76 -0
  62. package/server/mcp/McpExecutionContext.ts +105 -0
  63. package/server/mcp/McpRouter.ts +591 -0
  64. package/server/mcp/index.ts +5 -0
  65. package/server/resolver/CascadeRunner.ts +1 -1
  66. package/server/resolver/database.resolver.ts +42 -5
  67. package/server/resolver/service.resolver.ts +29 -0
  68. package/server/resolver/signal.resolver.ts +16 -1
  69. package/server/routeTreeBuilder.ts +2 -44
  70. package/server/rscWorker.tsx +6 -2
  71. package/server/subRouteIndexDocument.tsx +61 -0
  72. package/server/systemPageDocument.tsx +2 -2
  73. package/server/systemPages.tsx +49 -16
  74. package/server/vendor/akanjs-fetch.ts +1 -0
  75. package/server/webRouter.ts +159 -35
  76. package/service/agent.service.ts +14 -0
  77. package/service/base.service.ts +2 -1
  78. package/service/index.ts +1 -0
  79. package/service/predefinedAdaptor/database.adaptor.ts +78 -24
  80. package/service/predefinedAdaptor/deepseekLlm.ts +230 -0
  81. package/service/predefinedAdaptor/index.ts +3 -0
  82. package/service/predefinedAdaptor/insightQuery.ts +183 -0
  83. package/service/predefinedAdaptor/llm.adaptor.ts +76 -0
  84. package/service/predefinedAdaptor/role.adaptor.ts +2 -0
  85. package/service/predefinedAdaptor/schedule.adaptor.ts +12 -5
  86. package/service/serviceModule.ts +17 -0
  87. package/service/types.ts +4 -0
  88. package/signal/agent/AgentCatalogue.ts +165 -0
  89. package/signal/agent/index.ts +1 -0
  90. package/signal/agent.signal.ts +42 -0
  91. package/signal/agentTurn.ts +8 -0
  92. package/signal/agentTurnStream.ts +48 -0
  93. package/signal/base.signal.ts +2 -1
  94. package/signal/endpointInfo.ts +38 -2
  95. package/signal/guard.ts +13 -1
  96. package/signal/guards.ts +52 -1
  97. package/signal/index.ts +6 -0
  98. package/signal/mcp/McpDocument.ts +286 -0
  99. package/signal/mcp/McpProgress.ts +106 -0
  100. package/signal/mcp/McpUriTemplate.ts +85 -0
  101. package/signal/mcp/Msg.ts +368 -0
  102. package/signal/mcp/index.ts +5 -0
  103. package/signal/mcp/mcpProtocol.ts +120 -0
  104. package/signal/middleware.ts +7 -3
  105. package/signal/openapi/openapi.ts +32 -171
  106. package/signal/schema/JsonSchemaBuilder.ts +211 -0
  107. package/signal/schema/index.ts +1 -0
  108. package/signal/signalContext.ts +85 -9
  109. package/signal/slice.ts +9 -9
  110. package/signal/types.ts +1 -1
  111. package/store/action.ts +11 -22
  112. package/store/actionTag.ts +33 -0
  113. package/store/agent/AgentBridge.ts +323 -0
  114. package/store/agent/AgentContext.ts +74 -0
  115. package/store/agent/AgentPrompts.ts +82 -0
  116. package/store/agent/AgentVisibility.ts +68 -0
  117. package/store/agent/ScreenReader.ts +208 -0
  118. package/store/agent/StoreCatalogue.ts +351 -0
  119. package/store/agent/StoreSurfaceSource.ts +122 -0
  120. package/store/agent/index.ts +9 -0
  121. package/store/agent/storeSurface.ts +28 -0
  122. package/store/agent/types.ts +50 -0
  123. package/store/agentic/StToolBuilder.ts +199 -0
  124. package/store/agentic/attachAgentic.ts +22 -0
  125. package/store/agentic/index.ts +5 -0
  126. package/store/agentic/readableValue.ts +17 -0
  127. package/store/agentic/useStExpose.ts +18 -0
  128. package/store/agentic/useStState.ts +35 -0
  129. package/store/baseSt.ts +7 -0
  130. package/store/databaseStateNames.ts +31 -0
  131. package/store/formSetterNames.ts +21 -0
  132. package/store/index.ts +8 -0
  133. package/store/rootStore.ts +3 -1
  134. package/store/sliceRole.ts +36 -0
  135. package/store/state.ts +2 -12
  136. package/store/store.ts +19 -1
  137. package/store/storeInstance.ts +165 -20
  138. package/store/storeRegistry.ts +16 -1
  139. package/store/types.ts +18 -0
  140. package/store/withSelector.ts +7 -8
  141. package/test/registerDom.ts +4 -0
  142. package/types/base/symbols.d.ts +4 -0
  143. package/types/client/cn.d.ts +5 -0
  144. package/types/client/csrTypes.d.ts +2 -0
  145. package/types/common/Logger.d.ts +2 -0
  146. package/types/common/deepObjectify.d.ts +4 -2
  147. package/types/common/index.d.ts +2 -1
  148. package/types/common/mcpExposure.d.ts +60 -0
  149. package/types/common/routeConvention.d.ts +8 -0
  150. package/types/constant/fieldInfo.d.ts +1 -0
  151. package/types/constant/getDefault.d.ts +5 -0
  152. package/types/constant/index.d.ts +2 -0
  153. package/types/constant/labelOf.d.ts +6 -0
  154. package/types/constant/mask.d.ts +34 -0
  155. package/types/constant/purify.d.ts +2 -2
  156. package/types/constant/types.d.ts +2 -2
  157. package/types/dictionary/DictionaryLookup.d.ts +14 -0
  158. package/types/dictionary/agent.dictionary.d.ts +1 -0
  159. package/types/dictionary/agentTurn.dictionary.d.ts +1 -0
  160. package/types/dictionary/base.dictionary.d.ts +1 -1
  161. package/types/dictionary/dictInfo.d.ts +6 -0
  162. package/types/dictionary/dictionary.d.ts +11 -9
  163. package/types/dictionary/index.d.ts +1 -0
  164. package/types/document/database.d.ts +20 -0
  165. package/types/document/filterMeta.d.ts +1 -0
  166. package/types/document/index.d.ts +1 -0
  167. package/types/document/into.d.ts +6 -1
  168. package/types/document/noDocumentError.d.ts +12 -0
  169. package/types/fetch/agentTurn.d.ts +593 -0
  170. package/types/fetch/client/fetchClient.d.ts +10 -0
  171. package/types/fetch/fetchType/endpointFetch.type.d.ts +5 -3
  172. package/types/fetch/index.d.ts +1 -0
  173. package/types/server/akanOption.d.ts +35 -7
  174. package/types/server/akanServer.d.ts +44 -1
  175. package/types/server/animatedImage.d.ts +7 -0
  176. package/types/server/artifact/routeClientCache.d.ts +6 -0
  177. package/types/server/assetEncoding.d.ts +7 -0
  178. package/types/server/devtools/types.d.ts +2 -2
  179. package/types/server/di/predefinedAdaptor.d.ts +4 -1
  180. package/types/server/index.d.ts +0 -2
  181. package/types/server/mcp/McpAuth.d.ts +62 -0
  182. package/types/server/mcp/McpDispatcher.d.ts +54 -0
  183. package/types/server/mcp/McpEventStream.d.ts +18 -0
  184. package/types/server/mcp/McpExecutionContext.d.ts +44 -0
  185. package/types/server/mcp/McpRouter.d.ts +60 -0
  186. package/types/server/mcp/index.d.ts +5 -0
  187. package/types/server/mcp.d.ts +1 -0
  188. package/types/server/subRouteIndexDocument.d.ts +8 -0
  189. package/types/server/systemPageDocument.d.ts +1 -0
  190. package/types/server/systemPages.d.ts +5 -0
  191. package/types/server/vendor/akanjs-fetch.d.ts +1 -0
  192. package/types/service/agent.service.d.ts +12 -0
  193. package/types/service/base.service.d.ts +4 -0
  194. package/types/service/index.d.ts +1 -0
  195. package/types/service/predefinedAdaptor/database.adaptor.d.ts +24 -2
  196. package/types/service/predefinedAdaptor/deepseekLlm.d.ts +64 -0
  197. package/types/service/predefinedAdaptor/index.d.ts +3 -0
  198. package/types/service/predefinedAdaptor/insightQuery.d.ts +50 -0
  199. package/types/service/predefinedAdaptor/llm.adaptor.d.ts +68 -0
  200. package/types/service/predefinedAdaptor/role.adaptor.d.ts +2 -0
  201. package/types/service/predefinedAdaptor/schedule.adaptor.d.ts +10 -6
  202. package/types/service/types.d.ts +4 -1
  203. package/types/signal/agent/AgentCatalogue.d.ts +100 -0
  204. package/types/signal/agent/index.d.ts +1 -0
  205. package/types/signal/agent.d.ts +1 -0
  206. package/types/signal/agent.signal.d.ts +29 -0
  207. package/types/signal/agentTurn.d.ts +9 -0
  208. package/types/signal/agentTurnStream.d.ts +16 -0
  209. package/types/signal/base.signal.d.ts +1 -1
  210. package/types/signal/endpointInfo.d.ts +21 -3
  211. package/types/signal/guard.d.ts +11 -0
  212. package/types/signal/guards.d.ts +22 -1
  213. package/types/signal/index.d.ts +6 -0
  214. package/types/signal/mcp/McpDocument.d.ts +65 -0
  215. package/types/signal/mcp/McpProgress.d.ts +40 -0
  216. package/types/signal/mcp/McpUriTemplate.d.ts +26 -0
  217. package/types/signal/mcp/Msg.d.ts +143 -0
  218. package/types/signal/mcp/index.d.ts +5 -0
  219. package/types/signal/mcp/mcpProtocol.d.ts +107 -0
  220. package/types/signal/mcp.d.ts +1 -0
  221. package/types/signal/openapi/openapi.d.ts +3 -3
  222. package/types/signal/schema/JsonSchemaBuilder.d.ts +47 -0
  223. package/types/signal/schema/index.d.ts +1 -0
  224. package/types/signal/schema.d.ts +1 -0
  225. package/types/signal/signalContext.d.ts +16 -1
  226. package/types/signal/slice.d.ts +8 -8
  227. package/types/signal/types.d.ts +1 -1
  228. package/types/store/actionTag.d.ts +21 -0
  229. package/types/store/agent/AgentBridge.d.ts +77 -0
  230. package/types/store/agent/AgentContext.d.ts +16 -0
  231. package/types/store/agent/AgentPrompts.d.ts +31 -0
  232. package/types/store/agent/AgentVisibility.d.ts +21 -0
  233. package/types/store/agent/ScreenReader.d.ts +11 -0
  234. package/types/store/agent/StoreCatalogue.d.ts +26 -0
  235. package/types/store/agent/StoreSurfaceSource.d.ts +18 -0
  236. package/types/store/agent/index.d.ts +9 -0
  237. package/types/store/agent/storeSurface.d.ts +14 -0
  238. package/types/store/agent/types.d.ts +49 -0
  239. package/types/store/agent.d.ts +1 -0
  240. package/types/store/agentic/StToolBuilder.d.ts +41 -0
  241. package/types/store/agentic/attachAgentic.d.ts +14 -0
  242. package/types/store/agentic/index.d.ts +5 -0
  243. package/types/store/agentic/readableValue.d.ts +3 -0
  244. package/types/store/agentic/useStExpose.d.ts +8 -0
  245. package/types/store/agentic/useStState.d.ts +12 -0
  246. package/types/store/agentic.d.ts +1 -0
  247. package/types/store/baseSt.d.ts +29 -22
  248. package/types/store/databaseStateNames.d.ts +25 -0
  249. package/types/store/formSetterNames.d.ts +16 -0
  250. package/types/store/index.d.ts +7 -0
  251. package/types/store/rootStore.d.ts +5 -1
  252. package/types/store/sliceRole.d.ts +25 -0
  253. package/types/store/store.d.ts +7 -2
  254. package/types/store/storeInstance.d.ts +33 -1
  255. package/types/store/storeRegistry.d.ts +5 -0
  256. package/types/store/types.d.ts +15 -0
  257. package/types/store/withSelector.d.ts +7 -8
  258. package/types/test/registerDom.d.ts +1 -0
  259. package/types/ui/Agent/Approval.d.ts +7 -0
  260. package/types/ui/Agent/Bubble.d.ts +13 -0
  261. package/types/ui/Agent/Chat.d.ts +24 -0
  262. package/types/ui/Agent/Context.d.ts +9 -0
  263. package/types/ui/Agent/Dock.d.ts +16 -0
  264. package/types/ui/Agent/Guide.d.ts +9 -0
  265. package/types/ui/Agent/Section.d.ts +10 -0
  266. package/types/ui/Agent/StateKey.d.ts +16 -0
  267. package/types/ui/Agent/Tool.d.ts +15 -0
  268. package/types/ui/Agent/Transcript.d.ts +13 -0
  269. package/types/ui/Agent/Zone.d.ts +23 -0
  270. package/types/ui/Agent/fetchRunner.d.ts +12 -0
  271. package/types/ui/Agent/index.d.ts +17 -0
  272. package/types/ui/Agent/index_.d.ts +1 -0
  273. package/types/ui/Agent/sessionHistory.d.ts +12 -0
  274. package/types/ui/Agent.d.ts +1 -0
  275. package/types/ui/Badge.d.ts +1 -1
  276. package/types/ui/Button.d.ts +1 -1
  277. package/types/ui/CsrImage.d.ts +1 -1
  278. package/types/ui/Dropdown.d.ts +2 -0
  279. package/types/ui/Image.d.ts +3 -3
  280. package/types/ui/Layout/BottomInset.d.ts +2 -1
  281. package/types/ui/Layout/index.d.ts +1 -1
  282. package/types/ui/Signal/style.d.ts +4 -1
  283. package/types/ui/UiOverride/context.d.ts +14 -2
  284. package/types/ui/agentAttrs.d.ts +14 -0
  285. package/types/ui/index.d.ts +4 -1
  286. package/types/ui/overlayLayer.d.ts +24 -0
  287. package/types/ui/recipe/badgeRecipe.d.ts +7 -3
  288. package/types/ui/recipe/buttonRecipe.d.ts +7 -3
  289. package/types/ui/recipe/inputRecipe.d.ts +5 -1
  290. package/types/vendor/use-agentic/AgentProvider.d.ts +18 -0
  291. package/types/vendor/use-agentic/AgentScope.d.ts +9 -0
  292. package/types/vendor/use-agentic/AgentSession.d.ts +50 -0
  293. package/types/vendor/use-agentic/Agentic.d.ts +21 -0
  294. package/types/vendor/use-agentic/AgenticSurface.d.ts +44 -0
  295. package/types/vendor/use-agentic/httpRunner.d.ts +15 -0
  296. package/types/vendor/use-agentic/index.d.ts +13 -0
  297. package/types/vendor/use-agentic/surfaceContext.d.ts +5 -0
  298. package/types/vendor/use-agentic/types.d.ts +133 -0
  299. package/types/vendor/use-agentic/useAgent.d.ts +4 -0
  300. package/types/vendor/use-agentic/useAgentGuide.d.ts +6 -0
  301. package/types/vendor/use-agentic/useAgentResource.d.ts +7 -0
  302. package/types/vendor/use-agentic/useAgentState.d.ts +13 -0
  303. package/types/vendor/use-agentic/useAgentTool.d.ts +16 -0
  304. package/types/vendor/use-agentic.d.ts +1 -0
  305. package/types/webkit/index.d.ts +3 -0
  306. package/types/webkit/lazy.d.ts +12 -0
  307. package/types/webkit/useCsrValues.d.ts +3 -3
  308. package/types/webkit/useEscapeKey.d.ts +5 -0
  309. package/types/webkit/useFrameRuntime.d.ts +6 -1
  310. package/types/webkit/useScreenScope.d.ts +18 -0
  311. package/ui/Agent/Approval.tsx +29 -0
  312. package/ui/Agent/Bubble.tsx +74 -0
  313. package/ui/Agent/Chat.tsx +225 -0
  314. package/ui/Agent/Context.tsx +38 -0
  315. package/ui/Agent/Dock.tsx +72 -0
  316. package/ui/Agent/Guide.tsx +16 -0
  317. package/ui/Agent/Section.tsx +24 -0
  318. package/ui/Agent/StateKey.tsx +44 -0
  319. package/ui/Agent/Tool.tsx +66 -0
  320. package/ui/Agent/Transcript.tsx +33 -0
  321. package/ui/Agent/Zone.tsx +48 -0
  322. package/ui/Agent/fetchRunner.ts +30 -0
  323. package/ui/Agent/index.ts +12 -0
  324. package/ui/Agent/index_.tsx +4 -0
  325. package/ui/Agent/sessionHistory.ts +33 -0
  326. package/ui/Badge.tsx +3 -3
  327. package/ui/BottomSheet.tsx +5 -0
  328. package/ui/Button.tsx +6 -2
  329. package/ui/Constant/Doc.tsx +1 -1
  330. package/ui/CsrImage.tsx +1 -1
  331. package/ui/Data/ListContainer.tsx +1 -1
  332. package/ui/DatePicker.tsx +5 -4
  333. package/ui/Dialog/Modal.tsx +12 -15
  334. package/ui/DraggableList.tsx +3 -1
  335. package/ui/Dropdown.tsx +33 -11
  336. package/ui/Field.tsx +30 -16
  337. package/ui/Image.tsx +3 -3
  338. package/ui/Input.tsx +14 -5
  339. package/ui/Layout/BottomInset.tsx +6 -1
  340. package/ui/Load/Units.tsx +11 -2
  341. package/ui/Load/View.tsx +7 -2
  342. package/ui/Loading/ProgressBar.tsx +8 -1
  343. package/ui/Menu.tsx +7 -8
  344. package/ui/Model/EditModal.tsx +37 -2
  345. package/ui/Model/SureToRemove.tsx +2 -1
  346. package/ui/Model/index_.tsx +42 -15
  347. package/ui/ObjectId.tsx +3 -4
  348. package/ui/Pagination.tsx +3 -4
  349. package/ui/Popconfirm.tsx +8 -7
  350. package/ui/Select.tsx +6 -4
  351. package/ui/Signal/RestApi.tsx +43 -16
  352. package/ui/Signal/WebSocket.tsx +1 -1
  353. package/ui/Signal/style.ts +6 -1
  354. package/ui/Switch.tsx +2 -0
  355. package/ui/System/CSR.tsx +6 -2
  356. package/ui/System/ThemeToggle.tsx +55 -33
  357. package/ui/ToggleSelect.tsx +4 -3
  358. package/ui/Tooltip.tsx +2 -1
  359. package/ui/UiOverride/context.ts +14 -2
  360. package/ui/agentAttrs.ts +19 -0
  361. package/ui/index.ts +10 -1
  362. package/ui/overlayLayer.ts +39 -0
  363. package/ui/recipe/badgeRecipe.ts +22 -3
  364. package/ui/recipe/buttonRecipe.ts +51 -2
  365. package/ui/recipe/factory.ts +2 -2
  366. package/ui/recipe/inputRecipe.ts +18 -4
  367. package/vendor/use-agentic/AgentProvider.tsx +39 -0
  368. package/vendor/use-agentic/AgentScope.tsx +20 -0
  369. package/vendor/use-agentic/AgentSession.ts +292 -0
  370. package/vendor/use-agentic/Agentic.tsx +44 -0
  371. package/vendor/use-agentic/AgenticSurface.ts +294 -0
  372. package/vendor/use-agentic/WIRE.md +57 -0
  373. package/vendor/use-agentic/httpRunner.ts +115 -0
  374. package/vendor/use-agentic/index.ts +14 -0
  375. package/vendor/use-agentic/surfaceContext.ts +9 -0
  376. package/vendor/use-agentic/types.ts +144 -0
  377. package/vendor/use-agentic/useAgent.ts +17 -0
  378. package/vendor/use-agentic/useAgentGuide.ts +16 -0
  379. package/vendor/use-agentic/useAgentResource.ts +30 -0
  380. package/vendor/use-agentic/useAgentState.ts +61 -0
  381. package/vendor/use-agentic/useAgentTool.ts +55 -0
  382. package/webkit/bootCsr.tsx +2 -33
  383. package/webkit/index.ts +3 -0
  384. package/webkit/lazy.tsx +27 -3
  385. package/webkit/useCsrValues.ts +121 -4
  386. package/webkit/useEscapeKey.tsx +42 -0
  387. package/webkit/useFrameRuntime.ts +65 -32
  388. package/webkit/useScreenScope.tsx +49 -0
@@ -0,0 +1,245 @@
1
+ import { type BaseEnv, ENDPOINT_META } from "akanjs/base";
2
+ import { Logger } from "akanjs/common";
3
+ import { DictionaryLookup } from "akanjs/dictionary";
4
+ import { NoDocumentError } from "akanjs/document";
5
+ import type { InjectRegistry, LiveRegistry } from "akanjs/service";
6
+ import type { Endpoint, EndpointCls } from "../../signal/endpoint";
7
+ import type { EndpointInfo } from "../../signal/endpointInfo";
8
+ import type { GuardCls } from "../../signal/guard";
9
+ import {
10
+ McpDocument,
11
+ McpErrorCode,
12
+ type McpExposedEndpoint,
13
+ type McpToolResult,
14
+ type PromptMessage,
15
+ } from "../../signal/mcp";
16
+ import type { MiddlewareCls } from "../../signal/middleware";
17
+ import { SignalContext } from "../../signal/signalContext";
18
+ import { McpExecutionContext } from "./McpExecutionContext";
19
+
20
+ /** Raised when the caller presented no credential at all, so the client should be told to authenticate. */
21
+ export class McpAuthRequiredError extends Error {}
22
+
23
+ /**
24
+ * A prompt failure whose message has already been through `#message` and is safe to put on the wire.
25
+ *
26
+ * It carries its JSON-RPC code because a prompt has no `isError` result to put a refusal in, so the code is the
27
+ * only place left to say whose fault it was. Without it a mistyped argument reads as `-32603 internal error`,
28
+ * while the *missing*-argument check `prompts/get` does itself answers `-32602` — the same mistake, two codes.
29
+ */
30
+ export class McpPromptError extends Error {
31
+ readonly code: number;
32
+ constructor(message: string, code: number) {
33
+ super(message);
34
+ this.code = code;
35
+ }
36
+ }
37
+
38
+ interface McpDispatcherProps {
39
+ registry: InjectRegistry;
40
+ env: BaseEnv;
41
+ live: LiveRegistry;
42
+ middleware: Map<string, MiddlewareCls>;
43
+ /** The one language error text is resolved in, matching the catalogue the client was handed. */
44
+ language?: string;
45
+ }
46
+
47
+ /** Executes one MCP tool call or resource read through the ordinary signal pipeline. */
48
+ export class McpDispatcher {
49
+ static readonly logger = new Logger("McpDispatcher");
50
+
51
+ readonly #props: McpDispatcherProps;
52
+ #endpoints: Map<string, { endpointInfo: EndpointInfo; endpoint: Endpoint }> | null = null;
53
+ /**
54
+ * Built on first use and then held: the merge behind it is not free, a server whose calls all succeed never
55
+ * needs it, and a caller that types an argument wrong drives that path as often as it likes.
56
+ *
57
+ * Not deferred for the reason the endpoint index below is. Dictionaries register at module evaluation, before
58
+ * any route exists — `McpRouter` builds one at boot to resolve the catalogue's own text — so a lookup made in
59
+ * the constructor would be correct, just paid for by every process whether or not a call ever fails.
60
+ */
61
+ #lookup: DictionaryLookup | null = null;
62
+
63
+ constructor(props: McpDispatcherProps) {
64
+ this.#props = props;
65
+ }
66
+
67
+ async call(exposed: McpExposedEndpoint, args: Record<string, unknown>, req: Request): Promise<McpToolResult> {
68
+ const found = this.#index().get(exposed.key);
69
+ if (!found) return McpDispatcher.#failure(`Tool "${exposed.key}" is declared but not mounted on this server.`);
70
+ try {
71
+ const value = await this.#exec(exposed.key, found, args, req);
72
+ const structuredContent = McpDocument.structuredContent(exposed.endpoint, value);
73
+ return {
74
+ content: [{ type: "text", text: McpDispatcher.#text(structuredContent, value) }],
75
+ ...(structuredContent === undefined ? {} : { structuredContent }),
76
+ isError: false,
77
+ };
78
+ } catch (error) {
79
+ const status = McpDispatcher.#statusOf(error);
80
+
81
+ if ((status === 401 || status === 403) && !req.headers.get("authorization")) throw new McpAuthRequiredError();
82
+ return McpDispatcher.#failure(this.#message(error, status, exposed.refName));
83
+ }
84
+ }
85
+
86
+ /**
87
+ * A prompt is user-chosen, not model-chosen, so a failure has nowhere to go but the JSON-RPC error — there is
88
+ * no `isError` result the model could read and recover from. Errors propagate to the router unchanged.
89
+ *
90
+ * The messages arrive already normalized: `SignalContext` does that for every `prompt`, so this route and the
91
+ * plain HTTP one return the same shape.
92
+ */
93
+ async prompt(exposed: McpExposedEndpoint, args: Record<string, unknown>, req: Request): Promise<PromptMessage[]> {
94
+ const found = this.#index().get(exposed.key);
95
+ if (!found)
96
+ throw new McpPromptError(
97
+ `Prompt "${exposed.key}" is declared but not mounted on this server.`,
98
+ McpErrorCode.internal,
99
+ );
100
+ try {
101
+ return (await this.#exec(exposed.key, found, args, req)) as PromptMessage[];
102
+ } catch (error) {
103
+ const status = McpDispatcher.#statusOf(error);
104
+ if ((status === 401 || status === 403) && !req.headers.get("authorization")) throw new McpAuthRequiredError();
105
+ throw new McpPromptError(this.#message(error, status, exposed.refName), McpDispatcher.#codeOf(status));
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Drops catalogue entries whose account-scoped guards refuse this caller — an anonymous agent should not be
111
+ * offered a shelf of admin tools it can only fail at. Entries with no such guard are kept and stopped at call
112
+ * time instead, so the listing is a UX filter and never the access decision.
113
+ *
114
+ * The context is deliberately not `init()`-ed: parsing arguments that a listing does not have would throw,
115
+ * and a resource guard reached here reads `undefined` and fails closed, which is the behaviour we want.
116
+ */
117
+ async filterForAccount<T extends { name: string }>(items: T[], req: Request): Promise<T[]> {
118
+ const index = this.#index();
119
+
120
+ const ids = new Map<GuardCls, number>();
121
+ const idOf = (GuardCls: GuardCls) => {
122
+ const id = ids.get(GuardCls);
123
+ if (id !== undefined) return id;
124
+ ids.set(GuardCls, ids.size);
125
+ return ids.size - 1;
126
+ };
127
+ const cached = new Map<string, Promise<boolean>>();
128
+ const verdicts = await Promise.all(
129
+ items.map(async (item) => {
130
+ const found = index.get(item.name);
131
+ if (!found) return true;
132
+ const guards = (found.endpointInfo.signalOption.guards ?? []).filter(
133
+ (GuardCls) => GuardCls.scope === "account",
134
+ );
135
+ if (!guards.length) return true;
136
+ const key = guards
137
+ .map(idOf)
138
+ .sort((a, b) => a - b)
139
+ .join(",");
140
+ const verdict =
141
+ cached.get(key) ??
142
+ new SignalContext(item.name, req as Bun.BunRequest, {
143
+ ...this.#props,
144
+ endpointInfo: found.endpointInfo,
145
+ adaptor: found.endpoint,
146
+ ctx: new McpExecutionContext(req, {}),
147
+ }).canListForAccount();
148
+ cached.set(key, verdict);
149
+ return await verdict;
150
+ }),
151
+ );
152
+ return items.filter((_item, idx) => verdicts[idx]);
153
+ }
154
+
155
+ async #exec(
156
+ key: string,
157
+ { endpointInfo, endpoint }: { endpointInfo: EndpointInfo; endpoint: Endpoint },
158
+ args: Record<string, unknown>,
159
+ req: Request,
160
+ ) {
161
+
162
+ const context = await new SignalContext(key, req as Bun.BunRequest, {
163
+ ...this.#props,
164
+ endpointInfo,
165
+ adaptor: endpoint,
166
+ ctx: new McpExecutionContext(req, args),
167
+ }).init();
168
+ return (await context.exec()) as unknown;
169
+ }
170
+
171
+ /**
172
+ * Built on first use and kept: nothing before a `tools/call` needs it, and a router constructed to answer one
173
+ * request — which tests and tooling do — should not walk the whole registry to do it. Not an ordering
174
+ * workaround; DI has finished filling the registry long before any route is created.
175
+ *
176
+ * Keyed by endpoint key, which is globally unique and is what MCP names a tool by.
177
+ */
178
+ #index() {
179
+ if (this.#endpoints) return this.#endpoints;
180
+ const endpoints = new Map<string, { endpointInfo: EndpointInfo; endpoint: Endpoint }>();
181
+ for (const [endpointCls, endpoint] of this.#props.registry.endpoint.entries()) {
182
+ const meta = (endpointCls as EndpointCls)[ENDPOINT_META] as { [key: string]: EndpointInfo };
183
+ for (const [key, endpointInfo] of Object.entries(meta)) endpoints.set(key, { endpointInfo, endpoint });
184
+ }
185
+ this.#endpoints = endpoints;
186
+ return endpoints;
187
+ }
188
+
189
+ #message(error: unknown, status: number | undefined, refName: string): string {
190
+
191
+ if (error instanceof NoDocumentError) return `No ${refName} found for the arguments given.`;
192
+ if (status && status < 500) {
193
+ const raw = error instanceof Error ? error.message : String(error);
194
+
195
+ this.#lookup ??= new DictionaryLookup(this.#props.language);
196
+ const text = this.#lookup.text(raw);
197
+ if (text) return text;
198
+
199
+ if (status === 401 || status === 403) return "You are not permitted to perform this action.";
200
+ return raw;
201
+ }
202
+
203
+ McpDispatcher.logger.error(`MCP call failed: ${error instanceof Error ? (error.stack ?? error.message) : error}`);
204
+ return "The server failed to complete this request.";
205
+ }
206
+
207
+ /**
208
+ * Anything without a status is treated as a crash, so the two failures an agent can trigger at will carry one:
209
+ * `McpArgumentError` (400) and `NoDocumentError` (404). Without them a mistyped id logged a stack and answered
210
+ * "the server failed", which is both a lie and a log-spam path any caller could drive.
211
+ */
212
+ static #statusOf(error: unknown): number | undefined {
213
+ const status = (error as { statusCode?: unknown } | null)?.statusCode;
214
+ return typeof status === "number" ? status : undefined;
215
+ }
216
+
217
+ /**
218
+ * The same split `#message` makes, in the currency a prompt reports failures in. `-32602` covers a not-found
219
+ * as well as a bad argument: this revision retired `-32002` and points resource-does-not-exist at invalid
220
+ * params, so the two caller mistakes share one code by the spec's own choice rather than for want of another.
221
+ */
222
+ static #codeOf(status: number | undefined) {
223
+ return status && status < 500 ? McpErrorCode.invalidParams : McpErrorCode.internal;
224
+ }
225
+
226
+ /**
227
+ * The text block every result carries, whether or not a structured one goes with it.
228
+ *
229
+ * A structured result is mirrored as its JSON, which is what the spec asks for so a client with no structured
230
+ * support still reads the payload. A scalar return has no structured half to mirror, and encoding one as JSON
231
+ * spent the block on syntax: a tool returning an id answered `"507f…"`, quotes included, which a model then has
232
+ * to know to strip. Numbers and booleans read the same either way; only a string differs.
233
+ *
234
+ * `JSON.stringify(undefined)` is `undefined` rather than a string, so a void return would otherwise ship a
235
+ * content block with no `text` at all.
236
+ */
237
+ static #text(structuredContent: unknown, value: unknown) {
238
+ if (structuredContent === undefined && typeof value === "string") return value;
239
+ return JSON.stringify(structuredContent ?? value) ?? "null";
240
+ }
241
+
242
+ static #failure(message: string): McpToolResult {
243
+ return { content: [{ type: "text", text: message }], isError: true };
244
+ }
245
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * One `text/event-stream` response carrying the notifications a single request produced, ending with that
3
+ * request's own result.
4
+ *
5
+ * This is the only channel a server has for pushing anything: `2026-07-28` removed the GET stream, session
6
+ * resumption and server-initiated requests, so nothing may be sent that is not related to a request in flight.
7
+ * Closing the stream is also how the client cancels — `notifications/cancelled` is stdio-only — which is why
8
+ * `cancel` is a constructor argument rather than something a caller could forget to wire.
9
+ */
10
+ export class McpEventStream {
11
+ /** Below any common proxy idle timeout, so a slow tool does not have its connection reaped mid-work. */
12
+ static readonly keepAliveMs = 15_000;
13
+
14
+ readonly #encoder = new TextEncoder();
15
+ readonly #stream: ReadableStream<Uint8Array>;
16
+ #controller: ReadableStreamDefaultController<Uint8Array> | null = null;
17
+ #keepAlive: ReturnType<typeof setInterval> | null = null;
18
+
19
+ constructor(onCancel: () => void) {
20
+ this.#stream = new ReadableStream<Uint8Array>({
21
+ start: (controller) => {
22
+ this.#controller = controller;
23
+ this.#keepAlive = setInterval(() => this.#enqueue(":\r\n"), McpEventStream.keepAliveMs);
24
+
25
+ this.#keepAlive.unref?.();
26
+ },
27
+ cancel: () => {
28
+ this.#stopKeepAlive();
29
+ this.#controller = null;
30
+ onCancel();
31
+ },
32
+ });
33
+ }
34
+
35
+ response() {
36
+ return new Response(this.#stream, {
37
+ headers: {
38
+ "content-type": "text/event-stream",
39
+
40
+ "cache-control": "no-cache, no-transform",
41
+ connection: "keep-alive",
42
+ "x-accel-buffering": "no",
43
+ },
44
+ });
45
+ }
46
+
47
+ write(message: object) {
48
+ this.#enqueue(`data: ${JSON.stringify(message)}\n\n`);
49
+ }
50
+
51
+ close() {
52
+ this.#stopKeepAlive();
53
+ const controller = this.#controller;
54
+ this.#controller = null;
55
+ try {
56
+ controller?.close();
57
+ } catch {
58
+ }
59
+ }
60
+
61
+ #enqueue(chunk: string) {
62
+ if (!this.#controller) return;
63
+ try {
64
+ this.#controller.enqueue(this.#encoder.encode(chunk));
65
+ } catch {
66
+
67
+ this.#stopKeepAlive();
68
+ this.#controller = null;
69
+ }
70
+ }
71
+
72
+ #stopKeepAlive() {
73
+ if (this.#keepAlive) clearInterval(this.#keepAlive);
74
+ this.#keepAlive = null;
75
+ }
76
+ }
@@ -0,0 +1,105 @@
1
+ import { type Cls, PrimitiveRegistry, type PrimitiveScalar } from "akanjs/base";
2
+ import { isMcpDescribableArg } from "akanjs/common";
3
+ import { deserialize, serialize } from "akanjs/constant";
4
+ import type { EndpointInfo } from "../../signal/endpointInfo";
5
+ import { HttpExecutionContext } from "../../signal/signalContext";
6
+
7
+ type McpArg = EndpointInfo["args"][number];
8
+
9
+ /**
10
+ * An argument the caller can fix, carrying a 400 so the dispatcher reports it as a tool error rather than as a
11
+ * server failure. Everything that rejects an argument — the nullable check, `ID._parse`, a scalar's own
12
+ * validator — throws a bare `Error`, and a bare `Error` is indistinguishable from a crash.
13
+ */
14
+ export class McpArgumentError extends Error {
15
+ readonly statusCode = 400;
16
+ }
17
+
18
+ /**
19
+ * Runs an endpoint for an MCP call while staying an HTTP context.
20
+ *
21
+ * MCP arrives over HTTP and the whole authorization stack reads the request through this context —
22
+ * `AccountMiddleware` resolves the bearer token off `getHttpContext().req`, and `Self`/`Me` and every guard read
23
+ * what it left there. A transport of its own would not adapt that stack, it would bypass it.
24
+ */
25
+ export class McpExecutionContext extends HttpExecutionContext {
26
+ readonly #arguments: Record<string, unknown>;
27
+
28
+ constructor(req: Request, args: Record<string, unknown>) {
29
+
30
+ super(req as Bun.BunRequest);
31
+ this.#arguments = args;
32
+ }
33
+
34
+ /**
35
+ * MCP passes one flat named object, so `param`/`search`/`body` all resolve by name from the same place. An
36
+ * absent value becomes `null` to match what a missing query string yields, letting `deserialize` apply the
37
+ * same nullability rules an HTTP call gets.
38
+ *
39
+ * A name nobody declared is the caller's mistake and is reported as one. `additionalProperties: false` travels
40
+ * in the published schema, but this server does not validate against it and plenty of clients do not either —
41
+ * so reading only the declared names dropped the rest in silence: `{ category, status }` on a slice that takes
42
+ * only `category` came back as a successful, unfiltered list, which a model reads as the filter having applied.
43
+ *
44
+ * "Declared" means what the *published schema* declares, which is why an `Any` argument counts as absent here.
45
+ * It is deliberately left out of that schema — the empty schema tells a model nothing — and the root list's raw
46
+ * `query` descriptor is the one that matters: read as sent, an agent could hand any model exposed through
47
+ * `mcp: { list: true }` an arbitrary query, which is precisely the narrowing a named filter slice exists to make
48
+ * deliberate. `additionalProperties: false` was never going to stop that on its own.
49
+ */
50
+ override async getArgs(endpointInfo: EndpointInfo): Promise<unknown[]> {
51
+ const declared = new Set(endpointInfo.args.filter(McpExecutionContext.#describable).map((arg) => arg.name));
52
+ const undeclared = Object.keys(this.#arguments).find((name) => !declared.has(name));
53
+ if (undeclared) throw new McpArgumentError(`Unknown argument "${undeclared}".`);
54
+ return endpointInfo.args.map((arg) => {
55
+ const value = McpExecutionContext.#lift(arg, this.#arguments[arg.name] ?? null);
56
+ try {
57
+ return deserialize(arg.argRef, arg.arrDepth, value, { key: arg.name, nullable: arg.option?.nullable });
58
+ } catch {
59
+
60
+ throw new McpArgumentError(McpExecutionContext.#argumentMessage(arg, value));
61
+ }
62
+ });
63
+ }
64
+
65
+ /**
66
+ * Returns the serialized value rather than a `Response`, so the router can put it straight into a JSON-RPC
67
+ * result. The `Response` in the signature is the base class's; `WebSocketExecutionContext` widens it the same
68
+ * way, and `SignalContext` only ever hands this value back to its caller.
69
+ */
70
+ override makeResponse(result: unknown, endpointInfo: EndpointInfo) {
71
+ if (endpointInfo.returns.arrDepth === 0 && PrimitiveRegistry.has(endpointInfo.returns.returnRef as Cls))
72
+ return result as unknown as Response;
73
+ return serialize(endpointInfo.returns.returnRef, endpointInfo.returns.arrDepth, result, "object", {
74
+ nullable: endpointInfo.returns.nullable,
75
+ }) as unknown as Response;
76
+ }
77
+
78
+ /**
79
+ * One value where a list was declared becomes a one-element list. Both callers produce it: form-style uri
80
+ * expansion writes `?tags=a` for a single tag, and a model routinely types a bare string for an array field.
81
+ * The http context never meets this because `searchParams.getAll` always returns an array, and `deserialize`
82
+ * hands a lone scalar straight back instead of lifting it — so the endpoint would receive a string where it
83
+ * iterates a list.
84
+ */
85
+ static #lift(arg: McpArg, value: unknown) {
86
+ return arg.arrDepth && value !== null && !Array.isArray(value) ? [value] : value;
87
+ }
88
+
89
+ /** The same rule `McpDocument` builds `properties` from, so what is refused is exactly what was not published. */
90
+ static #describable(arg: McpArg) {
91
+ const refName = PrimitiveRegistry.has(arg.argRef as Cls)
92
+ ? PrimitiveRegistry.getName(arg.argRef as typeof PrimitiveScalar)
93
+ : "";
94
+ return isMcpDescribableArg({ refName });
95
+ }
96
+
97
+ static #argumentMessage(arg: McpArg, value: unknown) {
98
+ if (value === null) return `Missing required argument "${arg.name}".`;
99
+ const primitive = PrimitiveRegistry.has(arg.argRef as Cls)
100
+ ? PrimitiveRegistry.getName(arg.argRef as typeof PrimitiveScalar)
101
+ : undefined;
102
+ const expected = primitive ? `${primitive}${"[]".repeat(arg.arrDepth)}` : undefined;
103
+ return `Invalid argument "${arg.name}"${expected ? `: expected ${expected}` : ""}.`;
104
+ }
105
+ }