Horizun PBI MCP
MCP server for interacting with local Power BI Desktop and .pbip projects, enabling DAX queries, model documentation, measure editing, and PBIR visual management via natural language.
README
Horizun PBI MCP
Servidor MCP (Model Context Protocol) para trabajar con Power BI Desktop local y con proyectos .pbip desde Claude Code.
v1.0.0-rc.3 — 90 tools, 859 pruebas (2 omitidas, ambas con su condición documentada). Cubre dos capas complementarias:
| Capa | Para qué | Cómo |
|---|---|---|
En vivo (Power BI Desktop abierto en localhost:<puerto>) |
Consultar datos (DAX), documentar el modelo, crear/editar medidas, refrescar | ADOMD.NET + TOM vía pythonnet |
En disco (proyecto .pbip) |
Generar/acomodar visuales, editar el modelo de forma durable | TMDL (modelo) + PBIR (informe), editando archivos |
Regla clave: el endpoint local solo expone la capa de DATOS (modelo semántico). Los visuales/páginas/layout NO están en ese endpoint ni en ninguna API en vivo — se editan por archivos PBIR. Este MCP respeta esa separación: no intenta mover visuales "en vivo".
Documentación
| Documento | Para qué |
|---|---|
docs/INSTALL.md |
Instalar y registrar el servidor en Claude Code, Claude Desktop, Codex o un cliente stdio |
docs/TOOL_INVENTORY.md |
Las 34 tools del baseline: dominio, clase de riesgo, precondiciones |
docs/ARCHITECTURE.md |
Arquitectura actual, deuda estructural e invariantes |
docs/CAPABILITY_MATRIX.md |
Convivencia con otros MCP de Power BI, con niveles de verificación |
AGENTS.md |
Reglas para modificar este repositorio sin romper el contrato |
docs/TOOL_CATALOG.md |
Las 90 tools por bloque, con su clase de riesgo |
docs/DUAL_MODE.md |
Por qué mode="both" está bloqueado (R15) |
docs/VALIDATION.md |
Las dos capas de validación PBIR y sus límites |
docs/RELEASE_CHECKLIST.md |
Qué se comprueba antes de publicar |
docs/TUTORIAL.md |
De la instalación a un dashboard, paso a paso |
docs/SECURITY.md |
Modelo de amenazas, garantías y lo que no promete |
docs/RECOVERY.md |
Qué hacer cuando algo queda a medias |
docs/PHASE_1A_DESIGN.md |
Diseño de la capa de seguridad |
CHANGELOG.md |
Historial de versiones |
tests/fixtures/README.md |
Estrategia de fixtures: sintéticos versionados + copia local ignorada |
Qué hace
- DAX en vivo: ejecuta consultas contra el modelo abierto y devuelve columnas/filas con tiempos.
- Documentación: tablas, columnas, medidas, relaciones, jerarquías, roles (RLS) y análisis de calidad → Markdown.
- Medidas: crear/editar/borrar medidas DAX en el modelo abierto (
live), en el archivo TMDL (pbip) o en ambos (both). - Refresh local: refresca el modelo abierto en Desktop (no el Service).
- PBIP: abrir/validar proyectos, backups automáticos.
- Visuales PBIR: listar/documentar visuales, crear visuales (clonando plantillas reales del informe), mover/redimensionar y acomodar por layouts.
Qué NO hace
- No mueve ni crea visuales "en vivo" en el lienzo abierto (Power BI Desktop no expone API para eso). Los visuales se editan por archivos PBIR con el proyecto
.pbip. - No refresca ni publica en el Power BI Service (solo local).
- No convierte un
.pbixa.pbippor ti: guarda el informe como Power BI Project (.pbip) con el formato de reporte mejorado (PBIR) activado. - No inventa campos ni medidas inexistentes al generar páginas.
Requisitos
- Windows (Power BI Desktop es Windows-only) con Power BI Desktop instalado.
- Python 3.10+ (probado en 3.14).
- .NET Framework 4.x (viene con Windows) — lo usa
pythonnet. - Dependencias Python:
mcp(incluye FastMCP),pythonnet,psutil,python-dotenv. - DLLs de ADOMD.NET + TOM (Analysis Services). Se descargan sin admin con
scripts/fetch_libs.py(no requieren instalarse en el GAC). - Para editar/crear visuales: el informe guardado como
.pbipcon PBIR activado. - (Opcional) Tabular Editor no es necesario — ver Decisiones técnicas.
Instalación
Directa desde Codex o Claude (recomendada)
No necesitas descargar ni registrar un .exe, crear .mcp.json ni localizar
manualmente este repositorio. El plugin prepara un entorno Python aislado en la
carpeta de datos del cliente y verifica todas las descargas.
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
Al abrir la primera sesión, el plugin ejecuta toda la preparación en segundo
plano automáticamente. Consulta pbi_install_status; cuando termine, reinicia
el cliente y quedarán disponibles las 90 tools pbi_*. No hay descargas ni
scripts adicionales que el usuario deba ejecutar manualmente.
Límite técnico honesto: no hay ejecutable propio, pero sí necesitas Windows, Power BI Desktop y Python 3.10+. El servidor debe correr localmente: un MCP remoto no puede acceder al motor local de Desktop ni a tus
.pbip.
Instalación manual para desarrollo
cd horizun-pbi-mcp
# 1) Dependencias Python
python -m pip install -r requirements.txt
# o: python -m pip install -e .
# 2) DLLs de Analysis Services (ADOMD.NET + TOM) -> carpeta libs/
# Versión fijada (19.84.1) y verificada por SHA-256 antes de instalar.
python scripts/fetch_libs.py
# 3) Esquemas oficiales del PBIR (necesarios para ESCRIBIR)
# Sin ellos, toda escritura PBIR falla con schema_unavailable.
python scripts/fetch_pbir_schemas.py
# 4) (opcional, recomendado) validador PBIR oficial de Microsoft
# Requiere Node >= 20. Añade validación semántica del informe completo.
python scripts/fetch_report_validator.py
# 5) (opcional) configuración
copy .env.example .env # y edítalo
Comprueba el resultado en cualquier momento:
python scripts/doctor.py
Verificar
Con Power BI Desktop abierto en un informe:
python src/server.py # arranca el servidor MCP (stdio); Ctrl+C para salir
Para una prueba rápida sin MCP, en Python:
import sys; sys.path.insert(0, "src")
from config import get_session
from 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)'))
Registro en un cliente MCP
Guía completa para Claude Code, Claude Desktop, Codex y clientes stdio genéricos: docs/INSTALL.md.
Cada cliente resuelve las variables de entorno, el directorio de trabajo y el intérprete de Python de forma distinta, así que en vez de una plantilla con ${VAR} que falla en la mitad de ellos, hay un generador que resuelve las rutas absolutas de tu máquina:
python scripts/make_mcp_config.py --client all
Sólo imprime. Para crear el .mcp.json local de este repositorio (que está en .gitignore):
python scripts/make_mcp_config.py --client claude-code --write
Antes de registrar nada, comprueba la instalación:
python scripts/doctor.py
Sale con código 0 si todo lo obligatorio está bien. Distingue dependencia faltante, DLL faltante, servidor que no arranca, contrato MCP inesperado, Desktop cerrado, sesión obsoleta y múltiples instancias. Que Power BI Desktop esté cerrado no hace fallar el diagnóstico base (usa --require-desktop si quieres exigirlo).
Variables de entorno (todas opcionales)
| Variable | Default | Descripción |
|---|---|---|
HORIZUN_PBI_MCP_LIBS_DIR |
./libs |
Carpeta con las DLLs de ADOMD.NET/TOM |
HORIZUN_PBI_MCP_DOTNET_RUNTIME |
netfx |
Runtime de pythonnet (netfx o coreclr) |
HORIZUN_PBI_MCP_MAX_ROWS |
1000 |
Límite de filas por defecto en DAX |
HORIZUN_PBI_MCP_OUTPUTS_DIR |
./outputs |
Documentación y change_log.md |
HORIZUN_PBI_MCP_BACKUPS_DIR |
./backups |
Backups de .pbip |
HORIZUN_PBI_MCP_LOG_LEVEL |
INFO |
DEBUG/INFO/WARNING/ERROR |
HORIZUN_PBI_MCP_DEFAULT_PBIP |
— | .pbip a abrir al iniciar |
Tools disponibles (90)
Catálogo completo por bloque:
docs/TOOL_CATALOG.md. Inventario del baseline con clase de riesgo y precondiciones:docs/TOOL_INVENTORY.md. Los nombres y firmas están congelados entests/golden/tools_v1.jsony verificados portests/test_tool_contract.py.
Conexión / DAX
pbi_list_desktop_models— lista modelos abiertos (puerto, connection string, catálogo, nº tablas).pbi_select_model— fija el modelo activo (porportsi hay varios).pbi_run_dax— ejecuta DAX (query,max_rows).pbi_test_connection— valida la conexión activa.pbi_validate_measures— valida DAX de medidas SIN modificar el modelo (dry-run conDEFINE MEASURE); útil antes de crearlas.
Documentación (Fase 3)
pbi_list_tables,pbi_list_measures,pbi_list_relationships— consource: live|pbip.pbi_analyze_model_quality— problemas típicos del modelo.pbi_document_model— documentación completa en Markdown aoutputs/.
Medidas (Fase 4) — mode: live|pbip|both, overwrite
pbi_create_measure,pbi_update_measure,pbi_delete_measure(destructiva:confirm=true).
Refresh (Fase 5)
pbi_refresh_model—type: full|calculate|clear_values,tablesopcional (local).
Proyecto PBIP (Fase 6)
pbi_open_pbip_project(path),pbi_validate_pbip_project,pbi_backup_pbip_project(mode: folder|zip,scope: report|model|both).
Edición de modelo
pbi_set_column_visibility/pbi_hide_columns— ocultar/mostrar columnas (p.ej. IDs).mode: live|pbip|both.pbi_set_relationship_direction— filtro cruzadosingle|bothde una relación.mode: live|pbip|both.pbi_disable_auto_date_time— activa/desactiva "Auto fecha y hora" (solopbip).
Informe PBIR (Fases 7–10)
pbi_list_report_pages,pbi_list_visuals(page),pbi_document_report_layout.pbi_create_visual—page,visual_type,fields,position,title(clona un visual existente como plantilla).pbi_update_visual_position,pbi_arrange_visuals(layout: grid|dashboard|executive_summary|custom).pbi_generate_report_page— página asistida a partir del modelo.
HTML dentro de Power BI
pbi_add_custom_visual— registra un custom visual de AppSource en el informe (por defecto HTML Content, que renderiza HTML/SVG desde una medida DAX).pbi_create_html_visual— crea un visual HTML Content enlazado a una medida que devuelve HTML (html_measure).pbi_create_measurecondata_category: "ImageUrl"— medidas que devuelven un data-URI SVG y se renderizan como imagen en tablas/matrices nativas.
Generación de hojas por lenguaje natural
pbi_page_building_blocks— inventario del contenido (modelo + catálogo de visuales existentes + canvas) para diseñar una hoja.pbi_preview_spec_html— maqueta HTML de una hoja propuesta (revisar antes de escribir).pbi_create_page_from_spec— materializa una hoja PBIR completa desde unspec(clona visuales existentes por estilo).pbi_export_page_html— exporta una página existente a maqueta HTML.
Toda tool devuelve {"ok": true/false, ...}; en error incluye error (código) y message (mensaje original del motor, sin ocultar).
Flujo de generación de hojas:
pbi_page_building_blocks→ (Claude interpreta tu instrucción y arma unspec) →pbi_preview_spec_html(revisas el HTML) →pbi_create_page_from_spec(se escribe el PBIR).
Ejemplos de uso (en lenguaje natural con Claude)
- Correr DAX: "Lista los modelos abiertos, selecciona el único, y corre
EVALUATE TOPN(10, Ventas)." - Documentar: "Documenta el modelo activo y analiza su calidad." → genera
outputs/model_documentation_*.md. - Crear medida: "Crea la medida
Margen % = DIVIDE([Utilidad],[Ventas])en la tabla Ventas, formato0.0%, modo both." - Listar visuales: "Abre el
.pbipen C:/…/Informe.pbip y lista los visuales de la página 'Resumen'." - Crear visual: ver
examples/sample_visual_specs.json. - Acomodar página: "Acomoda la página 'Resumen' con layout executive_summary."
Más DAX en examples/sample_queries.md.
⚠️ Edición de PBIR y estado de Desktop: las ediciones de informe (visuales/layout) se hacen en archivos; conviene hacerlas con Power BI Desktop cerrado y reabrir para verlas (si Desktop está abierto y guardas, sobrescribe los cambios en disco). Las ediciones de modelo en vivo (medidas
live) requieren Desktop abierto y se persisten al guardar (Ctrl+S).
Troubleshooting
- No detecta el puerto / "No se detecto ningun modelo": abre el informe en Power BI Desktop; el puerto cambia en cada arranque (el MCP lo descubre solo). Si usas la versión de Microsoft Store, igual se detecta por proceso.
adomd_not_installed/tom_not_installed: ejecutapython scripts/fetch_libs.py. Verifica quelibs/Microsoft.AnalysisServices.AdomdClient.dllexista.clr_not_available: falta .NET; pruebaPBI_MCP_DOTNET_RUNTIME=coreclr.- Error DAX: el mensaje del motor se devuelve tal cual en
message. Revisa la sintaxis (EVALUATE, comillas). pbir_not_enabled: el informe no está en PBIR. Guarda como.pbipy activa Formato de reporte mejorado (PBIR) en Opciones → Características de vista previa (si aplica en tu versión) antes de guardar.- Power BI no recarga los cambios de visuales: ciérralo y reábrelo; PBIR se carga al abrir, no en caliente.
- Permisos/OneDrive: si el
.pbipestá en OneDrive, cierra Desktop antes de editar archivos y espera a que OneDrive termine de sincronizar; los backups se guardan enbackups/.
Decisiones técnicas
- TOM vía
pythonnet(no Tabular Editor CLI). Se evaluaron: (1) Tabular Editor 2 CLI, (2)pythonnetcargando TOM, (3) editar TMDL directo. Comopythonnetfunciona en Python 3.14 y las DLLs de ADOMD.NET/TOM se pueden vendorizar enlibs/sin admin ni GAC, se eligió cargarlas directamente conpythonnet(runtimenetfx). Es más estable, sin dependencias externas de instalación, y da control total (crear/editar medidas y refrescar como lo hace Tabular Editor). La edición durable sigue disponible por TMDL en.pbip. - Visuales por clonación.
pbi_create_visualclona un visual existente del mismo tipo como plantilla (conserva el andamiaje de formato/tema) y solo cae a una plantilla mínima si no hay ninguno, avisando que debe validarse en Desktop. - Seguridad (Fase 11): backup automático antes de cada escritura en
.pbip; JSON atómico (no deja archivos corruptos); no sobrescribe JSON ilegible; validación de rutas;change_log.mdenoutputs/; operaciones destructivas requierenconfirm=true.
Limitaciones / riesgos abiertos
Ninguna de estas es un defecto que se pueda corregir desde aquí. Están documentadas porque afectan a lo que el servidor puede prometer.
Esquemas que Microsoft no publica
Power BI Desktop escribe visualContainer/2.10.0 en informes recientes, y esa URL devuelve 404 en el origen oficial. Lo mismo con bookmarks/2.0.0. El CLI oficial de Microsoft tampoco puede validarlos — emite PBIR_SCHEMA_UNREACHABLE y se salta la validación de esquema de esos archivos.
Consecuencia: las escrituras sobre archivos que declaren esos esquemas se bloquean con schema_unavailable (rule=no_publicado_upstream). Es deliberado y fail-closed: validar 2.10.0 contra 2.7.0 sería adivinar, y additionalProperties: false rechazaría propiedades nuevas legítimas.
Medido sobre un informe real de 443 documentos: 176 se validan, 240 quedan bloqueados por esta causa.
G10 queda como excepción de release documentada.
mode="both" bloqueado
live exige Power BI Desktop abierto; pbip lo exige cerrado. No hay ningún estado del sistema en que ambos destinos puedan escribirse con seguridad en una llamada. Ver docs/DUAL_MODE.md. R15 abierto.
filters e interactions del page spec
Se rechazan con unsupported_feature indicando la ruta JSON exacta. No se descartan en silencio. Su serialización a PBIR está pendiente.
Otras
- PBIR debe estar activado en el
.pbip;pbi_validate_pbip_projectlo comprueba. - El nombre amigable del informe abierto no siempre es legible desde el motor (se reporta puerto + catálogo).
- El parser TMDL en disco es pragmático (tablas, columnas, medidas, relaciones); para metadatos ricos, usa la ruta
live. pbi_generate_report_pagees una composición heurística; no inventa campos y avisa lo que ignora.- El servidor arranca sin Node; lo que queda bloqueado son las escrituras que necesiten el validador oficial.
Estructura del proyecto
horizun-pbi-mcp/
├─ src/
│ ├─ server.py # FastMCP + registro de tools
│ ├─ config.py # settings + sesión (modelo/pbip activos)
│ ├─ logging_config.py
│ ├─ reporting.py # documentación Markdown + calidad
│ ├─ powerbi/ # capa en vivo (ADOMD/TOM)
│ ├─ pbip/ # capa en disco (TMDL/PBIR)
│ ├─ tools/ # tools MCP por área
│ └─ utils/ # JSON, archivos, validación, change_log
├─ scripts/fetch_libs.py # descarga DLLs de Analysis Services
├─ examples/ tests/ outputs/ libs/
├─ README.md PLAN.md pyproject.toml requirements.txt .env.example
Pruebas
python -m pytest -q
859 pruebas, 2 omitidas. Las dos omisiones son de entorno y dicen cómo ejecutarlas:
| Omitida | Condición |
|---|---|
test_run_dax_live |
Requiere una instancia de Power BI Desktop sirviendo un modelo. python -m pytest -m live |
test_no_llega_a_cero_por_acumular_infos |
Requiere que el modelo sintético dispare solo reglas informativas |
Marcadores disponibles:
python -m pytest -m "not packaging" # rápido: omite wheel y sdist
python -m pytest -m live # contra Power BI Desktop abierto
python -m pytest -m live_validator # contra el CLI oficial de Microsoft
Verificar el contrato MCP (las 90 tools están congeladas):
python -m tests.contract_utils
Devuelve 0 si no hay rupturas, 1 si las hay, con un informe que dice qué cambió y si rompe compatibilidad.
Diagnóstico de la instalación:
python scripts/doctor.py
Licencia
Código abierto bajo la licencia Apache License 2.0. Consulta también NOTICE para atribuciones y marcas de terceros.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。