MCP SQL Server
Enables deployment of the MCP server using Docker containers, with configuration via environment variables and docker-compose for simplified setup and management.
Supports configuration through environment variables loaded from .env files, allowing customization of connection settings, security parameters, timeouts, and caching behavior.
Provides access to the repository for cloning and installation, with documentation and setup instructions accessible through GitHub.
Integrates structured logging through the pino logger, with configurable log levels for detailed application monitoring and troubleshooting.
Supports development using TypeScript, with type-safety and compilation features for robust server implementation and monitoring of code changes during development.
Provides an XML-based interface for submitting queries, executing stored procedures, and exploring database schemas when interacting with the 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., "@MCP SQL Servershow me the top 10 customers by total purchase amount"
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.
MCP MSSQL Server
This is a Model Context Protocol (MCP) server for SQL Server interactions. It allows Large Language Models (LLMs) to execute SQL queries, run stored procedures, and explore database schemas with enhanced security and robustness.
Features
Read-Only SQL Query Execution: Run single-statement
SELECTqueries against SQL Server databases. Every query is validated and then run inside a transaction that is always rolled back. Results are streamed and paged, so only the requested page is held in memory.Allow-Listed Stored Procedures: Execute stored procedures named in
SQL_ALLOWED_PROCEDURES, with typed input and output parameters. Without an allow-list the tool is not offered at all.Schema Exploration: View tables and views with their columns, primary keys and foreign keys, with results cached for performance.
Robust Connection Management: One connection pool per database, created on first use and reused across calls, with configurable retry logic and timeouts. The server starts answering MCP requests without waiting for the database.
Enhanced Security:
T-SQL-aware validation that accepts exactly one
SELECT(orWITH ... SELECT) statement.Every query and procedure call runs in a transaction that is always rolled back.
SQL_ALLOWED_DATABASESenvironment variable to whitelist accessible databases, including 3-part names inside queries.SQL_ALLOWED_PROCEDURESallow-list for stored procedures.
Configurable Caching: Database schema information is cached with a configurable Time-To-Live (TTL).
Structured Logging: Integrated
pinologger for detailed and structured application logs.Docker Ready: Simple deployment with Docker.
Related MCP server: SQL Server MCP
Quick Start
Using Docker (Recommended)
# Clone the repository (if you haven't already)
git clone https://github.com/JubinSaniei/mcp-mssql
# cd mcp-mssql
# Copy example configuration and edit with your settings
cp .env.example .env
nano .env # Edit with your SQL Server details and other configurations
# Start the Docker container
docker-compose up -dFor complete Docker setup instructions, see the Docker README.
Configuration
The server is configured using environment variables, read and validated by config.ts. The server does not read a .env file itself: Docker Compose loads .env from the project root, and when running locally you can pass it with node --env-file=.env dist/server.js (you can start from .env.example).
Numbers must be whole numbers within their allowed range; an invalid value (for example SQL_PORT=abc) stops the server at startup with a message naming the variable. An unset or empty variable takes its default.
For a detailed guide on all configuration options and how to set them up, please see CONFIG.
Category | Variable | Description | Default (from config.ts) |
Connection |
| SQL Server hostname or IP |
|
| SQL Server port |
| |
| SQL Server username |
| |
| SQL Server password |
| |
| Default database name to connect to |
| |
Security |
| Encrypt the connection; only the value |
|
| Trust the server certificate; only the value |
| |
| Comma-separated list of databases the server is allowed to access. If empty, access is less restricted (relies on DB user permissions). |
| |
| Comma-separated list of stored procedures |
| |
Results |
| Maximum rows returned per result set |
|
Timeouts & Retries |
| Connection timeout (ms) |
|
| Request timeout for queries (ms) |
| |
| Connection attempts per pool connect |
| |
| Initial delay (ms) before retrying a failed connection |
| |
| Maximum delay (ms) between connection retries (exponential backoff) | 10 × | |
Connection Pool |
| Max connections in each pool |
|
| Min connections in each pool (must not exceed |
| |
| Idle timeout for connections in a pool (ms) |
| |
Caching |
| Time-To-Live for schema cache (ms) |
|
Logging |
| Log level for the pino logger: |
|
The MCP server name (mssql-mcp) is fixed, and its version is read from package.json.
Using with Claude
To add this MCP server to Claude CLI:
# Add the MCP server using the config file
claude mcp add-json mssql-mcp "$(cat claude-mcp-config.json)"
# To add it globally
claude mcp add-json -s user mssql-mcp "$(cat claude-mcp-config.json)"
# Start a conversation with Claude using this MCP
claude mcp mssql-mcpIn the Claude conversation, you can:
Execute
SELECTqueries:<mcp:execute_query database="YourDatabaseName"> SELECT TOP 10 * FROM YourTable </mcp:execute_query>(The
databaseattribute is optional if operating on the defaultSQL_DATABASEor ifSQL_ALLOWED_DATABASESimplies a single choice.)Execute stored procedures (only available when
SQL_ALLOWED_PROCEDURESis set, and only for the procedures it lists):<mcp:execute_stored_procedure database="YourDatabaseName"> { "procedure": "YourSchema.YourProcedureName", "parameters": [ {"name": "Param1", "type": "nvarchar", "length": 50, "value": "SomeValue"}, {"name": "Param2", "type": "decimal", "precision": 18, "scale": 2, "value": 12.5}, {"name": "Total", "type": "int", "direction": "out"} ] } </mcp:execute_stored_procedure>The procedure name must be schema-qualified.
typemust be a SQL Server type name (case-insensitive); unknown types are rejected. Output parameter values are returned inoutputParameters.Explore database schema:
<mcp:schema> YourDatabaseName </mcp:schema>(If
YourDatabaseNameis omitted, it defaults to theSQL_DATABASEspecified in the environment variables.)
Connection Handling
The DatabaseService keeps one mssql connection pool per database, keyed case-insensitively by database name.
Efficiency: Each pool is created on first use and reused by later calls to the same database. Pools for databases other than
SQL_DATABASEare closed after 10 minutes without use.Startup: The MCP transport starts first; the default pool connects in the background. If the database is down, the server still starts, and tool calls return a connection error (
errorType: "ConnectionError") until it is reachable again.Resilience: Connecting retries with exponential backoff (
SQL_RETRY_*); concurrent calls share one connection attempt. A rejected login is not retried. A pool whose connection is lost (ESOCKET/ECONNCLOSED) is replaced on the next call; the failed call itself is not retried.Cancellation: When the MCP client cancels a call, the running SQL is cancelled and its transaction rolled back.
No Session State Across Calls: Each call runs in its own rolled-back transaction on whichever pooled connection is free, so temporary tables or session variables created in one call are not available in another.
Results and Errors
Results are compact JSON. Binary values are returned as
0x...hex strings (truncated after 64 bytes, with the full length noted), andbigintvalues as strings.Date and time values, in result sets and in stored procedure output parameters, are returned as their exact SQL text, with as many fractional-second digits as the column's declared scale. They never depend on the server's time zone:
Type
Example
date"2026-10-01"time(n)"13:45:00.1234567"(time(0):"13:45:00")datetime2(n)"2026-10-01T12:34:56.1234567"(noZ, no offset)datetimeoffset(n)"2026-10-01T12:34:56.1234567+05:30"(the stored offset)datetime"2026-10-01T12:34:56.123"smalldatetime"2026-10-01T12:34:00"The
mssql/tediousdriver drops the offset ofdatetimeoffsetvalues. To keep it, the server wraps the driver's internal value reader (tedious/lib/value-parser.js) at startup, after a self-check confirms that the wrapper recovers known offsets. If the self-check fails (for example after atediousupgrade changes that internal module), the server logs a warning, anddatetimeoffsetvalues are returned as the same instant in UTC, e.g."2026-10-01T07:04:56.1234567+00:00". The tool descriptions say which mode is active.A date/time value inside a
sql_variantcolumn is returned as date-and-time text with trailing fractional zeros removed, e.g."2026-10-01T12:34:56.5". The driver does not report the base type or scale of a variant, so adatevalue appears as"2026-10-01T00:00:00"and atimevalue as"1970-01-01T13:45:00". Adatetimeoffsetvalue keeps its stored offset and is returned as its local time plus that offset, e.g."2026-10-01T07:18:20+05:30". If the self-check has failed (utc-fallbackmode), a variantdatetimeoffsetcannot be told apart from adatetime2: it is returned as its UTC time with no offset marker, e.g."2026-10-01T01:48:20".execute_queryreturnsrecordsets(each withcolumns, positionalrows,recordCount,hasMoreand, when there are more rows,nextOffset) andpagination(offset,limit,hasMore,nextOffset,returnedRowCount).limitdefaults toSQL_MAX_ROWS, and larger values are capped at it. Each page re-runs the query, so useORDER BYfor stable pages.execute_stored_procedurereturnsrecordsets(each capped atSQL_MAX_ROWSrows;hasMoremarks a capped result set),outputParameters,returnValueandrowsAffected.Errors are returned as
{ "error", "errorType", "code", "sqlErrorNumber" };codeis the driver error code (e.g.ETIMEOUT,ESOCKET,EREQUEST) andsqlErrorNumberthe SQL Server error number, when present. Query timeouts are reported asQueryTimeout, connection timeouts asConnectionTimeout, and client cancellations asCancelled. Stack traces stay in the server log.
Development
Local Development Setup
# Install dependencies
npm install
# Create and configure your .env file
cp .env.example .env
nano .env
# Run the server from source with tsx (`npm run dev` does the same; environment variables must be set)
npm start
# Or build and run the compiled server
npm run build
node --env-file=.env dist/server.js
# Checks
npm run typecheck # tsc --noEmit
npm run lint # ESLint
npm test # vitestSecurity Notes
Read-only guarantees
Single-statement
SELECTvalidation:execute_queryaccepts exactly one statement, and it must start withSELECTorWITH. The query is tokenised with T-SQL rules ('...'strings with''escapes,N'...',[...]and"..."identifiers,--and nested/* */comments), so keywords inside strings, comments or bracketed names are ignored, and a second statement can't be hidden inside something that only looks like a string. Statement separators,GO, and keywords such asINSERT,UPDATE,DELETE,MERGE,EXEC,INTO,OPENQUERY,OPENROWSET,WAITFOR,DECLAREorSETare rejected. The query must also parse as a singleSELECT.Always rolled back: every
execute_querycall, and every allowed stored procedure call, runs asBEGIN TRANSACTION→ statement →ROLLBACK, whether the statement succeeds, fails, is cut off once the requested page is full, or is cancelled by the client. Any change a transaction can undo is discarded, and the connection goes back to the pool with no open transaction; if the rollback itself fails, that connection is closed and its pool replaced. Actions a transaction can't undo, such as some system procedures, linked-server calls orBACKUP, are not covered by this backstop.Procedures are allow-list only:
execute_stored_procedureruns only the procedures named inSQL_ALLOWED_PROCEDURES. Names must be schema-qualified (schema.procor[schema].[proc]) and are compared case-insensitively; an unqualified name is rejected, because SQL Server would resolve it against the caller's default schema. Any other name is rejected with a permission error. When the list has no valid entries, the tool is not registered at all. The outer rollback does not undo changes a procedure commits itself (for example with its ownCOMMIT, or aROLLBACKfollowed by further writes), so allow-list only procedures you trust to be read-only.Database Whitelisting: Use the
SQL_ALLOWED_DATABASESenvironment variable to restrict which databases the server can interact with. 3-part names in queries (OtherDb.dbo.Table) are checked against the same list, and 4-part (linked-server) names are rejected. For details, seeDATABASE_WHITELISTING.md.Input Validation: Database names and stored procedure names undergo format validation.
Parameterized Inputs: Stored procedure parameters are passed as typed parameters by the
mssqllibrary, not concatenated into SQL.
Recommended: read-only database login
The checks above reduce risk, but the only airtight guarantee is a login that cannot write. Connect the server with a dedicated login that is a member of db_datareader, has EXECUTE denied, and is mapped only into the databases listed in SQL_ALLOWED_DATABASES:
CREATE LOGIN mcp_reader WITH PASSWORD = '<strong password>';
-- Repeat in each allowed database
USE YourDatabaseName;
CREATE USER mcp_reader FOR LOGIN mcp_reader;
ALTER ROLE db_datareader ADD MEMBER mcp_reader;
DENY EXECUTE TO mcp_reader;If you allow specific procedures through SQL_ALLOWED_PROCEDURES, grant EXECUTE on just those procedures instead of denying it database-wide (a database-level DENY EXECUTE overrides object-level grants).
Troubleshooting
If you encounter issues:
Check container logs:
docker logs mssql-mcp(if using Docker).Check the server's console output for pino logs if running locally.
Verify all required environment variables in your
.envfile are correctly set, especiallySQL_PASSWORD,SQL_SERVER,SQL_USER, andSQL_DATABASE.Ensure the database(s) you are trying to access are listed in
SQL_ALLOWED_DATABASESif you have set this variable. APermissionErrorsaying a database "is not on this server's list of allowed databases, or it does not exist" means the name matched no entry (names compare case-insensitively, with[...]or"..."delimiters removed). Without the variable,sqlErrorNumber4060("Cannot open database") means the database doesn't exist or the login can't access it.Confirm network connectivity to your SQL Server instance from where the MCP server is running.
Run
npm testto check the query validator and the rest of the unit tests; they need no database.
For detailed Docker troubleshooting, see the Docker README.
This server cannot be deployed
Maintenance
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Text-to-SQL MCP server: read-only queries on PostgreSQL, MySQL and SQL Server with your real schema
A Model Context Protocol server for Wix AI tools
Enable secure connectivity between Sentry issues and debugging data, and LLM clients, using a Model Context Protocol (MCP) server.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that enables LLMs like Claude to interact with SQLite and SQL Server databases, allowing for schema inspection and SQL query execution.695 npm386MIT
- AlicenseBqualityDmaintenanceA Model Context Protocol server that enables AI assistants (Cursor, Windsurf, Claude Code) to interact with Microsoft SQL Server databases by providing connectivity through environment-configurable connections.81,300 npm8MIT
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that provides comprehensive access to Microsoft SQL Server databases, enabling Language Models to inspect schemas, execute queries, manage database objects, and perform advanced database operations.8-
- AlicenseAqualityCmaintenanceA Model Context Protocol server that enables LLMs like Claude to interact with Microsoft SQL Server databases through natural language, supporting queries, data manipulation, and table management.83,470 npmMIT