Build a Power BI model
Goal
Put an EA repository into Power BI as a generated semantic model: a complete Power BI project with the business tables visible, EA's own tables hidden, every relationship declared, a count measure on each entity table, a measure for each relationship that has to be inactive, and a description on every business table, column and measure. This is for a reporting developer or architect who wants EA data in the organization's reporting tool, and in Microsoft 365 Copilot. You end with a Power BI project that reads the business layer from the delivery way you chose, a checked layer behind it, and an honest statement of whether the data is live or a snapshot.
Where it runs
This scenario needs the MCP server, local code execution for the generator and, for Power BI Desktop, computer use.
| Surface | How it runs |
|---|---|
| Claude Code | Fully |
| Claude Cowork | Not available. The generator needs local code execution on the machine where EA runs, and a local Claude Cowork session runs code in an isolated virtual machine instead. A cloud session has no local MCP server. |
| Claude Desktop chat | Not available. The generator needs local code execution, which Claude Desktop chat does not have. |
| VS Code with GitHub Copilot | Fully, except the UI steps, which you perform: starting EA and opening the model, handling any EA dialog (you screenshot it, paste the screenshot into the conversation so the assistant can analyze it, then dismiss it), and opening, refreshing, checking and publishing the generated project in Power BI Desktop. |
What reaches Power BI
The generator reads the definition file that every build of the business layer writes (Build a reporting database), so it needs no database connection to produce the project. The model is the same on every delivery way: the same tables, names, columns, types, relationships, measures, descriptions, hidden tables and layout. Only two things differ, where each table's rows come from and the storage mode:
| Delivery way | Where Power BI reads the rows | Storage mode | Data |
|---|---|---|---|
| Views in the EA repository's own database | The business-layer views and the scoped views of EA's tables, in their schema inside the EA database | DirectQuery when you want live data; otherwise Import | Live in DirectQuery, which queries the production database. A snapshot as of the last refresh in Import |
| A separate reporting database | The same views, in the separate database on a SQL Server you run or in a SQL database in Microsoft Fabric | Import (DirectQuery is refused) | A snapshot as of the last build or refresh |
| Parquet files | One Parquet file per table, written into the profile's folder together with the project | Import (DirectQuery is refused) | A snapshot as of the last build or refresh |
So do not treat the three as different Power BI capabilities. They are one model with three sources, and a report built on one keeps working on another. Do not quietly build a snapshot when live data was asked for. The report keeps working and the numbers go stale silently. Live data is available only from views in the EA database, in DirectQuery.
What the project holds.
- The business tables, visible, with their key columns hidden but present, because the relationships use them.
- EA's nine tables, hidden but present, so a report can still reach anything EA holds that a business table does not carry.
- A description on every business table, column and measure. Each comes from the descriptions file you approved, or else the technology's own notes, or else a fixed template that names the object. Your business terms come from the file.
- Relationships declared by the generator, never detected by Power BI. The business layer filters EA's tables; the other direction makes Power BI refuse the project for ambiguous paths. A relationship is inactive when it would be a second relationship between the same two tables, or a second filter path. A combination that links an entity type to itself gets one inactive relationship, on the target side.
- Two kinds of measure, and no others: a count measure on each entity table, for example "Business Application count", and a traversal measure for each inactive relationship whose many side is a connector table, placed on that connector table and named for what it answers, for example "Uses by target Business Application". The traversal measure is what makes the target side of a self-link reachable.
- One blank member on every entity table. Power BI shows "(Blank)" in a slicer and one extra row in a table visual, because the business layer filters EA's element table. The count measures are right; a figure one too high is the blank member.
- A default layout: business tables in bands at the top, EA's tables in a band below.
- An Overview report page on a fresh project: a table of the Table Directory and a card for each entity count measure.
- No automatic date tables, and every column summarizes by nothing, so a numeric tag is not offered as a sum. Internal identifiers are derived from each object's path, so regenerating the same model gives the same files.
Why a generated model. Handing Power BI a set of tables and letting it infer relationships fails silently. On a 40-table build of the Westbrook reference model loaded with no relationships, Power BI's own detection proposed 63 relationships where the model needed 38: 28 were invented from shared values such as a data classification, and a real relationship was switched off with no warning. On the business layer of the same model, read back from Power BI's engine, the engine agreed with every declared relationship (83 of 83), row counts equaled SQL Server's, and traversals equaled the SQL joins, in both Import and DirectQuery. These figures belong to that one model and show the shape of a result, not what to expect on yours.
Nothing here writes to EA.
Before you start
- The business layer is built and checked for your delivery way (Build a reporting database), so its definition file exists beside the reporting profile. An unchecked layer is not a deliverable.
- For Parquet files: the pyarrow Python library installed (
pip install pyarrow). It is deliberately not shipped, and the step stops with the install command when it is missing. CSV is never a substitute, and Excel is never an output: Parquet carries column names and types, where the same tables loaded through Excel arrived as anonymous columns. - Power BI Desktop with two preview features on: the Power BI project (
.pbip) save option, and "Store semantic model using TMDL format". Confirm them in your build before promising the project will open. The project-format behavior was measured on Power BI Desktop 2.158.1177.0; quote the build with any behavior you describe. - A short folder for the project. Windows has a 260-character path limit, and the project's own nested folders add to it.
- One stable project name per model; do not vary it between runs.
- Local code execution, with Python 3 on the machine, for the generator (see Supported clients and Power BI generator). Without it the scenario is not available.
Steps
- AI with computer use; otherwise you If EA is not running or the model is not open, start EA and open it. AI Power Tools
ea-start-hereruns the session preflight. - AI
ea-power-biasks the three delivery-way questions with their consequences, all at once, then waits. You answer, and for views in the EA database, choose DirectQuery or Import. - AI
ea-power-bichecks the preconditions, each of which stops the build: the definition file exists and the layer has been checked; pyarrow is installed, for Parquet files. AI with computer use; otherwise you confirm the two preview features in Power BI Desktop. - AI Power Tools When people will ask about business terms,
ea-power-bireads the distinct values of each tagged value concerned from EA with a read-only query (execute_sql). AI It asks what each term means and which values it covers, and shows any wording it suggests as a draft. You define the terms and approve the text; the descriptions file is written beside the profile only on your yes. - Engine
ea-power-bigenerates the project, with the descriptions file when there is one. For either database way, the generator writes it from the definition file, in Import, or in DirectQuery for views in the EA database when you want live data. For Parquet files, the Parquet step writes one file per table into the profile's folder, then the project. AI It reads the printed counts aloud: tables, relationships, inactive relationships and measures, then the size line. - AI with computer use; otherwise you
ea-power-biopens the project in Power BI Desktop, waits for the initial load, and presses Refresh once. - AI with computer use; otherwise you
ea-power-bichecks the result in Power BI: the counts match those printed, EA's tables and the key columns are hidden, each entity table has a count measure, and the traversal measures sit on the connector tables. You review it. - AI
ea-power-bireports back, in a fixed order.
Step 4, the descriptions file. Microsoft 365 Copilot cannot know what your organization's words mean. On the Westbrook Bank reference model it missed the Archive applications in 4 of 4 runs when asked which applications are being retired, and was right in 4 of 4 once the lifecycle column's description said that retiring means Sunset or Archive. The file can describe a business table, its columns and its measures; an entry replaces the technology's note or the template for that object only. The generator refuses the file, and writes no project, when an entry names something the model does not have, names one of EA's own tables, is empty, or is longer than 250 characters. Pass it on every generation, or the descriptions fall back to the notes and templates.
Step 5, the Parquet files. Types are declared from the definition file, never inferred from the data, so a refresh cannot change a column's type by which rows happen to be filled. Every field may be empty, an empty table is still written with its columns, and a value that does not fit its column is refused, not repaired. The project records the folder as an absolute path: move the folder or the project and you must regenerate. The generated files use the line endings and encoding Power BI writes itself, because Power BI rejects a file whole on a single formatting violation. Do not hand-edit them.
Step 5, the size line. After its counts, the generator prints the model's size in tables plus columns, for the full model and for the visible business layer, and warns past 1,000, the limit Microsoft documents for Copilot's index, that Copilot may leave some out. It only warns.
Step 6, opening it. Expect the semantic model to load, then the report. A generated Import project holds no data until it is refreshed, so Power BI Desktop offers a refresh after opening. Wait for the initial load before refreshing: a refresh started from two places at once failed with a cyclic-reference error that was not a model defect. Opening a second project starts a new Power BI process, so close projects you are done with, and do not launch Power BI again when an instance is already running.
Regenerating. When the definition changes, generate again. The semantic model's definition is replaced, so a table that left the definition leaves the project, and an existing report folder is left untouched, so the visuals you built are kept, and a project with an existing report gets no Overview page. With Power BI's "Detect and reload external PBIP changes" option on, Power BI offers to apply the changes. The generated files are the source of truth: edits made to the model inside Power BI are lost on the next build, so keep business definitions in the descriptions file. Regenerating does not repair a damaged report: move the report folder aside first, then re-create your pages.
After a refresh of the business layer (Build a reporting database):
- Views in the EA database, DirectQuery: nothing to do; every query reads the views live.
- Views in the EA database or a separate reporting database, Import: refresh the model in Power BI Desktop.
- Parquet files: run the Parquet step again to rewrite the files, then refresh the model in Power BI Desktop.
Step 8, what the assistant says, in order: (1) the delivery way, and whether the model is live or a snapshot with its as-of time; (2) that the business layer was checked, with the result; (3) the project path, the table, relationship and measure counts, the size line, the storage mode, and whether a descriptions file was used; (4) that EA's tables and the key columns are hidden, not absent, so a reader comparing with the database hears why some tables are not in the field list, and that each entity table shows one blank member; (5) what is outside the model: left-out packages, elements the inclusion choice left out, the "(excluded)" stand-ins, and every flag you continued past. It never quotes a figure from the model without the populated count behind it.
Prompts to use
Opening:
Follow-ups:
- Import: "Generate the Power BI project from the Westbrook definition file in Import mode and read me the table, relationship and measure counts."
- Parquet: "We have no database to run. Write the Parquet files and the Power BI project from the last build."
- Live: "Our EA repository is on SQL Server and the steering group wants live figures. Generate the project in DirectQuery over the views, and tell me what that costs."
- Check: "Open the project, refresh it once, and tell me whether the relationships and measures are what you generated."
- Business terms: "When we ask which applications are being retired, the answer is wrong. Show me the lifecycle values our business applications carry, help me write down what retired means, and regenerate the project with it."
- Copilot: "Publish the Westbrook project so people can ask Microsoft 365 Copilot about it. What do our administrators need to turn on?"
- Failure: "Power BI says the project will not open and names no file. What do I check?"
Recommended models
| Model | Fit | Why |
|---|---|---|
| Claude Fable 5.1 | Recommended | The delivery-way conversation, honest framing of live versus snapshot, and diagnosing a failed open are judgment-heavy |
| Claude Opus 5.5 | Recommended | Same, over a long multi-step build |
| Claude Sonnet 5.5 | Capable | Reliable on the generator and the checks; supervise the delivery-way conversation and the live-or-snapshot framing |
| Claude Haiku 4.5 | Not recommended | The framing and the failure diagnosis are the hard parts |
Ratings are guidance based on the kind of reasoning the scenario needs, not measured benchmarks.
Checking the result
- Correct. The counts the generator printed match what Power BI shows. The business layer was checked before the project was generated. A spot-check of one traversal measure (connectors into a named element) matches the repository, and a count measure equals the table's row count in the database, not one more. No relationship was added by hand or detected by Power BI. Every entry in the descriptions file is text you approved. Red flag: a relationship Power BI shows that the generator did not print; a business definition you never saw.
- Complete. The model loads, then the report, and the refresh completes. Every table in the definition is in the project, with EA's tables and the key columns hidden, a count measure on each entity table and the traversal measures on the connector tables. What is outside the model is stated. Every figure comes with its populated count.
- Nothing unintended changed. EA is not modified. Regenerating left your report folder untouched.
Inspecting the project with Microsoft's Power BI Modeling MCP server
Microsoft publishes a separate MCP server for reading and editing Power BI semantic models. It is Microsoft's product: you install it, Microsoft's license agreement governs it, and AI Power Tools does not ship or support it. Any Claude client that runs local MCP servers can use it, not only Visual Studio Code. It is optional, and the scenario above does not depend on it.
Where it comes from. Either route gives the same server.
- The Power BI Authoring MCP extension for Visual Studio Code. After you install it, the server is the file
%USERPROFILE%\.vscode\extensions\analysis-services.powerbi-modeling-mcp-<version>-win32-x64\server\powerbi-modeling-mcp.exe. - The
@microsoft/powerbi-modeling-mcppackage on npm, run withnpx. This needs Node.js.
Accept Microsoft's license agreement. The server blocks every other call until it is accepted. Read the agreement, then set the environment variable PBI_MODELING_MCP_ACCEPT_EULA to true, or add --accepteula to the server's arguments. In an interactive session the assistant can instead call the server's accept_eula tool after you authorize it.
Register it with Claude Code. One command, run once:
claude mcp add --transport stdio --env PBI_MODELING_MCP_ACCEPT_EULA=true powerbi-authoring-local -- npx -y @microsoft/powerbi-modeling-mcp@latest --start --readonly
To use the extension's file instead, replace npx -y @microsoft/powerbi-modeling-mcp@latest with the full path to powerbi-modeling-mcp.exe.
Register it with Claude Desktop. Add this entry to mcpServers in %APPDATA%\Claude\claude_desktop_config.json, then quit and restart Claude Desktop:
"powerbi-authoring-local": {
"command": "npx",
"args": ["-y", "@microsoft/powerbi-modeling-mcp@latest", "--start", "--readonly"],
"env": { "PBI_MODELING_MCP_ACCEPT_EULA": "true" }
}
To use the extension's file, set command to the full path of powerbi-modeling-mcp.exe (backslashes doubled in JSON) and drop "-y" and the package name from args.
Start with --readonly. It blocks every write to the semantic model, which is all that inspecting needs. Without it the server can edit the model, and --require-confirmation makes it ask before each write.
What it connects to. You name the target in the conversation:
- a model open in Power BI Desktop, by file name
- a semantic model in a Fabric workspace, by model name and workspace name
- a Power BI project, by the semantic model's
definitionfolder
Example: list the relationships of the generated project. For a project generated from the Westbrook Bank definition file, ask:
The assistant connects to the folder and reads the model through the server's connection_operations, model_operations and relationship_operations. The result is the model's own list: each relationship with its two tables and columns, its direction, its cardinality and whether it is active. Compare it with the relationship count the generator printed. On a Westbrook Bank project measured with server version 1.0.0, the server loaded 51 tables and 83 relationships. These figures belong to that one model.
Changes are held in memory. A model loaded from a folder lives in the server's memory. An edit made through the server is not written to disk until the assistant exports the model to a TMDL folder, and the server warns about this when it loads the model. The generated project remains the source of truth: a later generation rewrites the semantic model's definition and discards edits exported into it.
Variations
- A different delivery way. The model is the same; regenerate from the definition file of the other way, and the report keeps working.
- Live figures. Only views in the EA database, in DirectQuery, give live data, and every query then reads the production database. On any other estate the answer is a snapshot, said plainly.
- Keeping it current. A scheduled AI agent refreshes the business layer (Build a reporting database); then follow the list above for the delivery way.
- A published model that refreshes in the Power BI service. Build the reporting database into a SQL database in Microsoft Fabric (Build a reporting database). In Power BI Desktop, choose Microsoft account when the data source asks for credentials; publish from Power BI Desktop; then in the service set the semantic model's data source credentials to OAuth2, privacy level Organizational. It refreshes with no gateway. If the credentials dialog says SSL (HTTPS) is needed for OAuth 2.0, the browser blocked Microsoft's sign-in pop-up: allow pop-ups for the Power BI site and try again. From a SQL Server you run, the service refreshes through an on-premises data gateway, as Microsoft describes it; that was not measured with the generated model.
- Microsoft 365 Copilot. Publish from Power BI Desktop: descriptions reached Microsoft 365 Copilot Chat within minutes of a Desktop publish, and descriptions changed by another route were not seen. Copilot finds reports more readily than models, so people name the report in the question, attach it, or paste the model's link. No Copilot capacity is needed (measured on a Power BI Pro workspace and a Fabric workspace). Your administrators provide a Microsoft 365 Copilot license and a Power BI Pro or Premium Per User license for each person who asks, the Microsoft 365 admin center setting "Fabric data available in Microsoft Copilot", and the Fabric tenant setting "Share Fabric data with your Microsoft 365 services"; the assistant never changes them. Answers vary between runs, so ask twice before quoting one. See ea-power-bi.
Limitations
- A published model cannot refresh from local Parquet files. It refreshes with no gateway from a SQL database in Microsoft Fabric.
- DirectQuery queries the production database. A separate reporting database is used in Import.
- Every entity table shows one blank member. Use the count measures for counts.
- Microsoft 365 Copilot was measured on one model, with Microsoft 365 Copilot Chat only, and its answers vary between runs.
- The Parquet project is tied to its folder by an absolute path. Regenerate rather than edit.
- The generated project holds no data until refreshed.
- A table visual can lose rows. A row on which every measure is blank is dropped, so an entity with no connectors in that direction disappears from a visual that shows only the measure. Show a column from the entity table beside the measure, or filter on the entity table.
- Common failures, each stopping the whole project: a description on a relationship; a report version written in the wrong form; EA's tables filtering the business layer. The generator avoids all three, and a hand edit reintroduces them. When a project will not open and the message names no file, read the inner exception from "Copy details to clipboard". If the model loads and the report fails, the report's theme is missing; regenerate rather than writing report files by hand.
- It does not fix data quality, and does not replace Prolaborate, EA's own reporting, or a data warehouse.