top of page

How I Used Power BI Modeling MCP + PBIP to Build a Contoso Star Schema, Generate Measures, Clean Metadata, and Auto-Hide Visual Filters

  • Jihwan Kim
  • 3 days ago
  • 6 min read

In this writing, I want to share how I started to learn using the Power BI Modeling MCP server together with Power BI Projects (.pbip) and VSCode, and how that experiment turned into a full workflow:

  • building a Contoso star schema with an AI agent,

  • generating a measure table,

  • cleaning up metadata (Sort by column), and

  • automatically hiding visual-level filters in the filter pane by editing the report JSON.

This is all from an actual hands-on session; the screenshots I’ll add are exactly the steps I took.


1. Setting up the playground: Contoso workspace, PBIP, and Git

I started in a Fabric workspace called Contoso with:

  • import_contoso_sales semantic model (Import)

  • import_contoso_sales report

  • A Lakehouse feeding the model

Both the semantic model and the report were stored as Power BI Projects (.pbip) and synced to a Azure DevOps repo, so the full model and report definitions were available as text (TMDL/JSON).

This PBIP + Git setup is what later allowed me (and the agent) to open the visual.json file and control the hidden state of visual filters.

 

ree


2. Connecting the Modeling MCP server from VS Code


Next, I opened:

  • Power BI project import_contoso_sales model

  • VS Code with the repo, plus the Power BI Modeling MCP Server extension installed

In the VS Code chat window, I told the agent:

“Use Power BI MCP server and connect to localhost:xxxxx import_contoso_sales.”

The Modeling MCP server exposed the local model as a set of tools the agent could call: list tables, read columns, create relationships, manage measures, etc.

Microsoft’s November 2025 feature summary and the official repo explain this pattern well: I define intent; the agent calls MCP tools to do the low-level work.

The agent confirmed the connection and gave me a quick model summary: one sales fact table and dimensions for date, product, customer, store, and currencyexchange.


ree



3. Letting the agent design and create the star schema relationships


Then I asked:

“Suggest how to create relationships between tables.”

The agent suggested a classic star schema:

  • date → sales

  • product → sales

  • customer → sales

  • store → sales

  • potential relationship involving currencyexchange


It initially tried to use a DateKey column that didn’t exist in sales, so I corrected it:

“In the sales table, there is no DateKey column.”

The agent re-inspected the table and updated its recommendation to use OrderDate (and optionally DeliveryDate) instead:

  • date[Date] → sales[OrderDate] (main relationship)

  • date[Date] → sales[DeliveryDate] (optional, second date role)


Then I moved from design to execution:

“Create relationship from date[Date] to sales[OrderDate], one to many.”
“From product, customer, and store table to sales table, create relationships as you suggested.”

Using the MCP modeling tools, the agent actually created the relationships. In Desktop I saw:

  • date_sales_orderdate

  • product_sales

  • customer_sales

  • store_sales

all appear and become active.



For the currencyexchange table, I asked:

“Analyze sales table and currencyexchange table, and suggest how to create relationship.”

The agent identified it as a complex many-to-many scenario (FromCurrency/ToCurrency + Date), proposed options (direct composite, bridge table, or reference only), and recommended treating it as a reference table for this model. I agreed:

“As per your recommendation, do not create relationship between currencyexchange table and sales table.”

So currencyexchange stayed as a reference table, which matches how I’d design this Contoso model manually.




ree


ree



ree


ree


ree


ree


ree



4. Asking the agent to propose and create a Measure table

Once the star schema was in place, I wanted a nice, clean measure table.


I asked:

“Analyze this data model, and suggest what DAX measures to create.”

The agent reviewed the model and suggested a solid starter set:

  • Total Sales

  • Total Revenue / NetPrice

  • Total Cost

  • Gross Profit & Gross Margin %

  • Total Quantity

  • Number of Orders

  • Number of Customers

  • Number of Stores

  • Number of Products Sold



Then I pushed it further:

“Create Measure table, and include the below DAX measures into the table.”

The agent:

  1. Created a Measure table.

  2. Created all DAX measures in that table (using SUMX, SUM, DISTINCTCOUNT, etc.).

  3. Left the dummy [Measure] column still visible.


To finish the cleanup, I asked:

“Hide [Measure] column from Measure table.”


The MCP server updated the metadata, and in Desktop the [Measure] column icon switched to hidden, leaving a tidy measure table with only measures. That’s exactly the kind of repetitive “click work” I like offloading to an agent.



ree



ree

ree



5. Bulk metadata cleanup: SummarizeBy and sort order


Next, I shifted focus to the Date table.


All the whole-number label columns (Year, YearMonthNumber, DayOfWeekNumber, etc.) should not default to Sum. I normally fix this column by column. This time I tried a bulk instruction:

“In date table, change ‘summarize by’ to None for all Whole number data type columns.”

The agent:

  1. Queried the Date table columns via MCP.

  2. Identified all Int64 (Whole number) columns.

  3. Updated their Summarize by setting to None in one batch.


Back in Desktop, the sigma icons disappeared from those attributes. Exactly what I wanted, and zero manual clicking.


For the YearMonth ordering, I asked:

“Analyze date table, and configure YearMonth column to be sorted chronological order.”

The agent checked:

  • YearMonth is a text display column.

  • YearMonthNumber is an integer representing chronological order.


Then it set the Sort by column of YearMonth to YearMonthNumber using the column MCP tools. In the matrix visual, YearMonth now sorted correctly instead of alphabetically.


At this point, the modeling side was in a good place:

  • Star schema built with MCP

  • Measures generated and centralized

  • Metadata cleaned up


Time to attack the real pain.



ree


ree


ree


ree



6. The painful part: visual-level filters in the filter pane

I built a simple matrix visual:

  • Rows: YearMonth

  • Values: Number of Orders, Number of Customers, Total Sales

In the Filters on this visual area, I now had four visual-level filters:

  • Number of Customers

  • Number of Orders

  • Total Sales

  • YearMonth


As a Power BI developer, this is where the repetitive pain usually starts. For production reports, I often don’t want users to interact with these visual filters. I want them hidden. Doing that through the UI means:

  • Open the filter pane

  • For each visual (and each filter), click eye-icons one by one.

  • Repeat across many pages and visuals

There’s no built-in “hide all visual filters” button. But with PBIP + Git, those filters are just JSON.




ree





7. Opening the PBIP and letting the agent edit visual.json

Because the report is stored as a Power BI Project (.pbip) and pbir format, the report structure looks like this in the repo:

import_contoso_sales.Report/
  definition/
    report.json
    pages/
      <pageId>/
        page.json
        visuals/
          <visualId>/
            visual.json

In VS Code, with that folder open, I gave the agent a precise instruction referencing the page and visual IDs:

“In this report, find the page <pageId>, and in the page, find the visualization <visualId>.The visualization shows four filters in the ‘Filters on this visual’ section in the filter pane.Make all of them hidden.”

ree


The agent:

  1. Opened page.json (no visual config there).

  2. Searched report.json for the visual ID.

  3. Located visual.json under the correct page folder.

  4. Found the four filters inside filterConfig.filters.


On the first attempt it added an isHidden property to each filter.

This failed validation. I corrected it:

“No, you did not do it correctly, change the isHidden to isHiddenInViewMode.”

This property is also mentioned in the Power BI embedded filter docs and in the PBIR developer-mode blog: isHiddenInViewMode = true hides a filter from the pane while keeping it applied.

After my correction, the agent updated each filter entry to:

"isHiddenInViewMode": true

Saved the file, and reported:

“All four filters now correctly use isHiddenInViewMode: true. The filters are properly configured to be hidden in view mode.”

I kept the change in Git, RE-OPENED the PBIP in Desktop, and checked the report.

Result:

  • The matrix still worked as expected.

  • In the filter pane, the four visual-level filters now showed with the little “hidden eye” icon: applied, but not visible to users.


That’s exactly the behavior I wanted, and I didn’t touch the filter pane UI at all.

As a bonus, this approach is scalable: the same pattern can be extended to loop through all visual.json files in the report and hide filters according to rules (e.g., “hide all measure filters, keep specific dimensions visible”).



ree

ree


ree


8. Why this matters for my day-to-day Power BI work


Looking back at this experiment, here’s what changed for me:

  • Modeling MCP turned a lot of modeling tasks into conversational intent: “Create these relationships”, “generate these measures”, “fix SummarizeBy”, “set the sort order.” The agent used MCP tools to do the heavy lifting.

  • PBIP PBIR + Git made report internals accessible: Visuals, filters, and layout are just JSON files. That opens the door for safe, reviewable automation using agents and Git history.

  • Hiding visual-level filters finally feels automatable: Instead of manually toggling visibility in the UI, I can now target the exact isHiddenInViewMode property in visual.json and let an agent apply it consistently. This directly attacks one of the most painful and repeatable tasks I have as a Power BI report developer.


In other words, this wasn’t just playing with a new feature. It was a full workflow where:

  1. Fabric + PBIP + Git gave me a proper developer surface, and

  2. Modeling MCP + an AI agent helped automate both semantic modeling and report hygiene.


I hope this helps having fun in combining Power BI Modeling MCP, PBIP, and a bit of JSON surgery to both improve your models and get rid of boring tasks like hiding visual-level filters in the filter pane.



Comments


bottom of page