kx-mcp-kdbai — KDB.AI backend
The KDB.AI backend extension (bundle) for the KX MCP composition container. It
exposes database/table introspection, structured query, and vector + hybrid search over a KDB.AI
service via the kdbai-client SDK, and is packaged as a
standard container bundle: a package exposing build_server() -> FastMCP, mounted under the kdbai
namespace.
It is mount-only: the composition container (kx-mcp-core) owns transport/host/port, so the
bundle has no standalone server of its own — build_server() just returns a configured FastMCP to
mount(). Run it via the container: uv run kx-mcp --bundles kdbai.
The bundle connects to a KDB.AI service. Unlike the kdb-x backend, it does not require a PyKX license —
kdbai-clientowns connectivity (qIPC or REST).
Table of contents
- Prerequisites
- KDB.AI setup
- Configuration
- Configure embeddings
- Capabilities
- Running the backend
- Troubleshooting
Prerequisites
- A reachable KDB.AI Server on a host and port the MCP server can reach. The bundle's default is
127.0.0.1:8082inqipcmode; selectingrestwithout an explicit port uses127.0.0.1:8081. See the KDB.AI documentation to install / run a server. - UV to run the server.
kdbai-client>=2.0.0(pulled in automatically with this bundle). The MCP host needs noQLIC/ PyKX license; the KDB.AI Server deployment owns its own licensing.
KDB.AI setup
Start (or point at) a KDB.AI Server, then configure the endpoint via KDBAI_DB_* (below); running the
container with this bundle performs its eager mount-time pre-flight. Static credentials and
service_account open a real SDK session, while passthrough has no caller token at startup and so
checks socket reachability only. A failed pre-flight disables this bundle, and the parent container
keeps serving any healthy ones:
uv run kx-mcp --bundles kdbai # connects to 127.0.0.1:8082 (qipc) by default
Configuration
The backend owns the KDBAI_DB_* environment prefix. The container CLI does not carry backend
config; configure the backend via env vars or .env. Transport/host/port/logging are the container's
concern (the KX_MCP_* prefix), not this bundle's — the mount-only refactor retired the bundle's
former KDBAI_MCP_* serving prefix.
| Setting | Env var | Default | Notes |
|---|---|---|---|
| Host | KDBAI_DB_HOST |
127.0.0.1 |
KDB.AI server hostname or IP |
| Port | KDBAI_DB_PORT |
mode-sensitive | 8082 for qipc, 8081 for REST; an explicit value always wins |
| Username | KDBAI_DB_USERNAME |
(empty) | |
| Password | KDBAI_DB_PASSWORD |
(empty) | set when auth is enabled |
| Mode | KDBAI_DB_MODE |
qipc |
qipc (fast binary) or rest (HTTP API) |
| REST protocol | KDBAI_DB_REST_PROTOCOL |
http |
http/https; REST mode only |
| QIPC TLS | KDBAI_DB_QIPC_TLS |
false |
TLS for qipc mode; see TLS note |
| Database | KDBAI_DB_DATABASE_NAME |
default |
default database for operations |
| Retry | KDBAI_DB_RETRY |
2 |
connect retry attempts |
Default k |
KDBAI_DB_K |
5 |
default neighbours returned from searches |
| Vector weight | KDBAI_DB_VECTOR_WEIGHT |
0.7 |
dense weight in hybrid search |
| Sparse weight | KDBAI_DB_SPARSE_WEIGHT |
0.3 |
sparse (BM25) weight in hybrid search |
| Embeddings CSV | KDBAI_DB_EMBEDDING_CSV_PATH |
(packaged utils/embeddings.csv) |
per-table embedding config |
Resolution order: env vars > .env file > defaults.
These defaults are a local-development posture: qipc, loopback, plaintext backend transport, empty static credentials, and no outbound identity strategy. Set transport security and an authentication strategy explicitly for production.
TLS (qipc mode). Enable with KDBAI_DB_QIPC_TLS=true. Point KX_SSL_CA_CERT_FILE at the CA cert
your TLS proxy uses; for local development you can bypass verification with KX_SSL_VERIFY_SERVER=NO.
Outbound auth — OAuth-protected KDB.AI (KDBAI_DB_OUTBOUND_*)
For a KDB.AI server running AUTH_TYPE=oauth, set KDBAI_DB_OUTBOUND_STRATEGY to one of:
service_account— the bundle obtains its own workload-identity bearer (OIDC client-credentials) through the sharedkx_auth_core.exchangeseam (the same outbound implementation shared by OAuth-capable extensions). One identity for the container.passthrough— the bundle forwards the inbound caller's validated bearer as the connection credential, so the KDB.AI server's ACL enforces on the end user'stenant/groups. Each principal gets its own cachedSession(keyed on thesubclaim), so users on one OAuth client never share a connection. Requires inbound auth (KX_MCP_AUTH): the forwarded bearer is the validated principal's token and nothing else — never a rawAuthorizationheader — so with inbound auth unset there would be no principal, no bearer, and every call would quietly open an anonymous session. That combination is refused at startup rather than allowed to look like it works.
Both strategies work in qipc (bearer as the connection password) and rest (bearer handed to
the SDK's file-backed JWTTokenManager via a temp external_token oauth config). Leave
KDBAI_DB_OUTBOUND_STRATEGY empty (default) for the static username/password path (AUTH_TYPE=static
/ no auth).
| Setting | Env var | Default | Notes |
|---|---|---|---|
| Strategy | KDBAI_DB_OUTBOUND_STRATEGY |
(empty = off) | service_account (container identity) or passthrough (end-user identity) |
| Token URL | KDBAI_DB_TOKEN_URL |
(empty) | OIDC token endpoint of the IdP (service_account only) |
| Client ID | KDBAI_DB_CLIENT_ID |
(empty) | client-credentials client id, distinct from KDBAI_DB_USERNAME (service_account only) |
| Client secret | KDBAI_DB_CLIENT_SECRET |
(empty) | client-credentials secret (service_account only) |
| Audience | KDBAI_DB_AUDIENCE |
(empty) | Keycloak: the token audience (= the server's OAUTH_CLIENT_ID) |
| Scopes | KDBAI_DB_SCOPES |
(empty) | Entra: the resource default scope, e.g. api://<client-id>/.default |
| TLS verify | KDBAI_DB_SSL_VERIFY |
true |
verify TLS on the outbound token call |
Server side (not this bundle): the KDB.AI server must be configured for OAuth —
AUTH_TYPE=oauth,OAUTH_CLIENT_ID(matching the tokenaud),OAUTH_ISSUERS, and the tenant/groups claim vars. See the KDB.AI OAuth 2.0 / Entra ID setup guides.
Validating outbound identity against a live KDB.AI
Validated live 2026-06-18 and committed in tests/deterministic/realidp/kdbai/ (tests/docs/TESTING.md
rows KA.1–KA.9, just test-kdbai). Against a real OAuth KDB.AI (kdbai-db 2.0.0-rc.2, Community
Edition) with Keycloak, confirmed the following. That server build is the tested configuration, not
a declared minimum server version:
- qipc-on-pykx-4 data path — a full create+insert+query round-trip on
pykx 4.0.0b5+kdbai-client 2.0.0over qipc (resolves the dependency-override risk in the root CLAUDE.md gotcha — the path works, not just imports). passthroughend-to-end through the container — withKDBAI_DB_OUTBOUND_STRATEGY=passthroughKX_MCP_AUTH=jwks, the inbound bearer is forwarded as the qipc credential and the server authenticates the end user: granting thetradergroup read on a database,kdbai_list_tablesreturned['T1']for alice (trader) and[]for bob (viewer) — different results purely by propagated identity. No bearer →401at the container's inbound gate.
- passthrough pre-flight fix — the bundle starts in passthrough mode against an OAuth server via
a tokenless socket reachability probe; the old anonymous open was rejected → exited. Regression:
tests/unit/test_kdbai_server.py::test_passthrough_preflight_is_socket_probe_not_authed_open.
To run the committed lane:
cd tests/deterministic/realidp/setup/keycloak
docker login portal.dl.kx.com -u <portal-email> -p <bearer-token>
mkdir -p kdbai-data acl-data && chmod 777 kdbai-data acl-data # gitignored; kdbai-db runs as 'nobody'
KDB_LICENSE_B64=$(base64 ~/.kx/kc.lic) docker compose --profile backends up -d # KDBX license (not KXAI)
uv run keycloak_setup.py keycloak_config.json
uv run seed.py # creates db_read/T1 + grants
cd - # back to repo root
cp tests/deterministic/realidp/envs/.env.kdbai.example \
tests/deterministic/realidp/envs/.env.kdbai # fill in values
just test-kdbai
Needs docker login portal.dl.kx.com (bearer token from
the KDB.AI docs)
- a kdb-x license. Uses
network_mode: host(Linux-ism; worked under colima). For a portable setup, replace with explicit port-maps +host.docker.internal.
For the agent-driven demo (Claude Code as the MCP client, two personas, ACL contrast) and the
native discovery proof (RFC 9728 → DCR → auth-code browser flow with no pre-injected token),
see demos/claude-code-live-kdbai/.
Configure embeddings
The similarity / hybrid search tools embed the query text using a provider configured per
database+table in src/kx_mcp_kdbai/utils/embeddings.csv. Two providers ship ready to use (OpenAI and
SentenceTransformers); add your own by subclassing EmbeddingProvider in
src/kx_mcp_kdbai/utils/embeddings.py and decorating it with @register_provider, then map your
database/table rows in the CSV. Set any required API keys (e.g. OPENAI_API_KEY) in the environment.
These are call-time prerequisites, not registration-time feature gates, so the search tools stay visible either way. Similarity search additionally needs an accessible database/table and a matching dense vector index, while hybrid search needs both dense and sparse indexes plus the configured sparse tokenizer/model. Missing configuration produces a tool error to fix, not a disabled bundle.
Capabilities
Names are shown bare (as registered by the bundle); under the container they are namespaced
kdbai_* (e.g. kdbai_query_data).
Tools
| Bare name | Purpose |
|---|---|
list_databases |
List all databases |
database_info |
Info for one database (incl. its tables) |
all_databases_info |
Info for all databases |
list_tables |
List tables in a database |
table_info |
Schema + statistics + indexes for a table |
query_data |
Structured query (filter / sort / group / aggregate / limit); strips embedding columns |
similarity_search |
Dense-vector similarity search against a named vector index |
hybrid_search |
Dense + sparse (BM25) search; weights from KDBAI_DB_VECTOR_WEIGHT / _SPARSE_WEIGHT |
session_info |
KDB.AI session information |
system_info |
KDB.AI system information |
process_info |
KDB.AI process information |
Resources
| Bare URI | Purpose |
|---|---|
file://guidance/kdbai-operations |
Query / search / hybrid syntax + filter examples |
Prompts
| Bare name | Purpose | Params |
|---|---|---|
table_analysis |
Detailed analysis prompt for a table | table_name, analysis_type? (overview/content/quality/search), sample_size? |
Running the backend
The bundle is mount-only — run it through the container:
uv run kx-mcp --bundles kdbai # or: --bundles kdbx,kdbai
Configure the backend with KDBAI_DB_* env vars (or .env) as above. The bundle registers bare
primitive names; the kdbai_ qualifier is supplied by the container's mount(namespace="kdbai").
Troubleshooting
- Connection error / bundle disabled — the KDB.AI Server is not reachable on the configured
host:port (qipc default
127.0.0.1:8082; REST default127.0.0.1:8081). The bundle logs a clear connectivity error and is not mounted; the parent continues serving other healthy bundles. - Authentication error — auth is enabled on the server; set
KDBAI_DB_PASSWORD(andKDBAI_DB_USERNAME). - qipc + TLS — set
KX_SSL_CA_CERT_FILE(orKX_SSL_VERIFY_SERVER=NOfor local dev). - First passthrough call fails authentication/authorization — startup checked reachability only; verify the inbound bearer is valid for KDB.AI and that its principal has the necessary server ACL.
- Search returns no embeddings / provider errors — confirm the table has a row in
embeddings.csv, the provider's API key is set, and the required dense (and, for hybrid, sparse) indexes exist.
Metadata
Release files for kx-mcp-kdbai 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kx_mcp_kdbai-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / kx_mcp_kdbai-0.5.0-py3-none-any.whl
| Download URL | kx_mcp_kdbai-0.5.0-py3-none-any.whl |
|---|---|
| Size | 47.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd40121bb3ac27c998cd1182c65c50be3fe1fc7a3d77275ff65b26100d46c645
|
|
BLAKE2b-256 checksum How to use checksums |
7ca43488d4ed3fc80780f401ff5d207456765800e295cd6546ec3be640e533ee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|