The embeddable collection-chat widget: an agentic Claude loop that answers questions grounded in a collection's documents, streamed to the browser over SSE.
| Service | Role |
|---|---|
| platform-frontend | Embed widget UI (iframe) — renders SSE stream |
| platform-api | POST /{orgid}/collections/{collection_id}/external-chat — auth, agentic loop, SSE |
| clj-pg-wrapper | Resolves Auth0 embed user (/api/v1/users/ensure) |
| DynamoDB | Embed API keys, collection config, chat history |
| Archestra | MCP gateway (http://archestra:9000/v1/mcp/{gateway-id}) |
| mcp-servers-runner | unstructured-collections-server (cap-uc) MCP tools behind Archestra |
| qdrant-svc | /search/hybrid vector + keyword retrieval |
| Anthropic API | Claude — https://api.anthropic.com/v1/messages (streamed) |
Not in this path: metamcp (
mcp.capitol.ai) fronts mcp-servers-runner for the LibreChat / customer-chat feature, a separate flow. Embed external-chat routes through Archestra, not metamcp.
sequenceDiagram
autonumber
participant B as Browser (embed iframe)<br/>platform-frontend
participant API as platform-api<br/>external_chat.py
participant CLJ as clj-pg-wrapper
participant DDB as DynamoDB
participant ARCH as Archestra<br/>MCP Gateway
participant MSR as mcp-servers-runner<br/>(cap-uc / unstructured)
participant QD as qdrant-svc
participant AN as Anthropic API<br/>Claude
B->>API: POST /{orgid}/collections/{cid}/external-chat<br/>(embed API key, message, conversation_id?)
API->>DDB: validate embed API key
API->>CLJ: ensure Auth0 embed user
CLJ-->>API: user_id
API->>DDB: load collection config
API->>DDB: hydrate conversation history
Note over API,AN: Agentic loop (streamed as SSE to browser)
loop until Claude returns final answer (tool-round cap)
API->>AN: stream messages + tool defs
AN-->>API: tool_use: cap-uc search
API->>ARCH: MCP call_tool (Bearer org token, organization_id arg)
ARCH->>MSR: proxy to unstructured-collections-server
MSR->>QD: /search/hybrid (custom_filters)
QD-->>MSR: chunk matches
MSR-->>ARCH: tool result
ARCH-->>API: tool result
API-->>B: SSE keepalive + partial tokens
end
AN-->>API: final assistant message
API->>DDB: persist user + assistant messages
API-->>B: SSE final answer + citations, [DONE]
- Auth boundary: embed API key (per-collection) validated first; Auth0 user resolved via clj-pg-wrapper.
- Tenant isolation:
organization_idpassed as an explicit MCP tool arg to close the Archestra passthrough cache leak (ENG-1335). - Long-conversation survival (ENG-3629): tool-round cap + SSE keepalive prevent gateway/read timeouts on long agentic loops.
- Streaming: single
httpx.AsyncClientreused across the loop; response streamed to the browser as SSE throughout, not just at the end.