msfabric-mcp
by NawafSheikh
README.md
# msfabric-mcp
A Model Context Protocol server for **Microsoft Fabric**, over stdio, in Python.
It gives an agent one connection that reaches both halves of Fabric:
- the **control plane**, through the public REST API at `api.fabric.microsoft.com/v1`
(workspaces, items, lakehouses, warehouses, notebooks, the job scheduler), and
- the **data plane**, through the **SQL analytics endpoint** of a warehouse or
lakehouse, behind an allowlist read-only guard.
Plus optional DAX against a Power BI semantic model.
Read-only by default. Writes are refused unless the operator sets
`FABRIC_ALLOW_WRITES`, and even then `UPDATE` and `DELETE` must carry a `WHERE`.
- Package: `msfabric-mcp` on PyPI
- Repository: <https://github.com/NawafSheikh/fabric-mcp>
- MCP registry name: `io.github.nawafsheikh/msfabric-mcp`
- License: MIT
---
## Honest positioning
Fabric MCP is a crowded shelf as of 2026-08-22. Here is what already exists and
where this one differs. Nothing below is a claim that the others are bad.
| What | Shape | Covers |
|---|---|---|
| **Fabric Core MCP Server** (Microsoft, preview) | remote, hosted by Microsoft, `com.microsoft/microsoft-fabric` in the MCP registry | ~30 control-plane tools: workspaces, items, folders, capacities, OneLake catalog search, item definitions, long-running operations. No T-SQL execution, no notebook job run, no DAX. ([docs](https://learn.microsoft.com/rest/api/fabric/articles/mcp-servers/core-remote/tools-core-mcp-server)) |
| **Power BI remote MCP server** (Microsoft, preview) | remote | report and semantic-model metadata, and DAX **generation** through Copilot (consumes Copilot capacity). ([docs](https://learn.microsoft.com/power-bi/developer/mcp/remote-mcp-server-get-started)) |
| **microsoft/fabric-rti-mcp** | local, open source | Real-Time Intelligence: Eventhouse and Azure Data Explorer, KQL. A different workload from lakehouse and warehouse T-SQL. ([repo](https://github.com/microsoft/fabric-rti-mcp)) |
| **`fabric-lakehouse-mcp`**, **`microsoft-fabric-mcp`** on PyPI, plus community servers such as `santhoshravindran7/Fabric-Analytics-MCP`, `Augustab/microsoft_fabric_mcp`, `sdebruyn/fabric-dw-mcp-cli` | local, open source | overlapping ground, each with its own slice |
| **`fabric-mcp`** on PyPI and npm | unrelated | that is the *other* Fabric, the `danielmiessler/fabric` prompt framework. This package deliberately does not use that name. |
Where `msfabric-mcp` sits:
1. **One server across both planes.** Microsoft's Core MCP server is control
plane only; you still need a second thing to run a query. Here, `list_items`
and `run_sql` live in the same process and the same credential.
2. **Local stdio, no preview enrollment.** The Microsoft servers are remote and
in preview. This runs on your machine against the generally available REST
API, so it works in any tenant you can already sign in to.
3. **The guard is the product.** `run_sql` is an allowlist, not a blocklist:
a statement runs only when it is positively classified as a read (or as a
permitted write with writes enabled). Comments are stripped first, statement
batches are refused, and procedure execution, `OPENROWSET`/`OPENQUERY`,
`GRANT`/`REVOKE`, `BACKUP`/`RESTORE` and `SHUTDOWN` are refused in every mode.
4. **Bounded output.** Every result set is capped in rows and in cell width, and
says when it truncated, so a wide `SELECT *` cannot flood a context window.
If you only need control-plane browsing inside a tenant that has the preview
enabled, use Microsoft's Core MCP server; it is first-party and will always
track the API faster. Use this one when you want SQL and jobs in the same
server, locally, with a hard read-only default.
---
## Install
```bash
pip install msfabric-mcp
```
SQL access needs a driver. Pick one:
```bash
pip install "msfabric-mcp[sql]" # pyodbc, plus ODBC Driver 18 for SQL Server
pip install "msfabric-mcp[mssql]" # mssql-python, no external ODBC manager
```
- **pyodbc** needs [ODBC Driver 18 for SQL Server](https://learn.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server)
installed separately (17 also works). The Entra token is passed with the
`SQL_COPT_SS_ACCESS_TOKEN` connection attribute (1256).
- **mssql-python** is Microsoft's own driver, needs Python 3.10+, installs its
connectivity layer with the wheel, and
[supports Fabric Data Warehouse and the Lakehouse SQL analytics endpoint](https://learn.microsoft.com/sql/connect/python/mssql-python/support-lifecycle).
The REST tools need neither driver. You can run the server with no SQL
configuration at all and still browse workspaces, items and jobs.
Requires Python 3.11 or later.
---
## Configure
Everything comes from environment variables. Nothing about a tenant, workspace,
warehouse or host is compiled into the package. See `.env.example`.
### Authentication
Three modes, all built on [`azure-identity`](https://learn.microsoft.com/python/api/overview/azure/identity-readme).
**1. `DefaultAzureCredential` (the default).** Set nothing. The credential chain
picks up an `az login` session, a VS Code sign-in, a managed identity, or the
standard `AZURE_CLIENT_ID` / `AZURE_TENANT_ID` / `AZURE_CLIENT_SECRET`
environment service principal.
```bash
az login
```
**2. Service principal.** Set all three and the mode is inferred:
| Variable | Meaning |
|---|---|
| `FABRIC_TENANT_ID` | directory (tenant) id |
| `FABRIC_CLIENT_ID` | application (client) id |
| `FABRIC_CLIENT_SECRET` | client secret |
The service principal must be added to the workspace with Admin, Member or
Contributor, and the tenant setting **Service principals can call Fabric public
APIs** must be on.
**3. Device code**, for a headless box or an SSH session:
```bash
FABRIC_AUTH_MODE=device_code
FABRIC_CLIENT_ID=<a public client app registration>
```
Tokens are cached in memory per scope and refreshed two minutes before expiry.
They are never written to disk, never logged, and never appear in any error
message the server returns.
### Scope and SQL
| Variable | Default | Meaning |
|---|---|---|
| `FABRIC_WORKSPACE_ID` | unset | default workspace, so tools need not repeat it. Optional: every tool also takes `workspace`. |
| `FABRIC_SQL_ENDPOINT` | unset | SQL analytics endpoint **host only**, no protocol. Found on the warehouse or lakehouse settings page. Optional: without it the SQL tools explain that they are not configured and the REST tools still work. |
| `FABRIC_SQL_DATABASE` | unset | default warehouse or lakehouse name |
| `FABRIC_SQL_DRIVER` | `auto` | `auto`, `pyodbc`, or `mssql_python` |
### Safety
| Variable | Default | Meaning |
|---|---|---|
| `FABRIC_ALLOW_WRITES` | `0` | **off**. While off, every write statement is refused with an explanation. Turn it on only for a workspace you are willing to change. |
| `FABRIC_MAX_ROWS` | `200` | rows returned per result set, capped at 5000 |
| `FABRIC_MAX_CELL_CHARS` | `200` | characters per cell, capped at 4000 |
No secret is ever printed. `health` reports *whether* a tenant id, client id and
secret are configured, never their values, and error messages carry an exception
class and a short service detail with the query string stripped.
### Client configuration
Claude Desktop, Claude Code, or any stdio MCP client:
```json
{
"mcpServers": {
"fabric": {
"command": "msfabric-mcp",
"env": {
"FABRIC_WORKSPACE_ID": "00000000-0000-0000-0000-000000000000",
"FABRIC_SQL_ENDPOINT": "your-endpoint.datawarehouse.fabric.microsoft.com",
"FABRIC_SQL_DATABASE": "your_warehouse"
}
}
}
}
```
Do not put `FABRIC_CLIENT_SECRET` in a config file that lives in a repository.
Use `az login`, a managed identity, or a secret manager that injects the
variable into the server process.
---
## Tools
| Tool | Reaches | What it does |
|---|---|---|
| `list_workspaces(name_filter?)` | REST | workspaces visible to the identity |
| `list_items(workspace?, item_type?, name_filter?)` | REST | items in a workspace, filtered by Fabric item type |
| `get_item(item_id, workspace?)` | REST | one item's metadata |
| `list_lakehouses(workspace?)` | REST | lakehouses |
| `list_warehouses(workspace?)` | REST | warehouses |
| `list_notebooks(workspace?)` | REST | notebooks |
| `list_tables(lakehouse?, database?, workspace?)` | REST or SQL | lakehouse tables via the [Tables API](https://learn.microsoft.com/rest/api/fabric/lakehouse/tables), or `INFORMATION_SCHEMA.TABLES` over the SQL endpoint |
| `describe_table(table, schema?, database?)` | SQL | columns, types, nullability, ordinal, from `INFORMATION_SCHEMA.COLUMNS`, parameterised |
| `run_sql(sql, database?)` | SQL | one guarded statement |
| `run_notebook(notebook, workspace?, parameters?)` | REST | starts a `RunNotebook` job, returns the job instance id, does not block |
| `get_job_status(item_id, job_instance_id, workspace?)` | REST | status, timings, failure reason |
| `execute_dax(dataset_id, query_text, workspace?)` | Power BI | a DAX `EVALUATE` query, optional |
| `health()` | both | configuration summary and a reachability probe |
Notebook and lakehouse arguments accept either a **display name or an id**; a
name is resolved through `list_items` on the fly.
### The SQL guard, precisely
`run_sql` accepts **one** statement per call, with comments stripped before any
decision is made. Then:
- Starts with `SELECT` or `WITH`, and contains no `SELECT ... INTO` or
`FOR UPDATE`: classified **read**, always allowed.
- Starts with `INSERT`, `UPDATE`, `DELETE`, `MERGE`, `CREATE`, `ALTER`, `DROP`,
`TRUNCATE`, or is a `SELECT ... INTO`: classified **write**. Refused unless
`FABRIC_ALLOW_WRITES` is set. `UPDATE` and `DELETE` additionally require a
`WHERE` clause even when writes are enabled.
- Anything else: refused, because it matched neither shape.
- `EXEC`/`EXECUTE`, `sp_*`, `xp_*`, `OPENROWSET`, `OPENDATASOURCE`, `OPENQUERY`,
`BULK INSERT`, `GRANT`, `REVOKE`, `DENY`, `BACKUP`, `RESTORE`, `SHUTDOWN`,
`RECONFIGURE`: refused in **every** mode.
- Multiple statements separated by `;`: refused, so each one can be judged alone.
Table and schema names supplied to `describe_table` are validated as plain
identifiers and the lookup itself is parameterised, so a name cannot carry SQL.
This is a guard against an agent's mistakes, not a substitute for permissions.
Grant the identity the least access it needs; the workspace role and the
warehouse's own object permissions remain the real boundary.
### Notes on `execute_dax`
Uses the JSON [`executeQueries`](https://learn.microsoft.com/rest/api/power-bi/datasets/execute-queries)
endpoint rather than the newer Arrow `executeDaxQueries`, because
`executeQueries` works on Pro, PPU and Premium/Fabric capacities and needs no
Arrow library. Its documented ceiling is 100,000 rows and 1,000,000 values per
query; `FABRIC_MAX_ROWS` applies on top of that. The tenant setting **Dataset
Execute Queries REST API** must be enabled, and the caller needs Build
permission on the semantic model. Only `EVALUATE` and `DEFINE` queries are
accepted.
---
## What it touches
- Outbound HTTPS to `api.fabric.microsoft.com`, `api.powerbi.com`, and Microsoft
Entra for tokens.
- Outbound TDS on 1433 to your SQL analytics endpoint, only when a SQL tool is
called and `FABRIC_SQL_ENDPOINT` is set. `Encrypt=yes`,
`TrustServerCertificate=no`.
- No local filesystem writes. No telemetry. No third-party service.
---
## Develop
```bash
git clone https://github.com/NawafSheikh/fabric-mcp
cd fabric-mcp
pip install -e ".[dev]"
pytest
python -m build
```
The whole test suite runs with no network, no Fabric tenant, and no ODBC driver
installed: REST calls go through an `httpx.MockTransport`, and the SQL layer
takes an injectable connection factory that the tests fill with a fake DB-API
connection.
## Contributing
Issues and pull requests welcome at
<https://github.com/NawafSheikh/fabric-mcp/issues>.
## Sources
Checked 2026-08-22.
- [Fabric REST API: Items](https://learn.microsoft.com/rest/api/fabric/core/items)
- [Fabric REST API: Workspaces](https://learn.microsoft.com/rest/api/fabric/core/workspaces/list-workspaces)
- [Fabric REST API: Job Scheduler](https://learn.microsoft.com/rest/api/fabric/core/job-scheduler)
- [Manage and execute notebooks in Fabric with APIs](https://learn.microsoft.com/fabric/data-engineering/notebook-public-api)
- [Manage a lakehouse with the REST API (List Tables)](https://learn.microsoft.com/fabric/data-engineering/lakehouse-api)
- [OneLake catalog and Fabric REST APIs](https://learn.microsoft.com/rest/api/fabric/articles/onelakecatalog/overview)
- [mssql-python support lifecycle (Fabric endpoints)](https://learn.microsoft.com/sql/connect/python/mssql-python/support-lifecycle)
- [Microsoft Python Driver for SQL Server](https://learn.microsoft.com/sql/connect/python/mssql-python/python-sql-driver-mssql-python)
- [Azure Identity client library for Python](https://learn.microsoft.com/python/api/overview/azure/identity-readme)
- [Power BI: Execute Queries](https://learn.microsoft.com/rest/api/power-bi/datasets/execute-queries)
- [Power BI: Execute DAX Queries (Arrow) overview](https://learn.microsoft.com/power-bi/developer/execute-dax-queries-arrow/overview)
- [Fabric Core MCP Server tools reference](https://learn.microsoft.com/rest/api/fabric/articles/mcp-servers/core-remote/tools-core-mcp-server)
- [Remote Power BI MCP server](https://learn.microsoft.com/power-bi/developer/mcp/remote-mcp-server-get-started)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues