Skip to main content

Horizun PBI MCP

MCP (Model Context Protocol) server for working with local Power BI Desktop and .pbip projects from Claude Code.

v1.5.4 — 134 tools. Two complementary Power BI layers, plus verified document exports, report content export and read-only SharePoint ingestion.


Install: one command, any Windows PC

Open PowerShell — a normal window, not "as administrator" — and paste this. It works whether the machine is fully set up or completely empty:

irm https://raw.githubusercontent.com/HorizunGroup/horizun-pbi-mcp/main/scripts/instalar.ps1 | iex

Then restart Claude once, and the 134 pbi_* tools are there. That's the whole install: nothing to download by hand, no .exe to trust, no config file to edit.

It installs only what is missing — Python, Git, Claude Code itself — for your user account, and it tells you what it did at every step. It is idempotent: if something is left pending (say your IT department blocks an install), fix it and paste the same line again; nothing is repeated or broken.

Starting point How long
Python and Claude already installed ~1 min, plus ~70 s while the runtime prepares itself
Completely empty PC 10–20 min, nearly all of it downloads

Already inside Claude Code? You can just ask instead of opening a terminal:

Install the Horizun Power BI MCP (HorizunGroup/horizun-pbi-mcp): add its marketplace, install the plugin, run its one-paste installer if any prerequisite is missing, and don't stop until pbi_install_status says ready. Tell me what you're doing at each step and how long is left.

Any language works — an LLM is reading that, not a parser. English is simply the version kept up to date. If you want the agent to narrate the whole thing with a plan and ETAs, use the guided install prompt.


Why this is safe to run on a work machine

Ease of install is worthless if the thing you installed is a liability. This is what the server does and does not do — each point is checkable in this repository, not a promise:

  • No administrator rights, ever. Everything installs at user scope. The installer contains no elevation path at all, and a test enforces that.
  • Nothing you do leaves your machine. There is no telemetry, no account, no sign-up and no phone-home. The telemetry module is local structured logging to stderr, and it redacts by design: DAX queries, result rows, measure expressions and anything secret-shaped are recorded by shape (length, row count) and never by content.
  • It only talks to your local Power BI. The live layer connects to the engine Power BI Desktop already runs on localhost. It cannot publish or refresh anything in the Power BI Service — that isn't a policy, it simply isn't implemented.
  • The only network access is the install itself, and every download is pinned to a version and verified by SHA-256 before use — no latest, no npx, fail-closed. (The one exception is SharePoint ingestion, which does nothing until you provide credentials, reads only, and takes secrets from the environment — never as a tool argument.)
  • Your files are backed up before they are touched. Every .pbip write makes an automatic backup first, JSON is written atomically so a crash can't leave a corrupt file, destructive operations refuse to run without confirm=true, and everything is appended to a change_log.md.
  • It refuses to guess. If it can't verify that Power BI Desktop has your project closed, it blocks the write instead of risking a silent overwrite — even when merely uncertain.
  • Apache-2.0, and the awkward parts are written down. See docs/SECURITY.md for the threat model and what it explicitly does not promise, and docs/BACKLOG.md for what is still open.

Layer For what How
Live (Power BI Desktop open on localhost:<port>) Query data (DAX), document the model, create/edit measures, refresh ADOMD.NET + TOM via pythonnet
On disk (.pbip project) Generate/arrange visuals, edit the model durably TMDL (model) + PBIR (report), editing files

Key rule: the local endpoint only exposes the DATA layer (semantic model). Visuals/pages/layout are NOT in that endpoint or in any live API — they're edited via PBIR files. This MCP respects that separation: it doesn't try to move visuals "live".


Documentation

Document For what
docs/INSTALL.md Install and register the server in Claude Code, Claude Desktop, Codex or a stdio client
docs/TOOL_INVENTORY.md The 34 baseline tools: domain, risk class, preconditions
docs/ARCHITECTURE.md Current architecture, structural debt and invariants
docs/CAPABILITY_MATRIX.md Coexistence with other Power BI MCPs, with verification levels
AGENTS.md Rules for modifying this repository without breaking the contract
docs/TOOL_CATALOG.md The 134 tools by block, with their risk class
docs/DUAL_MODE.md Why mode="both" is blocked (R15)
docs/VALIDATION.md The two PBIR validation layers and their limits
docs/RELEASE_CHECKLIST.md What is checked before publishing
docs/BACKLOG.md What remains open, with evidence and how to check it
docs/TUTORIAL.md From installation to a dashboard, step by step
docs/SECURITY.md Threat model, guarantees and what it does not promise
docs/RECOVERY.md What to do when something is left half-done
docs/PHASE_1A_DESIGN.md Design of the security layer
CHANGELOG.md Version history
tests/fixtures/README.md Fixture strategy: versioned synthetic + ignored local copy

What it does

  • Live DAX: runs queries against the open model and returns columns/rows with timings.
  • Documentation: tables, columns, measures, relationships, hierarchies, roles (RLS) and quality analysis → Markdown.
  • Measures: create/edit/delete DAX measures in the open model (live), in the TMDL file (pbip) or in both (both).
  • Local refresh: refreshes the open model in Desktop (not the Service).
  • PBIP: open/validate projects, automatic backups.
  • .pbix.pbip conversion: report to PBIR (copied if the .pbix already carries it, translated if it keeps the legacy format) and model to TMDL, single file or batch folder.
  • PBIR visuals: list/document visuals, create visuals (cloning real templates from the report), move/resize and arrange by layouts.

What it does NOT do

  • It doesn't move or create visuals "live" on the open canvas (Power BI Desktop doesn't expose an API for that). Visuals are edited via PBIR files with the .pbip project.
  • It doesn't refresh or publish to the Power BI Service (local only).
  • It doesn't extract the model from a .pbix without Power BI Desktop: the DataModel stream is a backup compressed with XPress9 that only the Analysis Services engine knows how to read. When converting, the .pbix is opened in Desktop to serialize the model.
  • It doesn't translate legacy format bookmarks to PBIR: their state model is different and the conversion reports them as pending (dropped) instead of losing them silently. Creating new bookmarks is possible (pbi_create_bookmark).
  • It doesn't invent fields or nonexistent measures when generating pages.

Requirements

  • Windows (Power BI Desktop is Windows-only) with Power BI Desktop installed.
  • Python 3.10+ (tested on 3.14).
  • .NET Framework 4.x (comes with Windows) — used by pythonnet.
  • Python dependencies: mcp (includes FastMCP), pythonnet, psutil, python-dotenv, openpyxl, reportlab, pypdf and msal.
  • ADOMD.NET + TOM DLLs (Analysis Services). Downloaded without admin rights via scripts/fetch_libs.py (no need to install in the GAC).
  • To edit/create visuals: the report saved as .pbip with PBIR enabled.
  • (Optional) Tabular Editor is not required — see Technical decisions.

Installation

The guided prompt — watch it install itself

Use this instead of the short prompt when you want the agent to narrate: a plan before it touches anything, an ETA before every step, and evidence after each one. Any Claude that can run commands will do (Claude Code, or the desktop app with terminal access). If you have none, install the CLI first with irm https://claude.ai/install.ps1 | iex and then paste this:

Install the Horizun PBI MCP (HorizunGroup/horizun-pbi-mcp) on this machine, end to end, under these rules:
1. PLAN FIRST, ACT SECOND. In a SINGLE pass, check what is already here: real Python >=3.10 (careful: the
   Microsoft Store alias does NOT count), the claude CLI, winget, and Power BI Desktop. Tell me the list of
   what's missing with a TOTAL time estimate before installing anything.
2. NEVER WORK SILENTLY. Before each step announce "Step N of M - what I'm about to do - how long (~X min)".
   If a command will take more than a minute, say so BEFORE running it. After each step show the evidence
   (version installed, path). If something takes longer than estimated, report it instead of leaving me waiting.
3. Install ONLY what is missing, at user scope, without asking for administrator:
   - Python: winget install -e --id Python.Python.3.12 --accept-source-agreements --accept-package-agreements
   - Claude Code CLI (if absent): irm https://claude.ai/install.ps1 | iex
   Remember the terminal you installed from does NOT see the new PATH: use absolute paths or refresh this
   process's PATH yourself; do not ask me to close and reopen windows.
4. If signing in to Claude is needed, that is my ONLY step: tell me exactly what to do and wait for me.
5. Register the plugin:
   claude plugin marketplace add HorizunGroup/horizun-pbi-mcp
   claude plugin install horizun-pbi-mcp@horizun
6. Start the runtime setup and monitor pbi_install_status, telling me every state change (DLL downloads,
   environment creation, schemas). Do not stop until it says ready.
7. Finish with the full verification: python --version, claude --version, claude plugin list, and remind me
   to restart the Claude session so the pbi_* tools load.
8. If anything fails: tell me WHAT failed, WHY, and the exact command to fix it. Never leave me in a
   half-finished state without describing it.
Real reference timings for your estimates: Python 2-4 min, Claude CLI 2-3 min, marketplace ~1 min,
plugin runtime 3-6 min. Do not promise less than that.
Same prompt in Spanish
Instala el Horizun PBI MCP (HorizunGroup/horizun-pbi-mcp) en este equipo, de punta a punta, bajo estas reglas:
1. PRIMERO EL PLAN, DESPUÉS LA ACCIÓN. En una sola pasada revisa qué existe ya: Python real >=3.10
   (cuidado: el alias de la Microsoft Store NO cuenta), el CLI de claude, winget y Power BI Desktop.
   Dime la lista de lo que falta con el tiempo estimado TOTAL antes de instalar nada.
2. NUNCA TRABAJES EN SILENCIO. Antes de cada paso anuncia "Paso N de M — qué voy a hacer — cuánto tarda (~X min)".
   Si un comando va a demorar más de un minuto, dilo ANTES de correrlo. Al terminar cada paso muestra la
   evidencia (versión instalada, ruta). Si algo lleva más de lo estimado, repórtalo en vez de dejarme esperando.
3. Instala SOLO lo que falte, en ámbito de usuario, sin pedir administrador:
   - Python: winget install -e --id Python.Python.3.12 --accept-source-agreements --accept-package-agreements
   - Claude Code CLI (si no existe): irm https://claude.ai/install.ps1 | iex
   Recuerda que la terminal donde instalaste NO ve el PATH nuevo: usa rutas absolutas o refresca el PATH del
   proceso tú mismo; no me pidas cerrar y abrir ventanas a mí.
4. Si hace falta iniciar sesión en Claude, ese es el ÚNICO paso mío: dime exactamente qué hacer y espérame.
5. Registra el plugin:
   claude plugin marketplace add HorizunGroup/horizun-pbi-mcp
   claude plugin install horizun-pbi-mcp@horizun
6. Arranca el setup del runtime y monitorea pbi_install_status, contándome cada cambio de estado
   (descarga de DLLs, creación del entorno, esquemas). No pares hasta que diga ready.
7. Cierra con la verificación completa: python --version, claude --version, claude plugin list, y
   recuérdame reiniciar la sesión de Claude para que aparezcan las herramientas pbi_*.
8. Si algo falla: dime QUÉ falló, POR QUÉ, y el comando exacto para arreglarlo. Nunca me dejes en un
   estado a medias sin describirlo.
Referencia de tiempos reales para tus estimaciones: Python 2-4 min, CLI de Claude 2-3 min,
marketplace ~1 min, runtime del plugin 3-6 min. No prometas menos de eso.
Por qué el prompt tiene estas reglas (para mantenedores)

Prueba de campo (2026-08-12, PC virgen): una instalación agentic SIN estas reglas gastó 15+ minutos percibidos como cuelgue, y el usuario abandonó. Las causas, y la regla que las mata:

Falla observada Regla que la corrige
Pasos largos sin ninguna señal → se siente colgado Regla 2: anunciar duración ANTES y reportar si se excede
El agente auditó/verificó en 8+ llamadas secuenciales antes de empezar Regla 1: UNA pasada de precheck y el plan completo
"claude no se reconoce" tras instalar (PATH de la terminal vieja) Regla 3: el agente refresca el PATH él mismo
El usuario no sabía cuánto faltaba ni si valía la pena esperar Plan con estimación total + tiempos de referencia al final
Fallo a mitad de camino = sistema en estado desconocido Regla 8: todo fallo termina en diagnóstico + comando de arreglo

No Claude at all? One-paste PowerShell installer

No Claude Code on the machine yet? One paste in a normal PowerShell window (no admin; it can install Claude Code too, and when IT blocks installs its output is the exact user-scope ticket to hand over):

irm https://raw.githubusercontent.com/HorizunGroup/horizun-pbi-mcp/main/scripts/instalar.ps1 | iex

What the agent runs underneath

You don't need to download or register a .exe, create .mcp.json or manually locate this repository. The plugin sets up an isolated Python environment in the client's data folder and verifies every download.

Codex:

codex plugin marketplace add HorizunGroup/horizun-pbi-mcp
codex plugin add horizun-pbi-mcp@horizun

Claude Code:

claude plugin marketplace add HorizunGroup/horizun-pbi-mcp
claude plugin install horizun-pbi-mcp@horizun

When the first session opens, the plugin runs the full setup automatically in the background. Check pbi_install_status; once it finishes, restart the client and the 134 pbi_* tools will be available. There are no downloads or additional scripts the user needs to run manually.

Honest technical limit: there's no dedicated executable, but you do need Windows, Power BI Desktop and Python 3.10+. The server must run locally: a remote MCP cannot access Desktop's local engine or your .pbip files.

Manual installation for development

cd horizun-pbi-mcp

# 1) Python dependencies
python -m pip install -r requirements.txt
#   or:  python -m pip install -e .

# 2) Analysis Services DLLs (ADOMD.NET + TOM) -> libs/ folder
#    Pinned version (19.84.1) and SHA-256 verified before installing.
python scripts/fetch_libs.py

# 3) Official PBIR schemas (needed to WRITE)
#    Without them, every PBIR write fails with schema_unavailable.
python scripts/fetch_pbir_schemas.py

# 4) (optional, recommended) Microsoft's official PBIR validator
#    Requires Node >= 20. Adds semantic validation of the full report.
python scripts/fetch_report_validator.py

# 5) (optional) configuration
copy .env.example .env    # and edit it

Check the result at any time:

python scripts/doctor.py

Verify

With Power BI Desktop open on a report:

python -m horizun_pbi_mcp.server   # starts the MCP server (stdio); Ctrl+C to exit

For a quick test without MCP, in Python:

import sys; sys.path.insert(0, "src")
from horizun_pbi_mcp.config import get_session
from horizun_pbi_mcp.powerbi import desktop_discovery, dax_runner
s = get_session()
print(desktop_discovery.discover_instances())
desktop_discovery.select_model(s)
print(dax_runner.run_dax(s, 'EVALUATE ROW("ok", 1)'))

Registering with an MCP client

Full guide for Claude Code, Claude Desktop, Codex and generic stdio clients: docs/INSTALL.md.

Each client resolves environment variables, the working directory and the Python interpreter differently, so instead of a ${VAR} template that fails on half of them, there's a generator that resolves the absolute paths on your machine:

python scripts/make_mcp_config.py --client all

It only prints. To create this repository's local .mcp.json (which is in .gitignore):

python scripts/make_mcp_config.py --client claude-code --write

Before registering anything, check the installation:

python scripts/doctor.py

Exits with code 0 if everything mandatory is fine. It distinguishes missing dependency, missing DLL, server that won't start, unexpected MCP contract, Desktop closed, stale session and multiple instances. Power BI Desktop being closed does not fail the base diagnostic (use --require-desktop if you want to require it).

Environment variables (all optional)

Variable Default Description
HORIZUN_PBI_MCP_LIBS_DIR ./libs Folder with the ADOMD.NET/TOM DLLs
HORIZUN_PBI_MCP_DOTNET_RUNTIME netfx pythonnet runtime (netfx or coreclr)
HORIZUN_PBI_MCP_MAX_ROWS 1000 Default row limit in DAX
HORIZUN_PBI_MCP_OUTPUTS_DIR ./outputs Documentation and change_log.md
HORIZUN_PBI_MCP_BACKUPS_DIR ./backups .pbip backups
HORIZUN_PBI_MCP_LOG_LEVEL INFO DEBUG/INFO/WARNING/ERROR
HORIZUN_PBI_MCP_DEFAULT_PBIP .pbip to open on startup
HORIZUN_PBI_MCP_SHAREPOINT_TENANT_ID Microsoft Entra tenant for SharePoint app-only access
HORIZUN_PBI_MCP_SHAREPOINT_CLIENT_ID Application/client ID registered in Entra
HORIZUN_PBI_MCP_SHAREPOINT_CLIENT_SECRET Client secret; environment only, never a tool argument
HORIZUN_PBI_MCP_PDFTOPPM auto-detected Optional exact path to Poppler pdftoppm for PDF render verification

Available tools (134)

Full catalog by block: docs/TOOL_CATALOG.md. Baseline inventory with risk class and preconditions: docs/TOOL_INVENTORY.md. Names and signatures are frozen in tests/golden/tools_v1.json and verified by tests/test_tool_contract.py.

Connection / DAX

  • pbi_list_desktop_models — lists open models (port, connection string, catalog, number of tables).
  • pbi_select_model — sets the active model (by port if there are several).
  • pbi_run_dax — runs DAX (query, max_rows).
  • pbi_test_connection — validates the active connection.
  • pbi_validate_measures — validates measure DAX WITHOUT modifying the model (dry-run with DEFINE MEASURE); useful before creating them.
  • pbi_validate_desktop_render — opens a .pbix/.pbip, captures the exact window by PID without depending on focus and only closes Desktop if the tool itself opened it.

Documentation (Phase 3)

  • pbi_list_tables, pbi_list_measures, pbi_list_relationships — with source: live|pbip.
  • pbi_analyze_model_quality — typical model issues.
  • pbi_document_model — complete documentation in Markdown to outputs/.

Excel, PDF and SharePoint

  • pbi_export_excel — verified workbook with model, report, audit and optional read-only DAX rows.
  • pbi_generate_pdf_report — executive/technical/audit PDF with optional dashboard PNG/JPEG captures.
  • pbi_sharepoint_list_folder — lists SharePoint Online folders through Microsoft Graph with pagination and limits.
  • pbi_sharepoint_download_folder — staged all-or-nothing download to outputs/sharepoint/, verified by size and SHA-256.
  • pbi_export_report_content — exports the report content: the data behind each visual, or a query the client declares. Needs the live model; refuses to export an unprocessed one instead of writing a blank file.

Measures (Phase 4)mode: live|pbip|both, overwrite

  • pbi_create_measure, pbi_update_measure, pbi_delete_measure (destructive: confirm=true).

Refresh (Phase 5)

  • pbi_refresh_modeltype: full|calculate|clear_values, tables optional (local).

PBIP project (Phase 6)

  • pbi_open_pbip_project (path), pbi_validate_pbip_project, pbi_backup_pbip_project (mode: folder|zip, scope: report|model|both).

.pbix.pbip conversion

  • pbi_inspect_pbix — X-ray of the file without converting it or opening Desktop: report format, whether it carries its own model, pages and resources.
  • pbi_list_convertible_pbix — preview of a folder: what would be copied, what would need translating and which ones need Desktop.
  • pbi_convert_pbix_to_pbip — generates the project. Accepts a .pbix or a folder (recursive), and returns per file what was written, the warnings and what was left out (dropped).

The report is translated without Desktop, but the model requires opening each .pbix in Power BI Desktop (the session is reused if it's already open, and closed if the tool opened it). With include_model=false only the report half is generated, instantly. The original .pbix is never modified.

Power BI Desktop does not open a .pbip with paths of 260 characters or more: pick a short out_dir (C:\pbip). The tool checks this before writing and aborts with the detail instead of leaving a project that won't open.

Model editing

  • pbi_set_column_visibility / pbi_hide_columns — hide/show columns (e.g. IDs). mode: live|pbip|both.
  • pbi_set_relationship_direction — cross filter single|both of a relationship. mode: live|pbip|both.
  • pbi_disable_auto_date_time — enables/disables "Auto date/time" (pbip only).

PBIR Report (Phases 7–10)

  • pbi_list_report_pages, pbi_list_visuals (page), pbi_document_report_layout.
  • pbi_create_visualpage, visual_type, fields, position, title (clones an existing visual as a template).
  • pbi_update_visual_position, pbi_arrange_visuals (layout: grid|dashboard|executive_summary|custom).
  • pbi_generate_report_page — assisted page generation from the model.

HTML inside Power BI

  • pbi_add_custom_visual — registers an AppSource custom visual in the report (defaults to HTML Content, which renders HTML/SVG from a DAX measure).
  • pbi_create_html_visual — creates an HTML Content visual bound to a measure that returns HTML (html_measure).
  • pbi_create_measure with data_category: "ImageUrl" — measures that return an SVG data-URI and render as an image in native tables/matrices.

Natural-language sheet generation

  • pbi_page_building_blocks — content inventory (model + catalog of existing visuals + canvas) to design a sheet.
  • pbi_preview_spec_htmlHTML mockup of a proposed sheet (review before writing).
  • pbi_create_page_from_spec — materializes a full PBIR sheet from a spec (clones existing visuals by style).
  • pbi_export_page_html — exports an existing page to an HTML mockup.

Every tool returns {"ok": true/false, ...}; on error it includes error (code) and message (the engine's original message, never hidden).

Sheet generation flow: pbi_page_building_blocks → (Claude interprets your instruction and builds a spec) → pbi_preview_spec_html (you review the HTML) → pbi_create_page_from_spec (the PBIR gets written).


Usage examples (in natural language with Claude)

  • Run DAX: "List the open models, select the only one, and run EVALUATE TOPN(10, Sales)."
  • Document: "Document the active model and analyze its quality." → generates outputs/model_documentation_*.md.
  • Create measure: "Create the measure Margin % = DIVIDE([Profit],[Sales]) in the Sales table, format 0.0%, mode both."
  • List visuals: "Open the .pbip at C:/…/Report.pbip and list the visuals on the 'Summary' page."
  • Create visual: see examples/sample_visual_specs.json.
  • Arrange page: "Arrange the 'Summary' page with executive_summary layout."

More DAX in examples/sample_queries.md.

⚠️ PBIR editing and Desktop state: report edits (visuals/layout) are made to files; it's best to make them with Power BI Desktop closed and reopen it to see them (if Desktop is open and you save, it overwrites the changes on disk). Live model edits (live measures) require Desktop open and are persisted on save (Ctrl+S).


Troubleshooting

  • Doesn't detect the port / "No se detecto ningun modelo": open the report in Power BI Desktop; the port changes on every startup (the MCP discovers it on its own). If you use the Microsoft Store version, it's still detected by process.
  • adomd_not_installed / tom_not_installed: run python scripts/fetch_libs.py. Check that libs/Microsoft.AnalysisServices.AdomdClient.dll exists.
  • clr_not_available: .NET is missing; try PBI_MCP_DOTNET_RUNTIME=coreclr.
  • DAX error: the engine's message is returned as-is in message. Check the syntax (EVALUATE, quotes).
  • pbir_not_enabled: the report isn't in PBIR. Save as .pbip and enable Power BI Project (PBIR) format under Options → Preview Features (if applicable to your version) before saving.
  • Power BI doesn't reload visual changes: close it and reopen it; PBIR loads on open, not live.
  • Permissions/OneDrive: if the .pbip is in OneDrive, close Desktop before editing files and wait for OneDrive to finish syncing; backups are saved in backups/.

Technical decisions

  • TOM via pythonnet (not the Tabular Editor CLI). Evaluated: (1) Tabular Editor 2 CLI, (2) pythonnet loading TOM, (3) editing TMDL directly. Since pythonnet works on Python 3.14 and the ADOMD.NET/TOM DLLs can be vendored into libs/ without admin or GAC, loading them directly with pythonnet (runtime netfx) was chosen. It's more stable, has no external installation dependencies, and gives full control (create/edit measures and refresh, just like Tabular Editor). Durable editing is still available via TMDL in .pbip.
  • Visuals by cloning. pbi_create_visual clones an existing visual of the same type as a template (preserving the format/theme scaffolding) and only falls back to a minimal template if none exists, warning that it must be validated in Desktop.
  • Security (Phase 11): automatic backup before every .pbip write; atomic JSON (never leaves corrupted files); doesn't overwrite unreadable JSON; path validation; change_log.md in outputs/; destructive operations require confirm=true.

Limitations / open risks

None of these is a defect that can be fixed from here. They're documented because they affect what the server can promise.

Schemas Microsoft doesn't publish

Power BI Desktop writes visualContainer/2.10.0 and 2.11.0 in recent reports, and those URLs return 404 at the official source. The same happens with bookmarks/2.0.0. Microsoft's own official CLI can't validate them either: it emits PBIR_SCHEMA_UNREACHABLE and skips validation of those files.

For visualContainer, 2.10/2.11 are compared against 2.7 because that downgrade was measured against 275 real files and only differs in what a later version might add. bookmarks/2.0.0 is blocked with schema_unavailable because there's no earlier version of the same family to check it against.

Measured on a real 443-document report: 176 validate, 240 remain blocked for this reason.

G10 remains a documented release exception.

mode="both" blocked

live requires Power BI Desktop open; pbip requires it closed. There's no system state in which both destinations can be safely written in a single call. See docs/DUAL_MODE.md. R15 open.

filters and interactions in the page spec

They are rejected with unsupported_feature indicating the exact JSON path. They aren't silently dropped. Their serialization to PBIR is pending.

Others

  • PBIR must be enabled in the .pbip; pbi_validate_pbip_project checks this.
  • The friendly name of the open report isn't always readable from the engine (port + catalog are reported instead).
  • The on-disk TMDL parser is pragmatic (tables, columns, measures, relationships); for rich metadata, use the live path.
  • pbi_generate_report_page is a heuristic composition; it doesn't invent fields and warns about what it ignores.
  • The server starts without Node; what gets blocked are the writes that need the official validator.

Project structure

horizun-pbi-mcp/
├─ src/horizun_pbi_mcp/    # single installable package
│  ├─ server.py            # FastMCP + tool registration
│  ├─ config.py            # settings + session (active model/pbip)
│  ├─ logging_config.py
│  ├─ reporting.py         # Markdown documentation + quality
│  ├─ branding.py          # product identity and version
│  ├─ powerbi/             # live layer (ADOMD/TOM)
│  ├─ pbip/                # on-disk layer (TMDL/PBIR)
│  ├─ services/            # security, validation, audit, workflows
│  ├─ tools/               # MCP tools by area
│  └─ utils/               # JSON, files, validation, change_log
├─ scripts/fetch_libs.py   # downloads Analysis Services DLLs
├─ examples/  tests/  outputs/  libs/
├─ README.md  PLAN.md  pyproject.toml  requirements.txt  .env.example

Tests

python -m pytest -q

2039 tests, 3 skipped. The skips are environmental and say how to run them:

Skipped Condition
test_run_dax_live Requires a Power BI Desktop instance serving a model. python -m pytest -m live
test_no_llega_a_cero_por_acumular_infos Requires the synthetic model to trigger only informational rules

Available markers:

python -m pytest -m "not packaging"     # fast: skips wheel and sdist
python -m pytest -m live                # against an open Power BI Desktop
python -m pytest -m live_validator      # against Microsoft's official CLI

Verify the MCP contract (the 134 tools are frozen):

python -m tests.contract_utils

Returns 0 if there are no breaks, 1 if there are, with a report stating what changed and whether it breaks compatibility.

Installation diagnostics:

python scripts/doctor.py

License

Open source under the Apache License 2.0. Also see NOTICE for third-party attributions and trademarks.

Release files for horizun-pbi-mcp 1.5.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for horizun-pbi-mcp 1.5.4
File Size Uploaded
horizun_pbi_mcp-1.5.4.tar.gz 791.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for horizun-pbi-mcp 1.5.4
File Interpreter ABI Platform
horizun_pbi_mcp-1.5.4-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / horizun_pbi_mcp-1.5.4.tar.gz

Download URL horizun_pbi_mcp-1.5.4.tar.gz
Size 791.7 kB
Tags Source
SHA-256 checksum
How to use checksums
ef6d25c094aa670c29b5ab7e5239d7347c52f61e744b6e67cc0e6dc676aabbe0
BLAKE2b-256 checksum
How to use checksums
6e6e2b691b5c3066626c5fc73d55d9c6d89ccef830f0f8a18e50f6a0d04eed2f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.

Transparency log

Release files / horizun_pbi_mcp-1.5.4-py3-none-any.whl

Download URL horizun_pbi_mcp-1.5.4-py3-none-any.whl
Size 553.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8444a6209b8082e0e042277af55c4c507a05283e95b2acd40b5bf01f0ad7b6a0
BLAKE2b-256 checksum
How to use checksums
766496dfefe0f6c46de3d3532ee8124538b749557c7559e136201944ed960580
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.

Transparency log

Release history Release notifications | RSS feed

2.1.1

2 release files

2.1.0

2 release files

2.0.2

2 release files

2.0.1

2 release files

This release

1.5.4 This release

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page