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-server Show me the top 10 rows from the Customers table."
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-mcp-server
A Model Context Protocol server for Microsoft SQL Server. Requires SQL Server 2017 or later (on-prem) or Azure SQL Database — several catalog queries (e.g. index/constraint/permission listings) use STRING_AGG, which does not exist before SQL Server 2017. Its tool surface — the 18 tool names, their operation values, parameters and output shapes — mirrors @henkey/postgres-mcp-server v1.0.7, the PostgreSQL MCP server many Claude/AI-client users already run, so a client that knows how to drive the Postgres server can drive this one the same way. henkey is AGPL-3.0; parity here is with the interface and behaviour, not the code — everything in this repository is written from scratch and licensed MIT (see LICENSE).
Quick start
npm install
npm run buildThis produces build/index.js, a stdio MCP server. Point an MCP client at it.
Claude Code (.mcp.json or claude mcp add):
{
"mssql-local": {
"type": "stdio",
"command": "node",
"args": [
"/path/to/mssql-mcp-server/build/index.js",
"--connection-string", "Server=localhost,1433;Database=MyDb;User Id=app;Password=***;Encrypt=true;TrustServerCertificate=true",
"--security-mode", "unsafe", "--allow-destructive"
]
}
}VS Code (mcp.json):
{
"servers": {
"mssql-local": {
"type": "stdio",
"command": "node",
"args": [
"/path/to/mssql-mcp-server/build/index.js",
"--connection-string", "Server=localhost,1433;Database=MyDb;User Id=app;Password=***;Encrypt=true;TrustServerCertificate=true",
"--security-mode", "unsafe", "--allow-destructive"
]
}
}
}Azure SQL Database, read-only — the default --security-mode is already readonly, so it does not need to be passed explicitly; shown here for clarity:
{
"mssql-azure": {
"type": "stdio",
"command": "node",
"args": [
"/path/to/mssql-mcp-server/build/index.js",
"--connection-string", "Server=<server>.database.windows.net,1433;Database=MyDb;User Id=app;Password=***;Encrypt=true;TrustServerCertificate=false",
"--security-mode", "readonly"
]
}
}Replace every placeholder (<server>.database.windows.net, MyDb, app, ***) with real values — never commit real credentials.
Connection strings may also be the ADO form shown above or a mssql:// URL (mssql://user:pass@host:1433/db?encrypt=true&trustServerCertificate=true); the server translates URL form itself (the underlying mssql driver only parses the ADO form).
Related MCP server: mcp-server-mssql
Security modes
Every tool call is classified into a risk category and checked against the server's --security-mode (default readonly) before it runs. destructive: true classifications additionally require --allow-destructive regardless of mode.
Mode | Allowed risks |
|
|
|
|
|
|
|
|
arbitrary_sqlalways requires--allow-destructiveas well asunsafe. A raw SQL fragment can contain any statement — awhereof1=1; DROP TABLE dbo.t --on anmssql_execute_mutationupdatereaches the engine as a multi-statement batch — so every classification of riskarbitrary_sqlis marked destructive, whatever produced it:whereonexecute_mutation/export_table_data/copy_between_databases,mssql_manage_queryexplainwithanalyze, a raw columndefaultonmanage_schema, a filtered-indexwhere, acheckExpression, RLS predicates, and function/trigger bodies. In practice--security-mode unsafeon its own now grants nothing beyondadmin;unsafeplus--allow-destructiveis what enables raw SQL.--allow-destructive— permits classifications marked destructive (drop/delete/truncate/revoke/disable/reset-style operations, and everyarbitrary_sqloperation above), on top of whatever the mode already allows. Several argument flags additionally escalate an otherwise non-destructive operation into this category, because each one silently discards or disables something that already exists:replace: trueonmssql_manage_functionscreateand onmssql_manage_triggerscreate(both emitCREATE OR ALTER, overwriting an existing body),replace: trueonmssql_manage_rlscreate_policy(drops and recreates the policy and its predicate functions), andlogin: falseonmssql_manage_usersalter(ALTER LOGIN … DISABLE).--allow-tool-connection-string— permits a tool call to supply its ownconnectionString(or, formssql_copy_between_databases,sourceConnectionString/targetConnectionString) instead of using the server's configured connection.mssql_copy_between_databaseshas no server-string fallback at all — both connection strings are required tool arguments, so the tool cannot be used unless this flag is set.
A denied call returns isError: true with one of two messages, taken verbatim from src/security/policy.ts:
Blocked by MSSQL MCP security policy: <reason>. Current mode "readonly" allows read operations.or, when the mode would allow the risk but the destructive flag is missing:
Blocked by MSSQL MCP security policy: <reason>. Destructive operations require --allow-destructive.Every denial is written to stderr as a single JSON line prefixed [MCP Audit] and, if --audit-file is set, appended to that file:
[MCP Audit] {"event":"mssql_mcp.security","outcome":"denied","reason":"security_policy_denied","toolName":"mssql_execute_sql","operation":null,"securityMode":"readonly","allowDestructive":false,"risk":"arbitrary_sql","destructive":true,"timestamp":"2026-08-26T12:00:00.000Z"}Allowed calls are recorded on the two channels differently, so the file can be a complete record without flooding the client's log:
--audit-fileadditionally records every allowed call whose risk is notread("outcome":"allowed") — everything that could have changed state.stderr carries an allowed call only when
MSSQL_MCP_AUDIT_ALLOWED=true.
MSSQL_MCP_AUDIT_ALLOWED is an environment variable only — there is no corresponding CLI flag. Audit lines never carry tool arguments, only the tool name, operation, mode and classification.
Warning at startup: in --security-mode admin or unsafe without --workspace-dir, the server prints once to stderr
[MCP Warning] File tools are enabled without --workspace-dir; export/import/copy can read and write any path this process can access. Set --workspace-dir to sandbox them.Configuration
Option | Env | Default | Meaning |
|
| — | Server-level connection string (ADO or |
|
|
|
|
|
|
| Permit drop/delete/truncate/revoke/disable/reset operations |
|
|
| Permit |
|
| — | JSON |
|
| — | If set, export/import paths must resolve inside it; relative paths resolve against it |
|
|
| Export/import size cap in bytes |
|
| — | Append JSON audit events to this file |
|
|
| Fallback for every |
|
-cs/-tc are rewritten to --connection-string/--tools-config before argument parsing (Commander v15 rejects multi-character short flags outright); --cs/--tc are additionally registered as ordinary long-form aliases, so -cs, --cs and --connection-string are all equivalent (likewise -tc/--tc/--tools-config).
An invalid --security-mode exits with status 1 and prints:
securityMode must be one of readonly, write, admin, or unsafe.Connection-string precedence (checked in this order): a tool-supplied connectionString (only when --allow-tool-connection-string is set) → --connection-string → MSSQL_CONNECTION_STRING → if none is set:
No connection string provided. Provide one in the tool arguments (requires --allow-tool-connection-string), via the --connection-string CLI option, or set the MSSQL_CONNECTION_STRING environment variable.Tools config: if --tools-config points at a file with an enabledTools array, only those tools are registered; unknown names log [MCP Warning] Tool "<n>" specified in config file but not found in available tools.; calling a known-but-disabled tool returns Error: Tool "<name>" is available but not enabled by the current server configuration.
The allow-list fails closed: a file that cannot be read or is not { "enabledTools": string[] } stops the server rather than quietly enabling every tool, printing one of
[MCP Error] Could not read tools configuration file at <path>: <reason>
[MCP Error] Invalid tools configuration file format at <path>: expected { "enabledTools": string[] }and exiting with status 1 before it serves anything.
Tools
All 18 tools are prefixed mssql_. Full parameter tables (types, defaults, whether each field is required) are generated from the server's own schemas in TOOL_SCHEMAS.md — run npm run docs to regenerate it after changing a tool's inputSchema.
Tool | Summary |
| Run a read-only |
|
|
| Run arbitrary T-SQL, including multi-batch scripts ( |
| Inspect tables, create/alter tables, manage enum-style |
| List, create, drop, rebuild/reorganize, and analyze index usage |
| List, create/drop primary key, unique, check and foreign key constraints |
| List, create, drop scalar/table-valued functions and stored procedures |
| List, create, drop, enable/disable DML triggers |
| Row-Level Security policies backed by generated predicate functions |
| Logins/users, role membership, grant/revoke permissions |
| Object/column descriptions stored as |
| Execution plans, slow-query and statistics reporting, stats reset |
| Configuration, performance and security analysis with recommendations |
| Diagnose connection, performance, lock and replication issues |
| Point-in-time database/table/query/lock/replication metrics and alerts |
| Stream a table (optionally filtered) to a local JSON or CSV file |
| Bulk-load a local JSON or CSV file into a table, inside one transaction |
| Stream rows from a table in one database into the same table in another |
Query execution notes
mssql_execute_queryruns exactly oneSELECT/WITHstatement. T-SQL does not need a;between statements, so a second one can simply be appended to a query —SELECT 1 AS a USE masterran both and left the pooled session inmasterfor every later call. Four rules enforce the single statement. The first three are applied to the query with the contents of string literals, comments and bracketed/quoted identifiers blanked out (so[Set],"Use"and'… use master'are data, not keywords); the fourth is a runtime check. Masking follows the engine's own lexing: a--comment ends at the first carriage return or newline (SELECT 1 AS a --\rUSE masteris not one long comment), block comments nest (/* a /* b */ c */is blanked whole), and the delimiters',",[,]are left in place so a blanked literal cannot be mistaken for "nothing was here":Statement keywords are rejected anywhere in the query:
USE,SET,DECLARE,BEGIN,WHILE,IF,GOTO,RETURN,PRINT,RAISERROR,THROW,COMMIT,ROLLBACK,SAVE,OPEN,CLOSE,DEALLOCATE,RECONFIGURE,CHECKPOINT,BREAK,CONTINUE,DISABLE,ENABLE,RECEIVE,SEND,REVERT,ADD, alongside the data-changing set (INSERT/UPDATE/DELETE/MERGE/INTO/EXEC/DDL/DBCC/WAITFOR/WRITETEXT/UPDATETEXT/READTEXT/SETUSER).Multi-word phrases whose individual words must stay legal on their own:
END CONVERSATION,MOVE CONVERSATION,GET CONVERSATION(a bareENDstill closes aCASE), andNEXT VALUE FOR— the one read-shaped expression that changes persistent state, because it advances aSEQUENCE(FETCH NEXT,(VALUES …),FOR XMLand a column namednext_valueare all unaffected).Structure: exactly one statement
SELECT— the firstSELECTat bracket depth 0 (for aWITHquery, the outer one after the CTE list). Any otherSELECTmust either sit inside brackets (a subquery, derived table, CTE body,EXISTS/IN,APPLY) or directly followUNION/UNION ALL/EXCEPT/INTERSECT. A(at depth 0 that opens a bracketedSELECTis itself only accepted where a subquery belongs — after a set operator,IN/EXISTS/ANY/ALL,FROM/JOIN/APPLY/AS/WHERE/ON, a comparison operator, a comma or another(— soSELECT 1 AS a (SELECT DB_NAME()), which SQL Server runs as two statements, is rejected. Anything that fails these isquery must contain exactly one statement.Result-set count, checked while the query runs. Every streamed path (
select, and thecount/existsfallbacks) refuses the query the moment the engine announces a second result set —query produced more than one result set; only a single SELECT statement is allowed— cancelling the request and returning that error instead of rows. This is what catchesSELECT 1 AS a ((SELECT DB_NAME())), where the smuggledSELECTis bracketed and so indistinguishable, token by token, from the subquery inISNULL((SELECT 1), 0). Precisely: a second SELECT smuggled inside doubled parentheses is refused when the engine announces its result set; if a rowlimitcancels the request before that happens, the smuggled statement may already have started executing server-side — it cannot return rows to the caller and, because the validator rejects every statement keyword and theNEXT VALUE FORconstruct, it cannot change database or session state. (The limit cancels as soon as a row beyond it arrives and the driver announces nothing afterwards; draining the whole first result set so the guard always fires would turn every limited readonly select into a full scan.) Subqueries,IN (SELECT …),EXISTS (SELECT …), CTEs (including recursive ones),CROSS APPLY, derived tables,(VALUES …)with an alias column list,UNION [ALL]/EXCEPT/INTERSECT,CASE … END,OFFSET … FETCH NEXT,WITH (NOLOCK)/WITH TIES,OPENJSON … WITH,GROUPING SETS,FOR XML/FOR JSON,OPTION (RECOMPILE),IIF,DATEADDand columns such asEndDate/BeginDate/Settings/Address/EndConversationall still work. Rules 1–3 are a keyword and structure scan, not a T-SQL parser, and they err towards rejection: an unbracketed column literally namedOpen,Close,SetorUseis rejected — bracket it. Usemssql_execute_sql(unsafe+--allow-destructive) for anything else.
mssql_execute_query'sselectoperation accepts an optionallimit, and defaults to 10000 rows when it is omitted; when the limit is reached the tool cancels the underlying request and returns exactly the rows collected so far. The success message then readsQuery executed successfully. Retrieved <n> rows. Row limit of <limit> reached; more rows may exist.— that second sentence is added only when a row beyond the limit actually arrived, so a result of exactlylimitrows never claims rows were left behind.countandexistsare unaffected (they never materialise rows).mssql_execute_sqlhas no row limit orlimitparameter at all; it returns every row every batch produces.
Export, import and copy
CSV parsing is strict, not lenient. A
"only opens quoted-field mode at the very start of a field; a"appearing elsewhere in an unquoted field is a literal character; a quoted field left open at end-of-file throwsUnterminated quoted field in CSV inputrather than silently merging the rest of the file into one record.mssql_import_table_datarequires a JSON file to contain a top-level array of objects (Input file does not contain an array of recordsotherwise). Two input columns that collapse to the same table column case-insensitively (e.g.Nameandname) are rejected asColumn <c> is specified more than once.timecolumns are coerced from a bareHH:MM:SS[.fff]string by anchoring it to1970-01-01in UTC; a cell that cannot be coerced to its column's type (an unparsable number, date, or hex binary value) is rejected withColumn <c>: cannot coerce "<v>" to <type>instead of reaching the driver as an opaque error or silently loading as NULL/zero.Computed and
rowversion/timestampcolumns are skipped, on bothmssql_import_table_dataandmssql_copy_between_databases: SQL Server refuses a supplied value for them (error 271), so any such column present in the input file or on the source table is dropped from the load and the target engine computes or stamps the value itself. This is silent — it is never reported as a missing or unknown column.Rows without an identity-column value present in the data are loaded through
mssql's bulksql.Tablepath withcheckConstraints: trueandfireTriggers: true— CHECK/FK constraints are enforced and INSERT triggers fire, just as they would for an ordinaryINSERT. Rows whose data does include identity-column values are loaded instead viaSET IDENTITY_INSERT ONand batched multi-rowINSERTstatements.mssql_copy_between_databasesreuses the same loader on the target side.mssql_export_table_datanever damages an existing file. Exporting to a path that already exists is an error —Output file already exists: <path>. Pass overwrite: true to replace it.— unless you passoverwrite: true. Either way rows are streamed into a temp file (<outputPath>.<pid>.<timestamp>.tmp) alongside the target and renamed onto it only once the export completed; if it fails partway (a permission error, a query error mid-stream, or the size cap being hit) only the temp file is removed, so the previous contents are still there and no corrupt/truncated file is left behind.CSV exports neutralise spreadsheet formulas. A string cell whose text starts with
=,+,-,@, a tab or a carriage return, and does not look like a number, is written with a leading'so Excel/Sheets treat it as text rather than evaluating it. Numeric-looking strings (-5,+62812) and real numbers are untouched, andmssql_import_table_datadoes not strip the quote — the exported file is the record.A cell that cannot be coerced on import is reported with at most 40 characters of its value (
Column Qty: cannot coerce "…" to int), so an error message and its[MCP Error]log line never carry a whole cell.File paths for export/import: when
--workspace-diris set, every resolved path must stay inside it (segment-based..and absolute-outside-workspace checks —Path "<path>" is outside the workspace directory.); a size cap from--max-file-bytesapplies to both the source file being read (File exceeds max file size of <n> bytes.) and the file being written (Generated export exceeds max file size of <n> bytes.); only.json/.csvextensions matching the requestedformatare accepted.
PostgreSQL → SQL Server differences
Because the tool surface mirrors a Postgres server, several tools map a Postgres concept onto a different SQL Server mechanism:
Postgres concept | SQL Server equivalent used here |
|
|
Row-level triggers, | SQL Server triggers are statement-level only; |
|
|
Roles |
|
|
|
|
|
|
|
manage_users behaviour notes
dropalways attemptsDROP LOGINfor a login-type user once the databaseUSERhas been dropped, whenever a server login with that name exists — it does not check whether some other database on the instance still maps a user to that login. (Design note: the spec originally described a "no other database user maps to it" check; the shipped behaviour is the simpler unconditional drop, reported and accepted as the code of record.)altermapssuperuser/createroletodb_owner/db_securityadmindatabase-role membership on Azure SQL Database (and to thesysadmin/securityadminserver roles elsewhere), the same mappingcreateuses;createdbhas no Azure SQL Database equivalent and is reported underunsupportedinstead of being applied.
Authentication
Connection strings accept:
SQL authentication:
User Id=...;Password=...(SQL login or Azure AD login with a password).Azure AD:
Authentication=Active Directory Password(withUser Id/Password) orAuthentication=Active Directory Default(uses the ambient Azure identity).NTLM:
Authentication=NTLM;Domain=CORPwithUser Id/Password.Windows integrated authentication (SSPI) is not supported. The underlying driver (
tedious) cannot do it; use a SQL login, NTLM with explicit credentials, or Azure AD instead.
Development
npm test # unit + integration (integration skipped without MSSQL_TEST_CONNECTION_STRING)
npm run test:unit
npm run test:integration
npm run typecheck
npm run docs # regenerate TOOL_SCHEMAS.mdIntegration tests need a local SQL Server instance and a dedicated login. .env.test (gitignored) supplies MSSQL_TEST_CONNECTION_STRING. The login is created once with a generated password (PowerShell, run against localhost\SQLEXPRESS with Windows auth):
$pw = -join ((48..57 + 65..90 + 97..122) | Get-Random -Count 24 | ForEach-Object { [char]$_ }) + 'aZ9!'
sqlcmd -S "localhost\SQLEXPRESS" -E -Q "IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = 'mssql_mcp_test') BEGIN CREATE LOGIN [mssql_mcp_test] WITH PASSWORD = N'$pw', CHECK_POLICY = OFF; ALTER SERVER ROLE [sysadmin] ADD MEMBER [mssql_mcp_test]; END ELSE ALTER LOGIN [mssql_mcp_test] WITH PASSWORD = N'$pw';"
"MSSQL_TEST_CONNECTION_STRING=Server=localhost,1433;Database=master;User Id=mssql_mcp_test;Password=$pw;Encrypt=true;TrustServerCertificate=true" | Set-Content -Encoding utf8 .env.test.env.test is gitignored; never commit or print its contents.
Known limitations
No Windows integrated auth.
OUTPUTon tables with triggers (returningin mutations) fails with SQL Server error 334.ONLINE = ONindex operations need Enterprise/Azure; Express returns an error.count/existson queries withORDER BYbut noTOPfall back to client-side streaming.Query Store statistics require Query Store to be enabled; plan-cache statistics are lost on restart /
DBCC FREEPROCCACHE.rolledBacktransaction count is not exposed by SQL Server DMVs and is alwaysnull.Computed and
rowversion/timestampcolumns are skipped on import and copy (SQL Server error 271 forbids supplying a value for them); the target engine assigns them.Symlinks and junctions inside
--workspace-dirare followed: the sandbox validates the path you pass, not where a link inside the workspace points. Do not place links to sensitive locations in a workspace directory.INSTEAD OFtriggers defined on views are not listed bymssql_manage_triggersgetand cannot be toggled withset_state— both work throughsys.tablesandALTER TABLE … ENABLE|DISABLE TRIGGER.The read-only validator for
mssql_execute_queryis a keyword and structure scan over masked SQL, not a T-SQL parser, and errs on the side of rejection: an unbracketed column namedOpen,Close,Set,Use,Save,SendorReturnis refused — bracket it ([Open]) or alias it. (Addis not affected:ADDis reserved in T-SQL, so it can never be an unbracketed column name.)mssql_export_table_datachecks that the output path does not exist and later renames its temp file onto it; those two steps are not atomic, so a file created by another process in between is replaced. The check guards against overwriting a file that was already there, not against a concurrent writer.Without
--workspace-dir, the file tools inadmin/unsafecan read and write anywhere the server process can reach; you are warned once at startup.Pools created from tool-supplied connection strings are closed after 60 seconds idle (swept every 15 seconds), measured from the last request issued on them and never while a request is in flight; the server's own
--connection-stringpool is never evicted. A call after eviction simply reconnects.
Available Tools
18 toolsmssql_analyze_databaseC
Analyze SQL Server database configuration and performance
Inputs: schema, analysisType, connectionString.
mssql_copy_between_databasesC
Copy data between two SQL Server databases
Inputs: tableName (required), sourceConnectionString (required), targetConnectionString (required), where, +3 more.
mssql_debug_databaseC
Debug common SQL Server issues
Inputs: issue (required), logLevel, connectionString.
mssql_execute_mutationB
Execute data modification operations (INSERT/UPDATE/DELETE/UPSERT) - operation="insert/update/delete/upsert" with table and data. Examples: operation="insert", table="Users", data={"Name":"John","Email":"john@example.com"}
Inputs: table (required), operation (required), data, where, +5 more.
mssql_execute_queryA
Execute SELECT queries and data retrieval operations - operation="select/count/exists" with query and optional parameters. Examples: operation="select", query="SELECT * FROM Users WHERE CreatedAt > @p1", parameters=["2024-01-01"]
Inputs: query (required), operation (required), limit, timeout, +2 more.
mssql_execute_sqlA
Execute arbitrary T-SQL - sql="ANY_VALID_TSQL" with optional parameters, GO batch separators and transaction support. Examples: sql="CREATE INDEX ...", sql="WITH cte AS (...) SELECT ...", transactional=true
Inputs: sql (required), timeout, expectRows, parameters, +2 more.
mssql_export_table_dataB
Export table data to JSON or CSV format
Inputs: tableName (required), outputPath (required), limit, where, +5 more.
mssql_import_table_dataC
Import data from JSON or CSV file into a table
Inputs: inputPath (required), tableName (required), format, schema, +4 more.
mssql_manage_commentsA
Manage SQL Server object descriptions (MS_Description extended properties) - get, set, remove comments on tables, columns, functions, and other objects. Examples: operation="get" with objectType="table", objectName="Users", operation="set" with comment text, operation="bulk_get" for discovery
Inputs: operation (required), schema, comment, tableName, +6 more.
mssql_manage_constraintsA
Manage SQL Server constraints - get, create foreign keys, drop foreign keys, create constraints, drop constraints. Examples: operation="get" to list constraints, operation="create_fk" with constraintName, tableName, columnNames, referencedTable, referencedColumns
Inputs: operation (required), schema, cascade, ifExists, +15 more.
mssql_manage_functionsA
Manage SQL Server functions and stored procedures - get, create, or drop with a single tool. Examples: operation="get" to list, operation="create" with functionName="fn_total", parameters="@price DECIMAL(10,2), @tax DECIMAL(5,2)", returnType="DECIMAL(10,2)", functionBody="RETURN @price + (@price * @tax)"
Inputs: operation (required), schema, cascade, replace, +10 more.
mssql_manage_indexesB
Manage SQL Server indexes - get, create, drop, rebuild/reorganize, and analyze usage with a single tool. Examples: operation="get" to list indexes, operation="create" with indexName, tableName, columns, operation="analyze_usage" for performance analysis
Inputs: operation (required), mode, type, where, +17 more.
mssql_manage_queryB
Manage SQL Server query analysis and performance - operation="explain" for execution plans, operation="get_slow_queries" for slow query analysis (Query Store or plan cache), operation="get_stats" for query statistics, operation="reset_stats" for clearing statistics
Inputs: operation (required), costs, limit, query, +11 more.
mssql_manage_rlsB
Manage SQL Server Row-Level Security - security policies with generated predicate functions. Examples: operation="create_policy" with tableName, policyName, predicateColumns=["TenantId"], using="@TenantId = CAST(SESSION_CONTEXT(N'TenantId') AS int)"
Inputs: operation (required), role, check, roles, +9 more.
mssql_manage_schemaA
Manage SQL Server schema - get schema info, create/alter tables, manage enum-style CHECK constraints. Examples: operation="get_info" for table lists, operation="create_table" with tableName and columns, operation="get_enums" to list IN-list CHECK constraints, operation="create_enum" with enumName, tableName, columnName and values
Inputs: operation (required), schema, values, columns, +6 more.
mssql_manage_triggersA
Manage SQL Server DML triggers - get, create, drop, and enable/disable triggers. Examples: operation="get" to list triggers, operation="create" with triggerName, tableName and triggerBody (or functionName to EXEC a procedure), operation="set_state" with triggerName, tableName, enable
Inputs: operation (required), when, enable, events, +11 more.
mssql_manage_usersA
Manage SQL Server logins, database users and permissions - create, drop, alter users, grant/revoke permissions. Examples: operation="create" with username="app_user", password="...", operation="grant" with username, permissions, target, targetType
Inputs: operation (required), login, schema, target, +17 more.
mssql_monitor_databaseC
Get real-time monitoring information for a SQL Server database
Inputs: schema, includeLocks, includeTables, includeQueries, +3 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 18 tools
Most tools target distinct resources (indexes, constraints, triggers, users), but there is overlap among execute_query, execute_mutation, and execute_sql, and between analyze_database, monitor_database, debug_database, and manage_query for performance/diagnostic work. Descriptions help somewhat, but an agent could still pick the wrong tool for custom T-SQL or monitoring.
All tools follow the mssql_<verb>_<object> snake_case pattern with predictable verbs like execute, manage, analyze, export, import, and copy. The naming is highly consistent and easy to navigate.
18 tools is slightly above the typical 3-15 well-scoped range, but the broad SQL Server administration scope justifies most entries. Each tool encapsulates a meaningful subdomain, so the count is reasonable if a bit heavy.
The surface covers data operations, schema, indexes, constraints, functions/procedures, triggers, RLS, users, comments, query performance, import/export, and database copying. Dedicated backup/restore and database-level lifecycle tools are missing, though arbitrary T-SQL via mssql_execute_sql provides a workaround.
Maintenance
Related MCP Connectors
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Hosted SQL Server MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
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.
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Related MCP Servers
- AlicenseAqualityNot gradedmaintenanceEnables AI assistants to interact with both local SQL Server and Azure SQL Database through natural language, supporting queries, data manipulation, and schema operations with built-in security features.82,310 npm1-
- AlicenseBqualityDmaintenanceEnables AI agents to interact with Microsoft SQL Server databases via MCP, supporting table listing, schema retrieval, and CRUD operations.31MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to connect to Microsoft SQL Server via the MCP protocol, supporting database schema queries, data reading, and arbitrary SQL execution.ISC
- AlicenseBqualityCmaintenanceEnables AI assistants to connect to Microsoft SQL Server for schema discovery, querying, stored procedures, DDL, performance diagnostics, and developer utilities with configurable security modes.3540 npmMIT