Connect Claude Code to your dbt project
A no-nonsense walkthrough for getting dbt Labs’ official MCP server running in Claude Code, Claude Desktop, or Cursor. Both Local and Remote modes, with the env vars, the JSON configs, the starter prompts that work out of the box, and the gotchas dbt Labs has not fixed yet.
uvxWho this is for
You have a dbt project (Core or Cloud) and you are tired of grepping the manifest to answer lineage questions. You want Claude to read your project as a structured graph, not as a folder of files. You want to be able to ask “what depends on stg_payments” in plain English and get the right answer.
You do not need to be a dbt power user. You do need to know your way around a terminal, have admin access (or friendly admin) to your dbt setup, and have Claude Code, Claude Desktop, or Cursor installed.
If you are reading the article version of this guide and clicked through for the setup, you are in the right place. If you landed here directly, the article that frames why any of this matters is here.
Prerequisites
You need a few things in place before the install actually works. Skim the list. If anything is missing, fix that first.
- A dbt project that parses cleanly. Run
dbt parsein your project directory. If it errors out, fix the errors before going any further. The MCP reads fromtarget/manifest.jsonand a missing or stale manifest is the most common reason setup appears to fail. - For Local mode: uv installed (the Python toolchain that ships
uvx).uvx --helpshould respond. On macOS,brew install uv. On Linux, the curl install script in the docs. On Windows, follow the PowerShell installer carefully and reopen your terminal after. - For Remote mode: a dbt Platform account with the Remote MCP feature enabled. Check Account Settings → AI in the dbt Platform UI. If Remote MCP is not listed, contact dbt support to enable it on your account.
- Claude Code, Claude Desktop, or Cursor installed. The MCP works the same in all three. The configs differ slightly, which is why this guide has each one separately.
- Read access to your dbt project repo if you are running Local against a cloned project, or to your dbt Platform environment if you are using Platform-backed features (Discovery API, Semantic Layer, Admin API).
Local or Remote?
The dbt MCP comes in two flavors. The choice is the most important decision in this guide. Pick the wrong one and you will spend an afternoon trying to get a feature working that does not exist on that path.
- Want the agent to run
dbt run,build,test,compile - Need codegen tools (model YAML from schema, staging scaffold, source YAML)
- Are an analytics engineer doing dev or audit work
- Want to use Fusion-specific tools (column lineage,
compile_sql) - Want the full toolset, accept some setup overhead
- Want a 2-minute install with no env vars
- Are a business user, BI partner, or stakeholder
- Need Discovery, Semantic Layer, and Admin API access
- Are deploying an agent for non-engineers
- Are fine without CLI execution or codegen
Most teams end up with both, on different machines, for different jobs. There is no rule saying you have to pick one. The two modes do not conflict.
Local setup
The Local server runs through uvx, which fetches the dbt-mcp package on demand. No virtualenv to manage, no pip install to debug. The whole thing is one config block in your MCP client and a handful of environment variables.
Step 1: Get your dbt Platform credentials
You need four values from dbt Platform. None of them are hard to find, but they live in different places.
- DBT_HOST: typically
cloud.getdbt.comfor US multi-tenant accounts, or your single-tenant URL. - DBT_TOKEN: a Platform service token. Account Settings → Service Tokens → Create. Give it Developer access at minimum. Copy the token immediately; it is not shown again.
- DBT_PROD_ENV_ID: the numeric ID of your production deploy environment. Open the environment in dbt Platform; the ID is in the URL after
/environments/. - DBT_USER_ID: your user ID. Open your profile page in dbt Platform; the ID is in the URL after
/users/.
If you are only using Local against a dbt Core project (no Platform features), you can skip these and just set DBT_PROJECT_DIR.
Step 2: Add the MCP server to your client
Pick the config block that matches your client. Paste it into the right config file. Reload the client.
The JSON shape is identical for all three clients. Only the config file path differs. Pick your client:
Config file: ~/.claude.json (user scope)
{
"mcpServers": {
"dbt": {
"command": "uvx",
"args": ["dbt-mcp"],
"env": {
"DBT_PROJECT_DIR": "/absolute/path/to/your/dbt/project",
"DBT_HOST": "cloud.getdbt.com",
"DBT_TOKEN": "dbtu_...",
"DBT_PROD_ENV_ID": "12345",
"DBT_USER_ID": "67890"
}
}
}
}
Or use the CLI, which writes the same block to the right file:
claude mcp add dbt -s user \ --env DBT_PROJECT_DIR=/absolute/path/to/your/dbt/project \ --env DBT_HOST=cloud.getdbt.com \ --env DBT_TOKEN=dbtu_... \ --env DBT_PROD_ENV_ID=12345 \ --env DBT_USER_ID=67890 \ -- uvx dbt-mcp
Config file: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) · %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"dbt": {
"command": "uvx",
"args": ["dbt-mcp"],
"env": {
"DBT_PROJECT_DIR": "/absolute/path/to/your/dbt/project",
"DBT_HOST": "cloud.getdbt.com",
"DBT_TOKEN": "dbtu_...",
"DBT_PROD_ENV_ID": "12345",
"DBT_USER_ID": "67890"
}
}
}
}
Config file: ~/.cursor/mcp.json (user scope) · .cursor/mcp.json (project scope)
{
"mcpServers": {
"dbt": {
"command": "uvx",
"args": ["dbt-mcp"],
"env": {
"DBT_PROJECT_DIR": "/absolute/path/to/your/dbt/project",
"DBT_HOST": "cloud.getdbt.com",
"DBT_TOKEN": "dbtu_...",
"DBT_PROD_ENV_ID": "12345",
"DBT_USER_ID": "67890"
}
}
}
}
On Windows, replace "command": "uvx" with the absolute path to your uvx.exe (typically C:\Users\YOU\.local\bin\uvx.exe). The PATH that Claude Code sees does not always match the PATH in your terminal. Absolute paths bypass that whole class of bug.
Remote setup
If you went with Remote, the setup is shorter than reading this section.
- In dbt Platform, open Account Settings → AI. Find the Remote MCP endpoint URL. It looks like
https://your-account.dbt.com/api/mcp/v1/sse. - In Claude Code, run
claude mcp add --transport sse dbt-remote https://your-account.dbt.com/api/mcp/v1/sse(replace with your actual URL). - Claude Code opens a browser tab for OAuth. Log into dbt Platform. Authorize.
- Reload Claude Code. The Remote server is now listed under available MCP servers.
Claude Desktop and Cursor support remote MCP servers the same way; the UI varies but the steps are identical (URL, OAuth, reload).
The Remote server’s text_to_sql tool consumes dbt Copilot credits. If your account runs out of credits, every Remote MCP tool stops working, not just text_to_sql. Lineage queries that should be free will start failing too. Check your Copilot quota first whenever the Remote server “suddenly stops working.”
Verify the connection
Reload your MCP client. Then run this prompt in a fresh chat:
List the first 10 models in my dbt project using the dbt MCP. Show me each model's name and its layer (staging, intermediate, mart).
If everything is wired up, what you should see is a tool call land, hit the dbt manifest, and return real model names from your project, something like this:
If nothing happens, or you see an error, jump to the troubleshooting section.
For a second smoke test:
Pick any mart model from my project. Show me its upstream lineage and list the tests defined on it.
This exercises get_mart_models, get_model_lineage_dev, and get_test_details in a single conversation. If it works, your install is solid.
12 starter prompts
These are the prompts that earned the MCP its keep on the first few projects I ran it against. Copy them, run them on your project, watch what comes back. You will start adapting them within a day.
List all mart models in my project. For each one, show me how many downstream consumers it has and flag any with zero. Those are candidates for retirement.
Walk the lineage for fct_orders (substitute your own canonical fact model). Show me the full upstream chain back to source tables.
Which tests cover dim_customers? List each test, what it asserts, and whether it is on a column or the whole model.
Find every mart model that has no tests defined. Rank them by number of downstream consumers, so the highest-impact untested models come first.
List every source defined in my project. For each one, tell me whether it has at least one downstream mart. Sources with no downstream marts are dead weight.
Scan my models for hardcoded date or timezone literals (anything like '2020-01-01' or - interval '5 hours'). Flag the SQL files and line numbers.
Generate a YAML for my int_payments model. Include column descriptions inferred from the SQL, and propose not_null tests on the primary key and any non-nullable foreign keys.
Generate a source YAML for the raw_stripe schema in my warehouse. Include all tables, with column types pulled from the actual schema.
Propose a staging model for the customers table in source raw_app. Use our project conventions for naming, columns, and basic tests.
List every metric defined in my project. For each one, show me the time grain, the dimensions, and a one-line description of what it measures.
Pull the value of my revenue metric for each of the last 90 days, grouped by region. Use the semantic layer, not raw SQL.
My BI dashboard shows monthly revenue of [X] for last month. Pull the same metric for the same period from the semantic layer. If they differ, propose a hypothesis for the drift.
Project hygiene before you connect
The MCP is only as good as the project it reads from. A few small things to fix first will dramatically improve what the agent can do:
- Parse cleanly.
dbt parsewith zero errors. The manifest is the agent’s source of truth. A broken parse means a stale or missing manifest, which means an agent guessing instead of reading. - Tag primary keys. Models with explicit primary key columns (via
uniquetests or the newprimary_keyconstraint) give the agent strong join inference. Without them, the agent guesses. - Document at least your marts. Even one-line descriptions on each mart model and its key columns shift agent behavior from “looks at the SQL and guesses what this means” to “reads the description and reasons correctly.”
- Define sources properly. Use
sources.yml. Avoid bareFROM raw.schema.tablein SQL. The agent uses sources to answer “where does this data originally come from.” - Name consistently. Stick to a convention (
stg_,int_,fct_,dim_,mart_, whatever you have agreed on). The agent uses naming to infer layer structure. Inconsistent naming makes the inference noisy. - Run
dbt parsebefore any audit session. Re-parse if you have pulled new changes or switched branches. It takes seconds.
None of this is dbt MCP specific. It is good hygiene for any dbt project. The MCP just makes the cost of bad hygiene visible.
Read-only safety pattern
The first question any sensible data lead asks: what stops the agent from running dbt run --full-refresh on production at 2am?
The answer is layered. Use all three layers.
Layer 1: Per-tool permissions in Claude Code. Claude Code lets you decide which tools the agent can call automatically and which require a prompt. The pattern that works:
- Always allowed:
get_all_models,get_mart_models,get_model_details,get_model_parents,get_model_lineage_dev,get_test_details,get_macro_details,get_seed_details,get_snapshot_details,list_metrics,get_dimensions,query_metrics. - Requires prompt: any CLI tool (
run,build,test,compile,clone), any codegen tool, any Admin API tool that triggers a job (trigger_job,retry_job).
Layer 2: Service token with minimum role. Generate the DBT_TOKEN under a service account with Developer role and read-only access to your production environment’s Discovery and Semantic Layer APIs. No job-trigger permission. The token literally cannot fire a run, no matter what the agent asks it to do.
Layer 3: Separate elevated session for writes. When you genuinely need to trigger a job or run a model, switch to a Claude Code profile with an elevated token, do the one task, switch back. Same pattern as sudo. The flip is intentional, which is the whole point.
Wire a dbt Platform webhook on job events to post to a Slack channel like #data-changelog. Your agent can do whatever you authorize, but every action becomes visible in real time. The combo of read-mostly defaults plus full audit visibility covers most operational risk.
Troubleshooting
The setup failure modes are predictable. If something is not working, scan this table first.
| Symptom | Likely cause and fix |
|---|---|
| Server not visible after restart | Wrong config file. Claude Code reads ~/.claude.json (user scope), not ~/.claude/mcp.json. Use claude mcp add dbt -s user -- to write to the right place. |
| “uvx: command not found” | uvx is not on the PATH that Claude Code can see. Put the absolute path to uvx in the command field, or install uv system-wide. |
| “No models found” or empty results | DBT_PROD_ENV_ID points at an environment with no successful deploys, or the wrong environment. Confirm the ID from the URL in dbt Platform. |
| 401 / Authentication failed | DBT_TOKEN is a personal access token, not a service token. Generate a Service Token specifically. Or the token’s account does not have Developer access. |
| Stale lineage in responses | The MCP reads from target/manifest.json. Re-run dbt parse in your project directory before the session. |
| Tool calls hang on Windows | PATH or quoting issue with uvx.exe. Use absolute path with forward slashes (C:/Users/YOU/.local/bin/uvx.exe). Some installs need administrator privileges. |
| Remote: all tools failing at once | Copilot credit exhaustion. Check the credit balance in dbt Platform. text_to_sql consumes credits and credit failure blocks the whole Remote server. |
| Agent picks raw SQL when it should use metrics | Your prompt is ambiguous. Say “use the semantic layer” explicitly. Or remove text_to_sql from the auto-allow list to force a planning step. |
| “Connection refused” on first run | Outbound HTTPS to cloud.getdbt.com is blocked, or behind a corporate proxy. Set HTTPS_PROXY in the env block of your MCP config. |
| Lineage chain longer than expected | The lineage tool includes ephemeral models. That is by design. Use get_model_parents with depth=1 if you only want immediate parents. |
If you hit something that is not in this table, the dbt community Slack channel #tools-dbt-mcp is the right place to ask. dbt Labs engineers monitor it.