@hotmeshio/long-tail 0.23.2 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/adapters/express.d.ts +9 -1
- package/build/adapters/express.js +32 -41
- package/build/api/auth-sso.d.ts +1 -1
- package/build/api/bot-accounts.d.ts +2 -0
- package/build/api/bot-accounts.js +4 -0
- package/build/api/capabilities.d.ts +7 -2
- package/build/api/capabilities.js +13 -2
- package/build/api/escalations/analytics.js +5 -0
- package/build/api/escalations/bulk.d.ts +2 -0
- package/build/api/escalations/bulk.js +9 -4
- package/build/api/escalations/helpers.d.ts +5 -0
- package/build/api/escalations/helpers.js +7 -0
- package/build/api/escalations/metadata.js +3 -0
- package/build/api/escalations/single.d.ts +3 -2
- package/build/api/escalations/single.js +8 -3
- package/build/api/mcp/tools.d.ts +12 -0
- package/build/api/mcp/tools.js +113 -9
- package/build/api/scan-codes/choice.js +31 -7
- package/build/api/settings.js +9 -0
- package/build/api/tasks.d.ts +3 -3
- package/build/api/tasks.js +30 -7
- package/build/api/workflows/input-lookups.js +1 -1
- package/build/api/workflows/invocable.js +2 -2
- package/build/api/workflows/invocation.js +1 -1
- package/build/api/yaml-workflows/deploy.d.ts +10 -2
- package/build/api/yaml-workflows/deploy.js +42 -2
- package/build/lib/db/schemas/038_oauth_server.sql +46 -0
- package/build/lib/events/browser-view.d.ts +15 -0
- package/build/lib/events/browser-view.js +101 -0
- package/build/lib/events/nats-ws-filter.d.ts +29 -0
- package/build/lib/events/nats-ws-filter.js +94 -0
- package/build/lib/events/nats-ws-proxy.d.ts +2 -0
- package/build/lib/events/nats-ws-proxy.js +39 -5
- package/build/lib/events/nats-ws-server-filter.d.ts +16 -0
- package/build/lib/events/nats-ws-server-filter.js +56 -0
- package/build/lib/events/nats-ws-ticket.d.ts +10 -0
- package/build/lib/events/nats-ws-ticket.js +42 -0
- package/build/lib/events/socketio.d.ts +10 -1
- package/build/lib/events/socketio.js +10 -3
- package/build/lib/http/index.d.ts +27 -0
- package/build/lib/http/index.js +55 -0
- package/build/modules/auth.d.ts +15 -24
- package/build/modules/auth.js +43 -126
- package/build/modules/capabilities.d.ts +62 -0
- package/build/modules/capabilities.js +188 -0
- package/build/modules/config.d.ts +14 -0
- package/build/modules/config.js +20 -0
- package/build/modules/defaults.d.ts +10 -0
- package/build/modules/defaults.js +12 -1
- package/build/modules/mcp-auth.d.ts +11 -0
- package/build/modules/mcp-auth.js +56 -0
- package/build/modules/oauth-server.d.ts +18 -0
- package/build/modules/oauth-server.js +40 -0
- package/build/routes/agents.js +46 -14
- package/build/routes/announcements.js +2 -2
- package/build/routes/auth-sso.js +2 -2
- package/build/routes/auth.js +2 -2
- package/build/routes/bot-accounts.js +26 -3
- package/build/routes/capabilities.js +4 -4
- package/build/routes/controlplane.js +2 -2
- package/build/routes/dba.js +2 -2
- package/build/routes/delegation.js +2 -2
- package/build/routes/diagnostics.js +2 -2
- package/build/routes/docs.js +2 -2
- package/build/routes/domain.js +2 -2
- package/build/routes/escalations/accumulate.d.ts +1 -1
- package/build/routes/escalations/acting.d.ts +1 -1
- package/build/routes/escalations/analytics.d.ts +1 -1
- package/build/routes/escalations/bulk.d.ts +1 -1
- package/build/routes/escalations/facets.d.ts +1 -1
- package/build/routes/escalations/index.js +2 -2
- package/build/routes/escalations/list.d.ts +1 -1
- package/build/routes/escalations/metadata.d.ts +1 -1
- package/build/routes/escalations/related.d.ts +1 -1
- package/build/routes/escalations/resolve.d.ts +1 -1
- package/build/routes/escalations/single.d.ts +1 -1
- package/build/routes/escalations/single.js +1 -1
- package/build/routes/exports.js +14 -13
- package/build/routes/file-browser.js +9 -8
- package/build/routes/files.js +2 -2
- package/build/routes/index.js +4 -2
- package/build/routes/insight.js +5 -4
- package/build/routes/knowledge.js +2 -2
- package/build/routes/maintenance.js +2 -2
- package/build/routes/mcp-endpoint.d.ts +3 -1
- package/build/routes/mcp-endpoint.js +18 -8
- package/build/routes/mcp.js +35 -15
- package/build/routes/me.js +2 -2
- package/build/routes/namespaces.js +4 -3
- package/build/routes/nats-credentials.js +27 -3
- package/build/routes/oauth-server/authorize.d.ts +2 -0
- package/build/routes/oauth-server/authorize.js +108 -0
- package/build/routes/oauth-server/grants.d.ts +2 -0
- package/build/routes/oauth-server/grants.js +35 -0
- package/build/routes/oauth-server/index.d.ts +8 -0
- package/build/routes/oauth-server/index.js +52 -0
- package/build/routes/oauth-server/registration.d.ts +2 -0
- package/build/routes/oauth-server/registration.js +38 -0
- package/build/routes/oauth-server/token.d.ts +2 -0
- package/build/routes/oauth-server/token.js +100 -0
- package/build/routes/oauth-well-known.d.ts +8 -0
- package/build/routes/oauth-well-known.js +31 -0
- package/build/routes/oauth.js +2 -2
- package/build/routes/overview.js +2 -2
- package/build/routes/personas.js +2 -2
- package/build/routes/pipelines.js +6 -5
- package/build/routes/roles.js +2 -2
- package/build/routes/scan-codes.js +2 -2
- package/build/routes/settings.js +2 -2
- package/build/routes/tasks.js +5 -5
- package/build/routes/topics.js +21 -9
- package/build/routes/users.js +25 -22
- package/build/routes/workflow-sets.js +13 -12
- package/build/routes/workflows/config.js +15 -2
- package/build/routes/workflows/discovery.js +2 -2
- package/build/routes/workflows/index.js +2 -2
- package/build/routes/workflows/invocation.js +11 -10
- package/build/routes/yaml-workflows/cron.js +19 -6
- package/build/routes/yaml-workflows/crud.js +13 -12
- package/build/routes/yaml-workflows/deployment.js +11 -10
- package/build/routes/yaml-workflows/index.js +2 -2
- package/build/routes/yaml-workflows/versions.js +2 -2
- package/build/services/agent/authority.d.ts +14 -0
- package/build/services/agent/authority.js +53 -0
- package/build/services/auth/bot-api-key.d.ts +2 -0
- package/build/services/auth/bot-api-key.js +10 -0
- package/build/services/auth/oauth-server/access-token.d.ts +36 -0
- package/build/services/auth/oauth-server/access-token.js +80 -0
- package/build/services/auth/oauth-server/authorization.d.ts +47 -0
- package/build/services/auth/oauth-server/authorization.js +54 -0
- package/build/services/auth/oauth-server/constants.d.ts +11 -0
- package/build/services/auth/oauth-server/constants.js +16 -0
- package/build/services/auth/oauth-server/index.d.ts +3 -0
- package/build/services/auth/oauth-server/index.js +26 -0
- package/build/services/auth/oauth-server/metadata.d.ts +21 -0
- package/build/services/auth/oauth-server/metadata.js +53 -0
- package/build/services/auth/oauth-server/registration.d.ts +42 -0
- package/build/services/auth/oauth-server/registration.js +134 -0
- package/build/services/auth/oauth-server/sql.d.ts +34 -0
- package/build/services/auth/oauth-server/sql.js +123 -0
- package/build/services/auth/oauth-server/store.d.ts +74 -0
- package/build/services/auth/oauth-server/store.js +151 -0
- package/build/services/auth/sql.d.ts +1 -0
- package/build/services/auth/sql.js +3 -1
- package/build/services/escalation/queries.js +7 -2
- package/build/services/export/index.d.ts +10 -0
- package/build/services/export/index.js +27 -0
- package/build/services/invocation-access.d.ts +25 -4
- package/build/services/invocation-access.js +39 -7
- package/build/services/mcp/client/connection-dispatch.d.ts +6 -1
- package/build/services/mcp/client/connection-dispatch.js +3 -2
- package/build/services/mcp/client/connection-lifecycle.d.ts +10 -2
- package/build/services/mcp/client/connection-lifecycle.js +45 -7
- package/build/services/mcp/client/connection-test.js +2 -6
- package/build/services/mcp/client/connection.d.ts +1 -1
- package/build/services/mcp/client/connection.js +3 -1
- package/build/services/mcp/client/index.d.ts +2 -2
- package/build/services/mcp/client/index.js +4 -1
- package/build/services/mcp/client/network-transport.d.ts +12 -0
- package/build/services/mcp/client/network-transport.js +20 -0
- package/build/services/mcp/client/tools.d.ts +13 -0
- package/build/services/mcp/client/tools.js +18 -0
- package/build/services/mcp/db-server/index.js +2 -1
- package/build/services/mcp/external-server.d.ts +9 -4
- package/build/services/mcp/external-server.js +34 -11
- package/build/services/mcp/playwright-server/index.js +2 -1
- package/build/services/mcp/registered-tools.d.ts +3 -0
- package/build/services/mcp/registered-tools.js +7 -0
- package/build/services/mcp/server-lifecycle.js +2 -1
- package/build/services/workflow-invocation.d.ts +16 -3
- package/build/services/workflow-invocation.js +42 -10
- package/build/services/yaml-workflow/deployer.d.ts +10 -2
- package/build/services/yaml-workflow/deployer.js +17 -5
- package/build/services/yaml-workflow/invoke.js +27 -26
- package/build/start/config.js +7 -0
- package/build/start/index.js +4 -22
- package/build/start/server.d.ts +6 -4
- package/build/start/server.js +11 -35
- package/build/start/socket-auth.js +2 -1
- package/build/start/workers.js +1 -1
- package/build/system/mcp-servers/admin/agent-subscriptions.js +24 -1
- package/build/system/mcp-servers/admin/agents.js +25 -2
- package/build/system/mcp-servers/admin/announcements.js +3 -2
- package/build/system/mcp-servers/admin/bot-accounts.js +37 -5
- package/build/system/mcp-servers/admin/escalations.d.ts +3 -5
- package/build/system/mcp-servers/admin/escalations.js +74 -70
- package/build/system/mcp-servers/admin/exports.js +7 -1
- package/build/system/mcp-servers/admin/index.js +24 -25
- package/build/system/mcp-servers/admin/overview.d.ts +2 -2
- package/build/system/mcp-servers/admin/run-read.d.ts +2 -0
- package/build/system/mcp-servers/admin/run-read.js +5 -0
- package/build/system/mcp-servers/admin/scan-codes.d.ts +2 -2
- package/build/system/mcp-servers/admin/scan-codes.js +5 -11
- package/build/system/mcp-servers/admin/schemas.d.ts +20 -20
- package/build/system/mcp-servers/admin/tasks.js +7 -2
- package/build/system/mcp-servers/admin/users.js +31 -4
- package/build/system/mcp-servers/admin/workflow-config.js +12 -1
- package/build/system/mcp-servers/admin/workflows.js +27 -5
- package/build/system/mcp-servers/admin/yaml-workflows.js +7 -1
- package/build/system/mcp-servers/caller-auth.d.ts +18 -0
- package/build/system/mcp-servers/caller-auth.js +29 -0
- package/build/system/mcp-servers/claude-code.js +2 -1
- package/build/system/mcp-servers/db-query/index.js +2 -1
- package/build/system/mcp-servers/file-storage.js +2 -1
- package/build/system/mcp-servers/http-fetch.js +2 -1
- package/build/system/mcp-servers/human-queue.js +7 -3
- package/build/system/mcp-servers/oauth.js +31 -4
- package/build/system/mcp-servers/schema-exchange.js +2 -1
- package/build/system/mcp-servers/vision.d.ts +1 -0
- package/build/system/mcp-servers/vision.js +17 -7
- package/build/system/seed/tool-manifests-admin.d.ts +2 -17985
- package/build/system/seed/tool-manifests-admin.js +121 -121
- package/build/system/seed/tool-manifests-data.d.ts +8 -374
- package/build/system/seed/tool-manifests-data.js +22 -4
- package/build/system/seed/tool-manifests-escalation.d.ts +2 -352
- package/build/system/seed/tool-manifests-escalation.js +11 -1
- package/build/system/seed/tool-manifests-events.d.ts +2 -116
- package/build/system/seed/tool-manifests-events.js +6 -2
- package/build/system/seed/tool-manifests-knowledge.d.ts +2 -221
- package/build/system/seed/tool-manifests-knowledge.js +41 -1
- package/build/system/seed/tool-manifests-workflows.d.ts +2 -71
- package/build/system/seed/tool-manifests-workflows.js +3 -1
- package/build/system/workflows/shared/principal-tools.d.ts +20 -0
- package/build/system/workflows/shared/principal-tools.js +64 -0
- package/build/system/workflows/shared/tool-executor.js +21 -11
- package/build/system/workflows/shared/tool-loader.js +8 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/auth.d.ts +1 -1
- package/build/types/capability.d.ts +14 -0
- package/build/types/capability.js +2 -0
- package/build/types/events.d.ts +1 -1
- package/build/types/index.d.ts +3 -1
- package/build/types/mcp.d.ts +3 -1
- package/build/types/oauth-server.d.ts +52 -0
- package/build/types/oauth-server.js +2 -0
- package/build/types/startup.d.ts +15 -7
- package/build/vitest.config.js +2 -1
- package/build/vitest.fast.config.d.ts +2 -0
- package/build/vitest.fast.config.js +20 -0
- package/build/vitest.llm.config.d.ts +2 -0
- package/build/vitest.llm.config.js +16 -0
- package/dashboard/dist/assets/{AdminDashboard-BPWsgMfZ.js → AdminDashboard-B3mkMIOT.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-BPWsgMfZ.js.map → AdminDashboard-B3mkMIOT.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-De9imyo5.js → AgentConfigPage-CQj2B678.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-De9imyo5.js.map → AgentConfigPage-CQj2B678.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-B6o96Y5G.js → AgentDetailPage-CzrD8JJI.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-B6o96Y5G.js.map → AgentDetailPage-CzrD8JJI.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DMEmiK_W.js → AgentsPage-jg2OFwyW.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DMEmiK_W.js.map → AgentsPage-jg2OFwyW.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-DeYMngwE.js → AvailableEscalationsPage-IS28XBRe.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-DeYMngwE.js.map → AvailableEscalationsPage-IS28XBRe.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-DDmpgGHZ.js → BotPicker-DvEJFpwS.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-DDmpgGHZ.js.map → BotPicker-DvEJFpwS.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-BqlklomG.js → BulkAssignModal-BoQCi-YC.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-BqlklomG.js.map → BulkAssignModal-BoQCi-YC.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-DOtjDTbK.js → CapabilitiesPage-kwlrcb_t.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-DOtjDTbK.js.map → CapabilitiesPage-kwlrcb_t.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CLr8LP0V.js → CollapsibleSection-UMIV4KIj.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CLr8LP0V.js.map → CollapsibleSection-UMIV4KIj.js.map} +1 -1
- package/dashboard/dist/assets/ConfirmDeleteModal-C5puwMg7.js +2 -0
- package/dashboard/dist/assets/ConfirmDeleteModal-C5puwMg7.js.map +1 -0
- package/dashboard/dist/assets/ConnectedAppsPage-drZa65kP.js +2 -0
- package/dashboard/dist/assets/ConnectedAppsPage-drZa65kP.js.map +1 -0
- package/dashboard/dist/assets/{CountdownTimer-DxX72PwV.js → CountdownTimer-LG03dVgR.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-DxX72PwV.js.map → CountdownTimer-LG03dVgR.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-CObc9Rs5.js → CredentialsPage-CaFQ6vLb.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-CObc9Rs5.js.map → CredentialsPage-CaFQ6vLb.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-Bb8GoNY5.js → CronLabel-Co5j7tzW.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Bb8GoNY5.js.map → CronLabel-Co5j7tzW.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-CmGhVlYl.js → ElapsedCell-WJyE9G0T.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-CmGhVlYl.js.map → ElapsedCell-WJyE9G0T.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-B4Jwy1w3.js → EntityTimelinePanel-CDFFfX9d.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-B4Jwy1w3.js.map → EntityTimelinePanel-CDFFfX9d.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-CZZbZ4Aa.js → EscalationListSchemaPage-CMrUlaKI.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-CZZbZ4Aa.js.map → EscalationListSchemaPage-CMrUlaKI.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-D0ko59_S.js → EscalationSchemaPage-Dx2Lyfrz.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-D0ko59_S.js.map → EscalationSchemaPage-Dx2Lyfrz.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-BcnJEKFD.js → EscalationTimeline-d3nvshOk.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-BcnJEKFD.js.map → EscalationTimeline-d3nvshOk.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-P0q5sck4.js → EscalationTitleSelect-DWQieOM9.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-P0q5sck4.js.map → EscalationTitleSelect-DWQieOM9.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BLPmh4AF.js → EscalationsOverview-BX8Cpi0X.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BLPmh4AF.js.map → EscalationsOverview-BX8Cpi0X.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-gBzi5tIS.js → EventTable-D1-ITVXS.js} +2 -2
- package/dashboard/dist/assets/{EventTable-gBzi5tIS.js.map → EventTable-D1-ITVXS.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-BulSsWb2.js → FilterBar-ABC9ctin.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-BulSsWb2.js.map → FilterBar-ABC9ctin.js.map} +1 -1
- package/dashboard/dist/assets/{FormattedValue-BMHRrvrL.js → FormattedValue-k27T4bG7.js} +2 -2
- package/dashboard/dist/assets/{FormattedValue-BMHRrvrL.js.map → FormattedValue-k27T4bG7.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage--997yNRr.js → GraphInvokePage-DKUErxWc.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage--997yNRr.js.map → GraphInvokePage-DKUErxWc.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-CwXFz--v.js → HomePage-C6u9dIpR.js} +2 -2
- package/dashboard/dist/assets/{HomePage-CwXFz--v.js.map → HomePage-C6u9dIpR.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Df4qZryJ.js → ListToolbar-gA5rFzkz.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Df4qZryJ.js.map → ListToolbar-gA5rFzkz.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DrogIAKJ.js → McpOverview-BOPo3J_i.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DrogIAKJ.js.map → McpOverview-BOPo3J_i.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-CJmvCAE6.js → McpQueryDetailPage-BRVVi0Zh.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-CJmvCAE6.js.map → McpQueryDetailPage-BRVVi0Zh.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-lygo4Yq0.js → McpQueryPage-Dmbb6SAc.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-lygo4Yq0.js.map → McpQueryPage-Dmbb6SAc.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-hvns2sCm.js → McpRunDetailPage-bMXNO-6V.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-hvns2sCm.js.map → McpRunDetailPage-bMXNO-6V.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-C2_7spTX.js → McpRunsPage-Bi9AMWja.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-C2_7spTX.js.map → McpRunsPage-Bi9AMWja.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-BlK8WlsY.js → OperationsPage-CvR74ZUJ.js} +3 -3
- package/dashboard/dist/assets/{OperationsPage-BlK8WlsY.js.map → OperationsPage-CvR74ZUJ.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-BeWBiMGX.js → OperatorDashboard-DctmZw10.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-BeWBiMGX.js.map → OperatorDashboard-DctmZw10.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-CNHpsX_i.js → PersonaDetailPage-Ubqm2rQH.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-CNHpsX_i.js.map → PersonaDetailPage-Ubqm2rQH.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-ChASEZRg.js → PersonasPage-BpFL2rpo.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-ChASEZRg.js.map → PersonasPage-BpFL2rpo.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-D5Lk-PKF.js → PortalPage-Dfc_Q02R.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-D5Lk-PKF.js.map → PortalPage-Dfc_Q02R.js.map} +1 -1
- package/dashboard/dist/assets/ProcessDetailPage-liJspvQh.js +2 -0
- package/dashboard/dist/assets/{ProcessDetailPage-DNgCIwRl.js.map → ProcessDetailPage-liJspvQh.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-pRjWuWlH.js → ProcessesListPage-C3OM5ZUy.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-pRjWuWlH.js.map → ProcessesListPage-C3OM5ZUy.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js +8 -0
- package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js.map +1 -0
- package/dashboard/dist/assets/{RoleDetailPage-Bh_UcfYY.js → RoleDetailPage-CrlYCh-R.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-Bh_UcfYY.js.map → RoleDetailPage-CrlYCh-R.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-CK17N7zz.js → RolesPage-BaazL_pt.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-CK17N7zz.js.map → RolesPage-BaazL_pt.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-BEKUP0p2.js → RunAsSelector-DxuV0fa1.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-BEKUP0p2.js.map → RunAsSelector-DxuV0fa1.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-Bd0Pflqx.js → ScanCodesPage-C0mvmYTq.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-Bd0Pflqx.js.map → ScanCodesPage-C0mvmYTq.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CnuhozmJ.js → ScanSchemeDetailPage-CiJgt5dZ.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CnuhozmJ.js.map → ScanSchemeDetailPage-CiJgt5dZ.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-CoLc-q3h.js → ScanStationPage-DzGaXc40.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-CoLc-q3h.js.map → ScanStationPage-DzGaXc40.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-COrfvkBi.js → StickyPagination-CqbjVY6T.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-COrfvkBi.js.map → StickyPagination-CqbjVY6T.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-Cif2egLy.js → StreamMessageDetail-wX3i0aqs.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-Cif2egLy.js.map → StreamMessageDetail-wX3i0aqs.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-BnZYTrAh.js → SwimlaneTimeline-C50PsFoV.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-BnZYTrAh.js.map → SwimlaneTimeline-C50PsFoV.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-DEz_dqyR.js → TaskDetailPage-bbNSv4Ae.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-DEz_dqyR.js.map → TaskDetailPage-bbNSv4Ae.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-oEfEGj0_.js → TasksListPage-CDWnm_d9.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-oEfEGj0_.js.map → TasksListPage-CDWnm_d9.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-Dz5TgZZZ.js → TimeAgo-BLjqlfoX.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-Dz5TgZZZ.js.map → TimeAgo-BLjqlfoX.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-BUTgE244.js → TimestampCell-CnW0ENb5.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-BUTgE244.js.map → TimestampCell-CnW0ENb5.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-BS4g6vt-.js → ToolTestPanel-DkMgCB-k.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-BS4g6vt-.js.map → ToolTestPanel-DkMgCB-k.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-C_I6JIVD.js → TopicDetailPage-g3pljKKX.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-C_I6JIVD.js.map → TopicDetailPage-g3pljKKX.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-Cr6-wfhJ.js → TopicsPage-CVcCYdy-.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-Cr6-wfhJ.js.map → TopicsPage-CVcCYdy-.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-ZFpWMaFF.js → UserName-D6zGIK2i.js} +2 -2
- package/dashboard/dist/assets/{UserName-ZFpWMaFF.js.map → UserName-D6zGIK2i.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-ByPixDZW.js → WorkflowExecutionPage-B8g81FCJ.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-ByPixDZW.js.map → WorkflowExecutionPage-B8g81FCJ.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-CWsJdMdR.js → WorkflowsDashboard-nxT3bv6W.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-CWsJdMdR.js.map → WorkflowsDashboard-nxT3bv6W.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Dk9gyqZN.js → WorkflowsOverview-grI-KAI2.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Dk9gyqZN.js.map → WorkflowsOverview-grI-KAI2.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CHwcrsaT.js → YamlWorkflowDetailPage-BoZ-hfBE.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CHwcrsaT.js.map → YamlWorkflowDetailPage-BoZ-hfBE.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-B5jRX2Ph.js → YamlWorkflowsPage-Bf04rwRv.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-B5jRX2Ph.js.map → YamlWorkflowsPage-Bf04rwRv.js.map} +1 -1
- package/dashboard/dist/assets/{agents-Dd7E-27d.js → agents-Dphpdi8l.js} +2 -2
- package/dashboard/dist/assets/{agents-Dd7E-27d.js.map → agents-Dphpdi8l.js.map} +1 -1
- package/dashboard/dist/assets/{bots-CpaYjZTk.js → bots-DIFE298x.js} +2 -2
- package/dashboard/dist/assets/{bots-CpaYjZTk.js.map → bots-DIFE298x.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CNjg_qv1.js → capabilities-D7Y7LClY.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CNjg_qv1.js.map → capabilities-D7Y7LClY.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DgmvnAtU.js → controlplane-D1TGcYsS.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DgmvnAtU.js.map → controlplane-D1TGcYsS.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Uj4U9g5H.js → escalation-columns-cwZE6xyo.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Uj4U9g5H.js.map → escalation-columns-cwZE6xyo.js.map} +1 -1
- package/dashboard/dist/assets/{index-x5z73M9N.js → index-BzYcUPdD.js} +2 -2
- package/dashboard/dist/assets/{index-x5z73M9N.js.map → index-BzYcUPdD.js.map} +1 -1
- package/dashboard/dist/assets/index-CeCtqujG.js +67 -0
- package/dashboard/dist/assets/index-CeCtqujG.js.map +1 -0
- package/dashboard/dist/assets/{index-RIFT3RlO.js → index-ChV7pBjM.js} +2 -2
- package/dashboard/dist/assets/{index-RIFT3RlO.js.map → index-ChV7pBjM.js.map} +1 -1
- package/dashboard/dist/assets/{index-OfO0173w.js → index-CniRa65p.js} +2 -2
- package/dashboard/dist/assets/{index-OfO0173w.js.map → index-CniRa65p.js.map} +1 -1
- package/dashboard/dist/assets/{index-ByBy9M3L.js → index-CxdjT1Yk.js} +2 -2
- package/dashboard/dist/assets/{index-ByBy9M3L.js.map → index-CxdjT1Yk.js.map} +1 -1
- package/dashboard/dist/assets/{index-C_K7OlzT.js → index-DAvi5_2T.js} +2 -2
- package/dashboard/dist/assets/{index-C_K7OlzT.js.map → index-DAvi5_2T.js.map} +1 -1
- package/dashboard/dist/assets/{index-BrwqtXRh.js → index-DN-kX7hL.js} +2 -2
- package/dashboard/dist/assets/{index-BrwqtXRh.js.map → index-DN-kX7hL.js.map} +1 -1
- package/dashboard/dist/assets/index-Dl_8hbYI.js +2 -0
- package/dashboard/dist/assets/index-Dl_8hbYI.js.map +1 -0
- package/dashboard/dist/assets/{index-D4Dlznn9.js → index-DpKOr311.js} +2 -2
- package/dashboard/dist/assets/{index-D4Dlznn9.js.map → index-DpKOr311.js.map} +1 -1
- package/dashboard/dist/assets/{index-CnOvJz6U.js → index-Dy1wWu2e.js} +2 -2
- package/dashboard/dist/assets/{index-CnOvJz6U.js.map → index-Dy1wWu2e.js.map} +1 -1
- package/dashboard/dist/assets/{index-BT1Ms5Q5.js → index-HLu98Sqh.js} +2 -2
- package/dashboard/dist/assets/{index-BT1Ms5Q5.js.map → index-HLu98Sqh.js.map} +1 -1
- package/dashboard/dist/assets/{index-BFASQ7_X.js → index-ag2pCAPu.js} +2 -2
- package/dashboard/dist/assets/{index-BFASQ7_X.js.map → index-ag2pCAPu.js.map} +1 -1
- package/dashboard/dist/assets/{index-BsHVgWH6.js → index-gkxPN7Vx.js} +2 -2
- package/dashboard/dist/assets/{index-BsHVgWH6.js.map → index-gkxPN7Vx.js.map} +1 -1
- package/dashboard/dist/assets/index-m9A3UYst.css +1 -0
- package/dashboard/dist/assets/{knowledge-Cci_r6Kl.js → knowledge-DnMs-SOJ.js} +2 -2
- package/dashboard/dist/assets/{knowledge-Cci_r6Kl.js.map → knowledge-DnMs-SOJ.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-NY4iL0L-.js → mcp-CwW-K3r4.js} +2 -2
- package/dashboard/dist/assets/{mcp-NY4iL0L-.js.map → mcp-CwW-K3r4.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-CbvZo_I_.js → mcp-query-BZt5e8_Q.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-CbvZo_I_.js.map → mcp-query-BZt5e8_Q.js.map} +1 -1
- package/dashboard/dist/assets/{personas-Fy-f7QQd.js → personas-UA-Xn60f.js} +2 -2
- package/dashboard/dist/assets/{personas-Fy-f7QQd.js.map → personas-UA-Xn60f.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-DKiuozxV.js → pipelines-Cu3PARum.js} +2 -2
- package/dashboard/dist/assets/{pipelines-DKiuozxV.js.map → pipelines-Cu3PARum.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CdM1Rkk9.js → tasks-BO6h8GJE.js} +2 -2
- package/dashboard/dist/assets/{tasks-CdM1Rkk9.js.map → tasks-BO6h8GJE.js.map} +1 -1
- package/dashboard/dist/assets/{topics-XNy2mf3n.js → topics-CWjCR-17.js} +2 -2
- package/dashboard/dist/assets/{topics-XNy2mf3n.js.map → topics-CWjCR-17.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-CyGcU3_S.js → useDebouncedValue-6t0jx1RB.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-CyGcU3_S.js.map → useDebouncedValue-6t0jx1RB.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-C2RIh_IN.js → useNamespace-CqpoQx6D.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-C2RIh_IN.js.map → useNamespace-CqpoQx6D.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-CDiV5fjf.js → useYamlActivityEvents-hmCQQwzB.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-CDiV5fjf.js.map → useYamlActivityEvents-hmCQQwzB.js.map} +1 -1
- package/dashboard/dist/assets/{validate-DcGWN82Y.js → validate-BIRn4a6d.js} +2 -2
- package/dashboard/dist/assets/{validate-DcGWN82Y.js.map → validate-BIRn4a6d.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-CH8UrouH.js → yaml-workflows-ziUdZhKY.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-CH8UrouH.js.map → yaml-workflows-ziUdZhKY.js.map} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/docs/agents.md +3 -1
- package/docs/api/http/agents.md +15 -1
- package/docs/api/http/escalations.md +3 -3
- package/docs/api/http/exports.md +3 -1
- package/docs/api/http/file-browser.md +3 -1
- package/docs/api/http/mcp-endpoint.md +5 -2
- package/docs/api/http/mcp-servers.md +34 -4
- package/docs/api/http/namespaces.md +2 -0
- package/docs/api/http/pipelines.md +2 -0
- package/docs/api/http/roles.md +11 -8
- package/docs/api/http/service-accounts.md +8 -2
- package/docs/api/http/settings.md +29 -2
- package/docs/api/http/tasks.md +3 -1
- package/docs/api/http/topics.md +7 -1
- package/docs/api/http/users.md +8 -2
- package/docs/api/http/workflows.md +25 -10
- package/docs/api/http/yaml-workflows.md +21 -0
- package/docs/api/mcp/admin.md +409 -49
- package/docs/api/mcp/file-storage.md +4 -0
- package/docs/api/mcp/http-fetch.md +6 -2
- package/docs/api/mcp/human-queue.md +53 -0
- package/docs/api/mcp/index.md +13 -10
- package/docs/api/mcp/knowledge.md +34 -0
- package/docs/api/mcp/oauth.md +1 -1
- package/docs/api/mcp/ortho.md +113 -0
- package/docs/api/mcp/vision.md +1 -1
- package/docs/api/sdk/bot-accounts.md +1 -0
- package/docs/api/sdk/escalations.md +2 -2
- package/docs/api/sdk/mcp.md +2 -2
- package/docs/api/sdk/settings.md +1 -1
- package/docs/api/sdk/tasks.md +2 -2
- package/docs/api/sdk/workflows.md +2 -2
- package/docs/api/sdk/yaml-workflows.md +1 -1
- package/docs/architecture.md +3 -1
- package/docs/auth.md +3 -2
- package/docs/cloud.md +7 -2
- package/docs/dashboard.md +16 -7
- package/docs/data.md +1 -1
- package/docs/escalation-strategies.md +9 -20
- package/docs/events.md +6 -0
- package/docs/iam.md +7 -5
- package/docs/mcp.md +159 -210
- package/docs/oauth-and-delegation.md +32 -21
- package/docs/topics.md +2 -0
- package/docs/workflows.md +14 -112
- package/package.json +5 -3
- package/dashboard/dist/assets/ConfirmDeleteModal-DW4DrPur.js +0 -2
- package/dashboard/dist/assets/ConfirmDeleteModal-DW4DrPur.js.map +0 -1
- package/dashboard/dist/assets/ProcessDetailPage-DNgCIwRl.js +0 -2
- package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js +0 -8
- package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js.map +0 -1
- package/dashboard/dist/assets/index-CtlBjl8o.js +0 -2
- package/dashboard/dist/assets/index-CtlBjl8o.js.map +0 -1
- package/dashboard/dist/assets/index-LRYC__mE.js +0 -67
- package/dashboard/dist/assets/index-LRYC__mE.js.map +0 -1
- package/dashboard/dist/assets/index-MYI2_Xb3.css +0 -1
package/docs/events.md
CHANGED
|
@@ -45,6 +45,12 @@ services:
|
|
|
45
45
|
- NATS_TOKEN=your-token
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
**Browser access.** The dashboard only subscribes. With the WebSocket proxy (`wsProxy`, so browsers reach NATS through Long Tail at `<basePath>/nats-ws`), `GET /api/nats-credentials` returns a WebSocket URL carrying a short-lived ticket for the signed-in person (`NATS_WS_TICKET_TTL_SECONDS`, default 300) and no NATS credential. The proxy admits only a ticket holder, writes the server's `NATS_TOKEN` into the connection itself, and drops anything the browser tries to publish. When browsers connect to NATS directly, set `NATS_DASHBOARD_TOKEN` to a subscribe-only NATS credential and the route hands that out instead of `NATS_TOKEN`.
|
|
49
|
+
|
|
50
|
+
**What a browser receives.** Builders (superadmin, or the `engineer` role) receive events whole. Everyone else receives the browser view: escalation events keep their routing fields (`id`, `type`, `subtype`, `status`, `priority`, `role`, `assigned_to`, `assigned_until`, `workflow_id`, `workflow_type`, `origin_id`, `task_id`, `parent_id`, `resolved_at`, `claimed_at`, and the bulk and reassignment fields), and every other event arrives without `data` and `milestones`. Records are read through the scoped API by id, so pages refresh as before; the invoke page reads its own run's result from `GET /api/workflows/:id/result`. The WebSocket proxy applies the view per connection from the ticket's person, and the Socket.IO adapter per socket from the person its authenticator returns (`{ userId }`; an authenticator that returns `true` admits the socket with the browser view). Server-side consumers, such as agent triggers and callbacks, receive events whole.
|
|
51
|
+
|
|
52
|
+
**Reconnecting.** The dashboard fetches a fresh ticket from `GET /api/nats-credentials` for every connection attempt, through the same client as every API call, so an expired session is refreshed first. After a drop the first retry lands at a random point within `NATS_RECONNECT_SPREAD_MS` (default 5000), so tabs that dropped together after a deploy return gradually; later retries back off with jitter from `NATS_RECONNECT_INITIAL_MS` (default 1000) up to `NATS_RECONNECT_MAX_MS` (default 60000), one attempt at a time. It waits while the tab is hidden, and stops only when the person is signed out; a new sign-in starts it again. On reconnect it reopens every active subscription and refetches the open pages once, spread across the same window. When live updates stay down longer than `NATS_LIVE_NOTICE_AFTER_MS` (default 30000), a "Live updates unavailable" notice appears in the announcement banner row. `GET /api/settings` carries these values as `events.reconnect` (`initialDelayMs`, `maxDelayMs`, `noticeAfterMs`, `spreadMs`).
|
|
53
|
+
|
|
48
54
|
Both adapters still publish events regardless of `EVENT_TRANSPORT` — the setting only controls what the dashboard listens on. This means server-side event consumers (callbacks, NATS subscribers) work independently of the dashboard transport.
|
|
49
55
|
|
|
50
56
|
## The event envelope
|
package/docs/iam.md
CHANGED
|
@@ -123,14 +123,14 @@ Use `execute_as` when a workflow needs permissions or credentials that differ fr
|
|
|
123
123
|
Two ways to set `execute_as`:
|
|
124
124
|
|
|
125
125
|
1. **Workflow config** — set `execute_as` in `lt_config_workflows`. Every invocation of that workflow runs as the specified service account.
|
|
126
|
-
2. **Per-request override** — pass `
|
|
126
|
+
2. **Per-request override** — pass `execute_as` in the invocation body. A superadmin may act as any account. A caller holding an admin-type grant may act as an account that holds no superadmin grant and whose every role the caller also holds, at the same or a higher type. No other caller may set it.
|
|
127
127
|
|
|
128
128
|
In both cases, the original invoker is preserved in `initiated_by`. The audit trail always shows both who asked and who executed.
|
|
129
129
|
|
|
130
130
|
### Lifecycle
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
|
-
# Create a service account (
|
|
133
|
+
# Create a service account (builder: superadmin or the engineer role)
|
|
134
134
|
POST /api/bot-accounts
|
|
135
135
|
{ "name": "data-bot", "description": "Nightly analytics" }
|
|
136
136
|
|
|
@@ -287,13 +287,15 @@ The MCP client also emits debug-level audit logs for every tool invocation:
|
|
|
287
287
|
| Credential | Scope | Lifetime | Revocation |
|
|
288
288
|
|---|---|---|---|
|
|
289
289
|
| User JWT | Full API (RBAC-scoped) | 24 hours | Logout / expiry |
|
|
290
|
-
| Bot API key | Full API (RBAC-scoped) | Until revoked |
|
|
290
|
+
| Bot API key | Full API (RBAC-scoped) | Until revoked | A builder revokes the key |
|
|
291
291
|
| Delegation token | Specific scopes | 5 min (max 1 hr) | Expires naturally |
|
|
292
292
|
| OAuth token | Provider scopes | Provider-set | User revokes in Connections |
|
|
293
293
|
|
|
294
|
-
Service accounts inherit the same RBAC constraints as human users. A service account with the `member` role cannot access admin endpoints. A service account
|
|
294
|
+
Service accounts inherit the same RBAC constraints as human users. A service account with the `member` role cannot access admin endpoints. A service account that holds none of a workflow's `invocation_roles` cannot invoke it.
|
|
295
295
|
|
|
296
|
-
|
|
296
|
+
Invocation roles are checked against the caller's current grants in the database, never the role claims a token carries. A workflow with an empty `invocation_roles` list is open to every authenticated caller. A superadmin, or a holder of the `admin` role at admin type, invokes any invocable workflow. `capabilityInvoke`, which calls tools with system authority, is invocable by superadmins only. Identity context for a compiled workflow comes from the server: a caller-supplied `_scope` in the input data is ignored.
|
|
297
|
+
|
|
298
|
+
The `execute_as` override never exceeds the caller's own authority. A superadmin may act as any account; a caller holding an admin-type grant may act as a non-superadmin account all of whose roles the caller holds at the same or a higher type. Anyone else is refused with `403`.
|
|
297
299
|
|
|
298
300
|
## Key Files
|
|
299
301
|
|
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)
|
|
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
|
|
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
|
|
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.**
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
##
|
|
303
|
+
## Connecting Long Tail Instances
|
|
250
304
|
|
|
251
|
-
|
|
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
|
-
###
|
|
307
|
+
### Set up the connection
|
|
254
308
|
|
|
255
|
-
|
|
309
|
+
**On the instance being called (the remote):**
|
|
256
310
|
|
|
257
|
-
Create a
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
```
|
|
271
|
-
|
|
272
|
-
"
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
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
|
-
|
|
335
|
+
Registration, testing and connecting require builder access on the calling instance.
|
|
282
336
|
|
|
283
|
-
|
|
284
|
-
|-----------|------|----------|-------------|
|
|
285
|
-
| `escalation_id` | string | yes | The escalation ID to check |
|
|
337
|
+
### What each side enforces
|
|
286
338
|
|
|
287
|
-
|
|
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
|
-
|
|
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
|
-
|
|
343
|
+
The key is part of `transport_config`, which is returned only to builders.
|
|
310
344
|
|
|
311
|
-
|
|
345
|
+
### Keys
|
|
312
346
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
|
|
351
|
+
### Troubleshooting
|
|
319
352
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
360
|
+
## Human Queue Server
|
|
340
361
|
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
350
|
-
{
|
|
351
|
-
"escalation_id": "uuid",
|
|
352
|
-
"status": "resolved",
|
|
353
|
-
"resolved_at": "2025-01-15T11:00:00Z"
|
|
354
|
-
}
|
|
355
|
-
```
|
|
366
|
+
### Tools
|
|
356
367
|
|
|
357
|
-
|
|
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
|
|
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
|
|
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
|
-
| `
|
|
405
|
-
| `
|
|
406
|
-
|
|
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 '
|
|
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: '
|
|
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.
|
|
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 `
|
|
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
|
|
516
|
-
npm run test:
|
|
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
|
|
1035
|
-
|
|
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:
|
|
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`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|