Power BI Report MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Power BI Report MCP ServerCreate a KPI card for total revenue on the summary page"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
"Create an executive summary page with 6 KPI cards, a revenue trend line chart, and a bar chart by country"
One prompt. One batch call. Full page in Power BI Desktop.
What's new in 0.9
Layout validator now reachable via
pbir_validate_wireframe(v0.9.6) — same checks the test suite runs (margins, gaps, overlap, off-canvas, banner geometry), callable from agents on a single page or across the entire reportTier C.1 catalog reduction +
pbir_guidefix (v0.9.5) — see CHANGELOG.md
What's new in 0.8
pbir_tool prefix — every tool name now starts withpbir_to avoid collisions with sibling MCP servers in the same sessionCowork plugin — drop a single
.pluginfile into Claude (no terminal, no Node install) — see Quick Start › Cowork pluginregisterToolmigration — modern MCP SDK entrypoint with structuredoutputSchemaon every read toolTypo catcher + auto-pageId — fewer "did you mean…" round-trips when there's only one page
Tighter
outputSchema(v0.8.2) — 14 read tools now ship per-tool zod response schemas; mutation tools keep the loose envelope
Full details: CHANGELOG.md.
What is this?
The first open-source MCP server for Power BI report authoring. It connects Claude (or any MCP-compatible client — see Tested clients) to Power BI's PBIR (Power BI Report) file format, turning natural language into real report pages — cards, charts, tables, themes, filters, and formatting.
No REST API keys. No Power BI service. Just local files + Claude.
You: "Build me a sales dashboard with KPIs, trend charts, and a detail table"
AI: pbir_create_page → pbir_add_visual (batch: 12 visuals) → pbir_set_report_theme → done.
Open in Power BI Desktop. ✓Why MCP?
MCP (Model Context Protocol) is an open standard that lets AI assistants call external tools. Instead of the AI generating code for you to run, it directly executes operations through the MCP server.
graph LR
subgraph AI["AI Assistant"]
LLM["Claude, GPT,<br/>Copilot, Cursor..."]
end
subgraph MCP["Two MCP Servers"]
direction TB
MODEL["powerbi-modeling-mcp<br/><i>Tables, columns, measures, DAX</i>"]
REPORT["powerbi-report-mcp<br/><i>Pages, visuals, themes, filters</i>"]
end
subgraph Files["Power BI Project"]
direction TB
SEM[".SemanticModel<br/><i>TMDL / measures</i>"]
REP[".Report<br/><i>PBIR / visual.json</i>"]
end
PBI["Power BI<br/>Desktop"]
LLM <-->|"stdio / MCP"| MODEL
LLM <-->|"stdio / MCP"| REPORT
MODEL <-->|"read"| SEM
REPORT <-->|"read/write"| REP
REP -->|"open .pbip"| PBIThe typical workflow:
1. Query the model --> "What tables and measures are available?" (modeling-mcp)
2. Build the report --> "Create a dashboard with those measures" (report-mcp)
3. Open in Desktop --> Ctrl+Shift+F5 to refreshBoth servers run simultaneously as MCP tools. The AI queries the semantic model for exact table/column/measure names, then uses those to build correctly-bound report pages — no guessing, no broken fields.
Zero vendor lock-in — built on @modelcontextprotocol/sdk + zod. No Anthropic, OpenAI, or Microsoft SDK imports.
How It Compares
This MCP Server | Manual PBI Desktop | Power BI REST API | pbi-tools | |
Input | Natural language | Mouse clicks | REST calls + auth | CLI commands |
Speed | 10-page report in minutes | Hours | Hours (code-heavy) | Minutes (extract/deploy) |
Auth required | None (local files) | None | Azure AD + Service Principal | None |
AI-native | Yes (MCP) | No | No | No |
Format | PBIR (file-based) | PBIX (binary) | Cloud-only | PBIX ↔ folder |
Creates visuals | Yes | Yes | Limited | No (metadata only) |
Themes & formatting | Yes | Yes | Limited | No |
Filters | Yes | Yes | Yes | No |
Works offline | Yes | Yes | No | Yes |
Quick Start
Full walkthrough: docs/quickstart.md
1. Install
git clone https://github.com/jonathan-pap/powerbi-report-mcp.git
cd powerbi-report-mcp
npm install
npm run build2. Configure your MCP client
Ready-to-use config files are in the configs/ folder — copy the one for your client, update the path, done.
Config | Client | Copy to |
Claude Desktop |
| |
Cursor |
| |
GitHub Copilot |
| |
Windsurf |
| |
Continue.dev |
| |
Cline | VS Code Settings → MCP Servers |
Claude Code (no config file needed):
claude mcp add powerbi-report-mcp node C:\path\to\powerbi-report-mcp\dist\index.jsEach config includes both powerbi-report-mcp and powerbi-modeling-mcp for full dual-layer access. See configs/README.md for optional settings (pre-connect to a report, load all tools at startup).
Optional: opt into minimal tool loading
For long Claude Code / Cowork sessions where catalog tokens matter, set MCP_TOOLS=minimal to load only the 12 default tools at startup (saves ~7,500 catalog tokens; the remaining 44 activate on demand via pbir_load_tools):
{
"mcpServers": {
"powerbi-report-mcp": {
"command": "node",
"args": ["/path/to/powerbi-report-mcp/dist/index.js"],
"env": {
"MCP_TOOLS": "minimal" // optional — saves ~7,500 catalog tokens
}
}
}
}Trade-off summary (full breakdown in Smart Tool Loading below):
Default (load-all) — All 56 tools available immediately. Best for unpredictable/exploratory sessions and clients that snapshot the tool list at startup. ~14,500 catalog tokens.
MCP_TOOLS=minimal— 12 default tools at startup; others activatable viapbir_load_tools. Best for known-narrow workflows. ~7,000 catalog tokens. Requires MCP client support fornotifications/tools/list_changedto surface activated tools mid-session — Claude Code/Desktop don't refresh; Cowork may; verify before relying.
3b. Cowork plugin
Prefer to skip the git clone/npm install dance? Grab the latest .plugin bundle from GitHub Releases and drag it into Claude — the plugin ships the server, skills, and a default MCP wiring in one file.
Step | Action |
1 | Download |
2 | Open Claude → Settings → Plugins → Install from file (or drag-and-drop the |
3 | Approve the bundled MCP server when prompted |
4 | In any Claude conversation: "Connect to C:\Projects\Sales.Report and list pages" |
Cowork is a hosted Claude experience with native plugin support. The plugin bundle is a single zip; nothing leaves your machine and the MCP server still runs locally over stdio.
3. Connect and build
Connect to C:\Projects\Sales.Report
Create a page called "Overview" with 4 KPI cards and a bar chart by country4. Open in Power BI Desktop
Open the .pbip file — or if already open, press Ctrl+Shift+F5 to refresh.
Headless / eval mode
For automated/eval use you can auto-bind a report at startup with the PBIR_REPORT_PATH env var instead of calling pbir_set_report:
PBIR_REPORT_PATH=evals/fixtures/sample.Report node dist/index.jsIf the path is invalid the server logs to stderr and continues running unbound (use pbir_set_report to recover). The CLI arg form (node dist/index.js <path>) still works and wins when both are set.
Smart Tool Loading
By default all 56 tools load at startup — this is the most compatible configuration, and what you want for Claude Desktop and most other MCP clients whose tool catalog is a snapshot taken at session start.
For token-sensitive setups (e.g. Claude Code with large prompt budgets on dev machines), you can opt into the minimal mode — only 12 core tools load at startup, and the LLM activates more on-demand via pbir_load_tools:
"env": { "MCP_TOOLS": "minimal" }graph TD
subgraph DEFAULT["11 Core Tools — always loaded in both modes"]
A1[pbir_set_report] --- A2[pbir_list_pages] --- A3[pbir_list_visuals] --- A4[pbir_create_page] --- A5[pbir_add_visual]
B1[pbir_get_visual] --- B2[pbir_format_visual] --- B3[pbir_update_visual_bindings] --- B4[pbir_set_report_theme] --- B5[pbir_bulk_bind]
C1[pbir_model_usage]
end
LT[pbir_load_tools -- always available]
subgraph ONDEMAND["43 On-Demand Tools"]
C1[pbir_delete_page] --- C2[pbir_rename_page] --- C3[pbir_duplicate_page] --- C4[pbir_move_visual] --- C5[pbir_delete_visual]
D1[pbir_set_datapoint_colors] --- D2[pbir_set_conditional_format] --- D3[pbir_add_page_filter] --- D4[pbir_set_visual_sort] --- D5[guide]
E1[pbir_list_bookmarks] --- E2[pbir_set_page_background] --- E3[...]
end
DEFAULT --> LT --> ONDEMAND
style DEFAULT fill:#1a7f37,color:#fff
style ONDEMAND fill:#333,color:#ccc
style LT fill:#0078D4,color:#fffMode | Tools at Startup | Token Overhead | Use Case |
| 56 + | ~16,500 tokens | Claude Desktop, most clients, first-time users |
| 12 + | ~3,400 tokens | Claude Code / clients that refresh the tool list mid-session |
| 56 + | ~16,500 tokens | Same as default; kept for backward-compat |
Default is "load everything" because Claude Desktop snapshots the MCP tool catalog at session start and never refreshes it — tools activated mid-session via
pbir_load_toolswould otherwise be invisible to the model. Clients that honourtools/list_changednotifications (Claude Code, Cowork) can opt intoMCP_TOOLS=minimalto claw back ~13k tokens.
Tool Reference
Default Tools
Tool | Description |
| Connect to a |
| List all pages (id, name, visual count) |
| List visuals on a page (id, type, position, title) |
| Create a new page |
| Add one or many visuals with bindings, formatting, colors |
| Inspect a visual's config and bindings |
| Format axes, legend, labels, borders, background |
| Replace data bindings on a visual |
| Apply a custom JSON theme to the whole report |
| Rebind multiple visuals in one call |
| Cross-reference semantic model with report — three-tier classification (direct/indirect/unused), DAX lineage, UDF functions, conditional formatting detection |
| List and activate on-demand tools |
Why pbir_model_usage is a default tool — the deletion fail-safe
pbir_model_usage ships in the default set (not on-demand) because it is the safety layer for AI-driven cleanup of the semantic model. When a user asks Claude to "remove unused measures" or "clean up dead columns", the model would otherwise guess based on measure names and delete things blindly — and break visuals that depend on indirect references.
With pbir_model_usage always available, the LLM can call it first and see the full dependency picture before touching anything:
Scenario | Without | With |
User: "delete all unused measures" | LLM guesses by name, deletes | LLM sees |
User: | LLM greps the visual JSON, misses conditional formatting bindings | LLM sees it bound to |
User: "which UDF functions can I drop?" | LLM has no lineage info | LLM sees reference counts per function and flags zero-reference functions |
The MCP tool gives Claude that understanding before it mutates anything — what prevents "oops" deletes. The tool returns a slim JSON response (~7K tokens) by default so it's cheap to call before every destructive operation.
On-Demand Tools (43)
Tool | Description |
| Show connected report path |
| Reopen report in PBI Desktop |
| Read report-level settings |
| Merge new report settings |
| All pages + visuals in one call |
| Delete a page and its visuals |
| Rename a page |
| Clone a page with all visuals |
| Set page order |
| Set default page on open |
| Change page dimensions |
| Show/hide from navigation |
| Auto-arrange visuals in a grid |
| Show/hide and expand/collapse the filter pane |
| Set page canvas background color and/or wallpaper |
| Set cross-filter/highlight interaction between visuals |
| Add, list, or remove report-level DAX measures |
Tool | Description |
| Remove a visual |
| Clone a visual |
| Reposition and resize |
| Swap type, keep bindings |
| List all visual types and buckets |
Tool | Description |
| Set title text, font, alignment |
| Per-series or per-category colors |
| Rules-based or gradient formatting |
| Set or change sort order (column/measure, ascending/descending) |
| Apply a preset theme to a page |
| Scan visuals for formatting overrides conflicting with theme |
Tool | Description |
| Get current theme JSON |
| Revert to default theme |
| List stored theme files |
| Compare proposed vs current theme |
Tool | Description |
| List page or visual filters |
| Add categorical, TopN, relative date, or advanced filter |
| Remove a filter by name |
| Remove all filters |
Tool | Description |
| Delete multiple visuals |
| Format multiple visuals |
Tool | Description |
| List all bookmarks in the report |
| Create a new bookmark |
| Delete a bookmark |
| Rename a bookmark |
Tool | Description |
| Domain knowledge for PBI development — topics: |
The pbir_guide tool provides focused, actionable knowledge to help AI agents make better decisions. Instead of loading large skill files into every session, agents call pbir_guide("topic") on demand. The SVG visuals topic includes 4 DAX templates, binding rules, and workflow steps.
Batch Mode — Build Pages Fast
Create an entire page in a single pbir_add_visual call:
{
"pageId": "abc123",
"visuals": [
{
"visualType": "shape", "shapeType": "rectangle",
"x": 0, "y": 0, "width": 1280, "height": 50,
"fillColor": "#1F3864", "textContent": "Sales Dashboard",
"textColor": "#FFFFFF", "textBold": true, "textSize": 20
},
{
"visualType": "card",
"x": 10, "y": 60, "width": 300, "height": 100,
"title": "Revenue",
"bindings": [
{ "bucket": "Fields", "fields": [{ "field": "Sales[Revenue]", "type": "measure" }] }
]
},
{
"visualType": "clusteredBarChart",
"x": 10, "y": 170, "width": 620, "height": 260,
"title": "Revenue by Country",
"bindings": [
{ "bucket": "Category", "fields": [{ "field": "Store[Country]", "type": "column" }] },
{ "bucket": "Y", "fields": [{ "field": "Sales[Revenue]", "type": "measure" }] }
],
"dataColors": [{ "color": "#0078D4" }]
}
]
}One call creates the banner, KPI card, and chart — with data bindings, titles, and colors.
Supported Visual Types
Full reference: docs/visual-types.md
Naming Gotchas
barChart = Stacked bar (NOT clustered)
columnChart = Stacked column (NOT clustered)
clusteredBarChart = Clustered bar ✓
clusteredColumnChart = Clustered column ✓
stackedBarChart = DOES NOT EXIST ✗ (use barChart)
scatterChart = Uses "Details" bucket, NOT "Category"
Combo charts = Use "ColumnY" + "LineY", NOT "Y" + "Y2"Quick Reference
Category | Types |
Bar/Column |
|
Line/Area |
|
Combo |
|
Pie/Donut |
|
Tables |
|
Cards |
|
Slicers |
|
Maps |
|
Scatter |
|
Other |
|
Decorative |
|
Formatting
pbir_format_visual(target="auto") → auto-routes to container or visual (default)
pbir_format_visual(target="container") → title, background, border, padding, shadow
pbir_format_visual(target="visual") → axes, legend, labels, line styles, data pointsCategory | Properties |
|
|
|
|
|
|
|
|
|
|
|
|
Category | Properties | Applies To |
|
| Bar, column, line, combo |
|
| Bar, column, line, combo |
|
| Charts with Series |
|
| Most charts |
|
| Line, area, combo |
|
| Most charts |
Hex colors starting with
#are automatically wrapped in PBIR format.
Themes & Conditional Formatting
Report-Level Theme
{
"name": "Corporate Brand",
"dataColors": ["#0078D4", "#00BCF2", "#00B294", "#FF8C00", "#E81123"],
"background": "#FFFFFF",
"foreground": "#1F3864",
"tableAccent": "#0078D4"
}Gradient Conditional Format
{
"formatType": "gradient",
"entity": "Sales", "property2": "Revenue", "isMeasure": true,
"minColor": "#FF6B6B", "midColor": "#FFD93D", "maxColor": "#6BCB77"
}Page Themes (presets)
dark · light · corporate · blue-purple
Filters
// Categorical — include specific values
{ "filterType": "categorical", "entity": "Store", "property": "Region", "values": ["East", "West"] }
// TopN — top 10 products (visual-level only)
{ "filterType": "topN", "entity": "Product", "property": "Name", "n": 10,
"topNDirection": "Top", "orderByEntity": "Sales", "orderByProperty": "Revenue",
"orderByIsMeasure": true, "visualId": "xyz" }
// Relative date — last 12 months
{ "filterType": "relativeDate", "entity": "Date", "property": "Date",
"period": "months", "count": 12, "dateDirection": "last" }Architecture
powerbi-report-mcp/
├── src/
│ ├── index.ts # Server entry, smart tool loading, safe() wrapper
│ ├── pbir.ts # PbirProject — PBIR file I/O abstraction
│ ├── context.ts # ServerContext interface
│ ├── model-usage.ts # Model usage analysis — three-tier classification, UDF parsing, conditional formatting
│ ├── tools/
│ │ ├── report.ts # Page & report management (20 tools)
│ │ ├── visuals.ts # Visual CRUD (8 tools)
│ │ ├── format.ts # Formatting, sort & colors (6 tools)
│ │ ├── bindings.ts # Data binding (1 tool)
│ │ ├── themes.ts # Report themes (6 tools)
│ │ ├── filters.ts # Page/visual filters (4 tools)
│ │ ├── bulk.ts # Bulk operations (3 tools)
│ │ ├── bookmarks.ts # Bookmark CRUD (4 tools)
│ │ └── guide.ts # Knowledge layer (1 tool, 2 topics)
│ └── helpers/
│ ├── createVisual.ts # Visual creation engine
│ ├── formatting.ts # PBIR formatting builder
│ └── defaults.ts # Theme presets
├── .usage/ # Generated usage dashboards (gitignored)
├── dist/ # Compiled JS (committed for no-build deploy)
├── pbi report/ # Sample report (financials model)
├── docs/ # Guides and references
└── skills/ # LLM skill documentsFull details: ARCHITECTURE.md
Data Flow
sequenceDiagram
actor User
participant AI as AI Assistant
participant Model as powerbi-modeling-mcp
participant Report as powerbi-report-mcp
participant PBI as Power BI Desktop
User->>AI: "Create a sales dashboard with KPIs and a chart by country"
AI->>Model: What measures are on the Sales table?
Model-->>AI: Net Revenue, Net Profit, Margin %, Orders, Units Sold
AI->>Report: pbir_create_page("Sales Dashboard")
Report-->>AI: pageId: abc123
AI->>Report: pbir_add_visual(batch: 6 cards + 2 charts + table)
Report-->>AI: 9 visuals created
AI->>Report: pbir_set_report_theme({ dataColors: [...] })
Report-->>AI: theme applied
AI-->>User: Done! Open .pbip in Power BI Desktop
User->>PBI: Ctrl+Shift+F5PBIR Folder Structure
MyProject.Report/
definition/
report.json # Report settings, theme config
pages/
pages.json # Page order and active page
{pageId}/
page.json # Page name, size, visibility
visuals/
{visualId}/
visual.json # Type, position, bindings, formatting
StaticResources/
RegisteredResources/ # Custom theme JSON files
definition.pbir # Semantic model referenceToken Efficiency
Mode | Tools Loaded | Tokens/Turn | Cost per 10-Page Report |
Default | 11 | ~3,100 | $0.01 – $0.45 |
All | 48 | ~14,500 | $0.02 – $2.50 |
Model | Input $/1M | Output $/1M | Base Report | Fully Styled |
GPT-4o-mini | $0.15 | $0.60 | $0.01 | $0.02 |
GPT-4.1-mini | $0.40 | $1.60 | $0.02 | $0.05 |
GPT-4.1 | $2.00 | $8.00 | $0.11 | $0.25 |
GPT-4o | $2.50 | $10.00 | $0.14 | $0.32 |
Claude Haiku 3.5 | $0.80 | $4.00 | $0.05 | $0.12 |
Claude Sonnet 4 | $3.00 | $15.00 | $0.19 | $0.45 |
Claude Opus 4 | $15.00 | $75.00 | $0.96 | $2.25 |
Approach | Calls | Tokens |
Batch + bulk (recommended) | 22–32 | ~28–32K |
Per-visual calls (naive) | 300+ | ~120K |
Use pbir_add_visual batch mode + inline title, dataColors, containerFormat to build fully styled pages in minimal calls.
Tested clients
The MCP is built on the standard MCP protocol. Currently verified against:
Client | Status | Config |
Claude Code | ✅ Tested |
|
Claude Desktop | ✅ Tested |
|
Claude Cowork | ✅ Tested | Drag the |
Other MCP-compatible clients (Cursor, Continue.dev, Cline, GitHub Copilot agent mode, OpenAI via mcp-proxy, custom @modelcontextprotocol/sdk agents) should work since this is a standard MCP server — but they haven't been verified against this codebase yet. If you try one and it works (or doesn't), please open an issue so we can update this table.
Documentation
Doc | Description |
5-minute setup guide | |
15 example prompts | |
Visual type reference + formatting containers per type | |
Layout guide — zones, spacing, 3 sample layouts with exact positions | |
PBIR schema discoveries | |
Codebase architecture | |
How to contribute | |
Version history |
Known Issues
Feature | Status | Notes |
Visual calculations | Disabled | Correct PBIR format identified but not rendering programmatically |
Tips
Pair with powerbi-modeling-mcp to query the semantic model for exact table/column names before binding
Use
Table[Column]shorthand in bindings:"field": "Sales[Revenue]"barChart= stacked bar,clusteredBarChart= clustered — there is nostackedBarChartAdd shapes before data visuals for correct z-order layering
pbir_format_visualmerges with existing formatting — safe to call incrementallyTopN filters are visual-level only — pass
visualIdtopbir_add_page_filterAll tools return
{ success: false, error: "..." }on failure — the server never crashesUse
pbir_model_usageto see which measures/columns are used in visuals — it classifies fields as direct (on a visual), indirect (referenced by direct measures/relationships), or unused (safe to remove). It detects conditional formatting bindings (images, reference labels, colors) that other tools missAlways call
pbir_model_usagebefore any delete / cleanup request — it's the fail-safe that stops the LLM from removing indirectly-referenced measures. See Whypbir_model_usageis a default tool for the full rationalepbir_model_usagealso parses UDF functions and calculation groups from TMDL/BIM, counts measure references per function, and surfaces DAX lineage
License
MIT — use it however you want.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jonathan-pap/powerbi-report-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server