stdio MCP server for Microsoft SQL Server.
- Connects to one SQL Server instance using credentials from
.env - Supports multiple named SQL Server connections in one MCP server
- Executes queries against different databases by passing
databaseon eachquerycall - Executes confirmed write/admin statements through a separate
write_querytool - Reads full SQL object definitions in chunks with
get_object_definition - Keeps
queryread-only and requires explicit confirmation on everywrite_querycall - Returns short text plus structured JSON responses for every MCP tool
- Node.js 20+
- Reachable Microsoft SQL Server
- Copy
.env.exampleto.env - Fill in either single-connection variables or multi-connection variables from
.env.example - Install dependencies with
npm install - Start in dev mode with
npm run devor build withnpm run build && npm start
- Run
docker compose up -d - Wait until
ms-mcp-mssqlbecomes healthy andmssql-initexits successfully - Copy
.env.exampleto.envand set:MSSQL_SERVER=localhostMSSQL_PORT=1433MSSQL_USER=saMSSQL_PASSWORD=YourStrong!Passw0rd
- Start the server with
npm run dev
This seeds AppDb and ReportingDb for multi-db smoke checks.
MSSQL_SERVER: SQL Server host or instance addressMSSQL_PORT: SQL Server port, default1433MSSQL_DOMAIN: optional Windows domain for NTLM login, for exampleEXAMPLEMSSQL_USER: login nameMSSQL_PASSWORD: login passwordMSSQL_ALLOW_WRITE:falseby default; settrueonly for connections that may be used bywrite_queryMSSQL_ENCRYPT: TLS encryption flag, defaulttrueMSSQL_TRUST_SERVER_CERTIFICATE: trust server certificate, defaultfalseMSSQL_CONNECTION_TIMEOUT_MS: connection timeout, default15000MSSQL_REQUEST_TIMEOUT_MS: request timeout, default30000MSSQL_MAX_ROWS: maximum returned rows before truncation, default1000MSSQL_MAX_RESULT_BYTES: maximum JSON payload size for returned rows, default1048576
Multi-connection mode:
MSSQL_CONNECTION_NAMES: comma-separated connection names, for exampledefault,reportingMSSQL_DEFAULT_CONNECTION: optional default connection name used when tool input omitsconnection- Per-connection variables use
MSSQL_<NAME>_..., for exampleMSSQL_DEFAULT_SERVERorMSSQL_REPORTING_DOMAIN - Connection names are normalized to env keys by replacing non-alphanumeric characters with
_and uppercasing
Checks connectivity to SQL Server and whether database listing is available.
Input accepts optional connection and optional database.
If database is provided, healthcheck also verifies that the selected connection can open that specific database, not just master.
Example:
{
"connection": "reporting",
"database": "Orchestrator"
}Returns configured connection names so clients can discover them without guessing. No input is required.
Returns databases from sys.databases with name, isSystemDatabase, isAccessible.
Input accepts optional connection.
Read-only tool. It accepts only SELECT and WITH statements, even on write-enabled connections.
Input:
{
"connection": "reporting",
"database": "MyDb",
"sql": "select * from Users where Id = @id",
"params": [
{ "name": "id", "type": "Int", "value": 42 }
]
}Successful structuredContent envelope:
{
"ok": true,
"code": "ok",
"message": "Query executed successfully",
"data": {
"rows": [],
"rowCount": 0,
"rowsAffected": [],
"columns": [],
"recordsets": 1,
"truncated": false
},
"meta": {
"server": "mssql.example.local",
"database": "MyDb",
"executionTimeMs": 12,
"writeEnabled": false
}
}Error envelope example:
{
"ok": false,
"code": "write_blocked",
"message": "Only SELECT or WITH queries are allowed in safe mode",
"details": {
"detectedCommand": "INSERT"
}
}Write/admin tool. It only works on connections where MSSQL_ALLOW_WRITE=true, requires explicit per-call confirmation, and only accepts a single statement.
Input:
{
"connection": "default",
"database": "sample_db",
"sql": "ALTER FUNCTION dbo.msg(@msg nvarchar(max)) RETURNS varchar(max) AS BEGIN RETURN @msg END",
"confirm": true
}If confirm is missing or false, the tool rejects the call without sending SQL to the server.
Reads a stored procedure, view, function, or trigger definition from sys.sql_modules.
Useful when query result formatting is too compact for large object bodies.
Input:
{
"connection": "reporting",
"database": "MyDb",
"schema": "dbo",
"object_name": "usp_DoWork",
"offset": 1,
"limit": 12000
}Notes:
offsetis a 1-based character offset in the definition textlimitis the maximum number of returned characters, up to50000- Use
nextOffsetfrom the response to fetch the next chunk for large procedures
query always stays read-only and only allows statements that start with SELECT or WITH.
write_query is available for connections with MSSQL_ALLOW_WRITE=true, but every call must include confirm=true and is limited to a single SQL statement.
Example:
{
"connection": "default",
"database": "sample_db",
"sql": "ALTER FUNCTION dbo.msg(@msg nvarchar(max)) RETURNS varchar(max) AS BEGIN RETURN @msg END",
"confirm": true
}Both tools block batches and known unsafe patterns when they do not match the tool's purpose.
This is a practical safeguard, not a full SQL sandbox.
- Run unit tests with
npm test - Run integration tests against Docker MSSQL with
npm run test:integration - Run TypeScript build with
npm run build
test:integration is opt-in and expects Docker MSSQL to be up with seeded databases from docker compose up -d.
See docs/mcp-client-config.md for Claude Desktop, Cursor, and OpenCode examples.