@hotmeshio/long-tail 0.23.2 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (499) hide show
  1. package/build/adapters/express.d.ts +11 -1
  2. package/build/adapters/express.js +42 -41
  3. package/build/api/auth-sso.d.ts +1 -1
  4. package/build/api/bot-accounts.d.ts +2 -0
  5. package/build/api/bot-accounts.js +4 -0
  6. package/build/api/capabilities.d.ts +7 -2
  7. package/build/api/capabilities.js +13 -2
  8. package/build/api/escalations/analytics.js +5 -0
  9. package/build/api/escalations/bulk.d.ts +2 -0
  10. package/build/api/escalations/bulk.js +9 -4
  11. package/build/api/escalations/helpers.d.ts +5 -0
  12. package/build/api/escalations/helpers.js +7 -0
  13. package/build/api/escalations/metadata.js +3 -0
  14. package/build/api/escalations/single.d.ts +3 -2
  15. package/build/api/escalations/single.js +8 -3
  16. package/build/api/mcp/tools.d.ts +12 -0
  17. package/build/api/mcp/tools.js +113 -9
  18. package/build/api/scan-codes/choice.js +31 -7
  19. package/build/api/settings.js +9 -0
  20. package/build/api/tasks.d.ts +3 -3
  21. package/build/api/tasks.js +30 -7
  22. package/build/api/workflows/input-lookups.js +1 -1
  23. package/build/api/workflows/invocable.js +2 -2
  24. package/build/api/workflows/invocation.js +1 -1
  25. package/build/api/yaml-workflows/cron.d.ts +3 -2
  26. package/build/api/yaml-workflows/cron.js +6 -1
  27. package/build/api/yaml-workflows/deploy.d.ts +15 -2
  28. package/build/api/yaml-workflows/deploy.js +69 -2
  29. package/build/lib/db/schemas/038_oauth_server.sql +46 -0
  30. package/build/lib/db/schemas/039_nats_ws_tickets.sql +12 -0
  31. package/build/lib/events/browser-view.d.ts +20 -0
  32. package/build/lib/events/browser-view.js +117 -0
  33. package/build/lib/events/nats-ws-filter.d.ts +29 -0
  34. package/build/lib/events/nats-ws-filter.js +109 -0
  35. package/build/lib/events/nats-ws-proxy.d.ts +7 -0
  36. package/build/lib/events/nats-ws-proxy.js +86 -7
  37. package/build/lib/events/nats-ws-server-filter.d.ts +16 -0
  38. package/build/lib/events/nats-ws-server-filter.js +56 -0
  39. package/build/lib/events/nats-ws-ticket.d.ts +19 -0
  40. package/build/lib/events/nats-ws-ticket.js +63 -0
  41. package/build/lib/events/socketio.d.ts +10 -1
  42. package/build/lib/events/socketio.js +10 -3
  43. package/build/lib/http/index.d.ts +27 -0
  44. package/build/lib/http/index.js +55 -0
  45. package/build/modules/auth.d.ts +15 -24
  46. package/build/modules/auth.js +43 -126
  47. package/build/modules/capabilities.d.ts +62 -0
  48. package/build/modules/capabilities.js +188 -0
  49. package/build/modules/config.d.ts +19 -0
  50. package/build/modules/config.js +27 -0
  51. package/build/modules/defaults.d.ts +10 -0
  52. package/build/modules/defaults.js +12 -1
  53. package/build/modules/maintenance.d.ts +2 -0
  54. package/build/modules/maintenance.js +7 -0
  55. package/build/modules/mcp-auth.d.ts +11 -0
  56. package/build/modules/mcp-auth.js +56 -0
  57. package/build/modules/oauth-server.d.ts +18 -0
  58. package/build/modules/oauth-server.js +40 -0
  59. package/build/routes/agents.js +47 -14
  60. package/build/routes/announcements.js +2 -2
  61. package/build/routes/auth-sso.js +2 -2
  62. package/build/routes/auth.js +2 -2
  63. package/build/routes/bot-accounts.js +26 -3
  64. package/build/routes/capabilities.js +4 -4
  65. package/build/routes/controlplane.js +2 -2
  66. package/build/routes/dba.js +2 -2
  67. package/build/routes/delegation.js +2 -2
  68. package/build/routes/diagnostics.js +2 -2
  69. package/build/routes/docs.js +2 -2
  70. package/build/routes/domain.js +2 -2
  71. package/build/routes/escalations/accumulate.d.ts +1 -1
  72. package/build/routes/escalations/acting.d.ts +1 -1
  73. package/build/routes/escalations/analytics.d.ts +1 -1
  74. package/build/routes/escalations/bulk.d.ts +1 -1
  75. package/build/routes/escalations/facets.d.ts +1 -1
  76. package/build/routes/escalations/index.js +2 -2
  77. package/build/routes/escalations/list.d.ts +1 -1
  78. package/build/routes/escalations/metadata.d.ts +1 -1
  79. package/build/routes/escalations/related.d.ts +1 -1
  80. package/build/routes/escalations/resolve.d.ts +1 -1
  81. package/build/routes/escalations/single.d.ts +1 -1
  82. package/build/routes/escalations/single.js +1 -1
  83. package/build/routes/exports.js +14 -13
  84. package/build/routes/file-browser.js +9 -8
  85. package/build/routes/files.js +2 -2
  86. package/build/routes/index.js +4 -2
  87. package/build/routes/insight.js +5 -4
  88. package/build/routes/knowledge.js +2 -2
  89. package/build/routes/maintenance.js +2 -2
  90. package/build/routes/mcp-endpoint.d.ts +3 -1
  91. package/build/routes/mcp-endpoint.js +18 -8
  92. package/build/routes/mcp.js +35 -15
  93. package/build/routes/me.js +2 -2
  94. package/build/routes/namespaces.js +4 -3
  95. package/build/routes/nats-credentials.js +27 -3
  96. package/build/routes/oauth-server/authorize.d.ts +2 -0
  97. package/build/routes/oauth-server/authorize.js +110 -0
  98. package/build/routes/oauth-server/grants.d.ts +2 -0
  99. package/build/routes/oauth-server/grants.js +35 -0
  100. package/build/routes/oauth-server/index.d.ts +8 -0
  101. package/build/routes/oauth-server/index.js +52 -0
  102. package/build/routes/oauth-server/registration.d.ts +2 -0
  103. package/build/routes/oauth-server/registration.js +38 -0
  104. package/build/routes/oauth-server/token.d.ts +2 -0
  105. package/build/routes/oauth-server/token.js +100 -0
  106. package/build/routes/oauth-well-known.d.ts +8 -0
  107. package/build/routes/oauth-well-known.js +31 -0
  108. package/build/routes/oauth.js +2 -2
  109. package/build/routes/overview.js +2 -2
  110. package/build/routes/personas.js +2 -2
  111. package/build/routes/pipelines.js +6 -5
  112. package/build/routes/roles.js +2 -2
  113. package/build/routes/scan-codes.js +2 -2
  114. package/build/routes/settings.js +2 -2
  115. package/build/routes/tasks.js +5 -5
  116. package/build/routes/topics.js +21 -9
  117. package/build/routes/users.js +25 -22
  118. package/build/routes/workflow-sets.js +13 -12
  119. package/build/routes/workflows/config.js +15 -2
  120. package/build/routes/workflows/discovery.js +2 -2
  121. package/build/routes/workflows/index.js +2 -2
  122. package/build/routes/workflows/invocation.js +11 -10
  123. package/build/routes/yaml-workflows/cron.js +20 -7
  124. package/build/routes/yaml-workflows/crud.js +13 -12
  125. package/build/routes/yaml-workflows/deployment.js +11 -10
  126. package/build/routes/yaml-workflows/index.js +2 -2
  127. package/build/routes/yaml-workflows/versions.js +2 -2
  128. package/build/services/agent/authority.d.ts +15 -0
  129. package/build/services/agent/authority.js +59 -0
  130. package/build/services/agent/trigger-registry.js +7 -2
  131. package/build/services/auth/bot-api-key.d.ts +2 -0
  132. package/build/services/auth/bot-api-key.js +10 -0
  133. package/build/services/auth/oauth-server/access-token.d.ts +36 -0
  134. package/build/services/auth/oauth-server/access-token.js +80 -0
  135. package/build/services/auth/oauth-server/authorization.d.ts +47 -0
  136. package/build/services/auth/oauth-server/authorization.js +54 -0
  137. package/build/services/auth/oauth-server/constants.d.ts +11 -0
  138. package/build/services/auth/oauth-server/constants.js +16 -0
  139. package/build/services/auth/oauth-server/index.d.ts +3 -0
  140. package/build/services/auth/oauth-server/index.js +27 -0
  141. package/build/services/auth/oauth-server/metadata.d.ts +21 -0
  142. package/build/services/auth/oauth-server/metadata.js +53 -0
  143. package/build/services/auth/oauth-server/registration.d.ts +42 -0
  144. package/build/services/auth/oauth-server/registration.js +134 -0
  145. package/build/services/auth/oauth-server/sql.d.ts +50 -0
  146. package/build/services/auth/oauth-server/sql.js +156 -0
  147. package/build/services/auth/oauth-server/store.d.ts +88 -0
  148. package/build/services/auth/oauth-server/store.js +171 -0
  149. package/build/services/auth/sql.d.ts +1 -0
  150. package/build/services/auth/sql.js +3 -1
  151. package/build/services/cron/index.js +5 -3
  152. package/build/services/escalation/queries.js +7 -2
  153. package/build/services/export/index.d.ts +10 -0
  154. package/build/services/export/index.js +27 -0
  155. package/build/services/invocation-access.d.ts +25 -4
  156. package/build/services/invocation-access.js +39 -7
  157. package/build/services/maintenance/index.js +8 -0
  158. package/build/services/mcp/client/connection-dispatch.d.ts +6 -1
  159. package/build/services/mcp/client/connection-dispatch.js +3 -2
  160. package/build/services/mcp/client/connection-lifecycle.d.ts +10 -2
  161. package/build/services/mcp/client/connection-lifecycle.js +45 -7
  162. package/build/services/mcp/client/connection-test.js +2 -6
  163. package/build/services/mcp/client/connection.d.ts +1 -1
  164. package/build/services/mcp/client/connection.js +3 -1
  165. package/build/services/mcp/client/index.d.ts +2 -2
  166. package/build/services/mcp/client/index.js +4 -1
  167. package/build/services/mcp/client/network-transport.d.ts +12 -0
  168. package/build/services/mcp/client/network-transport.js +20 -0
  169. package/build/services/mcp/client/tools.d.ts +13 -0
  170. package/build/services/mcp/client/tools.js +18 -0
  171. package/build/services/mcp/db-server/index.js +2 -1
  172. package/build/services/mcp/external-server.d.ts +9 -4
  173. package/build/services/mcp/external-server.js +34 -11
  174. package/build/services/mcp/playwright-server/index.js +2 -1
  175. package/build/services/mcp/registered-tools.d.ts +3 -0
  176. package/build/services/mcp/registered-tools.js +7 -0
  177. package/build/services/mcp/seed-service-account.d.ts +4 -1
  178. package/build/services/mcp/seed-service-account.js +11 -6
  179. package/build/services/mcp/server-lifecycle.js +2 -1
  180. package/build/services/workflow-invocation.d.ts +16 -3
  181. package/build/services/workflow-invocation.js +42 -10
  182. package/build/services/yaml-workflow/deployer.d.ts +10 -2
  183. package/build/services/yaml-workflow/deployer.js +17 -5
  184. package/build/services/yaml-workflow/invoke.js +31 -26
  185. package/build/services/yaml-workflow/workers/register.js +3 -13
  186. package/build/services/yaml-workflow/workers/step-tool.d.ts +7 -0
  187. package/build/services/yaml-workflow/workers/step-tool.js +69 -0
  188. package/build/start/config.js +7 -0
  189. package/build/start/index.js +4 -22
  190. package/build/start/server.d.ts +6 -4
  191. package/build/start/server.js +11 -35
  192. package/build/start/socket-auth.js +2 -1
  193. package/build/start/workers.js +1 -1
  194. package/build/system/mcp-servers/admin/agent-subscriptions.js +25 -1
  195. package/build/system/mcp-servers/admin/agents.js +25 -2
  196. package/build/system/mcp-servers/admin/announcements.js +3 -2
  197. package/build/system/mcp-servers/admin/bot-accounts.js +37 -5
  198. package/build/system/mcp-servers/admin/escalations.d.ts +3 -5
  199. package/build/system/mcp-servers/admin/escalations.js +74 -70
  200. package/build/system/mcp-servers/admin/exports.js +7 -1
  201. package/build/system/mcp-servers/admin/index.js +24 -25
  202. package/build/system/mcp-servers/admin/overview.d.ts +2 -2
  203. package/build/system/mcp-servers/admin/run-read.d.ts +2 -0
  204. package/build/system/mcp-servers/admin/run-read.js +5 -0
  205. package/build/system/mcp-servers/admin/scan-codes.d.ts +2 -2
  206. package/build/system/mcp-servers/admin/scan-codes.js +5 -11
  207. package/build/system/mcp-servers/admin/schemas.d.ts +26 -26
  208. package/build/system/mcp-servers/admin/tasks.js +7 -2
  209. package/build/system/mcp-servers/admin/users.js +31 -4
  210. package/build/system/mcp-servers/admin/workflow-config.js +12 -1
  211. package/build/system/mcp-servers/admin/workflows.js +27 -5
  212. package/build/system/mcp-servers/admin/yaml-workflows.js +13 -21
  213. package/build/system/mcp-servers/caller-auth.d.ts +18 -0
  214. package/build/system/mcp-servers/caller-auth.js +29 -0
  215. package/build/system/mcp-servers/claude-code.js +2 -1
  216. package/build/system/mcp-servers/db-query/index.js +2 -1
  217. package/build/system/mcp-servers/file-storage.js +2 -1
  218. package/build/system/mcp-servers/http-fetch.js +2 -1
  219. package/build/system/mcp-servers/human-queue.js +7 -3
  220. package/build/system/mcp-servers/oauth.js +31 -4
  221. package/build/system/mcp-servers/schema-exchange.js +2 -1
  222. package/build/system/mcp-servers/vision.d.ts +1 -0
  223. package/build/system/mcp-servers/vision.js +17 -7
  224. package/build/system/mcp-servers/workflow.js +13 -25
  225. package/build/system/seed/tool-manifests-admin.d.ts +2 -17985
  226. package/build/system/seed/tool-manifests-admin.js +121 -121
  227. package/build/system/seed/tool-manifests-data.d.ts +8 -374
  228. package/build/system/seed/tool-manifests-data.js +22 -4
  229. package/build/system/seed/tool-manifests-escalation.d.ts +2 -352
  230. package/build/system/seed/tool-manifests-escalation.js +11 -1
  231. package/build/system/seed/tool-manifests-events.d.ts +2 -116
  232. package/build/system/seed/tool-manifests-events.js +6 -2
  233. package/build/system/seed/tool-manifests-knowledge.d.ts +2 -221
  234. package/build/system/seed/tool-manifests-knowledge.js +41 -1
  235. package/build/system/seed/tool-manifests-workflows.d.ts +2 -71
  236. package/build/system/seed/tool-manifests-workflows.js +3 -1
  237. package/build/system/workflows/shared/principal-tools.d.ts +20 -0
  238. package/build/system/workflows/shared/principal-tools.js +64 -0
  239. package/build/system/workflows/shared/tool-executor.js +21 -11
  240. package/build/system/workflows/shared/tool-loader.js +8 -1
  241. package/build/tsconfig.tsbuildinfo +1 -1
  242. package/build/types/auth.d.ts +1 -1
  243. package/build/types/capability.d.ts +14 -0
  244. package/build/types/capability.js +2 -0
  245. package/build/types/events.d.ts +1 -1
  246. package/build/types/index.d.ts +3 -1
  247. package/build/types/maintenance.d.ts +2 -2
  248. package/build/types/mcp.d.ts +3 -1
  249. package/build/types/oauth-server.d.ts +52 -0
  250. package/build/types/oauth-server.js +2 -0
  251. package/build/types/startup.d.ts +15 -7
  252. package/build/vitest.config.js +2 -1
  253. package/build/vitest.fast.config.d.ts +2 -0
  254. package/build/vitest.fast.config.js +20 -0
  255. package/build/vitest.llm.config.d.ts +2 -0
  256. package/build/vitest.llm.config.js +16 -0
  257. package/dashboard/dist/assets/{AdminDashboard-BPWsgMfZ.js → AdminDashboard-B3mkMIOT.js} +2 -2
  258. package/dashboard/dist/assets/{AdminDashboard-BPWsgMfZ.js.map → AdminDashboard-B3mkMIOT.js.map} +1 -1
  259. package/dashboard/dist/assets/{AgentConfigPage-De9imyo5.js → AgentConfigPage-CQj2B678.js} +2 -2
  260. package/dashboard/dist/assets/{AgentConfigPage-De9imyo5.js.map → AgentConfigPage-CQj2B678.js.map} +1 -1
  261. package/dashboard/dist/assets/{AgentDetailPage-B6o96Y5G.js → AgentDetailPage-CzrD8JJI.js} +3 -3
  262. package/dashboard/dist/assets/{AgentDetailPage-B6o96Y5G.js.map → AgentDetailPage-CzrD8JJI.js.map} +1 -1
  263. package/dashboard/dist/assets/{AgentsPage-DMEmiK_W.js → AgentsPage-jg2OFwyW.js} +2 -2
  264. package/dashboard/dist/assets/{AgentsPage-DMEmiK_W.js.map → AgentsPage-jg2OFwyW.js.map} +1 -1
  265. package/dashboard/dist/assets/{AvailableEscalationsPage-DeYMngwE.js → AvailableEscalationsPage-IS28XBRe.js} +2 -2
  266. package/dashboard/dist/assets/{AvailableEscalationsPage-DeYMngwE.js.map → AvailableEscalationsPage-IS28XBRe.js.map} +1 -1
  267. package/dashboard/dist/assets/{BotPicker-DDmpgGHZ.js → BotPicker-DvEJFpwS.js} +2 -2
  268. package/dashboard/dist/assets/{BotPicker-DDmpgGHZ.js.map → BotPicker-DvEJFpwS.js.map} +1 -1
  269. package/dashboard/dist/assets/{BulkAssignModal-BqlklomG.js → BulkAssignModal-BoQCi-YC.js} +2 -2
  270. package/dashboard/dist/assets/{BulkAssignModal-BqlklomG.js.map → BulkAssignModal-BoQCi-YC.js.map} +1 -1
  271. package/dashboard/dist/assets/{CapabilitiesPage-DOtjDTbK.js → CapabilitiesPage-kwlrcb_t.js} +2 -2
  272. package/dashboard/dist/assets/{CapabilitiesPage-DOtjDTbK.js.map → CapabilitiesPage-kwlrcb_t.js.map} +1 -1
  273. package/dashboard/dist/assets/{CollapsibleSection-CLr8LP0V.js → CollapsibleSection-UMIV4KIj.js} +2 -2
  274. package/dashboard/dist/assets/{CollapsibleSection-CLr8LP0V.js.map → CollapsibleSection-UMIV4KIj.js.map} +1 -1
  275. package/dashboard/dist/assets/ConfirmDeleteModal-C5puwMg7.js +2 -0
  276. package/dashboard/dist/assets/ConfirmDeleteModal-C5puwMg7.js.map +1 -0
  277. package/dashboard/dist/assets/ConnectedAppsPage-drZa65kP.js +2 -0
  278. package/dashboard/dist/assets/ConnectedAppsPage-drZa65kP.js.map +1 -0
  279. package/dashboard/dist/assets/{CountdownTimer-DxX72PwV.js → CountdownTimer-LG03dVgR.js} +2 -2
  280. package/dashboard/dist/assets/{CountdownTimer-DxX72PwV.js.map → CountdownTimer-LG03dVgR.js.map} +1 -1
  281. package/dashboard/dist/assets/{CredentialsPage-CObc9Rs5.js → CredentialsPage-CaFQ6vLb.js} +2 -2
  282. package/dashboard/dist/assets/{CredentialsPage-CObc9Rs5.js.map → CredentialsPage-CaFQ6vLb.js.map} +1 -1
  283. package/dashboard/dist/assets/{CronLabel-Bb8GoNY5.js → CronLabel-Co5j7tzW.js} +2 -2
  284. package/dashboard/dist/assets/{CronLabel-Bb8GoNY5.js.map → CronLabel-Co5j7tzW.js.map} +1 -1
  285. package/dashboard/dist/assets/{ElapsedCell-CmGhVlYl.js → ElapsedCell-WJyE9G0T.js} +2 -2
  286. package/dashboard/dist/assets/{ElapsedCell-CmGhVlYl.js.map → ElapsedCell-WJyE9G0T.js.map} +1 -1
  287. package/dashboard/dist/assets/{EntityTimelinePanel-B4Jwy1w3.js → EntityTimelinePanel-CDFFfX9d.js} +2 -2
  288. package/dashboard/dist/assets/{EntityTimelinePanel-B4Jwy1w3.js.map → EntityTimelinePanel-CDFFfX9d.js.map} +1 -1
  289. package/dashboard/dist/assets/{EscalationListSchemaPage-CZZbZ4Aa.js → EscalationListSchemaPage-CMrUlaKI.js} +3 -3
  290. package/dashboard/dist/assets/{EscalationListSchemaPage-CZZbZ4Aa.js.map → EscalationListSchemaPage-CMrUlaKI.js.map} +1 -1
  291. package/dashboard/dist/assets/{EscalationSchemaPage-D0ko59_S.js → EscalationSchemaPage-Dx2Lyfrz.js} +2 -2
  292. package/dashboard/dist/assets/{EscalationSchemaPage-D0ko59_S.js.map → EscalationSchemaPage-Dx2Lyfrz.js.map} +1 -1
  293. package/dashboard/dist/assets/{EscalationTimeline-BcnJEKFD.js → EscalationTimeline-d3nvshOk.js} +2 -2
  294. package/dashboard/dist/assets/{EscalationTimeline-BcnJEKFD.js.map → EscalationTimeline-d3nvshOk.js.map} +1 -1
  295. package/dashboard/dist/assets/{EscalationTitleSelect-P0q5sck4.js → EscalationTitleSelect-DWQieOM9.js} +2 -2
  296. package/dashboard/dist/assets/{EscalationTitleSelect-P0q5sck4.js.map → EscalationTitleSelect-DWQieOM9.js.map} +1 -1
  297. package/dashboard/dist/assets/{EscalationsOverview-BLPmh4AF.js → EscalationsOverview-BX8Cpi0X.js} +2 -2
  298. package/dashboard/dist/assets/{EscalationsOverview-BLPmh4AF.js.map → EscalationsOverview-BX8Cpi0X.js.map} +1 -1
  299. package/dashboard/dist/assets/{EventTable-gBzi5tIS.js → EventTable-D1-ITVXS.js} +2 -2
  300. package/dashboard/dist/assets/{EventTable-gBzi5tIS.js.map → EventTable-D1-ITVXS.js.map} +1 -1
  301. package/dashboard/dist/assets/{FilterBar-BulSsWb2.js → FilterBar-ABC9ctin.js} +2 -2
  302. package/dashboard/dist/assets/{FilterBar-BulSsWb2.js.map → FilterBar-ABC9ctin.js.map} +1 -1
  303. package/dashboard/dist/assets/{FormattedValue-BMHRrvrL.js → FormattedValue-k27T4bG7.js} +2 -2
  304. package/dashboard/dist/assets/{FormattedValue-BMHRrvrL.js.map → FormattedValue-k27T4bG7.js.map} +1 -1
  305. package/dashboard/dist/assets/{GraphInvokePage--997yNRr.js → GraphInvokePage-DKUErxWc.js} +2 -2
  306. package/dashboard/dist/assets/{GraphInvokePage--997yNRr.js.map → GraphInvokePage-DKUErxWc.js.map} +1 -1
  307. package/dashboard/dist/assets/{HomePage-CwXFz--v.js → HomePage-C6u9dIpR.js} +2 -2
  308. package/dashboard/dist/assets/{HomePage-CwXFz--v.js.map → HomePage-C6u9dIpR.js.map} +1 -1
  309. package/dashboard/dist/assets/{ListToolbar-Df4qZryJ.js → ListToolbar-gA5rFzkz.js} +2 -2
  310. package/dashboard/dist/assets/{ListToolbar-Df4qZryJ.js.map → ListToolbar-gA5rFzkz.js.map} +1 -1
  311. package/dashboard/dist/assets/{McpOverview-DrogIAKJ.js → McpOverview-BOPo3J_i.js} +2 -2
  312. package/dashboard/dist/assets/{McpOverview-DrogIAKJ.js.map → McpOverview-BOPo3J_i.js.map} +1 -1
  313. package/dashboard/dist/assets/{McpQueryDetailPage-CJmvCAE6.js → McpQueryDetailPage-BRVVi0Zh.js} +2 -2
  314. package/dashboard/dist/assets/{McpQueryDetailPage-CJmvCAE6.js.map → McpQueryDetailPage-BRVVi0Zh.js.map} +1 -1
  315. package/dashboard/dist/assets/{McpQueryPage-lygo4Yq0.js → McpQueryPage-Dmbb6SAc.js} +2 -2
  316. package/dashboard/dist/assets/{McpQueryPage-lygo4Yq0.js.map → McpQueryPage-Dmbb6SAc.js.map} +1 -1
  317. package/dashboard/dist/assets/{McpRunDetailPage-hvns2sCm.js → McpRunDetailPage-bMXNO-6V.js} +2 -2
  318. package/dashboard/dist/assets/{McpRunDetailPage-hvns2sCm.js.map → McpRunDetailPage-bMXNO-6V.js.map} +1 -1
  319. package/dashboard/dist/assets/{McpRunsPage-C2_7spTX.js → McpRunsPage-Bi9AMWja.js} +2 -2
  320. package/dashboard/dist/assets/{McpRunsPage-C2_7spTX.js.map → McpRunsPage-Bi9AMWja.js.map} +1 -1
  321. package/dashboard/dist/assets/{OperationsPage-BlK8WlsY.js → OperationsPage-CvR74ZUJ.js} +3 -3
  322. package/dashboard/dist/assets/{OperationsPage-BlK8WlsY.js.map → OperationsPage-CvR74ZUJ.js.map} +1 -1
  323. package/dashboard/dist/assets/{OperatorDashboard-BeWBiMGX.js → OperatorDashboard-DctmZw10.js} +2 -2
  324. package/dashboard/dist/assets/{OperatorDashboard-BeWBiMGX.js.map → OperatorDashboard-DctmZw10.js.map} +1 -1
  325. package/dashboard/dist/assets/{PersonaDetailPage-CNHpsX_i.js → PersonaDetailPage-Ubqm2rQH.js} +2 -2
  326. package/dashboard/dist/assets/{PersonaDetailPage-CNHpsX_i.js.map → PersonaDetailPage-Ubqm2rQH.js.map} +1 -1
  327. package/dashboard/dist/assets/{PersonasPage-ChASEZRg.js → PersonasPage-BpFL2rpo.js} +2 -2
  328. package/dashboard/dist/assets/{PersonasPage-ChASEZRg.js.map → PersonasPage-BpFL2rpo.js.map} +1 -1
  329. package/dashboard/dist/assets/{PortalPage-D5Lk-PKF.js → PortalPage-Dfc_Q02R.js} +2 -2
  330. package/dashboard/dist/assets/{PortalPage-D5Lk-PKF.js.map → PortalPage-Dfc_Q02R.js.map} +1 -1
  331. package/dashboard/dist/assets/ProcessDetailPage-liJspvQh.js +2 -0
  332. package/dashboard/dist/assets/{ProcessDetailPage-DNgCIwRl.js.map → ProcessDetailPage-liJspvQh.js.map} +1 -1
  333. package/dashboard/dist/assets/{ProcessesListPage-pRjWuWlH.js → ProcessesListPage-C3OM5ZUy.js} +2 -2
  334. package/dashboard/dist/assets/{ProcessesListPage-pRjWuWlH.js.map → ProcessesListPage-C3OM5ZUy.js.map} +1 -1
  335. package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js +8 -0
  336. package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js.map +1 -0
  337. package/dashboard/dist/assets/{RoleDetailPage-Bh_UcfYY.js → RoleDetailPage-CrlYCh-R.js} +2 -2
  338. package/dashboard/dist/assets/{RoleDetailPage-Bh_UcfYY.js.map → RoleDetailPage-CrlYCh-R.js.map} +1 -1
  339. package/dashboard/dist/assets/{RolesPage-CK17N7zz.js → RolesPage-BaazL_pt.js} +2 -2
  340. package/dashboard/dist/assets/{RolesPage-CK17N7zz.js.map → RolesPage-BaazL_pt.js.map} +1 -1
  341. package/dashboard/dist/assets/{RunAsSelector-BEKUP0p2.js → RunAsSelector-DxuV0fa1.js} +2 -2
  342. package/dashboard/dist/assets/{RunAsSelector-BEKUP0p2.js.map → RunAsSelector-DxuV0fa1.js.map} +1 -1
  343. package/dashboard/dist/assets/{ScanCodesPage-Bd0Pflqx.js → ScanCodesPage-C0mvmYTq.js} +2 -2
  344. package/dashboard/dist/assets/{ScanCodesPage-Bd0Pflqx.js.map → ScanCodesPage-C0mvmYTq.js.map} +1 -1
  345. package/dashboard/dist/assets/{ScanSchemeDetailPage-CnuhozmJ.js → ScanSchemeDetailPage-CiJgt5dZ.js} +2 -2
  346. package/dashboard/dist/assets/{ScanSchemeDetailPage-CnuhozmJ.js.map → ScanSchemeDetailPage-CiJgt5dZ.js.map} +1 -1
  347. package/dashboard/dist/assets/{ScanStationPage-CoLc-q3h.js → ScanStationPage-DzGaXc40.js} +2 -2
  348. package/dashboard/dist/assets/{ScanStationPage-CoLc-q3h.js.map → ScanStationPage-DzGaXc40.js.map} +1 -1
  349. package/dashboard/dist/assets/{StickyPagination-COrfvkBi.js → StickyPagination-CqbjVY6T.js} +2 -2
  350. package/dashboard/dist/assets/{StickyPagination-COrfvkBi.js.map → StickyPagination-CqbjVY6T.js.map} +1 -1
  351. package/dashboard/dist/assets/{StreamMessageDetail-Cif2egLy.js → StreamMessageDetail-wX3i0aqs.js} +2 -2
  352. package/dashboard/dist/assets/{StreamMessageDetail-Cif2egLy.js.map → StreamMessageDetail-wX3i0aqs.js.map} +1 -1
  353. package/dashboard/dist/assets/{SwimlaneTimeline-BnZYTrAh.js → SwimlaneTimeline-C50PsFoV.js} +2 -2
  354. package/dashboard/dist/assets/{SwimlaneTimeline-BnZYTrAh.js.map → SwimlaneTimeline-C50PsFoV.js.map} +1 -1
  355. package/dashboard/dist/assets/{TaskDetailPage-DEz_dqyR.js → TaskDetailPage-bbNSv4Ae.js} +2 -2
  356. package/dashboard/dist/assets/{TaskDetailPage-DEz_dqyR.js.map → TaskDetailPage-bbNSv4Ae.js.map} +1 -1
  357. package/dashboard/dist/assets/{TasksListPage-oEfEGj0_.js → TasksListPage-CDWnm_d9.js} +2 -2
  358. package/dashboard/dist/assets/{TasksListPage-oEfEGj0_.js.map → TasksListPage-CDWnm_d9.js.map} +1 -1
  359. package/dashboard/dist/assets/{TimeAgo-Dz5TgZZZ.js → TimeAgo-BLjqlfoX.js} +2 -2
  360. package/dashboard/dist/assets/{TimeAgo-Dz5TgZZZ.js.map → TimeAgo-BLjqlfoX.js.map} +1 -1
  361. package/dashboard/dist/assets/{TimestampCell-BUTgE244.js → TimestampCell-CnW0ENb5.js} +2 -2
  362. package/dashboard/dist/assets/{TimestampCell-BUTgE244.js.map → TimestampCell-CnW0ENb5.js.map} +1 -1
  363. package/dashboard/dist/assets/{ToolTestPanel-BS4g6vt-.js → ToolTestPanel-DkMgCB-k.js} +2 -2
  364. package/dashboard/dist/assets/{ToolTestPanel-BS4g6vt-.js.map → ToolTestPanel-DkMgCB-k.js.map} +1 -1
  365. package/dashboard/dist/assets/{TopicDetailPage-C_I6JIVD.js → TopicDetailPage-g3pljKKX.js} +2 -2
  366. package/dashboard/dist/assets/{TopicDetailPage-C_I6JIVD.js.map → TopicDetailPage-g3pljKKX.js.map} +1 -1
  367. package/dashboard/dist/assets/{TopicsPage-Cr6-wfhJ.js → TopicsPage-CVcCYdy-.js} +2 -2
  368. package/dashboard/dist/assets/{TopicsPage-Cr6-wfhJ.js.map → TopicsPage-CVcCYdy-.js.map} +1 -1
  369. package/dashboard/dist/assets/{UserName-ZFpWMaFF.js → UserName-D6zGIK2i.js} +2 -2
  370. package/dashboard/dist/assets/{UserName-ZFpWMaFF.js.map → UserName-D6zGIK2i.js.map} +1 -1
  371. package/dashboard/dist/assets/{WorkflowExecutionPage-ByPixDZW.js → WorkflowExecutionPage-B8g81FCJ.js} +2 -2
  372. package/dashboard/dist/assets/{WorkflowExecutionPage-ByPixDZW.js.map → WorkflowExecutionPage-B8g81FCJ.js.map} +1 -1
  373. package/dashboard/dist/assets/{WorkflowsDashboard-CWsJdMdR.js → WorkflowsDashboard-nxT3bv6W.js} +2 -2
  374. package/dashboard/dist/assets/{WorkflowsDashboard-CWsJdMdR.js.map → WorkflowsDashboard-nxT3bv6W.js.map} +1 -1
  375. package/dashboard/dist/assets/{WorkflowsOverview-Dk9gyqZN.js → WorkflowsOverview-grI-KAI2.js} +2 -2
  376. package/dashboard/dist/assets/{WorkflowsOverview-Dk9gyqZN.js.map → WorkflowsOverview-grI-KAI2.js.map} +1 -1
  377. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CHwcrsaT.js → YamlWorkflowDetailPage-BoZ-hfBE.js} +2 -2
  378. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CHwcrsaT.js.map → YamlWorkflowDetailPage-BoZ-hfBE.js.map} +1 -1
  379. package/dashboard/dist/assets/{YamlWorkflowsPage-B5jRX2Ph.js → YamlWorkflowsPage-Bf04rwRv.js} +2 -2
  380. package/dashboard/dist/assets/{YamlWorkflowsPage-B5jRX2Ph.js.map → YamlWorkflowsPage-Bf04rwRv.js.map} +1 -1
  381. package/dashboard/dist/assets/{agents-Dd7E-27d.js → agents-Dphpdi8l.js} +2 -2
  382. package/dashboard/dist/assets/{agents-Dd7E-27d.js.map → agents-Dphpdi8l.js.map} +1 -1
  383. package/dashboard/dist/assets/{bots-CpaYjZTk.js → bots-DIFE298x.js} +2 -2
  384. package/dashboard/dist/assets/{bots-CpaYjZTk.js.map → bots-DIFE298x.js.map} +1 -1
  385. package/dashboard/dist/assets/{capabilities-CNjg_qv1.js → capabilities-D7Y7LClY.js} +2 -2
  386. package/dashboard/dist/assets/{capabilities-CNjg_qv1.js.map → capabilities-D7Y7LClY.js.map} +1 -1
  387. package/dashboard/dist/assets/{controlplane-DgmvnAtU.js → controlplane-D1TGcYsS.js} +2 -2
  388. package/dashboard/dist/assets/{controlplane-DgmvnAtU.js.map → controlplane-D1TGcYsS.js.map} +1 -1
  389. package/dashboard/dist/assets/{escalation-columns-Uj4U9g5H.js → escalation-columns-cwZE6xyo.js} +2 -2
  390. package/dashboard/dist/assets/{escalation-columns-Uj4U9g5H.js.map → escalation-columns-cwZE6xyo.js.map} +1 -1
  391. package/dashboard/dist/assets/{index-x5z73M9N.js → index-BzYcUPdD.js} +2 -2
  392. package/dashboard/dist/assets/{index-x5z73M9N.js.map → index-BzYcUPdD.js.map} +1 -1
  393. package/dashboard/dist/assets/index-CeCtqujG.js +67 -0
  394. package/dashboard/dist/assets/index-CeCtqujG.js.map +1 -0
  395. package/dashboard/dist/assets/{index-RIFT3RlO.js → index-ChV7pBjM.js} +2 -2
  396. package/dashboard/dist/assets/{index-RIFT3RlO.js.map → index-ChV7pBjM.js.map} +1 -1
  397. package/dashboard/dist/assets/{index-OfO0173w.js → index-CniRa65p.js} +2 -2
  398. package/dashboard/dist/assets/{index-OfO0173w.js.map → index-CniRa65p.js.map} +1 -1
  399. package/dashboard/dist/assets/{index-ByBy9M3L.js → index-CxdjT1Yk.js} +2 -2
  400. package/dashboard/dist/assets/{index-ByBy9M3L.js.map → index-CxdjT1Yk.js.map} +1 -1
  401. package/dashboard/dist/assets/{index-C_K7OlzT.js → index-DAvi5_2T.js} +2 -2
  402. package/dashboard/dist/assets/{index-C_K7OlzT.js.map → index-DAvi5_2T.js.map} +1 -1
  403. package/dashboard/dist/assets/{index-BrwqtXRh.js → index-DN-kX7hL.js} +2 -2
  404. package/dashboard/dist/assets/{index-BrwqtXRh.js.map → index-DN-kX7hL.js.map} +1 -1
  405. package/dashboard/dist/assets/index-Dl_8hbYI.js +2 -0
  406. package/dashboard/dist/assets/index-Dl_8hbYI.js.map +1 -0
  407. package/dashboard/dist/assets/{index-D4Dlznn9.js → index-DpKOr311.js} +2 -2
  408. package/dashboard/dist/assets/{index-D4Dlznn9.js.map → index-DpKOr311.js.map} +1 -1
  409. package/dashboard/dist/assets/{index-CnOvJz6U.js → index-Dy1wWu2e.js} +2 -2
  410. package/dashboard/dist/assets/{index-CnOvJz6U.js.map → index-Dy1wWu2e.js.map} +1 -1
  411. package/dashboard/dist/assets/{index-BT1Ms5Q5.js → index-HLu98Sqh.js} +2 -2
  412. package/dashboard/dist/assets/{index-BT1Ms5Q5.js.map → index-HLu98Sqh.js.map} +1 -1
  413. package/dashboard/dist/assets/{index-BFASQ7_X.js → index-ag2pCAPu.js} +2 -2
  414. package/dashboard/dist/assets/{index-BFASQ7_X.js.map → index-ag2pCAPu.js.map} +1 -1
  415. package/dashboard/dist/assets/{index-BsHVgWH6.js → index-gkxPN7Vx.js} +2 -2
  416. package/dashboard/dist/assets/{index-BsHVgWH6.js.map → index-gkxPN7Vx.js.map} +1 -1
  417. package/dashboard/dist/assets/index-m9A3UYst.css +1 -0
  418. package/dashboard/dist/assets/{knowledge-Cci_r6Kl.js → knowledge-DnMs-SOJ.js} +2 -2
  419. package/dashboard/dist/assets/{knowledge-Cci_r6Kl.js.map → knowledge-DnMs-SOJ.js.map} +1 -1
  420. package/dashboard/dist/assets/{mcp-NY4iL0L-.js → mcp-CwW-K3r4.js} +2 -2
  421. package/dashboard/dist/assets/{mcp-NY4iL0L-.js.map → mcp-CwW-K3r4.js.map} +1 -1
  422. package/dashboard/dist/assets/{mcp-query-CbvZo_I_.js → mcp-query-BZt5e8_Q.js} +2 -2
  423. package/dashboard/dist/assets/{mcp-query-CbvZo_I_.js.map → mcp-query-BZt5e8_Q.js.map} +1 -1
  424. package/dashboard/dist/assets/{personas-Fy-f7QQd.js → personas-UA-Xn60f.js} +2 -2
  425. package/dashboard/dist/assets/{personas-Fy-f7QQd.js.map → personas-UA-Xn60f.js.map} +1 -1
  426. package/dashboard/dist/assets/{pipelines-DKiuozxV.js → pipelines-Cu3PARum.js} +2 -2
  427. package/dashboard/dist/assets/{pipelines-DKiuozxV.js.map → pipelines-Cu3PARum.js.map} +1 -1
  428. package/dashboard/dist/assets/{tasks-CdM1Rkk9.js → tasks-BO6h8GJE.js} +2 -2
  429. package/dashboard/dist/assets/{tasks-CdM1Rkk9.js.map → tasks-BO6h8GJE.js.map} +1 -1
  430. package/dashboard/dist/assets/{topics-XNy2mf3n.js → topics-CWjCR-17.js} +2 -2
  431. package/dashboard/dist/assets/{topics-XNy2mf3n.js.map → topics-CWjCR-17.js.map} +1 -1
  432. package/dashboard/dist/assets/{useDebouncedValue-CyGcU3_S.js → useDebouncedValue-6t0jx1RB.js} +2 -2
  433. package/dashboard/dist/assets/{useDebouncedValue-CyGcU3_S.js.map → useDebouncedValue-6t0jx1RB.js.map} +1 -1
  434. package/dashboard/dist/assets/{useNamespace-C2RIh_IN.js → useNamespace-CqpoQx6D.js} +2 -2
  435. package/dashboard/dist/assets/{useNamespace-C2RIh_IN.js.map → useNamespace-CqpoQx6D.js.map} +1 -1
  436. package/dashboard/dist/assets/{useYamlActivityEvents-CDiV5fjf.js → useYamlActivityEvents-hmCQQwzB.js} +2 -2
  437. package/dashboard/dist/assets/{useYamlActivityEvents-CDiV5fjf.js.map → useYamlActivityEvents-hmCQQwzB.js.map} +1 -1
  438. package/dashboard/dist/assets/{validate-DcGWN82Y.js → validate-BIRn4a6d.js} +2 -2
  439. package/dashboard/dist/assets/{validate-DcGWN82Y.js.map → validate-BIRn4a6d.js.map} +1 -1
  440. package/dashboard/dist/assets/{yaml-workflows-CH8UrouH.js → yaml-workflows-ziUdZhKY.js} +2 -2
  441. package/dashboard/dist/assets/{yaml-workflows-CH8UrouH.js.map → yaml-workflows-ziUdZhKY.js.map} +1 -1
  442. package/dashboard/dist/index.html +2 -2
  443. package/docs/agents.md +3 -1
  444. package/docs/api/http/agents.md +15 -1
  445. package/docs/api/http/escalations.md +3 -3
  446. package/docs/api/http/exports.md +3 -1
  447. package/docs/api/http/file-browser.md +3 -1
  448. package/docs/api/http/mcp-endpoint.md +8 -5
  449. package/docs/api/http/mcp-servers.md +34 -4
  450. package/docs/api/http/namespaces.md +2 -0
  451. package/docs/api/http/pipelines.md +2 -0
  452. package/docs/api/http/roles.md +11 -8
  453. package/docs/api/http/service-accounts.md +8 -2
  454. package/docs/api/http/settings.md +29 -2
  455. package/docs/api/http/tasks.md +3 -1
  456. package/docs/api/http/topics.md +7 -1
  457. package/docs/api/http/users.md +8 -2
  458. package/docs/api/http/workflows.md +25 -10
  459. package/docs/api/http/yaml-workflows.md +21 -0
  460. package/docs/api/mcp/admin.md +409 -49
  461. package/docs/api/mcp/file-storage.md +4 -0
  462. package/docs/api/mcp/http-fetch.md +6 -2
  463. package/docs/api/mcp/human-queue.md +53 -0
  464. package/docs/api/mcp/index.md +13 -10
  465. package/docs/api/mcp/knowledge.md +34 -0
  466. package/docs/api/mcp/oauth.md +1 -1
  467. package/docs/api/mcp/ortho.md +113 -0
  468. package/docs/api/mcp/vision.md +1 -1
  469. package/docs/api/sdk/bot-accounts.md +1 -0
  470. package/docs/api/sdk/escalations.md +2 -2
  471. package/docs/api/sdk/mcp.md +2 -2
  472. package/docs/api/sdk/settings.md +1 -1
  473. package/docs/api/sdk/tasks.md +2 -2
  474. package/docs/api/sdk/workflows.md +2 -2
  475. package/docs/api/sdk/yaml-workflows.md +1 -1
  476. package/docs/architecture.md +3 -1
  477. package/docs/auth.md +3 -2
  478. package/docs/cloud.md +7 -2
  479. package/docs/dashboard.md +16 -7
  480. package/docs/data.md +1 -1
  481. package/docs/escalation-strategies.md +9 -20
  482. package/docs/events.md +6 -0
  483. package/docs/iam.md +7 -5
  484. package/docs/maintenance.md +51 -28
  485. package/docs/mcp.md +159 -210
  486. package/docs/oauth-and-delegation.md +32 -21
  487. package/docs/topics.md +2 -0
  488. package/docs/workflows.md +14 -112
  489. package/package.json +5 -3
  490. package/dashboard/dist/assets/ConfirmDeleteModal-DW4DrPur.js +0 -2
  491. package/dashboard/dist/assets/ConfirmDeleteModal-DW4DrPur.js.map +0 -1
  492. package/dashboard/dist/assets/ProcessDetailPage-DNgCIwRl.js +0 -2
  493. package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js +0 -8
  494. package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js.map +0 -1
  495. package/dashboard/dist/assets/index-CtlBjl8o.js +0 -2
  496. package/dashboard/dist/assets/index-CtlBjl8o.js.map +0 -1
  497. package/dashboard/dist/assets/index-LRYC__mE.js +0 -67
  498. package/dashboard/dist/assets/index-LRYC__mE.js.map +0 -1
  499. package/dashboard/dist/assets/index-MYI2_Xb3.css +0 -1
package/docs/mcp.md CHANGED
@@ -9,9 +9,9 @@ Your agents speak MCP. Long Tail makes their tool calls durable and exposes huma
9
9
  - [Compiled Workflows as Tools](#compiled-workflows-as-tools)
10
10
  - [The Cycle](#the-cycle)
11
11
  - [Connecting an Agent to Long Tail](#connecting-an-agent-to-long-tail) — the `/mcp` endpoint, service accounts, multi-environment `.mcp.json`, example prompts
12
+ - [Connecting Long Tail Instances](#connecting-long-tail-instances): one instance calling another's tools over MCP
12
13
  - [Human Queue Server](#human-queue-server) — escalation as MCP tools
13
- - [Document Vision Server](#document-vision-server) — AI tools as 3 MCP tools
14
- - [MCP-Native Workflow](#mcp-native-workflow) — both sides MCP, end to end
14
+ - [Document Vision Server](#document-vision-server): AI tools as MCP tools
15
15
  - [Server Registration Lifecycle](#server-registration-lifecycle) — two paths, startup sequence, when things connect
16
16
  - [External MCP Servers](#external-mcp-servers) — Path B: dashboard/API registration
17
17
  - [Built-in Servers](#built-in-servers) — servers that ship by default
@@ -153,7 +153,7 @@ Long Tail is itself an MCP server. Any MCP-aware client — Claude Code, Claude
153
153
  |---|---|
154
154
  | URL | `POST https://<host>/mcp` |
155
155
  | Transport | Streamable HTTP, stateless — one request and one response per call |
156
- | Auth | `Authorization: Bearer <token>` — a signed user token (JWT) or a service-account key |
156
+ | Auth | `Authorization: Bearer <token>`: an OAuth access token (people, see below), a service-account key (machines), or a signed user token (JWT). The host's session cookie does not authenticate `/mcp`. |
157
157
 
158
158
  ### Access: which tools, and which records
159
159
 
@@ -164,19 +164,73 @@ Two things decide what a connected agent can do, and both must pass.
164
164
  - `mcp:read` — the read-only tools: listing, searching, diagnosing, stream and escalation stats, exports. Anything that only reports.
165
165
  - `mcp:full` — those, plus the tools that change state: create an escalation, claim and resolve one, invoke a workflow, update a configuration, prune the database.
166
166
 
167
- A deployment can also be set read-only as a whole, which holds every key to read access whatever its scope, and can hide entire groups of tools. Production is the place to do this by default.
167
+ A deployment can also be set read-only as a whole with `mcp.exposure.readOnly` in `start()`, which exposes only read-safe tools to every key and OAuth grant whatever its scope, and can hide entire groups of tools (`allowServers`, `denyServers`). Production is the place to do this by default.
168
168
 
169
- **Role decides which records.** Scope opens a tool; the account's role decides whether the action is allowed on a given target. An account with `mcp:full` but only the `reviewer` role can resolve reviewer escalations — it cannot route work to finance or manage users. Administrative tools (users, roles, configuration, pruning) require an admin or superadmin role.
169
+ **Role decides which tools and which records.** Each tool declares the capability its caller needs, the same gates the dashboard's REST routes use, and a tool appears only to accounts that hold it:
170
170
 
171
- Put plainly: **scope is which tools, role is which records.** A read key answers questions; a full key with the right role also acts.
171
+ | Capability | Who holds it | Tools |
172
+ |---|---|---|
173
+ | Caller | Any account | Escalations, tasks, workflow invocation, a run's status and execution history (for a builder, or the person who started the run or it runs as), scan codes, docs, reads of users, roles and configuration, the account's own OAuth connections |
174
+ | Admin | Admin or superadmin | Workflow configuration, diagnostics, pruning, assigning and removing a user's roles |
175
+ | Builder | Superadmin, or the `engineer` role | Users, bot accounts, knowledge, YAML workflows, agents, topics, MCP server connections and calling an external server's tools, control plane, workflow envelopes and state exports, terminating workflows, HTTP requests, file reads and writes, Claude Code tasks |
176
+ | Role manager | Admin, superadmin, or the `engineer` role | Roles, personas, scan rules, announcements |
177
+ | Superadmin | Superadmin | Other users' OAuth connections, the human-queue tools workflows use to create and resolve escalations |
172
178
 
173
- Creating an escalation shows both at work. `escalate_to_human` changes state, so the key needs `mcp:full`, and the account needs a role allowed to route to that queue. Reading the same queue back — `get_available_work`, `check_resolution` — needs only `mcp:read`. The rule holds for every tool: reading is cheap to grant, writing is deliberate.
179
+ Within a tool, the account's role decides whether the action is allowed on a given target. Workflow invocation runs as the account and follows the workflow's invocation roles. Assigning a role follows the same rule as the dashboard: only a superadmin assigns the superadmin type, and an admin without the `engineer` role assigns only roles they hold. An account with `mcp:full` but only the `reviewer` role can resolve reviewer escalations; it cannot route work to finance or manage users.
180
+
181
+ A built-in tool declares its capability with `gate` on its manifest entry. A tool whose entry has no `gate` is not exposed at `/mcp`. A host's in-process servers (`mcp.serverFactories` with a `config.toolManifest`) declare `gate` the same way; it applies when the tool is called over REST or chosen by an LLM inside a workflow, and a host tool with no `gate` requires builder.
182
+
183
+ Builder is the most powerful capability after superadmin. It includes registering an MCP server with the `stdio` transport, which runs a command on the Long Tail host with that host's environment and network. Grant the `engineer` role with the same care as host access.
184
+
185
+ Put plainly: **scope is read or write; role is which tools and which records.** A read key answers questions; a full key with the right role also acts.
186
+
187
+ Resolving an escalation shows both at work. `admin_resolve_escalation` changes state, so the key needs `mcp:full`, and the account needs write access to that escalation's role. Reading the same queue first, with `find_escalations` or `search_by_facets`, needs only `mcp:read`. The rule holds for every tool: reading is cheap to grant, writing is deliberate.
174
188
 
175
189
  **Read-safe workflow invocation.** A workflow registered with `read_safe: true` in its config (a side-effect-free lookup) is invocable by read-scoped callers through `invoke_workflow_read_safe` — the read-safe variant of `invoke_workflow`. Any workflow may be attempted; one without the flag fails with a clear error, so the flag on the config is the whole contract. Declare it on the worker profile (`readSafe: true`) or set it through the workflow-config admin surface; the flag is fail-closed and defaults off.
176
190
 
191
+ ### Connect with OAuth
192
+
193
+ People connect with OAuth: add the URL to the client, sign in once in the browser, and pick what the client may do. No key goes in any file.
194
+
195
+ ```bash
196
+ claude mcp add --transport http long-tail https://<host>/mcp
197
+ ```
198
+
199
+ Then run `/mcp` in Claude Code and pick Authenticate. The browser opens the consent page, which shows the app, the account and where it returns, and offers two choices:
200
+
201
+ | Choice | The client may |
202
+ |---|---|
203
+ | Allow read-only | Read what you can read, and run workflows marked read-safe |
204
+ | Allow as me | Do anything you can do: claim, resolve, invoke and administer wherever your roles allow |
205
+
206
+ Allow as me appears only when it grants more than read-only: when you can write in some role, or hold an admin tier. Either way the client acts as you, so every result is limited to your roles, and every action is recorded as you.
207
+
208
+ Access tokens last 5 minutes; the client refreshes them silently with a refresh token that rotates on each use and lasts 30 days. Every request reads the grant: a client acts with your roles as they are now, and a disconnected app, a revoked token or a deactivated account stops working on the next request. Disconnect a client under **Connected apps** in the user menu; the same happens when the client revokes its token.
209
+
210
+ **Enable it** with `auth.oauthServer` in `start()`, or `LT_OAUTH_ISSUER` in the environment:
211
+
212
+ ```typescript
213
+ start({
214
+ auth: {
215
+ oauthServer: {
216
+ issuer: 'https://api.example.com/longtail', // the public base URL Long Tail is served under
217
+ allowedRedirectUris: ['https://claude.ai/api/mcp/auth_callback'], // exact https redirects, beyond loopback
218
+ },
219
+ },
220
+ });
221
+ ```
222
+
223
+ Clients register themselves (RFC 7591). Loopback redirects (`http://127.0.0.1`, `localhost`, `[::1]`, any port) are always allowed, which covers Claude Code and Claude Desktop; an `https` redirect is allowed only when it equals a URI in `allowedRedirectUris`.
224
+
225
+ **Embedded deployments** mount two routers, and let four paths reach Long Tail without the host's login:
226
+
227
+ - `adapter.getRouter()` under the base path, as today, and `adapter.getWellKnownRouter()` at the host's root. The well-known router answers only its two documents and passes every other request on.
228
+ - Let these through the host's session gate: `/mcp`, `/api/oauth/register`, `/api/oauth/token`, `/api/oauth/revoke` (and `/api/oauth/metadata` if used). They carry their own credentials.
229
+ - Keep `/api/oauth/authorize` and the dashboard behind the host's login: that is where the person signs in before consenting.
230
+
177
231
  ### 1. Create a service account
178
232
 
179
- In the dashboard: **Admin → Bot Accounts → Create**, assign the role(s) the account should act under, then generate an API key and choose its scope — `mcp:read` for an investigator, `mcp:full` for an operator that also makes changes. The raw key is shown once. The same is available as admin tools: `create_bot_account`, then `create_bot_api_key`.
233
+ In the dashboard: create one under **Accounts → Service Accounts**, assign the role(s) the account should act under, then generate an API key and choose its scope — `mcp:read` for an investigator, `mcp:full` for an operator that also makes changes. The raw key is shown once. The same is available as admin tools: `create_bot_account`, then `create_bot_api_key`.
180
234
 
181
235
  Give each environment its own account and key, scoped to the least it needs.
182
236
 
@@ -246,115 +300,85 @@ The full tool reference is in [the admin server doc](api/mcp/admin.md). A read k
246
300
  **Settings** — *read*
247
301
  - "What versions and features is this deployment running?"
248
302
 
249
- ## Human Queue Server
303
+ ## Connecting Long Tail Instances
250
304
 
251
- The Human Queue is a built-in MCP server that exposes Long Tail's escalation API as standard MCP tools. Any MCP-compatible client — Claude, LangGraph, CrewAI, a custom agent — can connect and work the queue.
305
+ One Long Tail instance can call another's tools over MCP. Each instance keeps its own database, roles, queues and workflows; the connection is a registered MCP server on the calling instance that points at the other instance's `/mcp`, authenticated with a service account the other instance issues. Separate teams (engineering, operations, sales) can each run an instance, and a shared instance can reach into all of them, without either side sharing a database or a login.
252
306
 
253
- ### Tools
307
+ ### Set up the connection
254
308
 
255
- #### `escalate_to_human`
309
+ **On the instance being called (the remote):**
256
310
 
257
- Create a new escalation for human review.
311
+ 1. Create a service account under **Accounts → Service Accounts**, or `POST /api/bot-accounts`. Give it the roles the connection should act under, and nothing more.
312
+ 2. Generate an API key for it with the scope the connection needs: `mcp:read` for a connection that only reads and runs read-safe workflows, `mcp:full` for one that also claims, resolves and invokes. The raw key is shown once.
258
313
 
259
- | Parameter | Type | Required | Description |
260
- |-----------|------|----------|-------------|
261
- | `role` | string | yes | Target role (e.g., `"reviewer"`) |
262
- | `message` | string | yes | What needs human review |
263
- | `data` | object | no | Contextual data for the reviewer |
264
- | `type` | string | no | Classification (default: `"mcp"`) |
265
- | `subtype` | string | no | Subtype (default: `"tool_call"`) |
266
- | `priority` | number | no | 1 (highest) to 4 (lowest), default: 2 |
314
+ **On the calling instance:**
267
315
 
268
- Returns:
316
+ 3. Register the remote's `/mcp` as a network server. In the dashboard: **Servers & Tools → Register Server**, choose **Network Service**, enter `https://<remote-host>/mcp`, choose **Streamable HTTP**, and put the key in **Headers (JSON)** as `{ "Authorization": "Bearer <key>" }`. Or over the API:
269
317
 
270
- ```json
271
- {
272
- "escalation_id": "uuid",
273
- "status": "pending",
274
- "role": "reviewer",
275
- "created_at": "2025-01-15T10:30:00Z"
276
- }
318
+ ```bash
319
+ curl -X POST https://<this-host>/api/mcp/servers \
320
+ -H "Authorization: Bearer $LT_TOKEN" -H 'Content-Type: application/json' \
321
+ -d '{
322
+ "name": "operations-longtail",
323
+ "transport_type": "streamable-http",
324
+ "transport_config": {
325
+ "url": "https://ops.example.com/mcp",
326
+ "headers": { "Authorization": "Bearer <remote service-account key>" }
327
+ },
328
+ "tags": ["longtail", "operations"],
329
+ "auto_connect": true
330
+ }'
277
331
  ```
278
332
 
279
- #### `check_resolution`
333
+ 4. Test and connect: the **Test** step (or `POST /api/mcp/servers/test-connection`) lists the tools the remote offers this account; `POST /api/mcp/servers/:id/connect` connects and caches the tool list. With `auto_connect: true` the connection opens at every start.
280
334
 
281
- Check the status of an escalation.
335
+ Registration, testing and connecting require builder access on the calling instance.
282
336
 
283
- | Parameter | Type | Required | Description |
284
- |-----------|------|----------|-------------|
285
- | `escalation_id` | string | yes | The escalation ID to check |
337
+ ### What each side enforces
286
338
 
287
- Returns:
288
-
289
- ```json
290
- {
291
- "escalation_id": "uuid",
292
- "status": "pending"
293
- }
294
- ```
295
-
296
- When resolved:
297
-
298
- ```json
299
- {
300
- "escalation_id": "uuid",
301
- "status": "resolved",
302
- "resolver_payload": { "approved": true, "note": "..." },
303
- "resolved_at": "2025-01-15T11:00:00Z"
304
- }
305
- ```
339
+ **The remote decides what the connection can do.** It treats the connection as its service account: it lists only the tools that account's roles allow, applies the key's scope (`mcp:read` sees read-only tools), honors its own `mcp.exposure` settings, filters every result to the account's read scope, and records every action as that account. Changing the account's roles on the remote changes what the connection can do on the next call.
306
340
 
307
- Returns `isError: true` if the escalation doesn't exist.
341
+ **The calling instance decides who may use the connection.** The stored key carries the remote account's authority, so calling an external server's tools directly is a builder capability: over REST (`POST /api/mcp/servers/:id/tools/:tool/call`) and in AI tool loops, a person without builder access is refused. Workflows and compiled pipelines that a builder deploys call the remote as part of their own run, which is how everyone else reaches it: through a deployed workflow, with its own invocation roles, rather than through the raw connection.
308
342
 
309
- #### `get_available_work`
343
+ The key is part of `transport_config`, which is returned only to builders.
310
344
 
311
- List pending, unassigned escalations for a role.
345
+ ### Keys
312
346
 
313
- | Parameter | Type | Required | Description |
314
- |-----------|------|----------|-------------|
315
- | `role` | string | yes | Role to filter by |
316
- | `limit` | number | no | Max results (default: 10) |
347
+ - **Rotate:** generate a new key on the remote, update the server's headers on the calling instance (`PUT /api/mcp/servers/:id`, or edit the server), then revoke the old key on the remote.
348
+ - **Revoke:** revoking the key on the remote ends the connection on its next call.
349
+ - **One account per connection:** give each calling instance its own service account on the remote, so each connection's access and audit trail stay separate.
317
350
 
318
- Returns:
351
+ ### Troubleshooting
319
352
 
320
- ```json
321
- {
322
- "count": 2,
323
- "escalations": [
324
- {
325
- "escalation_id": "uuid",
326
- "type": "mcp",
327
- "subtype": "tool_call",
328
- "description": "Address mismatch for MBR-2024-001",
329
- "priority": 2,
330
- "role": "reviewer",
331
- "created_at": "2025-01-15T10:30:00Z"
332
- }
333
- ]
334
- }
335
- ```
336
-
337
- #### `claim_and_resolve`
353
+ | Symptom | Meaning |
354
+ |---|---|
355
+ | Test fails with `Unauthorized` | The remote rejected the key: missing, mistyped, revoked, or not sent (check **Headers**) |
356
+ | A tool is missing from the list | The remote account's roles do not allow it, or the key is `mcp:read` and the tool changes state |
357
+ | A call answers `Tool ... not found` | The same: the remote does not offer that tool to this account |
358
+ | A call answers `need builder access` | The calling instance refused it: calling external tools directly needs builder access there |
338
359
 
339
- Claim an escalation and resolve it in one atomic operation.
360
+ ## Human Queue Server
340
361
 
341
- | Parameter | Type | Required | Description |
342
- |-----------|------|----------|-------------|
343
- | `escalation_id` | string | yes | The escalation to resolve |
344
- | `resolver_id` | string | yes | Who/what is resolving (e.g., `"my-agent"`) |
345
- | `payload` | object | yes | Resolution data |
362
+ The Human Queue is a built-in MCP server that exposes Long Tail's escalation API as standard MCP tools. Any MCP-compatible client — Claude, LangGraph, CrewAI, a custom agent — can connect and work the queue.
346
363
 
347
- Returns:
364
+ These tools act with full authority, so at `/mcp` they are listed for superadmin accounts. Workflows and agents inside Long Tail call them directly. An external agent with any other role works the queue through the role-checked escalation tools: `find_escalations`, `claim_escalation`, `admin_resolve_escalation`.
348
365
 
349
- ```json
350
- {
351
- "escalation_id": "uuid",
352
- "status": "resolved",
353
- "resolved_at": "2025-01-15T11:00:00Z"
354
- }
355
- ```
366
+ ### Tools
356
367
 
357
- Returns `isError: true` if the escalation isn't available (already claimed, already resolved, or doesn't exist).
368
+ | Tool | Purpose |
369
+ |------|---------|
370
+ | `escalate_to_human` | Create an escalation for human review |
371
+ | `check_resolution` | Check whether an escalation is resolved and read its payload |
372
+ | `get_escalation_lookups` | Read the knowledge lookups pinned on an escalation |
373
+ | `get_available_work` | List pending, unclaimed escalations for a role |
374
+ | `claim_and_resolve` | Claim and resolve an escalation in one atomic call |
375
+ | `resolve_escalation` | Resolve an escalation that is already claimed |
376
+ | `resolve_batch_item` | Fill one declared item of a batch escalation |
377
+ | `accumulate_item` | Add one item to an open accumulator escalation |
378
+ | `remove_item` | Remove one held item from an open accumulator |
379
+ | `escalate_and_wait` | Create an escalation and pause the workflow until it is resolved |
380
+
381
+ Parameters and examples for each are in the [Human Queue reference](api/mcp/human-queue.md).
358
382
 
359
383
  ### Scope and one-time users
360
384
 
@@ -389,21 +413,20 @@ const work = await client.callTool({
389
413
 
390
414
  **Over stdio or SSE:** Connect your MCP client to Long Tail's Streamable HTTP endpoint or spawn the server as a subprocess. The tools and responses are identical regardless of transport.
391
415
 
392
- The Human Queue handles the people side. The Document Vision server handles the AI side — wrapping model capabilities as MCP tools.
416
+ The Human Queue handles the people side. The Vision server handles the AI side, wrapping model capabilities as MCP tools.
393
417
 
394
418
  ## Document Vision Server
395
419
 
396
- The Document Vision server (`services/mcp/vision-server.ts`) wraps AI processing activities as MCP tools. It follows the same singleton pattern as the Human Queue server — Zod schemas at module level, `createVisionServer()` / `stopVisionServer()` lifecycle.
397
-
398
- The included implementation wraps OpenAI Vision extraction and member database validation. The pattern applies to any AI capability you want to expose as MCP tools.
420
+ The Vision server (`system/mcp-servers/vision.ts`, server ID `long-tail-vision`) wraps LLM vision calls as MCP tools. Zod schemas sit at module level, and `createVisionServer()` returns a fresh `McpServer` instance per call because the MCP SDK allows one transport per server. Full parameter reference: [Vision tools](api/mcp/vision.md).
399
421
 
400
422
  ### Tools
401
423
 
402
424
  | Tool | Arguments | Returns |
403
425
  |------|-----------|---------|
404
- | `list_document_pages` | *(none)* | `{ pages: string[] }` |
405
- | `extract_member_info` | `{ image_ref, page_number }` | `{ member_info: MemberInfo \| null }` |
406
- | `validate_member` | `{ member_info: MemberInfo }` | `{ result, databaseRecord? }` |
426
+ | `analyze_image` | `{ image, prompt? }` | `{ description, text_content, objects }` |
427
+ | `describe_image` | `{ image, context? }` | `{ description }` |
428
+
429
+ `image` accepts a storage path, a data URI, or an `https://` URL. Images larger than 7680px on either side are downscaled before the model call. Without an LLM API key, both tools return `{ error: 'LLM API key not configured' }`.
407
430
 
408
431
  ### Connecting
409
432
 
@@ -412,7 +435,7 @@ Same `InMemoryTransport` pattern as the Human Queue:
412
435
  ```typescript
413
436
  import { Client as McpClient } from '@modelcontextprotocol/sdk/client/index.js';
414
437
  import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
415
- import { createVisionServer } from '@hotmeshio/long-tail/services/mcp/vision-server';
438
+ import { createVisionServer } from '../system/mcp-servers/vision';
416
439
 
417
440
  const server = await createVisionServer();
418
441
  const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@@ -421,13 +444,11 @@ await server.connect(serverTransport);
421
444
  const client = new McpClient({ name: 'my-vision-client', version: '1.0.0' });
422
445
  await client.connect(clientTransport);
423
446
 
424
- // Discover tools
425
447
  const { tools } = await client.listTools();
426
448
 
427
- // Call a tool
428
449
  const result = await client.callTool({
429
- name: 'list_document_pages',
430
- arguments: {},
450
+ name: 'describe_image',
451
+ arguments: { image: 'screenshots/page-1.png' },
431
452
  });
432
453
  ```
433
454
 
@@ -436,90 +457,16 @@ const result = await client.callTool({
436
457
  To wrap your own AI capabilities as MCP tools, follow the same pattern:
437
458
 
438
459
  1. Define Zod schemas at module level (avoids TS2589 deep inference errors)
439
- 2. Use the singleton pattern with `create` / `stop` lifecycle
460
+ 2. Expose a `create` / `stop` lifecycle
440
461
  3. Register tools with `(server as any).registerTool()` (type cast required by SDK)
441
462
 
442
- See `services/mcp/vision-server.ts` and `services/mcp/server.ts` for working examples.
443
-
444
- ## MCP-Native Workflow
445
-
446
- The `verify-document-mcp` workflow demonstrates both MCP servers working together. Every activity call — listing pages, extracting data, validating members — routes through the Vision MCP server. When the workflow escalates, the Human Queue MCP server manages the review cycle. Both sides speak the same protocol.
447
-
448
- ### How It Works
449
-
450
- ```
451
- verify-document-mcp workflow
452
- |
453
- +-- proxyActivities --> MCP client -- InMemoryTransport --> Vision MCP Server
454
- | +- list_document_pages
455
- | +- extract_member_info (-> OpenAI Vision)
456
- | +- validate_member (-> member DB)
457
- |
458
- +-- return { type: 'escalation' }
459
- |
460
- +-- interceptor --> Human Queue MCP Server
461
- +- check_resolution
462
- +- get_available_work
463
- +- claim_and_resolve
464
- ```
465
-
466
- ### The Activity Wrapper Pattern
467
-
468
- The key insight: MCP tool calls are wrapped as activities with the **same function signatures** as direct implementations. The workflow doesn't know (or care) that MCP is underneath — it just calls `extractMemberInfo()`. But each call routes through the MCP protocol, making every AI tool invocation protocol-native.
469
-
470
- ```typescript
471
- import { Client as McpClient } from '@modelcontextprotocol/sdk/client/index.js';
472
- import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
473
- import { createVisionServer } from '../../services/mcp/vision-server';
474
-
475
- let client: McpClient | null = null;
476
-
477
- async function getClient(): Promise<McpClient> {
478
- if (client) return client;
479
- const server = await createVisionServer();
480
- const [ct, st] = InMemoryTransport.createLinkedPair();
481
- await server.connect(st);
482
- client = new McpClient({ name: 'verify-mcp-client', version: '1.0.0' });
483
- await client.connect(ct);
484
- return client;
485
- }
486
-
487
- export async function extractMemberInfo(
488
- imageRef: string,
489
- pageNumber: number,
490
- ): Promise<MemberInfo | null> {
491
- const c = await getClient();
492
- const result = await c.callTool({
493
- name: 'extract_member_info',
494
- arguments: { image_ref: imageRef, page_number: pageNumber },
495
- });
496
- return parseResult(result).member_info;
497
- }
498
- ```
499
-
500
- Because the signatures match the original activities, the workflow uses `proxyActivities()` at module scope — the standard pattern. Each proxied call is a durable checkpoint. If the process crashes after a Vision MCP tool call completes, replay uses the cached result.
501
-
502
- ### The Pipeline
503
-
504
- 1. **List pages** via MCP tool `list_document_pages`
505
- 2. **Extract** member info from each page via MCP tool `extract_member_info` (routes to OpenAI Vision)
506
- 3. **Merge** multi-page extractions into a single record
507
- 4. **Validate** against member database via MCP tool `validate_member`
508
- 5. **Return or escalate** — match returns; mismatch escalates to the Human Queue
509
-
510
- When the workflow escalates, agents can query and resolve the escalation through the Human Queue MCP server — the same protocol used for the AI tools.
463
+ See `system/mcp-servers/vision.ts` and `services/mcp/server-lifecycle.ts` for working examples.
511
464
 
512
465
  ### Running the Tests
513
466
 
514
467
  ```bash
515
- # Vision server tool tests (no OpenAI key needed for most)
516
- npm run test:mcp:vision
517
-
518
- # Full integration (needs OpenAI key for extraction + workflow tests)
519
- OPENAI_API_KEY=sk-... npm run test:mcp:vision
520
-
521
- # With verbose output
522
- npx vitest run tests/workflows/verify-document-mcp.test.ts --reporter=verbose
468
+ # Vision server tool tests
469
+ npm run test:vision
523
470
  ```
524
471
 
525
472
  The examples above use built-in servers. Long Tail can also connect to any external MCP server.
@@ -722,7 +669,9 @@ Point Long Tail at a URL. The server runs elsewhere.
722
669
  }
723
670
  ```
724
671
 
725
- For Streamable HTTP, use `"transport_type": "streamable-http"`. Same `transport_config`.
672
+ For Streamable HTTP, use `"transport_type": "streamable-http"`. Same `transport_config`. A server that authenticates its callers takes `headers`, sent with every request: `"transport_config": { "url": "...", "headers": { "Authorization": "Bearer <token>" } }`.
673
+
674
+ **Another Long Tail instance** is a remote server like any other. See [Connecting Long Tail Instances](#connecting-long-tail-instances).
726
675
 
727
676
  **Dashboard:** Select **Network Service**, enter the URL, choose SSE or Streamable HTTP, walk through Discovery/Test/Review.
728
677
 
@@ -918,7 +867,7 @@ When `mcp.server.enabled` is `true` (the default), the Human Queue server starts
918
867
 
919
868
  ## REST API
920
869
 
921
- All routes are mounted at `/api/mcp`.
870
+ All routes are mounted at `/api/mcp`. Each route carries the same gate as its `/mcp` twin: registering, editing, deleting, testing, connecting and disconnecting a server require builder access (superadmin or the `engineer` role). Server reads are open to any account; `transport_config` is returned to builders only.
922
871
 
923
872
  ### Server Registration
924
873
 
@@ -959,6 +908,8 @@ curl -X POST http://localhost:3000/api/mcp/servers/$ID/tools/search/call \
959
908
  -d '{ "arguments": { "query": "hello" } }'
960
909
  ```
961
910
 
911
+ A tool call runs as the caller, or as the `execute_as` account when the caller may act as it, and a built-in tool passes the same manifest gate it carries at `/mcp`.
912
+
962
913
  Server registrations are persisted in PostgreSQL so they survive restarts.
963
914
 
964
915
  ## Database Schema
@@ -1031,41 +982,39 @@ The shared test utility at `tests/setup/mcp.ts` wraps this pattern as `createMcp
1031
982
  ### Running MCP Tests
1032
983
 
1033
984
  ```bash
1034
- # Human Queue protocol tests (8 tests — real client, real server, real DB)
1035
- npm run test:mcp
985
+ # Human Queue protocol tests plus MCP registry, CRUD, and REST tests (real client, real server, real DB)
986
+ npx vitest run tests/services/mcp/servers.test.ts
1036
987
 
1037
988
  # Vision MCP server tool tests
1038
- npm run test:mcp:vision
1039
-
1040
- # Full integration with OpenAI Vision
1041
- OPENAI_API_KEY=sk-... npm run test:mcp:vision
989
+ npm run test:vision
1042
990
 
1043
- # All tests
991
+ # All backend tests except those that call a live model
1044
992
  npm test
993
+
994
+ # Fast backend tests: skips tests/workflows and *.llm.test.ts, blanks LLM keys
995
+ npm run test:fast
996
+
997
+ # Tests that call a live model
998
+ npm run test:llm
1045
999
  ```
1046
1000
 
1047
1001
  ### What the Protocol Tests Prove
1048
1002
 
1049
- The `tests/mcp.test.ts` suite includes 8 tests:
1050
-
1051
- 1. **Tool discovery** — `listTools()` returns the expected tools
1052
- 2. **Create** — `escalate_to_human` writes a real PostgreSQL record
1053
- 3. **Check** — `check_resolution` reads status from DB
1054
- 4. **List** — `get_available_work` filters by role
1055
- 5. **Resolve** — `claim_and_resolve` atomically claims and resolves
1056
- 6. **Full lifecycle** — escalate -> check -> list -> resolve -> check -> list (empty)
1057
- 7. **Error: not found** — checking a nonexistent ID returns `isError: true`
1058
- 8. **Error: already resolved** — claiming a resolved escalation returns `isError: true`
1003
+ The `MCP protocol (InMemoryTransport)` block in `tests/services/mcp/servers.test.ts` includes 9 tests:
1059
1004
 
1060
- The `tests/workflows/verify-document-mcp.test.ts` suite adds:
1005
+ 1. **Tool discovery**: `listTools()` returns the 7 tools registered by `services/mcp/server`
1006
+ 2. **Create**: `escalate_to_human` writes a real PostgreSQL record
1007
+ 3. **Check**: `check_resolution` reads status from DB
1008
+ 4. **List**: `get_available_work` filters by role
1009
+ 5. **Resolve**: `claim_and_resolve` atomically claims and resolves
1010
+ 6. **Outcome metadata**: `claim_and_resolve` records outcome metadata on the row
1011
+ 7. **Full lifecycle**: escalate -> check -> list -> resolve -> check -> list (empty)
1012
+ 8. **Error: not found**: checking a nonexistent ID returns `isError: true`
1013
+ 9. **Error: already resolved**: claiming a resolved escalation returns `isError: true`
1061
1014
 
1062
- 1. **Vision tool discovery** — `listTools()` returns 3 Vision tools
1063
- 2. **list_document_pages** — returns page refs from storage
1064
- 3. **validate_member** — match, mismatch, and not_found cases
1065
- 4. **extract_member_info** — extracts via OpenAI Vision (needs API key)
1066
- 5. **Full MCP-native workflow** — extraction -> validation -> escalation -> Human Queue MCP resolution
1015
+ `tests/services/mcp/vision-server.test.ts` covers the Vision server: tool discovery (`analyze_image`, `describe_image`), the missing-LLM-key error for each tool, and independent server instances.
1067
1016
 
1068
- Every test verifies both the MCP response and the actual database state.
1017
+ Every protocol test verifies both the MCP response and the actual database state.
1069
1018
 
1070
1019
  ## Custom Adapters
1071
1020
 
@@ -247,14 +247,19 @@ External MCP servers authenticate to Long Tail using service tokens — long-liv
247
247
 
248
248
  ### Generating a Service Token
249
249
 
250
- ```
251
- POST /api/mcp/servers/:id/service-token
252
- Authorization: Bearer <admin-jwt>
250
+ Service tokens are issued in server code with `generateServiceToken` from `services/auth/service-token.ts`. Run it from a script or startup hook that has database access:
251
+
252
+ ```typescript
253
+ import { generateServiceToken } from './services/auth';
253
254
 
254
- { "name": "ext-calendar-server", "scopes": ["delegation:validate"] }
255
+ const { id, rawToken } = await generateServiceToken(
256
+ 'ext-calendar-server', // name
257
+ serverId, // lt_mcp_servers id, or null
258
+ ['delegation:validate'], // scopes
259
+ );
255
260
  ```
256
261
 
257
- Returns the raw token **once**. The system stores only a bcrypt hash.
262
+ Returns the raw token **once**. The system stores only a bcrypt hash. `listServiceTokens(serverId)` lists a server's tokens without hashes, and `revokeServiceToken(id)` deletes one.
258
263
 
259
264
  ### Using a Service Token
260
265
 
@@ -272,7 +277,7 @@ curl -H "Authorization: Bearer lt_svc_a1b2c3..." \
272
277
  An external MCP server running in a separate container (or separate docker-compose) follows this pattern:
273
278
 
274
279
  1. **Register** with Long Tail as an SSE-based MCP server.
275
- 2. **Receive a service token** from an admin.
280
+ 2. **Receive a service token** issued with `generateServiceToken` (the example reads it from `LT_SERVICE_TOKEN`).
276
281
  3. **Accept tool calls** with `_auth.token` in the args.
277
282
  4. **Validate** the delegation token against Long Tail's delegation API.
278
283
  5. **Fetch** user-scoped credentials (OAuth tokens, files, etc.) via the delegation API.
@@ -353,14 +358,11 @@ echo "Workflow $WORKFLOW_ID started with userId in envelope"
353
358
  ### 4. Test External MCP Server Delegation
354
359
 
355
360
  ```bash
356
- # Start with external server overlay
357
- docker compose -f docker-compose.yml -f docker-compose.external.yml up -d --build
358
-
359
- # Generate a service token for the external server (requires admin JWT)
360
- SERVICE_TOKEN=$(curl -s -X POST http://localhost:3000/api/mcp/servers/<server-id>/service-token \
361
- -H "Authorization: Bearer $TOKEN" \
362
- -H 'Content-Type: application/json' \
363
- -d '{"name":"ext-test","scopes":["delegation:validate"]}' | jq -r .rawToken)
361
+ # Issue a service token with generateServiceToken (see Generating a Service Token),
362
+ # then start the external server overlay with it. The overlay passes it to the
363
+ # external container as LT_SERVICE_TOKEN.
364
+ LT_EXTERNAL_SERVICE_TOKEN=lt_svc_... \
365
+ docker compose -f docker-compose.yml -f docker-compose.external.yml up -d --build
364
366
 
365
367
  # Create a delegation token manually (for testing)
366
368
  DELEGATION=$(node -e "
@@ -381,16 +383,25 @@ curl -X POST http://localhost:9090/tools/fetch_external_data \
381
383
  ### 5. Run Unit Tests
382
384
 
383
385
  ```bash
384
- # Delegation token tests (9 tests)
385
- npx vitest run tests/delegation-tokens.test.ts
386
+ # Delegation token tests
387
+ npx vitest run tests/services/delegation
388
+
389
+ # OAuth provider tests
390
+ npx vitest run tests/services/oauth
386
391
 
387
- # OAuth tests (28 tests)
388
- npx vitest run tests/oauth
392
+ # OAuth authorization server tests (MCP clients)
393
+ npx vitest run tests/services/auth/oauth-server tests/routes/oauth-server-*.test.ts
389
394
 
390
- # All backend tests (487 tests)
395
+ # Fast backend tests: skips tests/workflows and *.llm.test.ts, blanks LLM keys
396
+ npm run test:fast
397
+
398
+ # All backend tests except those that call a live model
391
399
  npx vitest run
392
400
 
393
- # Frontend tests (520 tests)
401
+ # Tests that call a live model (spend provider credits)
402
+ npm run test:llm
403
+
404
+ # Frontend tests
394
405
  cd dashboard && npx vitest run
395
406
  ```
396
407
 
@@ -403,7 +414,7 @@ cd dashboard && npx vitest run
403
414
  | User JWT | 24 hours | Full API access | Login endpoint | Dashboard, API routes |
404
415
  | Bot API key | Long-lived | Full API access (RBAC-scoped) | Admin | Programmatic clients, CI/CD |
405
416
  | Delegation token | 5 minutes | Specific scopes (e.g., `oauth:google:read`) | Workflow activities | MCP tools, delegation API |
406
- | Service token | Long-lived | Server-specific (e.g., `delegation:validate`) | Admin | External MCP servers |
417
+ | Service token | Long-lived | Server-specific (e.g., `delegation:validate`) | Server code (`generateServiceToken`) | External MCP servers |
407
418
  | OAuth access token | Provider-set (~1hr) | Provider scopes (e.g., `email`, `profile`) | OAuth flow | External APIs |
408
419
 
409
420
  ### Trust Boundaries
package/docs/topics.md CHANGED
@@ -130,6 +130,8 @@ Two MCP tools give agents programmatic access to the catalog:
130
130
 
131
131
  This enables autonomous wiring: an agent can discover available topics, read their schemas, and create subscriptions — all through tool calls.
132
132
 
133
+ `list_topics` is open to any account. Registering, editing, deleting and publishing topics, over MCP or REST, requires builder access (superadmin or the `engineer` role). Publishing to a `system.` or `agent.` subject over REST requires superadmin.
134
+
133
135
  ## LTTopicConfig
134
136
 
135
137
  The TypeScript interface for static topic declarations: