Iceberg MCP Server (via Impala)
Provides read-only SQL access to Apache Iceberg tables through Apache Impala, with schema discovery, query execution, and per-user impersonation/authorization.
Deploys within Cloudera AI to expose an MCP server and chat app for querying Cloudera-managed Iceberg data through Impala, using CAI login and user identity for access control.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Iceberg MCP Server (via Impala) Show me the top 10 orders by amount in the sales table."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Cloudera Iceberg MCP Server (via Impala)
A Model Context Protocol server that lets AI assistants query Iceberg tables through Apache Impala, read-only and as the person who asked. It comes with a chat app that runs inside Cloudera AI (CAI).
Tools offered to the AI:
get_schema(): the tables in the configured database, with their columns.execute_query(query): run one read-only SQL statement and return the rows as JSON.
Architecture

The core rule: every query runs in Impala as the individual who asked, never as a shared service account. Ranger decides what that person may read, and Impala's query log records their name.
How a question becomes a query
A person asks a question in an AI app.
The app calls the MCP server, carrying proof of who the person is.
The MCP server verifies that proof and works out the person's Cloudera username.
It connects to Impala as a dedicated machine user and asks to run the query as that person (impersonation, Impala's
doAs).Impala checks that the machine user is allowed to impersonate that person, then Ranger checks that the person may read the tables.
The query log records both names: the person (
db_user) and the machine user that connected for them (db_user_connection).
Two ways in, one identity rule
External app (e.g. Azure AI Foundry) | Chat app hosted in Cloudera AI ( | |
Who signs the person in | Their identity provider (Microsoft Entra ID; in principle any standard OIDC provider) | Cloudera AI's own login (e.g. company SSO) |
Proof sent to the MCP server | A signed token issued for that person | CAI's proxy stamps the authenticated caller on every request (callers cannot forge it); the chat app, the only trusted caller, names the person |
What the MCP server checks | Signature, issuer, audience, expiry (optionally a required scope) | Caller is CAI-authenticated and listed in |
Network perimeter | Optional Apache Knox gateway in front, which checks the token before it reaches Cloudera | Not needed: traffic stays inside Cloudera |
MCP Application login setting | Off (the token is the gate) | On (CAI login is the gate) |
The identity mode is chosen by settings (see Configuration). A third, test mode, runs every call as one fixed user with no identity check. It exists only to prove a first deployment and must not be exposed beyond a controlled test.
Layers of protection
Layer | Where | What it stops |
1. Caller identity | MCP server (token check) or CAI login | Anonymous or forged callers |
2. Identity mapping and allowlists | MCP server ( | Unknown or unwanted users |
3. Read-only guard | MCP server | Writes and stacked statements (defence in depth) |
4. Impersonation allowlist | Impala ( | The machine user acting as anyone not on the list |
5. Data permissions | Ranger, per person | Reading data the person is not entitled to |
6. Audit trail | Impala query log and Ranger audit | Untraceable access: every query is recorded under the person's name |
Safe defaults throughout:
Deny by default. Missing, invalid or unmapped identities are refused.
No silent fallbacks. The server refuses to start without an identity mode, never falls back to the machine user, and refuses to combine Entra with CAI mode.
Misconfiguration fails closed. In CAI mode the server refuses to start if its Application allows unauthenticated access. Even then, CAI strips forged identity headers (tested), so calls would be refused, not impersonated.
Secrets stay out of the repo. The machine user's password lives only in Application settings, and the diagnostic
whoamitool never returns a token.
The chat app's model is either Cloudera AI Inference (inside Cloudera, authenticated with the user's CAI login token) or AWS Bedrock (AWS access keys or a Bedrock API key). Either way, the model only sees results that the person's own permissions allowed.
Verified end to end
An Azure AI Foundry agent queried through the MCP server, and Impala's query log showed the real end user as
db_user, with the machine user asdb_user_connection.The CAI chat app answered questions for two different users. Each person's queries appear in the query log under their own name, and Ranger checked each person's own access.
See docs/install-guide.md for the full setup (Impala, Ranger, impersonation, deployment) and
docs/build-plan.md for the design history.
Related MCP server: Cloudera Iceberg MCP Server
Deploy on Cloudera AI
.project-metadata.yaml turns this repo into a Cloudera AI project template. You choose the mode
with MCP_MODE:
| What gets deployed | CAI login |
| MCP server for apps in this workspace, plus the chat app (if a model is configured) | On, for both |
| MCP server for an external app that sends Entra ID tokens | Off; the server checks every token |
| MCP server where every call runs as | Off; anyone with the URL can query |
In Cloudera AI: New Project > Git, paste this repo's URL, then Configure Project.
Fill in the environment variables it asks for:
Variable
What to enter
MCP_MODEcai,entraortestIMPALA_HOSTImpala coordinator host
IMPALA_USERThe machine user's workload username (machine users get an extra
srv_prefix)IMPALA_PASSWORD_B64Its password, base64-encoded:
printf %s 'PASSWORD' | base64 -w0IMPALA_PORT,IMPALA_DATABASEDefaults are
443anddefaultcai:
CAI_INFERENCE_BASE_URLorBEDROCK_MODEL_IDThe chat app's model;
CAI_TRUSTED_CALLERSdefaults to youentra:
ENTRA_TENANT_ID,ENTRA_AUDIENCEFrom the server's Entra app registration
test:
MCP_TEST_USERThe Cloudera user every request runs as
Launch. It installs dependencies, creates an optional sample-data job (not run automatically), and runs
scripts/create_mcp_app.py, which creates the applications for the mode with the right CAI login setting. The MCP endpoint is the MCP application's URL plus/mcp.Check it:
scripts/curl_mcp.sh https://<application-url> list(see below).
If the template's variables don't reach the project (a known issue in some CAI versions), set them
in Project Settings > Advanced > Environment Variables and run python scripts/create_mcp_app.py
from a session. See docs/install-guide.md §5d.
Before you start, on the Impala side: the machine user must be allowed to impersonate the end users
(authorized_proxy_user_config), and they need Ranger access to the tables (install guide §4). To
try it with demo data, run the Load MovieLens sample data job, then set IMPALA_DATABASE to
mcp_demo in the MCP application's settings and restart it.
Things to know:
Unauthenticated applications can be blocked by a workspace admin ("unauthenticated access to applications prevented by site-wide configuration"). Entra and test mode need them allowed.
In test mode anyone with the URL can run read-only queries as
MCP_TEST_USER. Stop it when idle.The subdomains
iceberg-mcpandiceberg-mcp-chatmust be unused in the workspace (change them withAPP_SUBDOMAIN), and the workspace must be able to reach PyPI. The runtime is PBJ Workbench, Python 3.12, Standard.The template is checked by tests (
tests/test_project_metadata.py,tests/test_create_apps.py), but the first import into a fresh workspace is the real test.
Check the server with curl
scripts/curl_mcp.sh https://<application-url> health # is it up? (no token needed)
scripts/curl_mcp.sh https://<application-url> list # which tools does it offer?
scripts/curl_mcp.sh https://<application-url> call get_schema
scripts/curl_mcp.sh https://<application-url> call execute_query '{"query":"SELECT effective_user()"}'A server that checks tokens needs one: TOKEN=<token> scripts/curl_mcp.sh ... (or TOKEN_FILE=<path>).
No token gives HTTP 401, which is the correct answer from such a server. The script needs only
curl. An MCP server expects a short conversation first (initialize, confirm, then your request),
which the script does for you; the three steps are described at the top of the script.
Configuration
Variable | Purpose |
| Impala coordinator |
| Machine user that authenticates (and is allowed to impersonate via |
| Machine user workload password, base64 preferred |
| Enable Entra token validation. Audience is the app registration's Application ID URI |
| Optional overrides (default to the v2.0 issuer/keys for the tenant; use |
| Claims tried in order for identity (default |
| Optional |
| Optional. If set (e.g. |
| Optional. |
| Optional comma-separated allowlist of Cloudera usernames |
| CAI mode, for callers hosted in Cloudera AI: comma-separated CAI usernames allowed to act on behalf of other users (send |
| Test deployments only: skip identity checks and run every call as this user. Ignored when |
Impala on-prem (a cluster managed by Cloudera Manager), limits and scale
Variable | Purpose |
| One coordinator, or several separated by commas (each may be |
|
|
| Kerberos only: keytab file of the machine user. Tickets are fetched and renewed from it automatically. Without it, a ticket must already be in the credential cache |
| Kerberos only: service name (default |
| Certificate authority file that issued Impala's certificate (typical on-prem). Without it the system trust store is used |
| Default |
| Impala query options for every session, e.g. |
| Seconds to wait for a coordinator that stops answering (default 60) |
| Largest result returned to the model (defaults 1000 rows, 200000 characters). A larger result is cut off and marked |
| Time limit per query (default 120). Sent to Impala as |
| Queries running at once in total (default 16) and per user (default 4), and how long a call waits for a free slot before it is refused (default 15 seconds) |
|
|
|
|
Do not put a round-robin load balancer between this server and Impala: the Impala client library opens a
new connection for every request, so the requests of one session land on different coordinators and fail.
List the coordinators in IMPALA_HOST, or use a balancer that keeps one client on one coordinator.
tests/onprem_lab/ holds the test environment these settings were checked in (a real LDAP directory, a
real Kerberos server and a stand-in for Impala), and scripts/test_doas.py runs the same checks against a real cluster.
The server refuses to start unless one identity mode is set: ENTRA_TENANT_ID+ENTRA_AUDIENCE (external
apps), CAI_TRUSTED_CALLERS (CAI-hosted apps) or MCP_TEST_USER (test only). Entra and CAI mode together
is refused, because they need opposite Application login settings.
Chat app (chat_app/)
Deploy as a second Application with script start_chat.py and CAI authentication on. Its dependencies
are the chat extra (pip install ".[chat]"), which start_chat.py installs.
Variable | Purpose |
| The CAI-mode MCP server endpoint, e.g. |
| Optional. CAI API key the chat app calls the MCP server with; its owner must be in |
| Cloudera AI Inference: the endpoint's OpenAI-compatible URL from its Model Endpoints page. The model name and login token are found automatically |
| AWS Bedrock, plus either |
|
|
| Testing only. CAI users who get an "Act as" box to query as someone else. Leave unset in production |
Testing
pip install -e ".[chat]" --group dev # everything comes from pyproject.toml
pytest # unit + end-to-end auth tests, no Cloudera needed
python scripts/test_doas.py --allowed <user> --denied <user> # against a real Impala VW
python scripts/get_entra_token.py # real Entra sign-in (device code) -> .entra_token
python scripts/call_mcp.py <url> get_schema --token-file .entra_token --claims # against a deployed serverUsage with AI frameworks
The ./examples folder contains several examples how to integrate this MCP Server with common AI Frameworks like LangChain/LangGraph, OpenAI SDK.
Transport
The MCP server's transport protocol is configurable via the MCP_TRANSPORT environment variable. Supported values:
stdio(default) — communicate over standard input/output. Useful for local tools, command-line scripts, and integrations with clients like Claude Desktop.http- expose an HTTP server. Useful for web-based deployments, microservices, exposing MCP over a network.sse— use Server-Sent Events (SSE) transport. Useful for existing web-based deployments that rely on SSE.
Copyright (c) 2025 - Cloudera, Inc. All rights reserved.
Available Tools
2 toolsexecute_queryA
Execute a read-only SQL query on the Impala database and return the rows as JSON. The query runs as the authenticated end user. Large results are cut off: the answer is then a JSON object with "truncated": true and a note, and it is not the complete data. Prefer aggregates, filters and LIMIT over fetching raw rows.
Inputs: query (required). Returns: Generic wrapper for non-object return types.
get_schemaA
List the tables in the current Impala database with their columns (name and type). Call this first, and use the exact column names it returns.
Inputs: no named parameters. Returns: Generic wrapper for non-object return types.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 2 tools
The two tools occupy clearly separate roles: `get_schema` for metadata discovery and `execute_query` for running read-only SQL. There is no realistic scenario where an agent would confuse one for the other, and the descriptions even specify the intended workflow order (schema first, then query).
Both names follow a strict verb_noun snake_case pattern (`execute_query`, `get_schema`), using consistent verbs and clear object nouns. No mixing of conventions or casing styles.
Two tools is on the thin side relative to the typical 3-15 range, but for a deliberately read-only SQL access layer both tools earn their place and form a complete minimal workflow. It is slightly under-provisioned but not wasteful or confusing.
The surface covers the core read-only lifecycle: inspect schema, then query. Minor conveniences (e.g. dedicated list-databases, table description, or EXPLAIN helper) are absent, but an agent can reach equivalent results by issuing SHOW/DESCRIBE through `execute_query`, so no hard dead ends exist. Write operations are intentionally excluded.
Maintenance
Related MCP Connectors
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Connect AI assistants to Preset to explore data, charts, and dashboards in authorized workspaces.
Amazon Ads, Seller Central, Vendor Central and AMC data for AI agents. Read-only by default.
Governed access to production AI-agent traces in an existing ClickHouse store.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables read-only access to Apache Iceberg tables via Impala, allowing LLMs to inspect database schemas and execute SQL queries to retrieve data from Iceberg tables.213Apache 2.0
- AlicenseNot gradedqualityDmaintenanceProvides read-only access to Iceberg tables via Apache Impala, enabling LLMs to inspect database schemas and execute SQL queries on Iceberg data.Apache 2.0
- AlicenseAqualityCmaintenanceProvides read-only SQL access to Apache Iceberg tables via HiveServer2, enabling querying, schema discovery, and database listing on Cloudera Data Platform.31Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to audit data governance, check access control roles, query namespaces, and inspect Iceberg metadata.1MIT