A local MCP server for read-only SQL Server / MS Fabric queries. Runs as a single-user process over stdio, authenticated as you (delegated Entra ID identity, not a service principal) — one server process per tenant.
- Python 3.14+ and uv
- Microsoft ODBC Driver 18 for SQL Server installed on your machine
- Either the Azure CLI logged in to the target tenant (
az login --tenant <tenant-id>), or just a browser available — the server falls back to an interactive browser login if there's no CLI session - An Entra ID account in the target tenant with read access to the target database (e.g.
db_datareader)
Each tenant gets its own set of environment variables:
| Variable | Required | Description |
|---|---|---|
MCP_SQL_SERVER_NAME |
yes | SQL Server / Fabric SQL endpoint hostname, e.g. xyz-xyz.datawarehouse.fabric.microsoft.com |
MCP_SQL_DATABASE_NAME |
yes | Default database to connect to |
MCP_AZURE_TENANT_ID |
yes | The Entra ID tenant ID — pins auth to this directory even if your machine has other az login sessions active |
MCP_MAX_ROWS |
no | Max rows returned per tool call (default: 25) |
ODBC_DRIVER |
no | ODBC driver name (default: ODBC Driver 18 for SQL Server) |
The server is a uvx-runnable console script (sql-server-mcp), no
manual install step needed - uvx builds an isolated environment for it
on first run and reuses it afterwards. This repo isn't published anywhere
yet, so point --from at a local checkout or a git URL:
uvx --from /path/to/sql-server-mcp sql-server-mcpOnce published to PyPI (or a private index), this simplifies to
uvx sql-server-mcp directly, with no --from needed.
On startup it checks the ODBC driver is installed, then acquires a token
(via az login if available, otherwise an interactive browser prompt) and
runs over stdio.
One block per tenant:
{
"mcpServers": {
"tenant-a-sql": {
"command": "uvx",
"args": ["--from", "/path/to/sql-server-mcp", "sql-server-mcp"],
"env": {
"MCP_SQL_SERVER_NAME": "tenant-a.datawarehouse.fabric.microsoft.com",
"MCP_SQL_DATABASE_NAME": "wh_silver",
"MCP_AZURE_TENANT_ID": "<tenant-a-tenant-id>"
}
},
"tenant-b-sql": {
"command": "uvx",
"args": ["--from", "/path/to/sql-server-mcp", "sql-server-mcp"],
"env": {
"MCP_SQL_SERVER_NAME": "tenant-b.datawarehouse.fabric.microsoft.com",
"MCP_SQL_DATABASE_NAME": "wh_gold",
"MCP_AZURE_TENANT_ID": "<tenant-b-tenant-id>"
}
}
}
}query(sql)— run a single read-onlySELECT. Table references must be fully qualified asdatabase.schema.table; there's no mutable "active database". Returns at mostMCP_MAX_ROWSrows, as a Markdown table.list_databases()— list user databases with status/metadata.search_schema(target, name, databases?, schema?, use_wildcard?)— search table or column metadata viaINFORMATION_SCHEMAacross one or more databases (all of them ifdatabasesis omitted).export_query(sql, path, format?)— run a single read-onlySELECTand write the full, uncapped result to a local Parquet or CSV file instead of returning it. For large results or when the output feeds into other local tools (pandas, DuckDB, etc.).
uv run pytest # unit tests, no network/DB/Azure required
uv run python scripts/manual_smoke_test.py # real end-to-end check against a live database