bipixie-mcp 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bipixie_mcp-0.3.0/LICENSE +21 -0
- bipixie_mcp-0.3.0/MANIFEST.in +40 -0
- bipixie_mcp-0.3.0/PKG-INFO +513 -0
- bipixie_mcp-0.3.0/README.md +476 -0
- bipixie_mcp-0.3.0/bipixie_mcp/__init__.py +57 -0
- bipixie_mcp-0.3.0/bipixie_mcp/auth.py +446 -0
- bipixie_mcp-0.3.0/bipixie_mcp/config.py +527 -0
- bipixie_mcp-0.3.0/bipixie_mcp/discovery.py +235 -0
- bipixie_mcp-0.3.0/bipixie_mcp/powerbi_client.py +1363 -0
- bipixie_mcp-0.3.0/bipixie_mcp/server.py +279 -0
- bipixie_mcp-0.3.0/bipixie_mcp/targeting.py +189 -0
- bipixie_mcp-0.3.0/bipixie_mcp/tools.py +3137 -0
- bipixie_mcp-0.3.0/bipixie_mcp.egg-info/PKG-INFO +513 -0
- bipixie_mcp-0.3.0/bipixie_mcp.egg-info/SOURCES.txt +18 -0
- bipixie_mcp-0.3.0/bipixie_mcp.egg-info/dependency_links.txt +1 -0
- bipixie_mcp-0.3.0/bipixie_mcp.egg-info/entry_points.txt +2 -0
- bipixie_mcp-0.3.0/bipixie_mcp.egg-info/requires.txt +16 -0
- bipixie_mcp-0.3.0/bipixie_mcp.egg-info/top_level.txt +1 -0
- bipixie_mcp-0.3.0/pyproject.toml +119 -0
- bipixie_mcp-0.3.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DataChant
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Source-distribution (sdist) contents for `bipixie-mcp` on PyPI.
|
|
2
|
+
#
|
|
3
|
+
# WHY THIS FILE EXISTS: the wheel is governed by [tool.setuptools.packages.find]
|
|
4
|
+
# in pyproject.toml (ships only `bipixie_mcp*`), but the sdist is NOT — setuptools
|
|
5
|
+
# would otherwise pull in adjacent dirs/files (e.g. tests/). The published sdist
|
|
6
|
+
# must carry ONLY the importable package + the metadata files PyPI needs, and must
|
|
7
|
+
# NEVER ship internal material — above all CONNECT-AND-TEST.md, which holds the
|
|
8
|
+
# internal SaaS sample tenant/workspace/dataset GUIDs. (.dockerignore guards the
|
|
9
|
+
# GHCR image but does NOT apply to `python -m build`.)
|
|
10
|
+
#
|
|
11
|
+
# setuptools auto-includes pyproject.toml, README.md (readme), LICENSE
|
|
12
|
+
# (license-files), and the bipixie_mcp package; the rules below PRUNE everything
|
|
13
|
+
# else so a future file move can't silently leak it.
|
|
14
|
+
|
|
15
|
+
# Internal docs with real sample GUIDs / tenant data — must never be published.
|
|
16
|
+
exclude CONNECT-AND-TEST.md
|
|
17
|
+
|
|
18
|
+
# Local config templates (the README documents configuration instead).
|
|
19
|
+
exclude .env
|
|
20
|
+
exclude .env.*
|
|
21
|
+
|
|
22
|
+
# Container / repo plumbing not needed by a pip/uvx install.
|
|
23
|
+
exclude Dockerfile
|
|
24
|
+
exclude .dockerignore
|
|
25
|
+
exclude .gitignore
|
|
26
|
+
|
|
27
|
+
# Non-package trees: tests, the live eval harness, hosted-deploy Bicep/PowerShell,
|
|
28
|
+
# and agent-config examples all stay out of the public package.
|
|
29
|
+
prune tests
|
|
30
|
+
prune evals
|
|
31
|
+
prune deploy
|
|
32
|
+
prune examples
|
|
33
|
+
|
|
34
|
+
# Caches / build cruft.
|
|
35
|
+
prune .venv
|
|
36
|
+
prune .pytest_cache
|
|
37
|
+
prune .mypy_cache
|
|
38
|
+
prune .ruff_cache
|
|
39
|
+
global-exclude *.py[cod]
|
|
40
|
+
global-exclude __pycache__
|
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bipixie-mcp
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: MCP server that gives AI agents read-only access to BI Pixie usage and engagement data via the Power BI REST executeQueries endpoint
|
|
5
|
+
Author-email: DataChant <support@bipixie.com>
|
|
6
|
+
Maintainer-email: DataChant <support@bipixie.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://bipixie.com
|
|
9
|
+
Project-URL: Documentation, https://bipixie.com/docs/cloud/
|
|
10
|
+
Project-URL: Support, https://bipixie.com/docs/cloud/contact-support
|
|
11
|
+
Keywords: mcp,power-bi,bi-pixie,analytics,model-context-protocol
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: fastmcp<3,>=2.11
|
|
23
|
+
Requires-Dist: msal>=1.28
|
|
24
|
+
Requires-Dist: azure-identity>=1.17
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Requires-Dist: pydantic>=2.7
|
|
27
|
+
Requires-Dist: pydantic-settings>=2.3
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "test"
|
|
31
|
+
Requires-Dist: respx>=0.21; extra == "test"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: bipixie-mcp[test]; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# BI Pixie MCP Server
|
|
39
|
+
|
|
40
|
+
A read-only [Model Context Protocol](https://modelcontextprotocol.io/) server that lets AI agents — Claude Code, Codex, Microsoft Fabric data agents, and Azure AI Foundry — query your BI Pixie usage and engagement data.
|
|
41
|
+
|
|
42
|
+
> **Note:** Requires an active BI Pixie license and a deployed BI Pixie semantic model. "BI Pixie" is a trademark of DataChant. This package is a client and grants no rights to the BI Pixie service or data.
|
|
43
|
+
|
|
44
|
+
**Phase 1 data source:** the existing "BI Pixie" semantic model, queried via the Power BI REST `executeQueries` endpoint. No new data infrastructure is required. The server is a pure-additive Python 3.12 package (`bipixie_mcp`) that lives in `mcp_server/` and does not touch any existing Function App, portal, or workload code.
|
|
45
|
+
|
|
46
|
+
**Validated against the live model.** All 8 core data tools (`describe_model`, `list_reports`, `top_reports_by_usage`, `report_health`, `user_adoption`, `page_engagement`, `feedback_summary`, `run_dax`) were executed successfully against the BI Pixie SaaS sample dataset (plus `suggest_questions` for discovery and four stdio-only navigation tools — see the tool catalog). Every measure resolved; ranked output is deterministically ordered. Results match the customer's own Power BI report numbers (e.g. top report "Executive Dashboard" = 484 report sessions; CSAT 0.59, NPS -58.3; data through 2026-05-07).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Contents
|
|
51
|
+
|
|
52
|
+
- [How it works](#how-it-works)
|
|
53
|
+
- [Prerequisites](#prerequisites)
|
|
54
|
+
- [Install](#install)
|
|
55
|
+
- [Configuration reference](#configuration-reference)
|
|
56
|
+
- [Local stdio quickstart — Claude Code](#local-stdio-quickstart--claude-code)
|
|
57
|
+
- [Local stdio quickstart — Codex](#local-stdio-quickstart--codex)
|
|
58
|
+
- [Hosted streamable-HTTP quickstart](#hosted-streamable-http-quickstart)
|
|
59
|
+
- [Tool catalog](#tool-catalog)
|
|
60
|
+
- [Security checklist](#security-checklist)
|
|
61
|
+
- [Tenant settings checklist](#tenant-settings-checklist)
|
|
62
|
+
- [Architecture notes](#architecture-notes)
|
|
63
|
+
- [Phase 2 — Fabric RTI scale-out](#phase-2--fabric-rti-scale-out)
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## How it works
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
AI agent (Claude Code / Codex / Foundry)
|
|
71
|
+
|
|
|
72
|
+
| MCP JSON-RPC (stdio OR POST /mcp)
|
|
73
|
+
v
|
|
74
|
+
bipixie_mcp.server (FastMCP, Python 3.12)
|
|
75
|
+
|
|
|
76
|
+
| Power BI REST executeQueries (read-only DAX)
|
|
77
|
+
| POST https://api.powerbi.com/v1.0/myorg/groups/{workspaceId}/datasets/{datasetId}/executeQueries
|
|
78
|
+
v
|
|
79
|
+
"BI Pixie" semantic model (IMPORT-mode, ~60 tables, validated DAX measures)
|
|
80
|
+
^
|
|
81
|
+
| data already loaded at refresh time
|
|
82
|
+
ADLS Gen2 bipixielake-{license_key}/events/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The server wraps the model's curated measures — the same numbers you see in your BI Pixie dashboard — in typed, filterable MCP tools. Because the measures are already validated by the model, agent results match your Power BI reports exactly.
|
|
86
|
+
|
|
87
|
+
**Two runtime targets, one codebase:**
|
|
88
|
+
|
|
89
|
+
| Target | Transport | `BIPIXIE_MCP_TRANSPORT` | Typical consumer |
|
|
90
|
+
|--------|-----------|------------------------|-----------------|
|
|
91
|
+
| Local developer machine | `stdio` | `stdio` (default) | Claude Code, Codex |
|
|
92
|
+
| Customer Azure environment | `streamable-http` | `streamable-http` | Fabric data agents, Azure AI Foundry, remote Claude Code |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Prerequisites
|
|
97
|
+
|
|
98
|
+
### Python
|
|
99
|
+
|
|
100
|
+
Python 3.12 or later.
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
python --version # must be 3.12+
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
On Windows with multiple Python versions installed, use `py -3.12` instead of `python`.
|
|
107
|
+
|
|
108
|
+
### Power BI tenant settings (customer admin action — required before first use)
|
|
109
|
+
|
|
110
|
+
The following settings must be enabled by a Power BI admin in your tenant. These are customer-side prerequisites; the server cannot self-provision them.
|
|
111
|
+
|
|
112
|
+
| Setting | Location in Power BI Admin portal | Why |
|
|
113
|
+
|---------|-----------------------------------|-----|
|
|
114
|
+
| **Dataset Execute Queries REST API** | Tenant settings > Integration settings | Hard gate. Disabled = 403 with no helpful body. |
|
|
115
|
+
| **Allow service principals to use Power BI APIs** | Tenant settings > Developer settings | Required for `service_principal` and `managed_identity` auth modes. |
|
|
116
|
+
| Workspace **Member** (or Admin) role for your SP or MI | Workspace settings > Manage access | Required so the app identity has Read + Build on the dataset. |
|
|
117
|
+
| (Optional) **Allow XMLA endpoints and Analyze in Excel** | Tenant settings | Only needed for `BIPIXIE_MCP_USE_ARROW=true` (Phase 1.5). Requires Premium/Fabric capacity. |
|
|
118
|
+
|
|
119
|
+
For `device_code` / `interactive` / `azure_cli` auth (local use), the customer's own user identity is used and workspace membership follows normal Power BI access — no service-principal enrollment needed.
|
|
120
|
+
|
|
121
|
+
### Entra app registration
|
|
122
|
+
|
|
123
|
+
For `azure_cli` (simplest local validation): **no app registration needed.** Reuses an existing `az login` session via `AzureCliCredential`. Run `az login` once in your shell, then set `BIPIXIE_MCP_AUTH_MODE=azure_cli` — no `BIPIXIE_MCP_CLIENT_ID` required.
|
|
124
|
+
|
|
125
|
+
For `device_code` / `interactive` (local, no existing az session): create a **public-client** app registration in your Entra tenant with:
|
|
126
|
+
- Redirect URI: `https://login.microsoftonline.com/common/oauth2/nativeclient` (for device code)
|
|
127
|
+
- API permission: `Power BI Service > Dataset.Read.All` (delegated)
|
|
128
|
+
- Token version: `requestedAccessTokenVersion = 2` (v2 tokens)
|
|
129
|
+
|
|
130
|
+
For `service_principal` (hosted): create a **confidential-client** app registration and add:
|
|
131
|
+
- API permission: `Power BI Service > Dataset.Read.All` (application)
|
|
132
|
+
- Grant admin consent
|
|
133
|
+
- Token version: `requestedAccessTokenVersion = 2`
|
|
134
|
+
|
|
135
|
+
For `managed_identity` (hosted, preferred): no app registration needed on the server side. The managed identity must be added as workspace Member.
|
|
136
|
+
|
|
137
|
+
For EasyAuth on the hosted endpoint itself (if deployed to Azure Container App / Function App), `allowedAudiences` must include both `{clientId}` and `api://{clientId}`, and `openIdIssuer` must be the v2 issuer: `https://login.microsoftonline.com/{tenantId}/v2.0`.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Install
|
|
142
|
+
|
|
143
|
+
The server runs locally (stdio) in VS Code, Cursor, Claude Code / Desktop, and Codex. Install it from **PyPI** — no clone required:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Zero-install runner (recommended) — always fetches the latest published version:
|
|
147
|
+
uvx bipixie-mcp
|
|
148
|
+
|
|
149
|
+
# Or install into the current environment:
|
|
150
|
+
pip install bipixie-mcp
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=bipixie&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22bipixie-mcp%22%5D%7D)
|
|
154
|
+
|
|
155
|
+
After installing, set the required `BIPIXIE_MCP_*` variables (see [Configuration reference](#configuration-reference)) — at minimum a tenant, workspace, and dataset, plus `BIPIXIE_MCP_AUTH_MODE=azure_cli` (then `az login`) for the simplest local auth.
|
|
156
|
+
|
|
157
|
+
<details>
|
|
158
|
+
<summary><strong>From source (maintainers / contributors)</strong></summary>
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pip install -e "mcp_server/[test]" # from the repo root
|
|
162
|
+
pip install -e ".[test]" # from the mcp_server/ directory
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
</details>
|
|
166
|
+
|
|
167
|
+
**Dependencies installed automatically:**
|
|
168
|
+
|
|
169
|
+
| Package | Purpose |
|
|
170
|
+
|---------|---------|
|
|
171
|
+
| `fastmcp>=2.11` | MCP server framework (stdio + streamable-HTTP) |
|
|
172
|
+
| `msal>=1.28` | MSAL Python — device-code / interactive token cache |
|
|
173
|
+
| `azure-identity>=1.17` | `DefaultAzureCredential`, `ClientSecretCredential` |
|
|
174
|
+
| `httpx>=0.27` | Async HTTP for Power BI REST calls |
|
|
175
|
+
| `pydantic>=2.7` | Data validation |
|
|
176
|
+
| `pydantic-settings>=2.3` | `BIPIXIE_MCP_*` env-var config |
|
|
177
|
+
|
|
178
|
+
Test extras (`pytest`, `pytest-asyncio`, `respx`) are included with `[test]`.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Configuration reference
|
|
183
|
+
|
|
184
|
+
All configuration is via environment variables (or a `.env` file in the working directory). Copy `.env.example` to `.env` and fill in your values. **Never commit `.env` or `~/.bipixie_mcp/token_cache.bin` to source control.**
|
|
185
|
+
|
|
186
|
+
| Variable | Required | Default | Description |
|
|
187
|
+
|----------|----------|---------|-------------|
|
|
188
|
+
| `BIPIXIE_MCP_TENANT_ID` | Yes | — | Entra (AAD) tenant GUID. Cloud customers: DataChant production tenant. Self-hosted: your own tenant GUID. Never hardcoded — wrong value breaks auth. |
|
|
189
|
+
| `BIPIXIE_MCP_AUTH_MODE` | No | `device_code` | Token-acquisition flow: `device_code` \| `interactive` \| `azure_cli` \| `service_principal` \| `managed_identity`. `azure_cli` reuses an existing `az login` session (no app registration, no client secret — simplest local validation). |
|
|
190
|
+
| `BIPIXIE_MCP_CLIENT_ID` | Yes (except azure_cli / managed_identity) | — | Entra app (client) ID. Public client for device-code/interactive; confidential for service_principal. Not needed for `azure_cli` or `managed_identity` (both obtain credentials without an explicit client registration). |
|
|
191
|
+
| `BIPIXIE_MCP_CLIENT_SECRET` | For SP only | — | Client secret for `service_principal` mode. In Azure, use a Key Vault reference (`@Microsoft.KeyVault(...)`). Never logged. |
|
|
192
|
+
| `BIPIXIE_MCP_WORKSPACE_ID` | One of ID/name | — | GUID of the Fabric/Power BI workspace containing the "BI Pixie" dataset. If unset, resolved from `BIPIXIE_MCP_WORKSPACE_NAME`. |
|
|
193
|
+
| `BIPIXIE_MCP_WORKSPACE_NAME` | One of ID/name | — | Workspace display name, used to resolve the workspace GUID at startup. Ignored when `WORKSPACE_ID` is set. |
|
|
194
|
+
| `BIPIXIE_MCP_DATASET_ID` | One of ID/name | — | GUID of the "BI Pixie" semantic model. If unset, resolved from `BIPIXIE_MCP_DATASET_NAME`. Fails fast on name collision — use an explicit ID when multiple "BI Pixie" datasets exist in the workspace. |
|
|
195
|
+
| `BIPIXIE_MCP_DATASET_NAME` | No | `BI Pixie` | Dataset display name for ID resolution. Override only if the customer renamed the model. |
|
|
196
|
+
| `BIPIXIE_MCP_POWERBI_API_BASE` | No | `https://api.powerbi.com/v1.0/myorg` | Power BI REST base URL. Change only for Sovereign Cloud (GovCloud / China). |
|
|
197
|
+
| `BIPIXIE_MCP_POWERBI_SCOPE` | No | `https://analysis.windows.net/powerbi/api/.default` | OAuth scope for executeQueries. Confirmed in `SemanticModelClient.ts:122-127` — Fabric-audience tokens are rejected by api.powerbi.com. |
|
|
198
|
+
| `BIPIXIE_MCP_TRANSPORT` | No | `stdio` | Runtime transport: `stdio` (local) or `streamable-http` (hosted). |
|
|
199
|
+
| `BIPIXIE_MCP_HTTP_HOST` | No | `0.0.0.0` | Bind host for streamable-http mode. Ignored in stdio mode. |
|
|
200
|
+
| `BIPIXIE_MCP_HTTP_PORT` | No | `8000` | Bind port for streamable-http mode. Azure injects `PORT` / `WEBSITES_PORT` automatically. |
|
|
201
|
+
| `BIPIXIE_MCP_DEFAULT_DAYS` | No | `30` | Default lookback window (days) when a tool's `days` argument is omitted. Cannot exceed the model's loaded history. |
|
|
202
|
+
| `BIPIXIE_MCP_DEFAULT_TOP_N` | No | `100` | Default row cap for ranking/list tools when `top_n` is omitted. |
|
|
203
|
+
| `BIPIXIE_MCP_MAX_ROWS` | No | `1000` | Hard server-side cap on rows returned by any tool. Enforced before serialization. |
|
|
204
|
+
| `BIPIXIE_MCP_PII_COLUMNS_ALLOWED` | No | `false` | When `false` (default), `ResponsePiiFilter` strips `Username` and `Client IP` columns from all results. Set `true` only after an informed GDPR review. The BI Pixie model ships no RLS, so this filter is the primary PII control across all auth modes. |
|
|
205
|
+
| `BIPIXIE_MCP_USE_ARROW` | No | `false` | Opt-in to the `executeDaxQueries` (Arrow) endpoint for larger result sets. Requires Premium/Fabric capacity and the "Allow XMLA endpoints" tenant setting. |
|
|
206
|
+
| `BIPIXIE_MCP_QUERY_RATE_LIMIT` | No | `60` | Client-side cap on executeQueries calls per minute per identity, to stay under the Power BI ~120/min quota. |
|
|
207
|
+
| `BIPIXIE_MCP_TOKEN_CACHE_PATH` | No | `~/.bipixie_mcp/token_cache.bin` | MSAL serializable token cache path (device_code / interactive modes). Persists the refresh token across restarts. Add to `.gitignore`. |
|
|
208
|
+
| `BIPIXIE_MCP_LOG_LEVEL` | No | `INFO` | Logging level (`DEBUG` / `INFO` / `WARNING` / `ERROR`). All logs go to **stderr** — stdout is reserved for the MCP JSON-RPC stream. |
|
|
209
|
+
|
|
210
|
+
**Cloud vs. self-hosted:** the config keys are identical in both deployments. Only the values differ — cloud customers supply DataChant's tenant GUID and their own workspace/dataset IDs; self-hosted enterprise customers supply their own tenant GUID, their own Entra app registration, and their own workspace/dataset IDs. Nothing is hardcoded in the server.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Local stdio quickstart — Claude Code
|
|
215
|
+
|
|
216
|
+
### 1. Set up your `.env`
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# mcp_server/.env
|
|
220
|
+
BIPIXIE_MCP_TENANT_ID=72f988bf-86f1-41af-91ab-2d7cd011db47 # your Entra tenant
|
|
221
|
+
BIPIXIE_MCP_CLIENT_ID=<your-public-client-app-id>
|
|
222
|
+
BIPIXIE_MCP_WORKSPACE_ID=<your-fabric-workspace-guid> # or use WORKSPACE_NAME
|
|
223
|
+
BIPIXIE_MCP_DATASET_NAME=BI Pixie
|
|
224
|
+
BIPIXIE_MCP_AUTH_MODE=device_code
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 2. Register with Claude Code (one-liner)
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
claude mcp add --transport stdio --scope project bipixie -- python -m bipixie_mcp.server
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Pass required env vars inline or let Claude Code inherit them from your shell.
|
|
234
|
+
|
|
235
|
+
### 3. Register via `.mcp.json` (project-scoped, checked in)
|
|
236
|
+
|
|
237
|
+
Create or add to `.mcp.json` in your project root:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"mcpServers": {
|
|
242
|
+
"bipixie": {
|
|
243
|
+
"type": "stdio",
|
|
244
|
+
"command": "python",
|
|
245
|
+
"args": ["-m", "bipixie_mcp.server"],
|
|
246
|
+
"env": {
|
|
247
|
+
"BIPIXIE_MCP_TENANT_ID": "${BIPIXIE_MCP_TENANT_ID}",
|
|
248
|
+
"BIPIXIE_MCP_CLIENT_ID": "${BIPIXIE_MCP_CLIENT_ID}",
|
|
249
|
+
"BIPIXIE_MCP_WORKSPACE_ID": "${BIPIXIE_MCP_WORKSPACE_ID}",
|
|
250
|
+
"BIPIXIE_MCP_DATASET_NAME": "BI Pixie",
|
|
251
|
+
"BIPIXIE_MCP_AUTH_MODE": "device_code"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
On first use, the server performs a device-code flow: it prints a URL and code to stderr, and the user authenticates in a browser. The MSAL token cache at `BIPIXIE_MCP_TOKEN_CACHE_PATH` persists the refresh token so subsequent restarts are silent.
|
|
259
|
+
|
|
260
|
+
**Important:** add `~/.bipixie_mcp/` to your global `.gitignore`. The token cache contains long-lived credentials.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Local stdio quickstart — Codex
|
|
265
|
+
|
|
266
|
+
Add to `~/.codex/config.toml`:
|
|
267
|
+
|
|
268
|
+
```toml
|
|
269
|
+
[mcp_servers.bipixie]
|
|
270
|
+
command = "python"
|
|
271
|
+
args = ["-m", "bipixie_mcp.server"]
|
|
272
|
+
env_vars = [
|
|
273
|
+
"BIPIXIE_MCP_TENANT_ID",
|
|
274
|
+
"BIPIXIE_MCP_CLIENT_ID",
|
|
275
|
+
"BIPIXIE_MCP_WORKSPACE_ID",
|
|
276
|
+
"BIPIXIE_MCP_DATASET_NAME",
|
|
277
|
+
"BIPIXIE_MCP_AUTH_MODE",
|
|
278
|
+
"BIPIXIE_MCP_CLIENT_SECRET", # only for service_principal mode
|
|
279
|
+
]
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Set the referenced variables in your shell environment before starting Codex. Use `BIPIXIE_MCP_AUTH_MODE=device_code` for interactive local use, `service_principal` for CI/automation.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Hosted streamable-HTTP quickstart
|
|
287
|
+
|
|
288
|
+
### Overview
|
|
289
|
+
|
|
290
|
+
Set `BIPIXIE_MCP_TRANSPORT=streamable-http`. The server exposes a single `POST /mcp` endpoint (MCP Streamable-HTTP protocol, not the deprecated SSE transport). FastMCP is instantiated with `stateless_http=True` so the server scales horizontally with no server-side session state.
|
|
291
|
+
|
|
292
|
+
### Recommended host: Azure Container App
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Build and push the image
|
|
296
|
+
docker build -t bipixie-mcp:latest ./mcp_server
|
|
297
|
+
az acr build --registry <your-acr> --image bipixie-mcp:latest ./mcp_server
|
|
298
|
+
|
|
299
|
+
# Deploy (minimal example — add RBAC and Key Vault refs for production)
|
|
300
|
+
az containerapp create \
|
|
301
|
+
--name bipixie-mcp \
|
|
302
|
+
--resource-group rg-pixie-ctl-dev-eastus \
|
|
303
|
+
--environment <your-aca-env> \
|
|
304
|
+
--image <your-acr>.azurecr.io/bipixie-mcp:latest \
|
|
305
|
+
--target-port 8000 \
|
|
306
|
+
--ingress external \
|
|
307
|
+
--env-vars \
|
|
308
|
+
BIPIXIE_MCP_TRANSPORT=streamable-http \
|
|
309
|
+
BIPIXIE_MCP_AUTH_MODE=managed_identity \
|
|
310
|
+
BIPIXIE_MCP_TENANT_ID=<tenant-id> \
|
|
311
|
+
BIPIXIE_MCP_WORKSPACE_ID=<workspace-guid> \
|
|
312
|
+
BIPIXIE_MCP_DATASET_NAME="BI Pixie"
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
For `service_principal` mode, inject `BIPIXIE_MCP_CLIENT_SECRET` as a Key Vault reference rather than a plaintext env var.
|
|
316
|
+
|
|
317
|
+
The managed identity assigned to the Container App must be added as **Member** (or Admin) on the target Power BI workspace.
|
|
318
|
+
|
|
319
|
+
### Auth at the edge (EasyAuth)
|
|
320
|
+
|
|
321
|
+
Front the Container App / Function App with **App Service EasyAuth** (Microsoft Entra ID provider):
|
|
322
|
+
|
|
323
|
+
- `requireAuthentication = true`
|
|
324
|
+
- Function-level auth: `ANONYMOUS` (EasyAuth is the gate — do NOT use function keys on Flex Consumption; see documented gotcha in CLAUDE.md)
|
|
325
|
+
- `allowedAudiences`: include both `<clientId>` and `api://<clientId>`
|
|
326
|
+
- `openIdIssuer`: `https://login.microsoftonline.com/<tenantId>/v2.0` (v2 tokens required)
|
|
327
|
+
|
|
328
|
+
### Register in Claude Code (remote)
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
claude mcp add \
|
|
332
|
+
--transport http \
|
|
333
|
+
--header "Authorization: Bearer <token>" \
|
|
334
|
+
bipixie \
|
|
335
|
+
https://<your-app>.azurecontainerapps.io/mcp
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Register in Azure AI Foundry
|
|
339
|
+
|
|
340
|
+
1. Open your Azure AI Foundry project.
|
|
341
|
+
2. Navigate to **Tools > Add tool > Custom > Model Context Protocol**.
|
|
342
|
+
3. Enter:
|
|
343
|
+
- **Endpoint URL**: `https://<your-app>/mcp`
|
|
344
|
+
- **Authentication**: Microsoft Entra
|
|
345
|
+
- **Type**: Project Managed Identity (machine-to-machine) or OAuth Identity Passthrough (per-user delegated tokens). Because the BI Pixie semantic model ships no RLS, both types see the same full usage data — choose based on your operational preference, not for data-access reasons.
|
|
346
|
+
- **Audience**: the App ID URI of your MCP Entra app registration (e.g. `api://<clientId>`)
|
|
347
|
+
4. Test connectivity. The tool list should populate with the eight BI Pixie tools.
|
|
348
|
+
|
|
349
|
+
Note the 100-second non-streaming timeout that Azure AI Foundry enforces on MCP tool calls. All BI Pixie tools complete well within this limit for typical query sizes.
|
|
350
|
+
|
|
351
|
+
### Register as a Fabric data agent tool
|
|
352
|
+
|
|
353
|
+
In the Fabric data agent builder, add an MCP tool pointing at the `/mcp` endpoint with Microsoft Entra auth. The data agent will use the eight typed tools alongside (or instead of) the model's built-in VerifiedAnswers and CopilotTooling conversational path. The two are complementary: the custom MCP server provides structured JSON output with filter parameters and pagination; the model's native Fabric Copilot integration provides natural-language Q&A over the existing 39 VerifiedAnswers.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Tool catalog
|
|
358
|
+
|
|
359
|
+
Call `describe_model` first — it returns the full queryable surface so the agent knows which table names, measures, and dimension columns are available before constructing a `run_dax` query.
|
|
360
|
+
|
|
361
|
+
| Tool | Required args | Optional args | What it returns |
|
|
362
|
+
|------|--------------|---------------|----------------|
|
|
363
|
+
| `describe_model` | — | `include_measure_descriptions` | Dataset ID/name, table list, measure catalog by domain, dimension columns, data freshness |
|
|
364
|
+
| `list_reports` | — | `days`, `top_n`, `workspace_name` | Tracked reports with sessions, total hours, unique users, last activity |
|
|
365
|
+
| `top_reports_by_usage` | — | `metric`, `days`, `top_n`, `ascending` | Reports ranked by `report_sessions` / `total_hours` / `users` / `interactive_sessions` / `avg_session_duration` / `interactions` (use `interactions` for "most/least clicks") |
|
|
366
|
+
| `report_health` | `report_name` | `days` | Full health card: sessions, hours, avg duration, interactive vs passive, users, CSAT (last + multiple), NPS |
|
|
367
|
+
| `user_adoption` | — | `days`, `granularity`, `report_name` | MAU, DAU, DAU/MAU, WAU, Engaged Users, New Users, Returning Users — summary or time series |
|
|
368
|
+
| `page_engagement` | — | `report_name`, `days`, `top_n` | Per-page: page sessions, avg duration, total interactions, avg interactions/session, slicer clicks, visual interactions, tooltip opens |
|
|
369
|
+
| `feedback_summary` | — | `days`, `report_name`, `group_by`, `granularity`, `survey_type`, `top_n` | CSAT (both `csat_multiple` — the report's headline, click-weighted — and `csat_last`), the sentiment split (positive/negative clicks, neutral users, response rate), NPS (score, rating, promoters/detractors/passives), and the survey story (respondents, responses, time savings, self-reported **financial gains $**). `group_by` (`report`/`icon`/`workspace`/`question`/`answer`/`survey_type`) breaks it out (domain-aware — only the measures that vary across the dimension); `granularity` (`daily`/`weekly`/`monthly`) returns a trend; an empty window self-heals with a `data_coverage` hint. `group_by_report` kept as a deprecated alias for `group_by="report"`. |
|
|
370
|
+
| `run_dax` | `dax` | `row_limit` | Escape hatch: execute any read-only `EVALUATE` DAX query and get rows as JSON |
|
|
371
|
+
|
|
372
|
+
### Local navigation tools (stdio only)
|
|
373
|
+
|
|
374
|
+
On the local **stdio** transport, the server also registers four navigation tools so you can point it at a different workspace/dataset without editing config or restarting — handy when one identity can see several `BI Pixie` models. They are enabled by default (`BIPIXIE_MCP_ALLOW_TARGET_SWITCHING=true`); set it to `false` to lock the server to the configured dataset. They are **never** exposed on the hosted (streamable-http) transport, which keeps its single-configured-dataset contract.
|
|
375
|
+
|
|
376
|
+
| Tool | Required args | What it does |
|
|
377
|
+
|------|--------------|--------------|
|
|
378
|
+
| `list_workspaces` | — | List the Power BI workspaces the server identity can see (read-only, one `GET /groups`). |
|
|
379
|
+
| `list_datasets` | `workspace_id` | List datasets in a workspace, flagging likely `BI Pixie` models via `is_bi_pixie`. |
|
|
380
|
+
| `set_active_dataset` | `workspace_id`, `dataset_id` | Re-point every tool at a different workspace+dataset for the rest of the session (resets on restart). Not read-only — it changes session state. |
|
|
381
|
+
| `get_active_dataset` | — | Show the workspace+dataset the tools are currently querying, with its freshness footer. |
|
|
382
|
+
|
|
383
|
+
### Freshness footer
|
|
384
|
+
|
|
385
|
+
Every tool response includes a freshness footer:
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"data_through": "2026-05-29",
|
|
390
|
+
"last_refresh_utc": "2026-05-30T04:12:00Z"
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
`data_through` is the `[Last Activity]` date in the model. `last_refresh_utc` is the most recent successful refresh from the Power BI refresh history API. Because the model is IMPORT mode, data is current as of the last scheduled refresh — not real-time.
|
|
395
|
+
|
|
396
|
+
### `run_dax` safety
|
|
397
|
+
|
|
398
|
+
`run_dax` passes every query through `DaxGuard` before dispatch:
|
|
399
|
+
|
|
400
|
+
- Query must begin with `EVALUATE` (a `DEFINE ... EVALUATE ...` preamble is allowed).
|
|
401
|
+
- The following write verbs hard-reject the query and return `{"error": "dax_rejected", "reason": "..."}`: `CREATE`, `ALTER`, `DELETE`, `DROP`, `MERGE`, `INSERT`, `UPDATE`, `PROCESS`, `REFRESH`, and related DDL keywords.
|
|
402
|
+
- The agent cannot change the workspace or dataset ID — the server is scoped to the single configured tenant context.
|
|
403
|
+
- Results pass `ResponsePiiFilter` (strips `Username` and `Client IP` columns when `BIPIXIE_MCP_PII_COLUMNS_ALLOWED=false`).
|
|
404
|
+
- Row count is capped at `BIPIXIE_MCP_MAX_ROWS`.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Security checklist
|
|
409
|
+
|
|
410
|
+
- **Never commit** `.env`, `token_cache.bin`, or any file containing `BIPIXIE_MCP_CLIENT_SECRET`. Add `mcp_server/.env` and `~/.bipixie_mcp/` to `.gitignore`.
|
|
411
|
+
- **The BI Pixie semantic model ships no row-level security (RLS).** Every auth mode therefore sees the same full usage data — this is by design. Each team or Enterprise tenant installs the BI Pixie Dashboard under its own license key and container and runs its own MCP server against its own model, so anyone who can run the server is already entitled to that model's usage data. The PII filter (`BIPIXIE_MCP_PII_COLUMNS_ALLOWED`, default `false`) — not RLS — is the control for user-identifying columns (`Username` / `Client IP`).
|
|
412
|
+
- **`run_dax` is read-only** — `DaxGuard` enforces this before every dispatch. No write, DDL, or refresh operation can reach the dataset.
|
|
413
|
+
- **Client secrets never appear in logs.** A redacting filter masks UUIDs and 40-plus-character hex strings from all log output. All logs go to stderr; stdout is reserved for the JSON-RPC stream.
|
|
414
|
+
- **Token cache (`~/.bipixie_mcp/token_cache.bin`)** contains serialized MSAL credentials. Protect it like a password. It is unused in `managed_identity` mode.
|
|
415
|
+
- **PII in the model:** the `User and IP Addresses` table contains plaintext UPNs and client IPs. `ResponsePiiFilter` strips `Username` / `Client IP` columns from all results by default. Only an operator who has reviewed GDPR implications should set `BIPIXIE_MCP_PII_COLUMNS_ALLOWED=true`.
|
|
416
|
+
- **Multi-tenant cloud hosting:** if the hosted server runs in the vendor Azure subscription and serves multiple customers, each customer should have its own service principal (separate `BIPIXIE_MCP_CLIENT_ID` / `BIPIXIE_MCP_CLIENT_SECRET`) so the ~120 req/min per-identity Power BI quota is not shared.
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Tenant settings checklist
|
|
421
|
+
|
|
422
|
+
Complete this checklist before connecting the server. All items require a Power BI admin.
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
[ ] Power BI Admin portal > Tenant settings > Integration settings:
|
|
426
|
+
"Dataset Execute Queries REST API" = ENABLED
|
|
427
|
+
(disabled = silent 403; this is the most common setup failure)
|
|
428
|
+
|
|
429
|
+
[ ] Power BI Admin portal > Tenant settings > Developer settings:
|
|
430
|
+
"Allow service principals to use Power BI APIs" = ENABLED
|
|
431
|
+
(required for service_principal and managed_identity auth modes)
|
|
432
|
+
|
|
433
|
+
[ ] Fabric workspace > Manage access:
|
|
434
|
+
Service principal / managed identity added as Member or Admin
|
|
435
|
+
(grants Read + Build on the dataset)
|
|
436
|
+
|
|
437
|
+
[ ] Entra app registration:
|
|
438
|
+
API permission "Power BI Service > Dataset.Read.All" granted and admin-consented
|
|
439
|
+
requestedAccessTokenVersion = 2 (v2 tokens required)
|
|
440
|
+
|
|
441
|
+
[ ] (Optional, Phase 1.5 only) Power BI Admin portal > Tenant settings:
|
|
442
|
+
"Allow XMLA endpoints and Analyze in Excel" = ENABLED
|
|
443
|
+
Workspace on Premium or Fabric capacity
|
|
444
|
+
(only needed when BIPIXIE_MCP_USE_ARROW=true)
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Architecture notes
|
|
450
|
+
|
|
451
|
+
### Why the existing semantic model (Phase 1)
|
|
452
|
+
|
|
453
|
+
The "BI Pixie" semantic model ships ~60 tables, a curated DAX measure library covering adoption, engagement, feedback, survey, and security, 39 VerifiedAnswers, and CopilotTooling annotations. The MCP server's typed tools wrap these confirmed measures — `[Report Sessions]`, `[Total Hours]`, `[Avg Session Duration (sec)]`, `[Interactive Sessions]`, `[MAU]`, `[DAU]`, `[DAU / MAU]`, `[Engaged Users]`, `[New Users]`, `[Returning Users]`, `[CSAT (Last Response)]`, `[CSAT (Multiple Responses)]`, `[Feedback Clicks]`, `[Positive Clicks]`, `[Negative Clicks]`, `[Average Satisfaction]`, `[Neutral Users]`, `[Respondents]`, `[% Feedback Responses]`, `[NPS]`, `[NPS Rating]`, `[NPS Promoters]`, `[NPS Detractors]`, `[NPS Passives]`, `[Survey Respondents]`, `[Survey Responses]`, `[Survey Time Savings (Hours)]`, `[Survey Financial Gains]`, `[Survey Avg Financial Gains]`, `[Page Sessions]`, `[Total Interactions Within Page]`, `[Slicer Clicks]`, `[Visual Interactions]`, `[Tooltip Opens]`, `[Avg Duration in Page (Sec)]` — so agent numbers match the Power BI report exactly.
|
|
454
|
+
|
|
455
|
+
The `executeQueries` endpoint is a public REST endpoint available on all Power BI tiers (Pro, PPU, Premium, Fabric). Aggregated measure queries return tens of rows, comfortably inside the 100K-row / 1M-value / 15 MB / 120-rpm caps.
|
|
456
|
+
|
|
457
|
+
### Package layout
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
mcp_server/
|
|
461
|
+
bipixie_mcp/
|
|
462
|
+
__init__.py # package marker, lazy public re-exports: __version__, Settings, get_settings, build_server, main
|
|
463
|
+
config.py # Settings (pydantic-settings, BIPIXIE_MCP_* prefix), get_settings(), ConfigError
|
|
464
|
+
auth.py # TokenProvider, build_credential(), AuthError
|
|
465
|
+
powerbi_client.py # DaxGuard, ResponsePiiFilter, PowerBIClient, QueryResult, ModelMetadata, McpSecurityError
|
|
466
|
+
tools.py # register_tools(), build_*_dax() helpers, METRIC_MEASURE_MAP, MEASURE_CATALOG
|
|
467
|
+
server.py # build_server(), main() — composition root and entrypoint
|
|
468
|
+
tests/
|
|
469
|
+
test_tools.py # pytest suite (no live Azure/Power BI — uses respx + AsyncMock)
|
|
470
|
+
examples/
|
|
471
|
+
agent-config.md # copy-paste registration recipes for Claude Code, Codex, Foundry
|
|
472
|
+
pyproject.toml # PEP 621 metadata, console-script bipixie-mcp = bipixie_mcp.server:main
|
|
473
|
+
.env.example # full BIPIXIE_MCP_* env template
|
|
474
|
+
README.md # this file
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Module contracts
|
|
478
|
+
|
|
479
|
+
- `config.Settings` — loaded once via `get_settings()` (lru_cache singleton). No network calls, no credentials built at import time. `validate_runtime()` fails fast with a human-readable `ConfigError` (no secrets in the message) before any network I/O.
|
|
480
|
+
- `auth.TokenProvider` — caches the bearer token process-wide, transparently refreshing ~5 minutes before the ~1-hour expiry. Never calls Power BI per-request.
|
|
481
|
+
- `powerbi_client.PowerBIClient` — async; `execute_dax()` enforces DaxGuard, rate limit, `max_rows`, error-envelope parsing, and `ResponsePiiFilter`. `resolve_ids()` resolves workspace/dataset names to GUIDs once and caches the result.
|
|
482
|
+
- `tools.register_tools()` — decorates the eight tools on the `FastMCP` instance. DAX builders (`build_*_dax`) are pure functions with no I/O, independently unit-tested. `report_name` and other user-supplied filter values are passed via `TREATAS({value}, table[column])` — never string-concatenated into a measure name — preventing DAX injection.
|
|
483
|
+
- `server.build_server()` — composition root: loads config, builds credential/client, registers tools, returns a configured `FastMCP` instance. `main()` is the console-script entry point and the `python -m bipixie_mcp.server` target.
|
|
484
|
+
|
|
485
|
+
### Running tests
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
cd mcp_server
|
|
489
|
+
py -3.12 -m pytest tests/ -v --tb=short
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Tests run without any Azure or Power BI connection (no live credentials required). Fixtures use `AsyncMock` for `PowerBIClient` methods and `respx` for HTTP-layer tests.
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Phase 2 — Fabric RTI scale-out
|
|
497
|
+
|
|
498
|
+
When Phase 1 limits bite — `executeQueries` 429 throttling under agent load, raw row-level drill-down beyond ~50K rows, time-series anomaly detection (`series_decompose_anomalies`), sub-2-second historical scans over 30+ days, or near-real-time "who is viewing this report right now" — the preferred upgrade path is **Microsoft Fabric Real-Time Intelligence (RTI)**.
|
|
499
|
+
|
|
500
|
+
The design:
|
|
501
|
+
1. Tee the existing BI Pixie Event Hub into a Fabric Eventstream -> Eventhouse `Events` table (new consumer group only — `event_consumer_app` -> ADLS stays untouched).
|
|
502
|
+
2. Backfill history from `bipixielake-{license_key}/events/` via the Fabric "Get data from Azure Storage" TSV wizard.
|
|
503
|
+
3. Replace (or supplement) the Phase-1 server with the **open-source `microsoft-fabric-rti-mcp` server** (`pip install microsoft-fabric-rti-mcp`) pointing at the Eventhouse KQL endpoint — or use the zero-install `api.fabric.microsoft.com/v1/mcp/dataPlane/.../kqlEndpoint` remote MCP endpoint.
|
|
504
|
+
|
|
505
|
+
Because `config.py` abstracts all connection details, the cut-over is a deployment/config change, not a rewrite of the agent-facing tool contract.
|
|
506
|
+
|
|
507
|
+
See `project/ai-next-generation-proposal.md` (Pillar 2, "Engagement-Enriched Fabric Ontology") for strategic context.
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## License
|
|
512
|
+
|
|
513
|
+
Internal tool — not published to PyPI. Part of the BI Pixie platform codebase.
|