Content
# Power BI Lead MCP Server
An MCP server that lets an AI agent act as — or work under — a **Power BI Lead**,
driving an eight-agent delivery pipeline over the
[`pbi-github-copilot-rag`](../pbi-github-copilot-rag) knowledge base.
It exposes that repository's existing assets as first-class MCP surfaces:
| MCP surface | What it carries |
|---|---|
| **Resources** (39+) | The RAG corpus — chat modes, skill instructions, templates, themes, governance rules, the tool registry — plus live workflow, approval, and audit state |
| **Prompts** (11) | One delegation contract per agent (0–7), plus Lead kickoff, release review, and troubleshooting |
| **Tools** (32) | Knowledge search, the six executable skill tools, scaffolding, twelve-stage workflow control, and human approval gates |
Implemented against the model in [`pbi-agentic-repos.md`](pbi-agentic-repos.md):
```
Knowledge (RAG) + Planner Agent + MCP Server + Report Design Agent
+ Report Authoring Agent + Desktop Bridge + Report Management Agent
+ Human Approval Gates
```
---
## Install
```bash
py -m pip install -r requirements.txt # only dependency: mcp>=1.9.0
cp .env.example .env # then edit the paths
```
Register it with your MCP client — see [`mcp.json`](mcp.json) for a ready-made block:
```json
{
"mcpServers": {
"pbi-lead": {
"command": "py",
"args": ["-m", "pbi_lead_mcp"],
"env": {
"PYTHONPATH": "D:/PBI Agent/pbi-microsoft-mcp/src",
"PBI_RAG_ROOT": "D:/PBI Agent/pbi-github-copilot-rag",
"PBI_WORKSPACE_ROOT": "D:/PBI Agent/workspace"
}
}
}
}
```
Verify:
```bash
py tests/smoke_test.py # 46 checks: surfaces, gates, scaffolding, live tool runs
```
---
## The eight agents
Each is an MCP prompt (`agent-<n>-<key>`) and a tool (`pbi_agent_brief`). A brief is a
delegation contract: mission, RAG reading list, allowed tools, output folder, approval
gates, and hard rules.
| # | Agent | Writes to | Gates it will hit |
|---|---|---|---|
| 0 | Planner | `plan/` | — |
| 1 | Semantic Model | `model/` | `write_tmdl`, `replace_semantic_model`, `delete_table`, `delete_measure` |
| 2 | Report Design | `design/` | — |
| 3 | Report Authoring | `report/` | — |
| 4 | Validation (Desktop Bridge) | `screenshots/` | — |
| 5 | Performance | `perf/` | — |
| 6 | Security & Compliance | `audit/` | — |
| 7 | Deployment | `releases/` | `publish_semantic_model`, `publish_report`, `deploy_production`, `refresh_dataset`, `modify_rls` |
---
## The twelve-stage workflow
State persists in `<workspace>/.pbi-lead/workflow.json`. Completing a stage auto-opens
the next. Stages marked ✅ cannot complete without Lead approval.
| # | Stage | Owner | Lead approval |
|---|---|---|---|
| 1 | Requirement Gathering | Planner | ✅ |
| 2 | STTM Analysis | Planner | |
| 3 | Semantic Modeling | Semantic Model | ✅ |
| 4 | DAX Development | Semantic Model | |
| 5 | Report Design | Report Design | |
| 6 | PBIR Generation | Report Authoring | |
| 7 | Desktop Validation | Validation | |
| 8 | Performance Optimization | Performance | |
| 9 | Security Review | Security | ✅ |
| 10 | Fabric Deployment | Deployment | ✅ |
| 11 | Production Governance | Security | |
| 12 | Continuous Knowledge Expansion | Planner | |
---
## Tools
### Discovery
`pbi_server_info` · `pbi_knowledge_search` · `pbi_knowledge_get` · `pbi_knowledge_list` ·
`pbi_knowledge_reindex` · `pbi_tool_scan` · `pbi_list_agents` · `pbi_agent_brief` · `pbi_get_theme`
### Executable skills — wrappers over the RAG repo's Python tools
`pbi_extract_semantic_model` · `pbi_extract_report` · `pbi_parse_sttm` ·
`pbi_validate_dax` · `pbi_scan_secrets` · `pbi_check_governance`
### Scaffolding
`pbi_scaffold_repository` · `pbi_scaffold_plan` · `pbi_scaffold_pbip` ·
`pbi_desktop_bridge_plan` · `pbi_deployment_plan` · `pbi_knowledge_contribute`
### Workflow
`pbi_workflow_start` · `pbi_workflow_status` · `pbi_workflow_stage` · `pbi_workflow_set_stage`
### Approval gates
`pbi_list_gated_actions` · `pbi_request_approval` · `pbi_decide_approval` ·
`pbi_list_approvals` · `pbi_check_approval`
### Audit
`pbi_audit_log` · `pbi_audit_tail`
---
## Security model
Rules **G-A1..G-A6** from the RAG repo's `copilot-instructions.md` are carried into every
agent brief and enforced structurally, not just by prompt:
- **No credential surface exists.** No tool in this server can read, mint, store, or
transmit a token. `.env` has no field that could hold one.
- **Fail-closed gates.** Ten actions — connect, publish, deploy, delete table/measure,
replace model, write TMDL, refresh, modify RLS — are blocked without a signed gate.
Gates are scoped to `(action, target)`, single-use, and expire in 60 minutes.
- **Only a human signs.** `pbi_decide_approval` requires `PBI_LEAD_APPROVAL_TOKEN`.
If it is unset, *nothing* can be signed in-band — a missing token never degrades to "allow".
- **Audit-by-default.** Every tool run, gate decision, and stage transition appends to
`docs/audit-trail.log`. Input *keys* are logged, never values.
- **The knowledge base can't be poisoned with secrets.** `pbi_knowledge_contribute`
refuses content matching a secret pattern — the corpus is re-served to every agent.
- **The Desktop Bridge is planned, not driven.** `pbi_desktop_bridge_plan` produces the
validation run for the Lead's workstation. An unattended agent controlling an
authenticated Desktop session would sidestep G-A3.
---
## Design notes
**Subprocess, not import.** The six RAG tools all print to stdout unconditionally, and
two of them (`secrets_scanner`, `governance_checker`) hardcode `Path(".")` as their output
root. Importing them in-process would corrupt the stdio JSON-RPC stream and make output
placement depend on a racy `os.chdir`. Each runs in a child process with explicit `cwd`
and captured stdout instead. Three of them also `sys.exit(1)` on *findings* — the bridge
treats that as "findings present", not failure.
**Lexical RAG, not vectors.** The corpus is ~250 curated documents. A BM25-ish index over
heading-split chunks beats a vector store here on latency, determinism, and auditability —
and every hit cites an exact path, heading, and line, which is what a governance reviewer
needs. `pbi_knowledge_reindex` rebuilds it.
**Concrete resources, not a URI template.** FastMCP compiles `{param}` to `[^/]+`, so a
template can never match a nested path like `.github/instructions/<agent>/<file>.md`.
Curated documents are registered individually, which also makes the corpus discoverable
through `resources/list`. The ~200 `LearningSample` data files are excluded from the
resource list and reachable via `pbi_knowledge_get`.
---
## Known upstream issue
All 11 `.pbix` files under `pbi-github-copilot-rag/LearningSample/` are 33–93 byte stubs,
not real archives (`zipfile.is_zipfile` is `False` for every one). `pbi_extract_semantic_model`
and `pbi_extract_report` cannot be exercised against them — the smoke test asserts a clean
error instead, and validates the bridge against the 208 real `.tmdl` files present. Replace
those stubs with real PBIX files to test extraction end to end.
---
## Layout
```
pbi-microsoft-mcp/
├── README.md · mcp.json · pyproject.toml · requirements.txt · .env.example
├── pbi-agentic-repos.md ← the specification this implements
├── src/pbi_lead_mcp/
│ ├── server.py ← FastMCP assembly: resources, prompts, tools
│ ├── config.py ← path + env resolution (no credential fields)
│ ├── rag.py ← lexical knowledge index + registry scan
│ ├── tools_bridge.py ← subprocess execution of the six skill tools
│ ├── agents.py ← the eight-agent roster and briefs
│ ├── workflow.py ← twelve-stage pipeline with gate enforcement
│ ├── approvals.py ← human approval gates
│ ├── scaffold.py ← repo / plan / PBIP / bridge / deployment generators
│ └── audit.py ← append-only audit trail
└── tests/smoke_test.py ← 46 end-to-end checks over a real MCP session
```