Data Engineering with DBT MCP

Transform raw PostgreSQL data into analytics with DBT and Cursor!

Introduction

This project has been archived

We're no longer updating this project - we recommend checking out our active projects instead!

If you've already completed this project, don't worry! Your documentation is still available for you to check out and share.

If you have any questions, leave a question in our Discord and we'll get back to you ASAP!

⚑️ 30 second Summary

You're a data analyst at an e-commerce company. Your database has orders scattered across multiple tables, customer data is inconsistent, and the sales team keeps asking "Who are our VIP customers?" You need to transform this messy data into clear answers - fast.

Data teams at GitLab, Glossier, and Instacart face this same challenge every day. Their solution? An open source tool called DBT (Data Build Tool) - a command-line tool that transforms raw SQL queries into tested, documented data models.

You'll use DBT to transform raw e-commerce data into customer analytics. You'll build a data model that shows how much each customer spends, groups customers by how they shop, and reveals what products sell best - all through Cursor's chat.

Why DBT?

Data in databases is messy and hard to analyze - orders in one table, customers in another, no clear metrics. Transformations combine and reshape this raw data into clean analytics tables that answer business questions like "Who are my VIP customers?" That's where DBT comes in - it helps you write, test, and organize these transformations as code.

What you'll build

Cursor connects with the DBT MCP, which lets you organise and transforms your SQL data using natural language prompts.

By the end of this project, you'll have:

  • A customer analytics model showing how much customers spend, how they behave, and what they buy.
  • Data quality tests ensuring your analytics are reliable.
  • πŸ’Ž Interactive DBT documentation with model descriptions, column details, and lineage graphs.

I haven't done Project #1 yet

No worries! This project builds on Project #1: PostgreSQL MCP, where you set up PostgreSQL with Docker and MCP.

You can either complete Project #1 first (recommended), or we'll guide you through a quick setup in Step #1 to catch up. Either way works.

πŸ’‘ New to DBT?

You don't need any prior DBT or data engineering experience. This project walks you through everything step-by-step!

Not sure if this project is right for you? Check if it matches your goals.

If you're up for a bit of a challenge, quiz yourself on the key concepts up ahead in this project! Don't be too nervous, you'll also get a quiz at the end of this project, to recap what you've learned.

Want a complete demo of how to do this project, from start to finish? Check out our 🎬 walkthrough with Kahu 🎬

This project is part of a series:

  1. Part 1: PostgreSQL MCP (recommended)
  2. Part 2: You are here!
  3. Part 3: Jupyter MCP
  4. Part 4: Grafana MCP

Set Up DBT and MCP Servers

Let's get DBT set up! We'll configure the DBT MCP server and get your transformation toolkit ready.

If you completed Project #1 of this series on Data Engineering with MCPs, this will be quick - we're just adding one more MCP server to your existing setup!

In this step, you're going to:

  • Initialize a DBT project to create the project structure.
  • Add the DBT MCP server to Cursor.

Check Your Current MCP Setup

Before we add DBT, let's see what MCP servers you already have configured.

  • Open Cursor from your Applications folder (Mac) or Start menu (Windows).
  • Click the settings icon (gear icon) in the top right.
  • Select Tools & MCP from the settings menu.

Now, look at your MCP servers list. What do you see?

βœ… I see Docker and Postgres MCP

Perfect! You already have Docker and PostgreSQL MCP servers configured (likely from Project #1: Data Engineering with Postgres & Docker MCP).

Let's verify your PostgreSQL container is running before we add the DBT MCP.

  • In Cursor, select Open Project and navigate to your MCP-data-series folder.
  • Open a new terminal in Cursor.

🍎 macOS

In Cursor, go to Terminal β†’ New Terminal from the menu bar.

πŸ–ΌοΈ Windows

In Cursor, go to Terminal β†’ New Terminal from the menu bar. Or press Ctrl+`.

  • Let's verify your PostgreSQL container is running (we need it running so DBT has data to transform). Run this command to check the container status:
docker ps -a

Why does DBT need PostgreSQL running?

DBT transforms data IN your database - it reads from source tables (customers, orders, products), runs transformations, and writes results as new tables. Without PostgreSQL running, DBT has no data to transform!

βœ… I see pg-local running

You should now see pg-local with a STATUS that starts with "Up" (like "Up 7 seconds ago").

Excellent! Your PostgreSQL container is ready. βœ…

⚠️ Stopped/Exited

STATUS that starts with "Exited" (like "Exited (0) 17 seconds ago").

No problem! Let's start it up:

  • Run this command in the terminal:
docker start pg-local

Wait 10-15 seconds for PostgreSQL to fully start, then verify:

  • Run this command in the terminal:
docker ps

You should now see pg-local with a STATUS that starts with "Up" (like "Up 48 seconds ago").

❌ Docker daemon not running

If you see an error like Cannot connect to the Docker daemon, it means Docker Desktop isn't running yet.

Fix:

  • Open Docker Desktop from your Applications folder (Mac) or Start menu (Windows).
  • Wait for the 🐳 whale icon to appear in your menu bar/system tray.
  • Once it's running, retry the command:
docker ps -a

You should now see your containers listed! Now check the output and select the tab above that matches what you see (container running, stopped, or no container found).

❌ No pg-local container

You'll need to recreate the container from Project #1.

  • Run this command in the terminal:
docker run --name pg-local -e POSTGRES_USER=app -e POSTGRES_PASSWORD=app -e POSTGRES_DB=demo -p 5432:5432 -d postgres:16

You should see a container id (like 'c0901...') if you container was created successfully.

What does this command do?

This creates your PostgreSQL container with the same configuration from Project #1. It sets up the app user, demo database, and maps port 5432.

Wait 15-20 seconds for the container to fully start.

Now you'll need to reload your demo data. If you don't have demo_data.sql in your MCP-data-series folder:

  • Download it from demo_data.sql
  • Save it to your MCP-data-series folder

Then load the data:

🍎 macOS/Linux
  • Run this command in the terminal:
cat demo_data.sql | docker exec -i pg-local psql -U app -d demo
πŸ–ΌοΈ Windows
  • Run this command in the terminal:
Get-Content demo_data.sql | docker exec -i pg-local psql -U app -d demo

You should see SQL output as tables are created and data is inserted.

❌ I don't see Docker and Postgres MCP

No worries! Here's the fast-track setup (15 minutes). We'll get Docker, PostgreSQL, and MCP servers configured.

What you'll set up:

  • Docker Desktop + PostgreSQL container
  • uv package manager
  • MCP servers (Docker + Postgres)
  • Demo data loaded

1. Install Docker Desktop

First, check if you already have Docker installed.

  • Open Terminal (Mac) or PowerShell (Windows)
  • Run this command:
docker --version

βœ… I see a version number

Perfect! Docker is already installed. Skip to step 2 below.

❌ Command not found

Let's install Docker Desktop:

🍎 macOS
  • Download from docker.com/products/docker-desktop
  • Choose Apple Chip (M1/M2/M3) or Intel Chip based on your Mac
  • Drag Docker.dmg to Applications folder
  • Open Docker Desktop, accept terms, click Finish
  • Look for 🐳 whale icon in menu bar (means it's running)
πŸ–ΌοΈ Windows
  • Download from docker.com/products/docker-desktop
  • Run installer, accept defaults, restart computer when prompted
  • Open Docker Desktop, skip sign-in
  • Look for 🐳 whale icon in system tray (means it's running)

If you see WSL 2 errors: Open PowerShell as Admin, run wsl --install, restart computer.

2. Install uv Package Manager

First, check if you already have uv installed.

  • Run this command in the terminal:
uv --version

βœ… I see a version number

Great! uv is already installed.

Now create your project folder:

  • Select Open Project and create a new folder on your Desktop
  • Name the folder MCP-data-series

❌ Command not found

Let's install uv:

  • Select Open Project and create a new folder on your Desktop called MCP-data-series
  • Open terminal in Cursor (Ctrl/Cmd + Shift + `)
🍎 macOS
πŸ–ΌοΈ Windows

Run the install command for your OS:

🍎 macOS
  • Run this command in the terminal:
curl -LsSf https://astral.sh/uv/install.sh | sh

Then verify:

  • Run this command in the terminal:
uv --version
πŸ–ΌοΈ Windows
  • Run this command in the terminal:
iwr https://astral.sh/uv/install.ps1 -UseBasicParsing | iex

Then verify:

  • Run this command in the terminal:
uv --version

If you get permission errors: Close terminal, right-click Cursor β†’ Run as Administrator, try again.

You should see a version number (like uv 0.4.18).

3. Create PostgreSQL Container + Load Data

  • Run these commands in terminal one by one:
uv init
docker run -d --name pg-local -p 5432:5432 -e POSTGRES_USER=app -e POSTGRES_PASSWORD=app -e POSTGRES_DB=demo postgres:16

Wait 20 seconds for PostgreSQL to start up, then download and load data:

🍎 macOS

  • Run these commands in terminal:
# Download demo data
curl -o demo_data.sql https://storage.googleapis.com/nextwork_course_resources/courses/ai/mcp-data-engineering/demo_data.sql

# Load into database
cat demo_data.sql | docker exec -i pg-local psql -U app -d demo

πŸ–ΌοΈ Windows

  • Run these commands in terminal:
# Download demo data
Invoke-WebRequest -Uri "https://storage.googleapis.com/nextwork_course_resources/courses/ai/mcp-data-engineering/demo_data.sql" -OutFile "demo_data.sql"

# Load into database
Get-Content demo_data.sql | docker exec -i pg-local psql -U app -d demo

You'll see SQL output scrolling by - that's 40,000+ rows being inserted!

4. Configure MCP Servers in Cursor

  • Click the settings icon (gear icon) in the top right of Cursor.
  • Select MCP from the left sidebar.
  • Click Add Custom MCP.

Your mcp.json file opens. Paste this config based on your OS:

🍎 macOS

{
  "mcpServers": {
    "docker": {
      "command": "uv",
      "args": ["run", "--with", "docker-mcp", "docker-mcp", "--access-mode=unrestricted"],
      "env": { "DOCKER_HOST": "unix:///var/run/docker.sock" }
    },
    "postgres": {
      "command": "uv",
      "args": ["run", "--with", "postgres-mcp", "postgres-mcp", "--access-mode=unrestricted"],
      "env": { "DATABASE_URI": "postgresql://app:app@localhost:5432/demo" }
    }
  }
}

πŸ–ΌοΈ Windows

{
  "mcpServers": {
    "docker": {
      "command": "uv",
      "args": ["run", "--with", "docker-mcp", "docker-mcp", "--access-mode=unrestricted"],
      "env": { "DOCKER_HOST": "npipe:////./pipe/docker_engine" }
    },
    "postgres": {
      "command": "uv",
      "args": ["run", "--with", "postgres-mcp", "postgres-mcp", "--access-mode=unrestricted"],
      "env": { "DATABASE_URI": "postgresql://app:app@localhost:5432/demo" }
    }
  }
}
  • Save with Cmd + S (Mac) or Ctrl + S (Windows)
  • Quit Cursor completely (Cmd+Q on Mac, Alt+F4 on Windows)
  • Reopen Cursor
  • Go back to Settings β†’ MCP
  • You should see two green indicators for docker and postgres!

βœ… You're all set! You now have the same setup as someone who completed Project #1. Continue below to add the DBT MCP server.

Initialize Your DBT Project

Before we can configure the DBT MCP, we need to create the DBT project folder structure. This is where all your transformations will live!

Make sure you're in your MCP-data-series folder:

  • Run this command in the terminal:
pwd

You should see the path to your MCP-data-series folder.

I'm not in MCP-data-series!

If the terminal shows a different folder, you need to navigate to MCP-data-series first. Get help navigating to your folder.

Now let's initialize DBT

  • Enter the following command into the terminal:
uv run --with dbt-core --with dbt-postgres dbt init

What does this command do?

This command uses uv to temporarily install DBT and run the initialization wizard. The --with flags install dbt-core and dbt-postgres just for this command.

This initialization wizard will set up everything DBT needs to transform your data:

  • Prompt you for connection details
  • Create a DBT project folder structure
  • Generate configuration files (dbt_project.yml for project settings, profiles.yml for database connection)
  • Set up example models you can learn from
  • Enter the database name demo

Configure Your DBT Profile

When DBT prompts you, enter these values in order:

  1. Which database would you like to use? β†’ Enter 1 (for postgres)
  2. host β†’ Enter localhost
  3. port β†’ Press Enter (accept default 5432)
  4. user β†’ Enter app
  5. password (or pass) β†’ Enter app
  6. database name (or dbname) β†’ Enter demo
  7. schema β†’ Enter app
  8. threads β†’ Press Enter (accept default 1)

What are these settings?

These are database connection settings that tell DBT how to connect to your PostgreSQL database:

  • host: Where PostgreSQL is running (localhost = your computer; in production this would be a remote server address)
  • port: PostgreSQL's default port 5432
  • user/pass: The application user from Project #1
  • dbname: The demo database with your e-commerce data
  • schema: The app schema where DBT will create new tables
  • threads: How many queries DBT runs simultaneously (1 is fine for local development)

These connection settings get saved in your profiles.yml file. Once saved, DBT uses this file to connect to your PostgreSQL database and run your transformations.

You should see a new folder structure (including a demo folder):

Let's explore what's inside:

  • In Cursor's file explorer, expand the demo folder to see your DBT project structure:

You'll notice DBT created quite a few folders and files! Don't worry - you won't need to touch most of them. Curious what each folder does?

The most important stuff in here is

  • models/ - Where you'll write your transformation SQL files that turn your e-commerce data into customer analytics
  • dbt_project.yml - Project configuration that tells DBT how to run your models

You'll work mainly in the models/ folder for this project!

Configure DBT MCP Server in Cursor

Time to add the DBT MCP server to Cursor! This will let you run DBT commands through chat.

  • Click the settings icon (gear icon) in the top right of Cursor.
  • Select MCP from the left sidebar.
  • Click Add Custom MCP.

Your mcp.json file will open. You should already have Docker and Postgres MCP servers from Project #1.

Now let's add the DBT MCP server:

🍎 macOS

Get your MCP-data-series path

  • Run this command in the terminal:
pwd
  • Copy the path from the output (Highlight text then use: Cmd + C)
  • Fill in the path from the output.
"dbt": {
  "command": "uv",
  "args": ["run", "--with", "dbt-mcp", "--with", "dbt-core", "--with", "dbt-postgres", "dbt-mcp", "--transport", "stdio"],
  "env": {
    "DBT_PROJECT_DIR": "[[YOUR_MCP_SERIES_PATH="your-mcp-data-series-path"]]/demo",
    "DBT_PROFILES_DIR": "/Users/[[YOUR_USERNAME="Your-Name"]]/.dbt"
  }
}
  • Replace YOUR_MCP_SERIES_PATH with the full path from pwd.
  • Replace YOUR_USERNAME with your Mac username.

Hint: You can find your username in the pwd command you just ran!

It's the part after /Users/ in the path.

Add to mcp.json

  • Scroll up and copy the filled-in config.
  • Add it to your mcpServers section in mcp.json.

πŸ–ΌοΈ Windows

Get your MCP-data-series path

  • Run this command in terminal to get the path with forward slashes:
(pwd).Path -replace '\\','/'

What does this command do?

pwd gets your current directory path, and -replace '\\','/' converts backslashes to forward slashes (which work better in JSON).

  • Copy the path from the output (Highlight text then use: Ctrl + C)
  • Fill in the path from the output.
"dbt": {
  "command": "uv",
  "args": ["run", "--with", "dbt-mcp", "--with", "dbt-core", "--with", "dbt-postgres", "dbt-mcp"],
  "env": {
    "DBT_PROJECT_DIR": "[[YOUR_MCP_SERIES_PATH="your-mcp-data-series-path"]]/demo",
    "DBT_PROFILES_DIR": "C:/Users/[[YOUR_USERNAME="YourName"]]/.dbt"
  }
}
  • Replace YOUR_MCP_SERIES_PATH with the path from the command above.
  • Replace YOUR_USERNAME with your Windows username.

Hint: You can find your username in the pwd command you just ran!

It's the part after C:/Users/ in the path.

Add to mcp.json

  • Scroll up and copy the filled-in config.
  • Add it to your mcpServers section in mcp.json.

Your complete mcp.json should now look like this (with three MCP servers):

Hint: Don't forget to add a comma!

When adding the DBT config to your mcp.json, make sure there's a comma (,) after the closing brace of your postgres MCP server. JSON requires commas between objects.

πŸ’‘ What does this DBT MCP configuration do?

  • command/args: Tells uv to run the DBT MCP server. The --with flags automatically install dbt-mcp, dbt-core, and dbt-postgres when the MCP server starts (no separate installation needed!)
  • DBT_PROJECT_DIR: Points to your DBT project folder
  • DBT_PROFILES_DIR: Points to where DBT stores database connection profiles (the profiles.yml file you configured earlier with your database settings)
  • Save the file with Cmd + S (Mac) or Ctrl + S (Windows).

Restart Cursor

For Cursor to pick up the new DBT MCP server, we need to restart it.

  • Quit Cursor completely (not just minimize!).

How do I quit Cursor?

  • Mac: Cursor β†’ Quit Cursor or Cmd+Q
  • Windows: File β†’ Exit or Alt+F4
  • Reopen Cursor and navigate back to your MCP-data-series folder.

Now verify all three MCP servers are connected:

  • Click the settings icon (gear icon) in the top right of Cursor.
  • Select MCP from the left sidebar.

What do you see?

βœ… Three green indicators

Awesome! You now have three MCP servers working together. Let's put them to use! πŸŽ‰

⚠️ DBT MCP isn't green

If your DBT MCP shows red or isn't connecting, common issues include:

  • Path errors: Double-check your DBT_PROJECT_DIR and DBT_PROFILES_DIR paths in mcp.json
  • Folder name: Verify your DBT project folder is named correctly (should be demo)
  • Missing demo folder: Make sure you ran dbt init first - it creates the demo folder
  • Username typo: Verify you replaced YOUR_USERNAME with your actual username

Get help debugging MCP issues or share your error with the NextWork community!

Build and Run Your DBT Model

Now that we've set up DBT and our MCP servers, we're ready to transform our data! You'll create a DBT model that transforms raw e-commerce data into customer analytics - the same kind of analysis that powers dashboards at Shopify and Amazon. Your model will estimate how much each customer is worth over time, group customers by how they act, and show your best‑selling product categories.

In this step, you're going to:

  • Write an SQL file that transforms your raw data into customer analytics.
  • Run the transformation using DBT MCP.
  • Query the results to discover customer insights.

What's the difference between SQL and DBT?

SQL is the structured language you use to write database queries (like SELECT * FROM customers). DBT is a tool that helps you write, test, and organize SQL transformations as code.

Think of it like this: SQL is the language, DBT is the framework. With raw SQL files, you'd have to manually run queries, remember dependencies, and write separate testing scripts. With DBT, you get automatic dependency management, built-in testing, and documentation - all organized as code.

Create Customer Analytics Model

Let's create a DBT model that calculates customer analytics. This model will combine data from multiple tables (customers, orders, products) to give you insights into customer behavior.

  • In Cursor's file explorer, navigate to your DBT project folder.
  • Open the models folder.

You should see an example folder with some sample models:

What's the example folder?

DBT creates example models when you initialize a project. These are templates you can learn from, but we'll create our own models in the main models folder.

Now let's create our analytics model:

  • Right-click in the example folder.
  • Select New File.
  • Name it customer_analytics.sql.
  • Paste the following SQL into the file:
-- models/customer_analytics.sql
with customer_orders as (
  select
    c.customer_id,
    c.email,
    c.tier,
    c.country,
    c.registration_date,
    count(distinct o.order_id) as total_orders,
    sum(o.total_amount) as lifetime_value,
    min(o.order_date) as first_order_date,
    max(o.order_date) as last_order_date,
    avg(o.total_amount) as avg_order_value
  from app.customers c
  left join app.orders o on c.customer_id = o.customer_id
  group by 1, 2, 3, 4, 5
),

product_preferences as (
  select
    oi.order_id,
    o.customer_id,
    p.category,
    sum(oi.quantity * oi.price) as category_spend
  from app.order_items oi
  join app.orders o on oi.order_id = o.order_id
  join app.products p on oi.product_id = p.product_id
  group by 1, 2, 3
),

top_category_per_customer as (
  select
    customer_id,
    category,
    sum(category_spend) as total_category_spend,
    row_number() over (partition by customer_id order by sum(category_spend) desc) as category_rank
  from product_preferences
  group by 1, 2
)

select
  co.*,
  tcc.category as favorite_category,
  (current_date - co.registration_date) as days_since_registration,
  (co.last_order_date - co.first_order_date) as customer_lifespan_days,
  case
    when co.total_orders = 0 then 'inactive'
    when co.total_orders < 5 then 'occasional'
    when co.total_orders < 15 then 'regular'
    else 'vip'
  end as customer_segment
from customer_orders co
left join top_category_per_customer tcc
  on co.customer_id = tcc.customer_id
  and tcc.category_rank = 1
  • Save the file with Cmd + S (Mac) or Ctrl + S (Windows).

What does this model do?

Don't worry if this looks complex - let's break down what's happening in plain English:

This SQL transformation analyzes your customers by:

  1. Calculating customer metrics - How many orders each customer placed, their total spending (lifetime value), and average order amount
  2. Finding product preferences - Which product categories each customer buys from and how much they spend in each category
  3. Identifying favorite categories - Determines each customer's #1 most-purchased category
  4. Segmenting customers - Groups customers into tiers: inactive (no orders), occasional (1-4 orders), regular (5-14 orders), or VIP (15+ orders)

DBT will run this SQL and create a new customer_analytics table in your database with all these insights!

πŸ’‘ What SQL concepts are used in this model?

This query uses several SQL techniques to organize and calculate the data:

CTEs (Common Table Expressions): The with customer_orders as (...) syntax creates temporary "mini-tables" that you can reference later in the query. This model breaks down the complex analysis into 3 readable steps: customer_orders (calculates metrics per customer), product_preferences (tracks category spending), and top_category_per_customer (finds each customer's favorite category).

Aggregates: Functions that calculate summary values from multiple rows:

  • count(distinct o.order_id) - Counts unique orders
  • sum(o.total_amount) - Adds up all order amounts
  • min(), max(), avg() - Find minimum, maximum, and average values

Window Functions: row_number() over (partition by...) lets you rank or number rows within groups:

  • partition by customer_id - Groups data by customer
  • order by sum(category_spend) desc - Ranks categories by spending
  • This identifies each customer's #1 favorite category!

Run Your DBT Model with MCP

Now for the magic! ✨ Let's use Cursor's chat to run your DBT model and watch it transform your data.

  • Open Cursor's chat (Ctrl+L or Cmd+L).
  • Send this prompt:
Using the DBT MCP, run the customer_analytics.sql model 
and summarize the results concisely in a table.

Cursor will use the DBT MCP to execute your model. You'll see output showing SQL compilation, number of rows processed, and execution time.

What just happened?

DBT compiled your customer_analytics.sql file, executed it against your database, and created a new customer_analytics table with the transformed results!

What do you see in your Cursor chat?

βœ… Model ran successfully

Perfect! Your customer analytics table is now in your database. Here's the kind of insights you just generated:

  • Total Customers: 2,000 analyzed
  • Customer Segments: 1,115 regular customers, 868 occasional, 17 inactive
  • Top Categories: Toys and Food are most popular
  • Average Lifetime Value: Regular customers spend $3,334 on average!

Your DBT model just turned raw database tables into actionable business insights. πŸŽ‰

❌ Cursor isn't connecting to DBT MCP

Hmm! Here are a few troubleshooting tips if Cursor can't connect to the DBT MCP:

  1. Make sure your Cursor chat is in Agent mode - not Ask mode!
  2. Check the Tools & MCP page in your Cursor Settings - is the DBT MCP showing any errors? Make sure to expand the MCP to view detailed error message, which you can paste into your Cursor chat to troubleshoot!
  3. Still not connecting? Troubleshoot here!

⚠️ Compilation or SQL error

If you see errors, common issues include:

  • "Relation does not exist": The model can't find the source tables. Make sure:
    • Your PostgreSQL container is running
    • The demo data is loaded
    • The schema name is correct (should be app)
  • "Column does not exist": Check that column names match your source tables exactly.
  • "Connection refused": PostgreSQL might not be ready yet. Wait 10 seconds and try again.

If you're still stuck, get help debugging your specific error.

Great work! You've built and run your first DBT transformation. Now let's add data quality tests!

Add Data Quality Tests

Companies like Airbnb and GitLab don't just transform data - they test it. You're about to add DBT tests to automatically catch data quality issues (like missing values, duplicates, or invalid data), ensuring your analytics are production-ready and trustworthy.

In this step, you're going to:

  • Add built-in tests to your DBT model.
  • Run tests to verify data quality.
  • Identify and fix a test failure.

Add Tests to Your Model

DBT includes built-in tests you can add to your schema.yml file. Let's add tests that verify your data is clean and reliable.

What is schema.yml?

The schema.yml file is where you define your models and add documentation and tests. It tells DBT what tests to run on which columns, making data quality checks automatic.

  • Open your models/schema.yml file in Cursor.
  • Update it to include tests under the columns:
version: 2

models:
  - name: customer_analytics
    description: "Customer analytics combining order history, spending patterns, and segmentation"
    columns:
      - name: customer_id
        description: "Unique identifier for each customer"
        tests:
          - not_null
          - unique
      - name: email
        description: "Customer email address"
        tests:
          - not_null
      - name: lifetime_value
        description: "Total amount spent by customer across all orders"
        tests:
          - not_null
      - name: customer_segment
        description: "Customer segment based on order frequency: inactive, occasional, regular, or VIP"
        tests:
          - not_null
          - accepted_values:
              values: ['inactive', 'occasional', 'regular', 'vip']
      - name: total_orders
        description: "Total number of orders placed by this customer"
        tests:
          - not_null
  • Save the file.

What do these tests do?

  • not_null: Ensures columns have no missing values (NULL). You added this to customer_id, email, lifetime_value, customer_segment, and total_orders.
  • unique: Ensures no duplicate values. You added this to customer_id to ensure each customer appears only once.
  • accepted_values: Ensures values match a specific list (prevents typos/bad data). You added this to customer_segment to ensure it only contains 'inactive', 'occasional', 'regular', or 'vip'.

These tests help catch issues like duplicate customer records, customers without emails, or misspelled segment names that could break your analytics!

Run Your Tests

Now let's run the tests and see if your data passes! πŸ§ͺ

  • In Cursor's chat, send this prompt:
Using the DBT MCP, run all tests for the customer_analytics model
and show me the results

DBT will run all your tests and show you the results:

βœ… All tests passed

Great! All your tests passed - your data quality is solid. You can skip the "Fix the Failing Test" section below.

Why did all my tests pass?

We typically expect the not_null test on lifetime_value to fail (since some customers have no orders). If all tests passed, it could mean:

  • Your model already handles NULL values (perhaps you used COALESCE or similar)
  • Your demo data happened to have no inactive customers
  • The test configuration is different

Either way, passing tests means your data is clean! Great job.

⚠️ Some tests failed (Expected!)

You'll likely see a test failure for not_null_customer_analytics_lifetime_value - that's actually good! You've caught a real data quality issue.

What is the data quality problem?

Some customers have NULL (missing) lifetime values because they never placed any orders. This matters because NULL values can break calculations and dashboards - if you try to sum or average these values, you'll get incorrect results.

Cursor will show which customers have NULL lifetime_value and explain they're inactive customers with no orders.

Fix the Failing Test

Now let's fix the data quality issue you identified.

  • In Cursor's chat, send this prompt:
Fix the failing test(s) in my customer_analytics model. Update the model
file to resolve the issue and explain what you changed.

Cursor will update your model and explain the change.

Now rerun the model and retest.

  • Send this prompt:
Using the DBT MCP, rerun the customer_analytics model, then run all
tests again and concisely summarize the new results.

Cursor will output the new results.

All tests should pass now! Look for output showing all tests passed, indicating your data quality checks succeeded.

What just happened?

You identified a data quality issue through testing, fixed it in your transformation logic, and verified the fix worked - all through chat. This is the exact workflow data engineers use every day to ensure reliable analytics!

Amazing! You've added production-grade testing to your analytics. Ready for the Secret Mission where you'll create professional documentation?

Secret mission

Ready for the Secret Mission? You'll generate DBT documentation with interactive lineage charts - the same tools data teams at Airbnb and GitLab use to visualize how data flows through their pipelines.

Document & Visualize Your Data Pipeline

Clean Up Your Resources

Clean Up Your Resources

Nice work completing Project #2! Choose how much you want to clean up based on whether you're continuing to Project #3.

Minimal (Keep for Project #3)

If you're continuing to Project #3, just stop the documentation server:

  • Go to your terminal in Cursor.
  • Press Ctrl + C to stop the docs server (if running).

Keep everything else - you'll use PostgreSQL, Docker, and the MCP servers in Project #3!

Remove DBT Only

If you're done with DBT but want to keep PostgreSQL for other projects, remove DBT only:

1. Stop documentation server:

  • Press Ctrl + C in your terminal (if docs server is running)

2. Remove DBT MCP from Cursor:

  • Click the settings icon in the top right
  • Select MCP from the left sidebar
  • Find the dbt server
  • Click the trash icon to remove it
  • Restart Cursor

3. Delete DBT project folder:

  • Delete the demo folder inside your MCP-data-series folder

Keep Docker, PostgreSQL container, and data for future projects!

Remove Everything

If you're done with the entire MCP series, here's how to clean up everything:

1. Stop and remove PostgreSQL container:

In Cursor's chat, send:

Using the Docker MCP, stop and remove the pg-local container

2. Remove all MCP servers:

  • Click settings icon β†’ MCP
  • Remove docker, postgres, and dbt servers
  • Restart Cursor

3. Delete project folder:

  • Delete the entire MCP-data-series folder from your Desktop

4. (Optional) Uninstall Docker Desktop:

🍎 macOS

  • Open Applications folder
  • Drag Docker to Trash
  • Empty Trash

πŸ–ΌοΈ Windows

  • Go to Settings β†’ Apps β†’ Apps & features
  • Find Docker Desktop
  • Click Uninstall

That's a wrap!

That's a wrap!

You did it! You've mastered DBT and built a complete data transformation pipeline using natural language in Cursor.

What you learned:

  • πŸ”§ How DBT transforms raw data into analytics-ready models
  • πŸ€– How the DBT MCP lets you run transformations through chat
  • πŸ“Š SQL analytics: CTEs, aggregations, and window functions
  • βœ… Data quality testing: schema tests and data validation
  • πŸ’Ž Documentation & lineage visualization for production data teams
  • πŸ’¬ How to orchestrate multiple MCP servers (Docker, PostgreSQL, DBT) together

Ready to quiz yourself? πŸ’ͺ

What's next?

In Project #3 of this Data Engineering x MCP series: Jupyter MCP - Notebooks as On-Demand APIs (coming soon), you'll use Jupyter notebooks to explore your data and create visualizations. Now that DBT has prepared your clean analytics tables, Jupyter will help you turn them into insights you can share.

Make sure to join the NextWork Community to be the first to hear when it's out 🀝

p.s. Does it say "Still tasks to complete!" at the bottom of the screen?

This means you still have screenshots left to upload, or questions left to answer!

  1. Press Ctrl+F (Windows) or Command+F (Mac) on your keyboard.
  2. Search for the text Return to later.
  3. Jump straight to your incomplete tasks!
  4. πŸ™‹β€β™€οΈ Still stuck? Ask the community!