Skip to main content
Glama
PlainsightPro

Plainsight Power BI MCP

Power BI MCP Gateway

A remote MCP server that lets any MCP client (Claude, VS Code and GitHub Copilot, Cursor, ChatGPT, your own agents) talk to Power BI semantic models as the signed-in user, with the organisation's business knowledge kept centrally on the server instead of in every client's instruction files.

It works with any Power BI semantic model in a workspace that has an XMLA endpoint, which means Premium Per User, Premium or Fabric capacity. It is independent of organisation, industry and model schema: everything domain-specific comes from a skills folder that each deployment supplies.

Why

Microsoft's hosted Power BI MCP server can run DAX for a user, but it needs a model id you have to know, it carries no business vocabulary, and its GenerateQuery tool runs on Copilot, which needs a Copilot licence and an F2 or P1 capacity (on Premium Per User it fails with AI_Scenarios_SkuNotSupported). The gateway sits in front of it:

Need

Microsoft's hosted server

Gateway

Which models exist

none; you must know the id

list_semantic_models: only what the user can open, curated ones with description, scope and key measures

Business knowledge

none

server instructions, get_business_context, one prompt per recipe, skill:// resources

DAX generation

GenerateQuery on Copilot: Copilot licence plus F2/P1 capacity, not Premium Per User

generate_dax on your own Foundry (Azure OpenAI) deployment, grounded in schema, glossary and rules, with one repair round; no Copilot, no Fabric capacity

Client onboarding

an Entra app registration per client

OAuth proxy with dynamic client registration: paste the URL, sign in

Execution

schema, DAX, report metadata

the same, called with the user's on-behalf-of token, so Build permission and row-level security apply

The gateway never calls GenerateQuery. generate_dax writes the query on the deployment's own Foundry model and runs it through the hosted server's ExecuteQuery, which only needs Build permission on the model and an XMLA-capable workspace. Microsoft's open-source skills-for-fabric and powerbi-modeling-mcp take the same route: the client's own LLM writes the DAX, guided by skill files. There is no Microsoft library for DAX generation; the reusable part is their DAX guideline text, which a deployment can fold into its skill://dax-rules.

Nothing runs under a service identity. Every Power BI call carries a token issued for the signed-in user, which is also what the Premium Per User terms of use require for multi-user applications.

Related MCP server: powerbi-mcp-proxy

Architecture

MCP client (Claude, VS Code, Cursor, ChatGPT, agent code)
   |  Streamable HTTP + OAuth 2.1 (dynamic client registration against the gateway)
   v
Gateway  (Azure Container Apps)                          FastMCP + Azure OAuth proxy
   |-- /mcp        tools, prompts, resources, instructions   <- skills folder, loaded at startup
   |-- /authorize  /token  /register  /auth/callback         <- Microsoft Entra ID behind it
   |
   |-- per call: on-behalf-of token for https://api.fabric.microsoft.com
   |      |-- Fabric REST      workspaces and semantic models the user can open
   |      `-- hosted Power BI MCP   GetSemanticModelSchema / ExecuteQuery / GetReportMetadata
   `-- managed identity -> Foundry model deployment (Responses API) for generate_dax

Tools

Tool

Purpose

list_semantic_models

Models the user can open; curated first with description, scope, date table, key measures, recipes

get_business_context

The deployment's glossary: vocabulary, measures, dates, model traps, recipe index

get_recipe

A validated query sequence for a recurring analysis

get_semantic_model_schema

Tables, columns, measures with descriptions, relationships

execute_dax

Run 1 to 4 DAX queries as the user (default 250 rows)

generate_dax

Question to DAX, optionally executed; returns DAX, explanation, assumptions, rows

get_report_metadata

Pages, visuals and filters of a report the user can open

recall / remember / forget

Notes users attach to one model (a correction, a trap, the measure for a recurring question). They follow the model: visible and writable only to people Power BI lets open it, and folded into the schema notes and generate_dax grounding

Prompts: one per recipe in the skills folder. Resources: skill://glossary, skill://dax-rules, skill://catalog, skill://recipes/{name}. The tool contract is in docs/connect/other-agents.md.

Skills: the part you own

skills/ in this repository is a fictional example (Contoso Retail). A deployment brings its own folder with the same five parts and the gateway is built with it:

File

Purpose

instructions.md

How the assistant should work with the tools; sent to every client

glossary.md

Business vocabulary, which measure answers which question, sign conventions, traps

dax-rules.md

House rules for DAX generation

recipes/*.md

Validated query sequences; each becomes a prompt and a resource

catalog.yaml

Curated models: id, workspace, scope, key measures, notes

Nothing about a real organisation belongs in this repository. See docs/skills-authoring.md for writing a folder and docs/private-skills.md for running many deployments from this one codebase.

Deploy

Prerequisites: PowerShell 7, Azure CLI 2.78+, signed in with rights to register Entra applications and grant admin consent, and Contributor on the subscription. The tenant needs the Power BI MCP endpoint enabled (see docs/administration.md).

# try it with the example skills
.\deploy\deploy_to_azure.ps1 -AcrName <globally unique registry name>

# a real deployment: private skills + resource names from a profile, engine pinned to a release
.\deploy\deploy_to_azure.ps1 -Profile C:\deployments\<org>\deploy\profile.json

The script creates or updates, idempotently: the Entra app (confidential client, access_as_user scope, delegated Power BI permissions, admin consent), a Foundry resource with a model deployment, a container registry, Log Analytics, a Container Apps environment and the container app with a managed identity. It stages only runtime code and the selected skills for the build; .env, Git history and private notes never reach the image. Re-run after changes; -SkipFoundry skips the model part, -SkipBuild keeps the running image.

Releases publish the engine image to ghcr.io/plainsightpro/powerbi-mcp-gateway:<version>; a deployment profile with EngineImage layers its skills on that image instead of building the source, which is how deployments upgrade without forking.

Connect

Users need the gateway URL, a Microsoft work account, a licence matching the workspace and Build permission on the models they query. Walkthroughs per tool, usage guidelines and troubleshooting are in docs/. In short:

claude mcp add --transport http powerbi https://<host>/mcp      # then /mcp and sign in

Claude Desktop, claude.ai, ChatGPT: add a custom connector with the URL, no client id. VS Code: {"type": "http", "url": "https://<host>/mcp"} in mcp.json; Cursor: {"url": "https://<host>/mcp"} under mcpServers.

Local development

uv sync                                  # .venv from uv.lock, dev tools included (ruff, pyright, pytest)
Copy-Item .env.example .env             # Entra app values, Foundry endpoint, optional PBIMCP_SKILLS_DIR
uv run pytest -q
uv run python -m powerbi_mcp             # http://localhost:8000/mcp

http://localhost:8000/auth/callback is registered on the Entra app by the deploy script, so a local server runs the full sign-in. az login supplies the Foundry credential locally; the signed-in user needs the Cognitive Services OpenAI User role on the Foundry resource, or set PBIMCP_FOUNDRY_API_KEY for the session.

Three checks exist: python -m powerbi_mcp --check-skills <folder> validates a skills folder offline, scripts/smoke_test.py runs the token exchange, catalog, schema, query and DAX generation headlessly with the Azure CLI identity (the deploy script's -PreauthorizeAzureCli enables it), and scripts/check_gateway.py https://<host>/mcp verifies a deployed gateway through the real browser sign-in.

Known limits

  • The app runs one replica. Its OAuth state (client registrations, encrypted tokens) lives in an Azure Table, so a redeploy keeps users signed in; scaling out additionally needs stateless_http=True on the server (MCP sessions are per replica).

  • Skills are deployment-wide, not filtered by the user's permissions; separate deployments for groups that must not share business knowledge.

  • generate_dax returns one query per call; multi-step analyses follow recipes.

License

MIT. Built by Plainsight; contributions welcome.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A self-hosted MCP server that proxies MCP clients to Power BI, using your own Entra tenant and Azure subscription. It enables DAX queries, workspace listing, and dataset management while preserving user-specific row-level security.
    2
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    MCP server enabling AI agents to directly query and manage Power BI datasets, reports, and workspaces via DAX, with built-in data security policies and support for both Power BI Desktop and Service.
    1
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Remote and centralized MCP server that enables AI models to interact with Microsoft Fabric (workspaces and items) via the Fabric Core REST API, using delegated OAuth 2.1 authentication with Microsoft Entra ID so each user's permissions and restrictions are respected.
    GPL 3.0