databricks-readonly-mcp
Read-only MCP server for Databricks, exposing Unity Catalog browsing and SQL execution with robust write protection via SQL AST analysis.
README
databricks-readonly-mcp
A Model Context Protocol (MCP) server that gives an LLM read-only access to Databricks. It exposes Unity Catalog browsing and SQL execution as tools, with two layers of defence against accidental writes:
- In-process AST guard. Every SQL statement is parsed with
sqlglotand rejected unless its root and entire tree are read-only (SELECT/WITH/SHOW/DESCRIBE/EXPLAIN/ set-operations).INSERT,UPDATE,DELETE,MERGE,DROP,CREATE,ALTER,TRUNCATE,USE,SET,GRANT,COPY,REFRESH,OPTIMIZE,VACUUM— all rejected before the HTTP call is made. CTE-wrapped writes (e.g.WITH x AS (DELETE …) SELECT * FROM x) are caught by a deep tree walk. - Read-only Databricks principal (recommended). Run the server under a
service principal or PAT that has only
USE CATALOG/USE SCHEMA/SELECTgrants. See Read-only principal below.
Transport is stdio only.
Install
pip install -e .
# or once published:
# uvx databricks-readonly-mcp
Configure
Create ~/.databricks-mcp/config.yaml (or point DATABRICKS_MCP_CONFIG at a
custom path). Two auth methods are supported per profile:
databricks_cli (recommended)
Delegates to a profile in ~/.databrickscfg via the Databricks SDK. Host
and credentials (PAT or OAuth U2M) come from there, and the SDK refreshes
OAuth tokens automatically. Set up once with the Databricks CLI:
databricks auth login --host https://your-workspace.cloud.databricks.com \
--profile ciq-beta
Then reference it in the MCP config:
default_profile: beta
profiles:
beta:
warehouse_name: esm_etl_wh # or warehouse_id: bd6e1945574f6d03
default_catalog: client_catalog
max_rows: 1000
auth:
method: databricks_cli
cli_profile: ciq-beta # name in ~/.databrickscfg
No tokens in YAML, no env vars. Good for laptops / interactive use.
Warehouse selection is one of (highest precedence first):
| Field | Behavior |
|---|---|
warehouse_id |
Pin a specific warehouse. No lookup; fastest startup. |
http_path |
/sql/1.0/warehouses/<id> — the <id> is used as warehouse_id. |
warehouse_name |
Resolved at startup via /api/2.0/sql/warehouses. Case-insensitive; must match exactly one. |
| (omit all) | Auto-pick: succeeds only if exactly one warehouse is visible to your principal. |
If you don't know which warehouse to pin, list them with:
databricks-readonly-mcp --profile beta --list-warehouses
Or pick one interactively (prompts on TTY, prints a YAML snippet to paste):
databricks-readonly-mcp --profile beta --pick-warehouse
Both modes run as one-shot CLI commands and exit; they don't start the MCP server.
token (for CI, headless servers)
Reads a PAT from the env var named in token_env. host must be set:
profiles:
prod:
host: https://your-prod-workspace.cloud.databricks.com
warehouse_id: prodwarehouseid
auth:
method: token
token_env: DATABRICKS_TOKEN_PROD # name of the env var; NOT the token
default_catalog: client_catalog
max_rows: 1000
See examples/config.example.yaml for a
complete template.
Profile selection precedence: --profile flag > DATABRICKS_MCP_PROFILE env
var > default_profile in the config.
Run
databricks-readonly-mcp --profile beta
# or
python -m databricks_mcp --profile beta
Wire into Claude Code / Claude Desktop
Add to your mcpServers config (e.g. ~/.claude.json):
When using auth.method: databricks_cli (recommended), no env block is
needed — credentials come from ~/.databrickscfg:
{
"mcpServers": {
"databricks": {
"command": "databricks-readonly-mcp",
"args": ["--profile", "beta"]
}
}
}
With auth.method: token, supply the env var:
{
"mcpServers": {
"databricks": {
"command": "databricks-readonly-mcp",
"args": ["--profile", "prod"],
"env": { "DATABRICKS_TOKEN_PROD": "dapi…" }
}
}
}
Restart Claude Code; the tools appear under the databricks server in /mcp.
Tools
| Tool | Args | Returns |
|---|---|---|
list_catalogs |
— | {catalogs: [{name, comment, owner, catalog_type}]} |
list_schemas |
catalog |
{schemas: [{name, full_name, comment, owner}]} |
list_tables |
catalog, schema |
{tables: [{name, full_name, table_type, data_source_format, comment}]} |
describe_table |
full_name |
{full_name, table_type, columns: […], properties} |
run_sql |
query, row_limit? |
{columns, rows, row_count, truncated, statement_id, execution_time_ms} <br/> Returns {error: "ReadOnlyViolation", message} when blocked. |
row_limit is always clamped to the profile's max_rows.
Read-only principal (recommended)
The AST guard is robust but software. Put a second wall up at the data plane by giving the server a principal that cannot write, even if asked to:
-- Run as a workspace admin once, per environment.
GRANT USE CATALOG ON CATALOG client_catalog TO `databricks-mcp-readonly`;
GRANT USE SCHEMA ON ALL SCHEMAS IN CATALOG client_catalog TO `databricks-mcp-readonly`;
GRANT SELECT ON ALL TABLES IN CATALOG client_catalog TO `databricks-mcp-readonly`;
GRANT CAN USE ON WAREHOUSE <warehouse_id> TO `databricks-mcp-readonly`;
-- explicitly: no MODIFY, no CREATE, no ALL PRIVILEGES, no warehouse mgmt.
Don't point this MCP at a PAT for a user that has broader grants. The guard catches the obvious cases, but a parser bug in any combination AST-allow-listing + over-privileged principal is the weakest configuration.
Development
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
pytest
Layout
src/databricks_mcp/
server.py stdio entrypoint, CLI parsing, FastMCP setup
tools.py tool functions registered onto FastMCP
client.py DatabricksReadClient — Statement API + Unity Catalog REST
sql_guard.py assert_readonly: sqlglot AST allow-list
config.py YAML loader, profile resolution
errors.py typed exceptions
tests/ pytest suite (sql_guard, config, client, tools)
Out of scope (v1)
- Job / cluster / warehouse management tools — not exposed.
- HTTP / SSE transport — stdio only.
- Multi-statement bodies, transactions — refused.
- Anything that writes, anywhere — refused.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.