MSSQL MCP Server
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., "@MSSQL MCP Serverlist all tables in the database"
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.
MSSQL Model Context Protocol (MCP) Server
A Node.js implementation of the Model Context Protocol server for Microsoft SQL Server. Exposes a configured database (or set of databases) to an MCP client via 11 introspection and query tools, table resources, and guided prompts - over either stdio or Streamable HTTP.
Quick start
npm install
cp .env.example .env # then edit credentials
npm start # stdio transport (Claude Desktop, VS Code, etc.)
npm run start:http # Streamable HTTP transport on :3000 (POST /mcp)By default the server is read-only. Set MSSQL_ENABLE_WRITES=true to opt into execute_write_query.
Related MCP server: Microsoft SQL Server MCP Server
Breaking changes from 2.x
2.x | 3.x |
|
|
|
|
|
|
Bespoke REST API in | MCP Streamable HTTP transport at |
New | Per- |
| + |
- | Prompts: |
Multi-Database Support
Two modes; the server auto-detects from the environment:
Single-database -
MSSQL_*variables, exposed asdbKey="maindb"Multi-database -
MSSQL_<NAME>_*variables, one config per<NAME>(lowercased)
Single-database mode
MSSQL_SERVER=your_sql_server_address
MSSQL_PORT=1433
MSSQL_USER=your_username
MSSQL_PASSWORD=your_password
MSSQL_DATABASE=your_database_name
MSSQL_ENCRYPT=true
MSSQL_TRUST_SERVER_CERTIFICATE=falseMulti-database mode
MSSQL_MAINDB_SERVER=...
MSSQL_MAINDB_USER=...
MSSQL_MAINDB_PASSWORD=...
MSSQL_MAINDB_DATABASE=main_db_name
MSSQL_MAINDB_ENCRYPT=true
MSSQL_MAINDB_TRUST_SERVER_CERTIFICATE=false
MSSQL_REPORTINGDB_SERVER=...
MSSQL_REPORTINGDB_USER=...
MSSQL_REPORTINGDB_PASSWORD=...
MSSQL_REPORTINGDB_DATABASE=reporting_db_name
MSSQL_REPORTINGDB_ENCRYPT=true
MSSQL_REPORTINGDB_TRUST_SERVER_CERTIFICATE=falseCustom names work the same way - MSSQL_ANALYTICS_* exposes dbKey="analytics", etc. Per-database credentials fall back to the global MSSQL_USER / MSSQL_PASSWORD / MSSQL_SERVER if omitted.
Configure either single-database or multi-database variables, not both. If any
MSSQL_<NAME>_DATABASEis present, multi-db wins.
Write opt-in
MSSQL_ENABLE_WRITES=true # enables execute_write_query; defaults to falseWhen disabled, execute_write_query returns an error before any connection attempt. execute_read_query always runs inside a transaction that is rolled back regardless of outcome, so accidental writes inside a "read" query are non-durable.
For real safety, also give the configured DB user only the grants you intend it to have - least privilege is the source of truth, not the tool split.
Environment variables
Consolidated reference. All 2.x variables still work identically - the only additions in 3.x are MSSQL_ENABLE_WRITES and the MSSQL_TEST_* family (integration-script only, never read by the server).
Database connection (used by the MCP server)
Variable | Mode | Required | Default | Notes |
| single | yes |
| Hostname or IP. |
| single | no | mssql default | Coerced to integer. |
| single | yes | - | Login name. |
| single | yes | - | - |
| single | yes | - | Exposed as |
| single | no |
| Set |
| single | no |
| Set |
| multi | no | global | Falls back to |
| multi | no | mssql default | - |
| multi | no | global | Falls back to |
| multi | no | global | Falls back to |
| multi | yes (per DB) | - | Presence of any |
| multi | no |
| - |
| multi | no |
| - |
Server behavior
Variable | Required | Default | Effect |
| no |
| When |
| no |
| HTTP transport only ( |
Integration script (scripts/integration.js, never read by the server)
Variable | Required | Default | Notes |
| no |
| Target SQL Server (Docker, LocalDB, anywhere). |
| no |
| - |
| no |
| - |
| yes | - | The script exits 2 without it. |
Single vs multi: configure either the bare
MSSQL_*variables or the prefixedMSSQL_<NAME>_*variables - not both. If anyMSSQL_<NAME>_DATABASEis present, multi-db mode wins. Your existing 2.x.envcontinues to work unchanged.
Transports
Stdio (default for MCP clients)
npm startRuns src/index.js. Use this from Claude Desktop, VS Code MCP, or any client that spawns the server as a subprocess.
Streamable HTTP
npm run start:http # listens on $PORT (default 3000)Endpoint: POST /mcp (JSON-RPC 2.0). The server runs in stateless mode - every POST gets its own server instance - which is easier to scale and matches the SDK's recommended default. GET /mcp and DELETE /mcp return 405 (no SSE streams in stateless mode).
GET /healthz returns { ok: true } for liveness checks.
Smoke test
curl -sS -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Tool catalog
All tools accept an optional dbKey. In single-database mode the default is maindb; in multi-database mode it's the first key loaded.
Every tool returns both human-readable content (JSON text) and parsed structuredContent (the same payload as a typed object).
Query tools
Tool | Annotations | Notes |
| readOnly, idempotent | Streamed, rollback-only. Server cancels after |
| destructive | Requires |
Catalog (paginated)
Tool | Inputs |
| - |
| optional |
| optional |
| optional |
| optional |
Per-object inspection
Tool | Inputs |
|
|
|
|
|
|
| optional |
Example: execute_read_query
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "execute_read_query",
"arguments": {
"query": "SELECT TOP 5 * FROM dbo.Users",
"dbKey": "maindb",
"limit": 5
}
}
}Result structuredContent:
{
"db": "your_database",
"dbKey": "maindb",
"rowCount": 5,
"totalRowsReturnedByQuery": 5,
"truncated": false,
"recordset": [{ "id": 1, "name": "Item1", "created_at": "2025-01-01" }]
}Resources
The server exposes one resource template:
mssql://<dbKey>@<schema>.<table>/dataReading the resource returns the first 100 rows as CSV with a leading # Database: <name> comment. resources/list enumerates every base table across every configured dbKey (capped at 500 tables per DB to bound the response).
Prompts
Prompt | Args | Purpose |
| optional | Step-by-step instructions for surveying an unknown database. |
|
| Produces a column/index/FK/sample-rows brief on one table. |
Integration with Claude Desktop or VS Code
The package ships an mssql-mcp-node bin, so you can invoke it via npx.
Single-database
{
"servers": {
"mssql-mcp-node": {
"command": "npx",
"args": ["-y", "mssql-mcp-node"],
"env": {
"MSSQL_SERVER": "your_server_name",
"MSSQL_PORT": "1433",
"MSSQL_USER": "your_username",
"MSSQL_PASSWORD": "your_password",
"MSSQL_DATABASE": "your_database",
"MSSQL_ENCRYPT": "true",
"MSSQL_TRUST_SERVER_CERTIFICATE": "false"
}
}
}
}Multi-database
{
"servers": {
"mssql-mcp-node": {
"command": "npx",
"args": ["-y", "mssql-mcp-node"],
"env": {
"MSSQL_MAINDB_SERVER": "your_server_name",
"MSSQL_MAINDB_USER": "your_username",
"MSSQL_MAINDB_PASSWORD": "your_password",
"MSSQL_MAINDB_DATABASE": "main_database",
"MSSQL_MAINDB_ENCRYPT": "true",
"MSSQL_MAINDB_TRUST_SERVER_CERTIFICATE": "false",
"MSSQL_REPORTINGDB_SERVER": "your_server_name",
"MSSQL_REPORTINGDB_USER": "your_username",
"MSSQL_REPORTINGDB_PASSWORD": "your_password",
"MSSQL_REPORTINGDB_DATABASE": "reporting_database",
"MSSQL_REPORTINGDB_ENCRYPT": "true",
"MSSQL_REPORTINGDB_TRUST_SERVER_CERTIFICATE": "false"
}
}
}
}To enable writes, also add "MSSQL_ENABLE_WRITES": "true". Use a dedicated SQL login with the minimum grants the workload needs.
Architecture
src/
├── index.js # stdio entry
├── http.js # Streamable HTTP entry
├── server.js # McpServer factory
├── config.js # env -> validated connection configs
├── validation.js # shared Zod shapes
├── resources.js # ResourceTemplate registration
├── prompts.js # MCP prompts
├── db/
│ ├── pools.js # per-dbKey ConnectionPool cache
│ ├── safety.js # runRead (rollback-only) + runWrite (gated)
│ └── introspection.js # parameterized INFORMATION_SCHEMA / sys.* queries
└── tools/
├── index.js # tool barrel
├── execute-read-query.js
├── execute-write-query.js
├── list-databases.js
├── describe-database.js
├── list-tables.js
├── list-views.js
├── list-indexes.js
├── list-foreign-keys.js
├── list-stored-procedures.js
├── describe-table.js
└── describe-procedure.jsSecurity model
Read isolation -
execute_read_queryand everylist_*/describe_*tool runs inside a transaction that is always rolled back. This is a guardrail against accidental writes (aSELECT ... INTO new_table, an INSERT smuggled past a comment), not a sandbox against an adversarial query: an explicitCOMMIT TRANSACTIONinside the user's SQL ends the outer transaction, and following statements run in autocommit mode. Use a least-privilege SQL login if you need real isolation against intentional misuse.Write opt-in -
execute_write_queryis gated byMSSQL_ENABLE_WRITES=true. When disabled it errors out before a connection is acquired, so no resources are spent and no probing is possible.Parameterized introspection - every
list_*/describe_*SQL uses@paramplaceholders rather than string concatenation; table identifiers are restricted by Zod to/^[a-zA-Z0-9_#$@]+(?:\.[a-zA-Z0-9_#$@]+)?$/(bareUsersor two-partdbo.Users- no spaces, brackets, or three-part names) and bracket-quoted ([schema].[table]) for the CSV resource path. Identifiers with spaces or non-ASCII characters aren't supported by the introspection tools; useexecute_read_querywith raw SQL for those.Cancellation - tool handlers honor the MCP request
AbortSignal; an aborted request firesrequest.cancel()on the underlying mssql request.Least privilege - the safest setup is a SQL login with only
SELECT(andEXECUTEif needed) on the relevant schemas. The MCP layer reinforces that, it doesn't replace it.
Testing
npm testRuns unit tests with the built-in node --test runner. No external DB needed - the suite covers config parsing, validation, identifier escaping, the rollback-only contract, pool caching/retry, parameterized SQL placeholders, and tool registration metadata.
For a manual smoke test against the HTTP transport:
PORT=3000 npm run start:http &
curl -s http://localhost:3000/healthz
curl -s -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'For interactive end-to-end testing against a real database, use the MCP Inspector:
npx @modelcontextprotocol/inspector node src/index.jsReal-DB integration test (disposable)
npm run integration spins up a throwaway database, exercises every tool against real SQL Server, and drops it. The script also covers the streaming-cutoff, rollback-isolation, and SQL-error-cleanup paths (no pool connection left borrowed after a failed read) that the unit tests can only mock.
Easiest setup is a one-shot Docker container:
docker run -d --name mcp-mssql-test \
-e "ACCEPT_EULA=Y" \
-e "MSSQL_SA_PASSWORD=YourStr0ng!Passw0rd" \
-p 1433:1433 \
mcr.microsoft.com/mssql/server:2022-latest
# wait ~10s for SQL Server to initialize, then:
MSSQL_TEST_PASSWORD='YourStr0ng!Passw0rd' npm run integration
# full cleanup:
docker rm -f mcp-mssql-testThe script creates mcp_test_<timestamp> inside the server, seeds it (Users, Orders with FK + index, a view, a stored procedure, 503 rows), runs ~30 tool-level assertions, and drops the database in a finally block - even on failure.
Override targets via MSSQL_TEST_SERVER, MSSQL_TEST_PORT, MSSQL_TEST_USER if you'd rather point it at an existing SQL Server, LocalDB, or Azure SQL.
License
MIT - see LICENSE.
Author
Mihai-Nicolae Dulgheru mihai.dulgheru18@gmail.com
This server cannot be deployed
Maintenance
Related MCP Connectors
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Draxlr's remote MCP server connects AI assistants to your SQL databases and dashboards. Explore schemas, run read-only queries, manage saved queries and dashboards, and export results, all with row-level security so each user sees only their own data.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Ask data questions in natural language. Get SQL, insights, and charts from your databases.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI assistants to interact with Microsoft SQL Server databases through query execution, schema discovery, CRUD operations, stored procedures, and data export with built-in safety controls.18Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to connect and query Microsoft SQL Server databases using natural language, executing read-only SQL queries for safe data inspection and analysis.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to securely interact with Microsoft SQL Server databases to query data, inspect schemas, and retrieve metadata with read-only operations by default and optional write capabilities.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Microsoft SQL Server databases through a standardized interface. Supports executing SQL queries, browsing database schemas, and viewing table data with flexible authentication options for both local and Azure SQL databases.6MIT