sql-server-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@sql-server-mcpshow me the top 10 rows from sales.dbo.orders"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
sql-server-mcp
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.
Prerequisites
Python 3.14+ and uv
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 sessionAn Entra ID account in the target tenant with read access to the target database (e.g.
db_datareader)
Related MCP server: powerbi-mcp-proxy
Configuration
Each tenant gets its own set of environment variables:
Variable | Required | Description |
| yes | SQL Server / Fabric SQL endpoint hostname, e.g. |
| yes | Default database to connect to |
| yes, unless using SQL login | The Entra ID tenant ID — pins auth to this directory even if your machine has other |
| no | SQL login username. If set, the server uses username + password authentication instead of Entra ID (and |
| with username | SQL login password. Must be set together with |
| no | Set to |
| no | Set to |
| no | Max rows returned per tool call (default: 25) |
Running it
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:
uvx sql-server-mcpTo run from a local checkout instead (e.g. during development), point
--from at the path:
uvx --from /path/to/sql-server-mcp sql-server-mcpOn startup it acquires a token (via az login if available, otherwise an
interactive browser prompt) and runs over stdio. Database connectivity uses
mssql-python, which bundles
its own driver — no separate ODBC driver install is required.
Example MCP client config
One block per tenant:
{
"mcpServers": {
"tenant-a-sql": {
"command": "uvx",
"args": ["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": ["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>"
}
}
}
}Tools
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.).
Development
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 databaseAvailable Tools
4 toolsexport_queryA
Execute a single read-only SELECT statement and write the full, uncapped result to a local Parquet or CSV file instead of returning it. Use this instead of query for large results or when the output will be processed by other local tools.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| path | Yes | ||
| format | No | parquet |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden well: read-only, single statement, uncapped result, and that the result is written to a local file rather than returned. It stops short of stating whether an existing file at `path` is overwritten, whether directories are created, or what happens on write failure — meaningful gaps for a file-writing tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, both load-bearing: the first defines the operation and its scope, the second handles routing. The key differentiator (file output, uncapped) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is unnecessary, and the description covers the unconventional part — that output goes to a file. Only file-collision/overwrite semantics and path expectations are missing, which is a modest gap given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It does partially: `sql` is constrained to a single read-only SELECT, and the output is a 'local' file in Parquet or CSV. But it never clarifies default format handling, whether `path` must be an existing directory, or expected path style, leaving the non-`sql` parameters thin.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb chain (execute a SELECT, write result to file) and an explicit scope ('single read-only SELECT', 'full, uncapped result'). It also names the sibling tool `query` and the condition that distinguishes the two, so the agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent to use this instead of `query` for large results or when output feeds other local tools, giving both the when and the alternative. No inference is required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_databasesA
List all user databases with status and metadata. Returns at most 25 rows.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations at all, the description carries the full burden, and it does disclose one valuable behavioral trait: results are capped at 25 rows. However, it says nothing about whether that cap means silent truncation, whether ordering is stable, or what access level is required, so a mutation-free read is only implied by 'List'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, with the resource scope leading and the result-size limit front-loaded immediately after. Nothing is repeated from the schema or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and with zero parameters there is little else to specify. The one remaining gap is that the 25-row cap is stated without explaining what an agent should do when it is hit, but given the tool has no pagination parameters this is a minor omission.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate beyond what the empty schema already shows. Baseline 4 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List all user databases') plus the payload ('status and metadata'), and the 'user' qualifier signals a scope boundary. It does not name or distinguish itself from siblings like search_schema or query, so an agent must infer that this is the inventory entry point rather than a content-retrieval tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance and no alternatives named; the agent is not told to call this before search_schema or query, nor when to prefer those instead. Usage is only implied by the word 'List'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryA
Execute a single read-only SELECT statement. Returns at most 25 rows. Table references must be fully qualified as database.schema.table - there is no mutable 'active database'.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose two operationally critical traits: results are truncated at 25 rows, and there is no mutable 'active database' so every table must be fully qualified. It omits timeout, permission, and error behavior, keeping it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the operation and its limits, then the qualification rule. Nothing is padded or redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with an output schema covering return values, the description supplies the essential constraints (read-only, single statement, row cap, qualification rule). Minor gaps remain around error/failure behavior, but nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single `sql` parameter has 0% schema description coverage, so the description must compensate. It does meaningfully: the value must be one read-only SELECT and must reference tables as database.schema.table, which is syntax the schema itself does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Execute a single read-only SELECT statement') with a clear read-only constraint and row cap. It implicitly separates this from export_query by capping results at 25 rows, but never explicitly names the sibling or contrasts with it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The read-only/single-statement/25-row constraints imply when this tool is inappropriate (large extracts), but the agent must infer that export_query is the alternative. No explicit when-to-use vs when-not-to-use routing is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_schemaB
Search table or column metadata across databases via INFORMATION_SCHEMA. Omit databases to search every database on the server. Returns at most 25 rows.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| schema | No | ||
| target | Yes | ||
| databases | No | ||
| use_wildcard | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose one genuinely important trait: results are capped at 25 rows. However, it does not say whether that cap is truncation (with more results available) or a hard limit, nor does it confirm read-only behavior beyond the implication of 'Search' and INFORMATION_SCHEMA.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what the tool does, followed by the scoping behavior and the result cap. Every sentence adds information and none is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. But for a five-parameter search tool with zero schema coverage, leaving `use_wildcard` and `schema` unexplained is a real gap an agent must guess around.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across five parameters, so the description must compensate. It explains `databases` (omit = all databases) and loosely maps to `target` and `name`, but `schema` and especially `use_wildcard` (defaulting to true, which materially changes matching behavior) are left entirely undocumented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: searching table/column metadata via INFORMATION_SCHEMA. This is clearly distinguishable from siblings like query or export_query, which operate on data rather than metadata. It falls short of a 5 only because it never names the sibling it displaces.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Omit `databases` to search every database on the server' gives one operational hint, but there is no guidance on when to choose this over query or list_databases. An agent must infer that this is the metadata-discovery tool rather than the data-retrieval tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.5.2- First observed
export_query - First observed
list_databases - First observed
query - First observed
search_schema
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: `query` for capped inline SELECTs, `export_query` for uncapped file output, `list_databases` for database enumeration, and `search_schema` for metadata lookup. The `query` vs `export_query` overlap is explicitly resolved by the description telling agents to prefer `export_query` for large results.
Three tools follow a clear verb_noun pattern (`list_databases`, `search_schema`, `export_query`), while `query` is a bare verb/noun that slightly breaks the pattern. The deviation is minor and still readable in context.
Four tools is well-scoped for a read-only SQL server interface, with each tool covering a distinct essential workflow: querying, exporting, listing databases, and searching schema metadata. Nothing feels redundant or missing at the count level.
The surface covers core read-only workflows well, including capped queries, large exports, database listing, and schema discovery via INFORMATION_SCHEMA. Minor gaps exist around dedicated table listing or describe-table convenience tools, but `search_schema` provides a workable path for those needs.
Maintenance
Related MCP Connectors
Official Microsoft MCP Server to query Microsoft Entra data using natural language
Hosted SQL Server MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Text-to-SQL MCP server: read-only queries on PostgreSQL, MySQL and SQL Server with your real schema
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceRead-only MCP server for SQL databases (SQL Server, Postgres, SQLite) with multi-server support and three-layer safety using AST validation and linting.MIT
- AlicenseNot gradedqualityDmaintenanceA 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.2MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for reading and analyzing Fabric semantic models. Supports getting model definitions and executing DAX queries against Power BI datasets.17-
- AlicenseNot gradedqualityAmaintenanceMCP server for safely exposing SQL Server database capabilities to LLM clients, with read-only mode, security features, and observability.29MIT