Predicts the DDL a dbt change will execute, before you run it. Reads files, not the warehouse.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
We haven't yet run this listing's install command through our automated sandbox check. This isn't a red flag β we're steadily working through the catalog.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Static analysis tool that warns about risky DDL changes before dbt run.
Like terraform plan for dbt, and used the same way: you run it before the thing
that changes your warehouse, not only in CI afterwards.
Runs on compiled SQL. It reads files and nothing else, so it works with any warehouse β Snowflake, BigQuery, Redshift, Postgres, DuckDB β through one code path.
dbt-plan analyzes compiled SQL diffs to catch dangerous schema changes at PR time:
* and lose it without their own file changing; and the tests whose fixtures
pin it down. Names the exposures whose owners need tellingCAST types between revisionsSELECT * resolution: reads the columns from the CTEs of the same statement, and follows a ref() into the referenced model's compiled SQLIt does NOT execute anything, connect to any warehouse, or simulate dbt run. It reads files, compares them, and warns you.
dbt-plan run does the whole thing in one command, and needs whatever credentials your
dbt compile normally needs.
Once you have a baseline, the inner loop is a single sub-second command. Edit a model or a
macro, recompile, and see what dbt run would do β before running it:
Measured on a project of 3 models, median of 3 runs:
| step | time |
|---|---|
dbt compile (Fusion) | 1.8 β 3.8 s |
dbt-plan check | 0.11 s |
dbt-plan snapshot | 0.10 s |
200 models, every one of them changed: 0.48 s. The compile is the cost, and you were compiling anyway β dbt-plan itself is fast enough to sit in the edit loop rather than at the end of it.
An agent editing models cannot eyeball a diff and hesitate. Give it the check and the reasons behind it:
The guidance leads with what an agent most often gets wrong: adding a model to
ignore_models, or downgrading on_schema_change from sync_all_columns to ignore,
silences a real finding without making the change safe.
Or give it the check as an MCP tool:
plan returns the verdict, the per-model operations, and β separately β a refusals
list naming everything dbt-plan declined to judge. That separation is the point: a person
reading "safe" may still glance at the diff, an agent reading it proceeds, so a
non-empty refusals must never be collapsed into the verdict.
Both tools accept target_dir when dbt writes artifacts outside the default target/,
for example plan(project_dir=".", target_dir="build").
The server is a separate package from the analysis core. The core is offline and
synchronous by design and tests/test_invariants.py fails the build on an asyncio or
network import anywhere inside it; an MCP server is both, so keeping them apart is what
keeps that guarantee provable.
Registry entry β the line below is how the MCP registry verifies that whoever publishes the entry also owns this PyPI package, so it has to stay in the README that ships:
dbt-plan is a static analysis warning tool, not a runtime simulator.
| In scope | Out of scope |
|---|---|
| Column ADD/DROP detection from compiled SQL | dbt run simulation |
| materialization Γ on_schema_change risk rules | Warehouse connection |
| Cascade: broken refs, build failures, inherited column loss | seed / source change detection |
| Config change detection (materialization, osc) | pre_hook / post_hook DDL analysis |
| Unit test fixtures and exposure owners downstream | seed / source fixtures dbt-plan cannot read |
| Enforced-contract violations: names, and types by family | Contract types compared more finely than family |
Explicit CAST type changes | Type changes on uncast columns |
SELECT * resolved through CTEs and ref() | SELECT * over a source or a raw table |
| CI exit codes + structured output | full_refresh mode judgment |
Design principle: false warnings are OK, false safe is never OK.
dbt-plan answers a narrower question than the warehouse-connected tools (Recce, SQLMesh, data-diff) and costs nothing to run, so it works as the cheap gate in front of them β and on the Fusion engine, which compiles without a warehouse connection, that includes fork pull requests where they cannot run at all. See use cases for the comparison, real timings, and what it gets wrong.
Ideas that look useful but contradict what this tool is:
| Idea | Why not |
|---|---|
| INFORMATION_SCHEMA query | Requires a warehouse connection. dbt-plan reads files and nothing else, which is what lets it run wherever its input exists β including a fork's pull request, once the project compiles on Fusion. |
Type changes on columns with no explicit CAST | The type is whatever the warehouse assigned, so seeing a change would mean asking it. Columns that are cast explicitly on both sides are compared β see below. |
| Materialization | on_schema_change | Predicted DDL | Safety |
|---|---|---|---|
| table | any | CREATE OR REPLACE TABLE | SAFE |
| view | any | CREATE OR REPLACE VIEW | SAFE |
| ephemeral | any | (no physical object) | SAFE |
| snapshot | any | REVIEW REQUIRED | WARNING |
| incremental | ignore | no DDL | SAFE |
| incremental | fail | build failure | WARNING |
| incremental | append_new_columns | ADD COLUMN only | SAFE |
| incremental | sync_all_columns | ADD + DROP COLUMN | DESTRUCTIVE if columns removed |
| any | (model removed) | MODEL REMOVED | DESTRUCTIVE |
| any | (unknown osc) | UNKNOWN on_schema_change | WARNING |
| materialized_view / custom | (not set by you) | UNKNOWN materialization | WARNING |
| materialized_view / custom | (you set one) | follows the incremental rules | per osc |
| any | (contract: {enforced: true}) | CONTRACT VIOLATION | WARNING |
Under a contract, a column's declared data_type is compared with its explicit CAST,
by family -- text against number against date/time against boolean. varchar and text
are the same family and not a finding; varchar and integer are a build failure.
Comparing more finely means a per-adapter type table, and a wrong answer about a type is
worse than no answer.
"Not set by you" means the author wrote no on_schema_change, in the model or in
dbt_project.yml. dbt resolves one for every model regardless, so the resolved value
asserts nothing; an explicit setting is a claim about how that materialization behaves
and is honoured. dbt-plan reads unrendered_config to tell them apart.
An enforced contract inverts the rules above: dbt requires every column to be declared,
so a column added to the SQL fails the build just as a removed one does. Names only β
dbt compares its declared data_type against the warehouse, which dbt-plan does not read.
Factual signals from GitHub, npm, and our automated checks β not a rating.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/dbt-plan)<a href="https://allmcps.com/mcp/dbt-plan"><img src="https://allmcps.com/api/badge/dbt-plan?style=directory" alt="Dbt Plan on AllMCPs" /></a>