Connecting AI clients to the KDBL Context Lake (K-Lake) MCP server¶
This is a practical guide for wiring AI clients into K-Lake's MCP server so they can search and retrieve your crawled and extracted content. It covers the four headline clients people ask about — Claude (Claude Desktop / claude.ai custom connectors), OpenAI ChatGPT (Business/Enterprise/Edu connectors), Microsoft Copilot Studio, and Google Gemini — plus the connectivity checks and the handful of auth gotchas that account for almost every failed connection.
Looking for the tools themselves? This guide is about connecting a client; the MCP skills reference catalogues what they can call — the six tools (search, read, browse), their inputs/outputs, and the locate→read→answer usage pattern.
Local / air-gapped client? All four clients above are cloud-hosted and need outbound internet — useless on an isolated network. For a fully on-prem client (a self-hosted LLM that retrieves over MCP with zero internet), see the Air-gapped AI demo: a self-hosted LLM + a local chat interface + an MCP bridge, all GPU-accelerated on your own cluster, authenticating with a PAT (no IdP needed).
Client UIs in this space move faster than this doc. Where a client's support is in beta, gated to a tier, or otherwise fiddly, that's called out — but always confirm the exact menu path against the vendor's current docs. The links here were checked in June 2026.
What our server is (the facts a client integrator needs)¶
In short:
- MCP revision
2025-11-25, Streamable HTTP transport, single endpoint at/mcp(POSTonly — aGET /mcpreturns405; there is no server-initiated SSE stream). - An OAuth 2.1 Resource Server. It does not run an authorization server — your IdP mints tokens; K-Lake only validates them. The client drives the OAuth 2.1 authorization-code-with-PKCE flow against your IdP and presents the resulting bearer token.
- Serves RFC 9728 Protected Resource Metadata, unauthenticated, at both
/.well-known/oauth-protected-resourceand/.well-known/oauth-protected-resource/mcp. A tokenless hit on/mcpreturns401with aWWW-Authenticate: Bearer …, resource_metadata="…"challenge pointing at that document, so a compliant client can self-discover. - The metadata document advertises
resource(the canonical URI),authorization_servers(the distinct OIDC issuers across all tenants),scopes_supported(fromKDBL_MCP_SCOPES, defaultkdbl.search,kdbl.read), andbearer_methods_supported: ["header"]. - It validates the bearer token's
audagainst the canonical resource URI (KDBL_MCP_RESOURCE_URI). Per tenant, the expected audience comes fromoidc_config.mcp_audience. A mismatchedaudis a401— this is the single most common cause of a failed connection (see Audience binding). - Accepts enterprise OIDC tokens (Microsoft Entra ID / Azure AD, Google, Okta, Keycloak) as well as K-Lake PATs (
kdblpat_…) and the cluster-admin token.
Tools exposed¶
Five read-only tools, all running inside a row-level-security-scoped transaction so results are trimmed to what the caller is authorized to see:
| Tool | Arguments | Returns |
|---|---|---|
search_content |
query (required), source_id (optional), limit (1–100, default 20) |
Ranked snippets over extracted text the caller can see, each with a citation and a resource link. |
get_file_text |
source_id, key (both required) |
Extraction status, chunk count, ordered text chunks, and reconstructed full text as an embedded resource. |
get_file_metadata |
source_id, key (both required) |
Size, mtime, etag, storage class, owner, indexed-at, content type, POSIX mode/uid/gid where captured. |
list_sources |
cursor (optional), limit (1–200, default 50) |
Paginated list of accessible sources, with a nextCursor. |
list_files |
source_id (required), cursor (optional), limit (1–200, default 50) |
Paginated list of files within a source, with a nextCursor. |
It serves only extracted text and metadata — never original file bytes.
Prerequisites¶
- The MCP server is enabled and reachable. Set
KDBL_MCP_ENABLED=trueandKDBL_MCP_RESOURCE_URIon the kdbl-api deployment, and confirm the public URL resolves. See Enabling the server for the full env table. - You know your public
/mcpURL — the URL the AI client will call, e.g.https://kdbl.example.com/mcp. This must equalKDBL_MCP_RESOURCE_URI. - Your IdP mints tokens whose
audis that resource URI, and the tenant'soidc_config.mcp_audienceis set to the same value. Read the next section before you wire up any client.
Audience binding (read this first)¶
This is the #1 thing that trips people up.
K-Lake follows the RFC 8707 model: an MCP access token must be audience-bound to the MCP resource URI, so a token issued for MCP cannot be replayed against the main K-Lake API (and vice versa). Concretely:
- The token your client presents must carry
aud = <KDBL_MCP_RESOURCE_URI>(e.g.https://kdbl.example.com/mcp). - K-Lake resolves the expected audience per tenant from
oidc_config.mcp_audience. Set this to the resource URI for every tenant that should be reachable over MCP. - If a tenant has no
mcp_audienceand the operator hasn't enabled theKDBL_MCP_ALLOW_API_AUDIENCEescape hatch, that tenant's tokens simply401— K-Lake will not silently fall back to validating against the tenant's API audience.
In practice that means two pieces of IdP/tenant configuration:
- On the IdP side, register K-Lake's MCP resource as an API/scope/application-ID-URI so issued tokens get the right
aud. (In Entra terms, expose an API with that Application ID URI; in Okta/Keycloak, define a resource/audience the client requests.) - On the K-Lake tenant, set
oidc_config.mcp_audienceto<KDBL_MCP_RESOURCE_URI>.
KDBL_MCP_ALLOW_API_AUDIENCE=true exists for IdPs that genuinely cannot mint resource-scoped tokens, but it weakens the no-replay guarantee — leave it off unless you must.
Quick connectivity check¶
Before touching any client UI, confirm the server is up and advertising the right issuers and resource. The metadata route is unauthenticated:
Expect something like:
{
"resource": "https://kdbl.example.com/mcp",
"authorization_servers": ["https://login.example.com/<tenant>/v2.0"],
"scopes_supported": ["kdbl.search", "kdbl.read"],
"bearer_methods_supported": ["header"]
}
Then run the end-to-end smoke test with a real token. It fetches metadata, then runs initialize + tools/list:
A cluster-admin token is fine for confirming initialize/tools/list here, but it cannot call the tools for retrieval — the tools are tenant-scoped (see Troubleshooting). For an end-to-end retrieval test use a tenant OIDC or PAT token.
Claude (Claude Desktop / claude.ai)¶
Claude calls these Custom Connectors built on remote MCP. Supported on Free, Pro, Max, Team, and Enterprise plans (Free is limited to a single connector). Claude itself drives the OAuth 2.1 authorization-code + PKCE flow and consent — K-Lake is purely the resource server, so no client secret is needed for a public/DCR flow; the Advanced settings fields exist only if your IdP requires a pre-registered client ID/secret.
Remote servers must be added through the connectors UI — Claude Desktop will not connect to a remote server configured via
claude_desktop_config.json(that file is for local stdio servers only).
Individual (Pro / Max), in Claude Desktop or claude.ai:
- Go to Settings → Connectors (in the app, Customize → Connectors).
- Click + Add (or the +), then Add custom connector.
- Paste your remote MCP URL:
https://<your-kdbl-host>/mcp. - (Optional) Under Advanced settings, set an OAuth Client ID / Client Secret if your IdP requires a pre-registered client.
- Click Add, then complete the OAuth sign-in when Claude prompts.
Team / Enterprise (organization owners):
- Organization settings → Connectors → Add → Custom → Web.
- Paste
https://<your-kdbl-host>/mcp, optionally add OAuth Client ID/Secret under Advanced settings, and Add. - Members then enable it individually via Customize → Connectors and sign in.
Note: Claude connects from Anthropic's cloud, so a K-Lake host behind a VPN/private network must allowlist Anthropic's egress IP ranges. (docs.claude.com publishes the current ranges.)
Auth flow: Claude hits /mcp → gets the 401 + resource_metadata challenge → fetches our PRM → picks the matching authorization_server → runs PKCE against your IdP → presents the resulting bearer (with aud = <resource URI>) on every call.
References (June 2026): Get started with custom connectors using remote MCP, Building custom connectors via remote MCP servers.
OpenAI ChatGPT (Business / Enterprise / Edu)¶
ChatGPT can connect to a custom remote MCP server, but mind two things:
- Tier and admin gating. Full custom MCP connectors run through Developer mode, available to ChatGPT Pro, Business, Team, Enterprise, and Edu plans on the web app. For Enterprise/Edu, a workspace admin must enable developer mode (Workspace Settings → Permissions/Roles → the developer-mode / custom-MCP-connector toggle), and can scope who may add or use connectors via RBAC. (As of Dec 17, 2025 OpenAI renamed "connectors" to "apps"; the UI may say either.)
- The historical search/fetch limitation. Without developer mode, ChatGPT only accepts servers that expose
searchandfetchtools and will ignore everything else. With developer mode on, that restriction is lifted — all of K-Lake's tools (search_content,get_file_text,get_file_window,list_sources,list_files,get_file_metadata) become available, subject to tool-confirmation settings. Our tool names don't match the legacysearch/fetchshape, so developer mode is effectively required to use K-Lake from ChatGPT.
Steps (admin/developer, web app):
- Admin enables Developer mode for the workspace (and, on Enterprise/Edu, grants the relevant users via RBAC).
- Settings → Connectors / Apps → Create / Import a custom MCP connector.
- Paste the server URL:
https://<your-kdbl-host>/mcp(HTTPS is required). - Complete the OAuth sign-in. ChatGPT handles client registration/authorization against your IdP and presents the bearer token to K-Lake.
Auth flow is the same resource-server pattern: ChatGPT discovers via PRM and presents an aud-bound bearer.
References (June 2026): Developer mode and MCP apps in ChatGPT, MCP and Connectors (OpenAI API docs).
Microsoft Copilot Studio¶
Copilot Studio adds an MCP server to an agent as a tool. Its OAuth handling is the most explicit of the four — you'll exchange a redirect URL with your IdP.
Steps:
- In your agent, go to Tools → Add a tool → New tool → Model Context Protocol (the wording tracks Microsoft Learn's current "add an existing MCP server" flow).
- Enter the server URL
https://<your-kdbl-host>/mcpand choose the Streamable HTTP transport. - For Authentication, pick OAuth 2.0:
- If your IdP supports Dynamic Client Registration (DCR) with discovery, choose that — it's the least-config path and leans on our PRM/discovery.
- Otherwise choose Manual and supply the Authorization URL, Token URL, Client ID/Secret, and scopes (
kdbl.search kdbl.read), with the resource/audience set to<KDBL_MCP_RESOURCE_URI>so issued tokens carry the rightaud. - Copilot Studio gives you a Redirect/Callback URL after you add the server. Register that URL on your IdP app registration (e.g. the Entra app's redirect URIs).
- Publish/test the agent; the first invocation prompts the user to sign in. Copilot Studio exchanges the auth code for a token (via Entra ID or your configured IdP) and includes that bearer on each MCP request, which K-Lake validates.
Because Entra ID is supported by K-Lake directly, an Entra-fronted Copilot Studio agent is the smoothest case — just make sure the Entra-issued token's aud equals the K-Lake resource URI and the tenant's mcp_audience matches.
References (June 2026): Connect your agent to an existing MCP server, Extend your agent with MCP.
Google Gemini¶
Google's MCP story is split across products and has been reshuffling (at Cloud Next 2026, Vertex AI was rebranded to the Gemini Enterprise Agent Platform and Agentspace was folded into Gemini Enterprise). The cleanest, confirmed path to a remote OAuth-secured MCP server today is the Gemini CLI, which configures remote servers via httpUrl with OAuth.
Gemini CLI — add to ~/.gemini/settings.json (or a project .gemini/settings.json):
{
"mcpServers": {
"kdbl": {
"httpUrl": "https://<your-kdbl-host>/mcp",
"authProviderType": "dynamic_discovery",
"oauth": {
"scopes": ["kdbl.search", "kdbl.read"],
"audiences": ["https://<your-kdbl-host>/mcp"]
}
}
}
}
authProviderType: "dynamic_discovery"lets the CLI read K-Lake's PRM and drive OAuth automatically;clientId/clientSecretand explicitauthorizationUrl/tokenUrlare only needed if your IdP doesn't support DCR.- Set
audiencesto the K-Lake resource URI so the requested token'saudis correct. Tokens are stored and refreshed by the CLI. - The
google_credentials/service_account_impersonationprovider types are for Google-hosted servers behind IAP/ADC and do not apply to K-Lake.
After saving, run /mcp inside Gemini CLI (or gemini mcp list) to confirm the server connected and the tools are listed.
Gemini Enterprise Agent Platform (formerly Vertex AI) / Gemini Enterprise: Google now ships managed remote MCP servers and an agent platform that can consume MCP, but the supported way to attach a third-party, customer-hosted, OAuth-secured MCP server through these consoles is still settling post-rebrand and varies by tier. Confirm the current path against Google Cloud's docs before relying on it — don't assume the Gemini CLI flow above maps one-to-one into the enterprise console.
References (June 2026): MCP servers with Gemini CLI, Configure MCP in an AI application (Google Cloud), Announcing official MCP support for Google services.
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
401 with WWW-Authenticate: Bearer … error="invalid_token" |
No token, or the token's aud doesn't match the resource URI. |
Confirm the IdP mints tokens with aud = <KDBL_MCP_RESOURCE_URI> and the tenant's oidc_config.mcp_audience equals it. This is the most common failure — see Audience binding. |
401 for a whole tenant, no matter the token |
That tenant has no mcp_audience and the API-audience fallback is off. |
Set oidc_config.mcp_audience on the tenant (or, as a last resort for IdPs that can't mint resource-scoped tokens, enable KDBL_MCP_ALLOW_API_AUDIENCE). |
403 origin not allowed |
A browser-context client sent an Origin not in the allowlist. |
Add the client's origin to KDBL_MCP_ALLOWED_ORIGINS. Server-to-server clients send no Origin and are unaffected. |
| Authenticates, but every tool call errors "tenant-scoped" | You used the cluster-admin token. It has no tenant to scope to, so tools refuse to run. | Use a tenant OIDC or PAT token for retrieval. The cluster-admin token is only good for initialize/tools/list smoke checks. |
405 on GET /mcp |
The client tried to open a server-initiated SSE stream. | Expected — K-Lake is request/response only over POST. Configure the client for Streamable HTTP without a persistent GET stream. |
| Client can't discover the auth server | PRM unreachable, or no tenant has an issuer configured. |
curl …/.well-known/oauth-protected-resource/mcp and confirm authorization_servers is non-empty. |
Every tool call and every auth denial is recorded — query it with kdbl-control … mcp audit or GET /api/mcp/audit. See Audit for the field reference and SIEM streaming.
See also¶
- MCP server — enabling, env vars, auth model, tools, and audit in full.
- Per-file security trimming — how results are scoped to the caller.
- Directory sync — group-to-identity correlation that powers the trimming.