Knowledge Base MCP - Architecture
2 min read
kb-mcp is a stateless proxy in front of a tenant's Unique knowledge base: every MCP tool call resolves to a live call against the Unique API, and no knowledge-base content is stored by kb-mcp itself. The only state kb-mcp owns is its own OAuth-proxy bookkeeping in Postgres: client registrations, tokens, and JTI replay-protection mappings.
Components
Component Descriptions
Component | Purpose |
|---|---|
MCP server (FastMCP, via | Exposes |
Zitadel | OIDC identity provider; |
Unique API | Source of truth for knowledge-base search, the content tree, and file content, called live via |
Postgres | Durable storage for OAuth-proxy state only; never holds knowledge-base data |
The Unique API address is plain configuration (UNIQUE_API_BASE_URL), not hardcoded. With networkPolicy.enabled, the egress rule to it is not created by the chart. See Deployment: Network Policies.
Authentication Architecture
kb-mcp runs its own OIDC flow, independent of the platform's normal Kong-fronted authentication. Deployed instances set routes.auth.jwt: false at the gateway precisely so the gateway doesn't also try to authenticate the request.
Token Isolation
The MCP client authenticates to kb-mcp via Zitadel; kb-mcp then calls the Unique API using the identity established through that session, not a service-wide credential. Every outbound call carries that identity as two headers, x-user-id and x-company-id, set by unique-toolkit from the resolved settings. kb-mcp has no broader access of its own to leak; see Permissions for how the Unique API turns that identity into a scoped result. Upstream Unique API credentials (UNIQUE_APP_ID/UNIQUE_APP_KEY, sent as Authorization/x-app-id) are only needed when the call has to cross the Kong gateway: local development, or a deployment that routes through Kong rather than calling the Unique API directly in-cluster. Direct in-cluster calls carry only the two identity headers: the network policy is what limits who can reach the Unique API at all, not an app credential.
Token Storage
Token / Secret | Storage | Notes |
|---|---|---|
Zitadel client id | Chart values / env var | Public PKCE client id, not a secret |
OAuth-proxy state (client registrations, access/refresh tokens, JTI mappings) | Postgres, encrypted with | Or an ephemeral per-process file store in local development ( |
Downstream OAuth-proxy JWT signing key |
| Local key material only, never transmitted to Zitadel |
Token Encryption
ENCRYPTION_KEY (a 32-byte hex value, openssl rand -hex 32) encrypts OAuth-proxy state at rest in Postgres. It is unrelated to ZITADEL_JWT_SIGNING_KEY, which signs kb-mcp's own downstream JWTs rather than protecting stored data.
Network Policy Shape
kb-mcp is deployed behind a default-deny CiliumNetworkPolicy in every Unique-internal environment. Ingress is limited to the platform gateway (internalServices.dependents.ingressGateway, on by default in the chart); egress is built up per overlay for DNS, the Unique API instance it calls, Zitadel/the platform gateway, and its Postgres host. See Network Policies in the Operator Guide for the concrete rules and the podPort-vs-servicePort gotcha that governs the egress rule to the Unique API.