powerbi-desktop-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| PBI_MCP_EDIT_ROOT | No | A folder that holds copies of your Power BI files. Set this to enable editing; with it unset, no edit tool can write anything. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_open_filesA | List every Power BI Desktop file currently open on this machine,
with the identifier ('instance') to pass to the other model tools.
Each entry has |
| get_model_summaryA | Get an overview of an open Power BI file's data model: table count,
measure count, relationship count, plus the full table/measure/
relationship lists. |
| list_tablesC | List every table in the data model, with visibility/description metadata where available. |
| list_columnsA | List columns across the model, or for one table if |
| list_measuresB | List DAX measures across the model, or for one table if |
| list_relationshipsB | List relationships between tables: from/to table and column, cardinality, active flag, cross-filter direction. |
| get_table_row_countC | Get the number of rows currently loaded in a table. |
| list_power_queryA | Get the Power Query (M) code behind the model: each loaded table's
query steps (the let/in M code, including its transformation step
names), plus shared queries/functions/staging steps that feed other
queries but don't load into a visible table themselves (Enable Load =
Off). Pass With |
| find_query_diagnosticsA | Find and read output from Power BI Desktop's built-in Query Diagnostics feature, if you've recorded a session. This plugin can't start/stop Query Diagnostics itself -- it's a manual step in the Power Query Editor's Tools tab (Start Diagnostics -> do the refresh you want traced -> Stop Diagnostics) with no local API to trigger it -- but once you've recorded one, this finds the resulting "Diagnostics" queries by name and, for any that were loaded into the model, returns the actual traced rows (step-by-step timing, data source queries, row counts, whether query folding happened, and so on -- the real intermediate evaluation data list_power_query's step breakdown can't provide). If the diagnostics queries exist but weren't loaded into the model, this tells you that and how to fix it rather than returning nothing. |
| diagnose_power_queryA | Fast health check across every table's Power Query load: which tables errored on last refresh (with the actual error message), and whether a table was refreshed before or after its query was last edited (a stale refresh). This is the live, authoritative signal for "is something broken" -- check this first, then use list_power_query to read the M code (with its step breakdown) for whichever table shows a problem. |
| list_all_dax_expressionsA | Get every piece of DAX in the model in one place: measures, calculated columns, and calculated tables, each with its full expression. Useful for an overall DAX audit/review rather than pulling measures and columns separately. |
| analyze_relationshipsA | List relationships with modeling-analysis flags attached: which are many-to-many, which cross-filter bidirectionally, which are inactive, and which visible tables have no relationships at all (isolated from the rest of the model). Use this over list_relationships when the goal is spotting model design issues rather than just reading the raw list. |
| list_security_rolesA | List row-level security (RLS) roles and each one's per-table filter
expression. Flags, per role, which tables it can access with no row
filter at all ( |
| list_data_sourcesA | Inventory every data source the model actually connects to (SQL servers, SharePoint sites, web APIs, files, etc.), by scanning every table and shared query's M code for known connector function calls. Returns each distinct connection plus which queries use it. Useful for "what does this dashboard actually talk to" -- spotting a dev/test server left in a query bound for production, an unexpected data source, or confirming everything points where it should. |
| analyze_model_sizeA | Get VertiPaq storage engine byte totals per table (exact) and the largest individual storage objects/columns (best-effort labeling) -- the same underlying data DAX Studio's and Tabular Editor's VertiPaq Analyzer use to show what's bloating a model's memory footprint. Use this for efficiency review: a surprisingly large table or column here is a concrete lead (unused high-cardinality column, a text column that should be split or removed, importing more history than needed, etc). |
| list_hierarchiesB | List user-defined hierarchies (e.g. Year > Quarter > Month, or Region > State > City) and their ordered levels, for a complete picture of the model's structure beyond flat tables/columns. |
| find_unused_fieldsA | Find visible columns and measures that no visual on any report page
actually uses (cross-references the live model against the offline
report layout). Get |
| audit_dashboardA | START HERE for a full review. Runs every check (refresh health, DAX
validity, relationships, row-level security, connections, embedded SQL,
query folding, SharePoint patterns, dependencies, report filters/hidden
pages, unused fields, model size, relationship data integrity, and
Power BI's own runtime logs) and returns ONE ranked list of findings,
each tagged with the tool to call for full detail. A failing check is
reported in |
| classify_connectionsB | Every data source the model reads, classified (on-prem SQL Server, SharePoint site, personal OneDrive, web, local/UNC file, ...) with the problems that matter for SQL / SharePoint / OneDrive dashboards: gateway needed for service refresh, localhost or OneDrive-synced local paths (only work on this PC), http, personal-OneDrive dependence, dev/test names, the same target spelled several ways (separate credentials), and parameters resolved to their values. |
| analyze_sql_queriesB | Review every hand-written SQL statement embedded in the M code ([Query=...], Value.NativeQuery): writes/DROP against real tables in a read query, TOP N caps that silently drop rows, SELECT *, hard-coded years / year-named tables, CAST to varchar without length (truncates at 30), NOLOCK, UNION vs UNION ALL, ORDER BY, temp-table batches, cross- database reads, and SQL built by concatenation. Also lists navigation- style SQL queries (which can fold). |
| analyze_folding_riskA | Static estimate of query folding per query: which steps normally push down to SQL, the first step that stops folding, row filters that run locally AFTER folding ended (the source sent every row first), Table.Buffer, and merges across different sources (joined locally). SharePoint/file sources never fold. It is an estimate from M text, not proof: confirm with 'View Native Query', and use read_mashup_traces for the engine's own folding-failure reports. |
| analyze_sharepoint_patternsB | SharePoint loading review: which lists/files each query pulls (by
ID), lists fetched by several queries, SharePoint.Files enumerating the
whole site then filtering by name, queries that never reduce columns or
rows, system columns deleted by name, errors swallowed by
|
| check_refresh_dependenciesC | The query dependency graph: what feeds what, chain depth, which loaded tables fail if each source (SQL server / SharePoint site) is unreachable, high fan-out staging queries, orphan queries nothing uses, parameters and their consumers, circular references. |
| read_mashup_tracesA | Read Power BI Desktop's own mashup-engine trace logs
(%USERPROFILE%\Microsoft\Power BI Desktop Store App\Traces): the
ONLY source of connector-level runtime evidence. Per SharePoint list:
request counts, failures with HTTP status (e.g. 500/400), durations,
the navigation table re-fetched per evaluation; per SQL command: the
text sent, seconds, rows read; the engine's own folding-failure
reports; container crashes. Pass |
| check_relationship_integrityB | For every relationship, count key values with no match on the other side. On many-to-one lookups these are rows that show under (Blank) and vanish from cross-filtered measures -- totals stop matching with no error. One-to-one/many-to-many are flagged only when unmatched from both sides (wrong columns or a data-type/format mismatch). |
| profile_tableA | Data-quality profile of one loaded table: per column blanks, distinct
count, min/max, longest text; flags entirely-blank / constant columns,
text at a truncation limit (30/255...), placeholder dates (1900/9999).
|
| compare_dashboardsA | Diff two dashboards. Each of |
| run_dax_queryA | Run an arbitrary DAX query (an EVALUATE statement, optionally with DEFINE MEASURE/VAR blocks above it) against an open Power BI file. Use this for anything the higher-level tools (list_tables, list_measures, etc.) don't cover -- ad hoc aggregations, filtering, top-N, DISTINCT lists, testing a candidate measure definition, and so on. Returns {"rows": [...], "row_count": n, "truncated": bool}. Results are
capped at |
| find_pbix_filesA | Scan folders recursively for .pbix / .pbit files on disk (no Power BI
Desktop needed). Defaults: Desktop, Documents, Downloads and OneDrive
Desktop/Documents (add more folders with POWERBI_MCP_SCAN_DIRS). Pass |
| get_report_layoutA | Parse a .pbix file's report layout offline (no need for Power BI Desktop to be running): pages, and per page the visuals with their type, title, and the fields each visual uses. Does not include the data model itself -- use the live-model tools for tables/measures/DAX. |
| review_fileA | Read one Power BI file's TEXT without changing anything: .pbip .pbir .pbids .rdl .tmdl, a PBIR .json
inside a *.Report folder, or a part of a .pbix/.pbit. For a .pbix/.pbit call it WITHOUT |
| propose_changeA | STEP 1 of any edit. Proposes replacing exact |
| finish_changeA | STEP 2 (apply) or UNDO (rollback) for a change from propose_change. Call ONLY after the user has
explicitly approved THAT change and read you the 6-digit approval code shown in the server's console
window; never guess a code or infer approval. With an empty |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 33 tools
Tools are largely distinct and deliberately layered: `audit_dashboard` is a documented orchestrator that points to detail tools, and `analyze_relationships` explicitly says to use it over `list_relationships` for design review. A few boundaries remain fuzzy — `list_data_sources` vs `classify_connections`, `get_model_summary` vs the individual `list_*` calls, and the cluster of Power Query tools (`diagnose_power_query`, `analyze_folding_risk`, `find_query_diagnostics`, `read_mashup_traces`, `list_power_query`) — but the descriptions do most of the disambiguating work.
Every name is snake_case, verb-first, and noun-scoped (list_tables, analyze_model_size, check_relationship_integrity, propose_change). Verb choice varies (list/get/find/analyze/check/audit/read/profile/compare/run) but semantically rather than arbitrarily, so the pattern stays predictable. The propose_change/finish_change pair reads as an intentional two-step workflow rather than a naming break.
33 tools is heavy for an agent to navigate, even though each one maps to a real, non-duplicated audit or inspection task. The audit_dashboard aggregator and clear START HERE guidance offset some of the load, but the surface is well past the comfortable 3-15 range for a single server.
Coverage is unusually broad: model metadata, DAX, Power Query/M, folding, RLS, data sources, runtime traces, offline report layout, file scanning, diffing, profiling, and a guarded propose/apply/rollback edit flow. Gaps are mostly acknowledged hard limits — the compressed DataModel/DataMashup in .pbix is never read or edited (so in-place .pbix measure edits are impossible), and the server cannot trigger refreshes or start/stop Query Diagnostics.