A .NET 9 MCP server that exposes read-only MSSQL Server tools to AI hosts (Cursor, Claude Desktop, etc.) over stdio.
Architecture & security
MCP host (Cursor, ...) MssqlMcpToolkit MSSQL Server
+--------------------+ +-------------------------------+ +--------------+
| agent / tools |<-- stdio --->| JSON-RPC handler | | login |
| (trusted spawn) | JSON-RPC | | | TDS | (least |
+--------------------+ | v |----->| privilege |
| catalog tools | | SELECT) |
| (fixed SQL + SqlParam) | +--------------+
| | |
| execute_read_query |
| | |
| v |
| QueryValidator | SELECT-only, fail-closed
| | |
| v |
| SqlExecutor (shared) | QueryOptions:
| | MaxRows / MaxCell / timeout
+-------------------------------+
No HTTP listener — transport is stdio only. Only execute_read_query goes through QueryValidator; catalog tools use fixed SQL (arguments bound with SqlParameter where needed). Row/cell/timeout caps apply in SqlExecutor. Details: Project overview, Security posture.
Documentation
| Document | Description |
|---|---|
| Documentation index | Master index for all project docs |
| Project overview | Architecture, protocol flow, security, and all MCP tools |
| Source tree | Repository layout and file responsibilities |
| Contributing | Development setup, conventions, and pull request guidelines |
| Release notes | Version history |
| Security policy | How to report vulnerabilities |
| Security posture | Protections, gaps, permissions, and production guidance |
| Code of conduct | Community standards |
Requirements
- MSSQL Server reachable from the machine running the server.
- An MCP host that can spawn the process.
- End users (release install): Windows x64, Linux x64, or macOS (arm64 / x64); no .NET SDK required.
- Developers: .NET 9 SDK or later (.NET 10 SDK recommended for
dotnet testwith Microsoft.Testing.Platform).
Install from Cursor Directory
Cursor runs npx -y mssql-mcp-toolkit. That launcher downloads the GitHub Release for the current operating system (Windows x64, Linux x64, macOS arm64, or macOS x64) into ~/.mssql-mcp-toolkit/v1.0.0/ (%USERPROFILE%\.mssql-mcp-toolkit\v1.0.0\ on Windows). No clone and no .NET SDK are required.
The first start stops before the server runs and prints that folder. Copy appsettings.json there to appsettings.local.json, replace the YOUR_* connection string and log path, then start mssql-mcp-toolkit again.
Install from GitHub Release (manual)
For local use in Cursor without cloning or building:
-
Open Releases and download the archive for your OS from the latest
v*tag (see RELEASE_NOTES.md):Platform Asset Windows x64 mssql-mcp-toolkit-win-x64.zipLinux x64 mssql-mcp-toolkit-linux-x64.tar.gzmacOS Apple Silicon mssql-mcp-toolkit-osx-arm64.tar.gzmacOS Intel mssql-mcp-toolkit-osx-x64.tar.gz -
Extract to a folder (for example
C:\Tools\mssql-mcp-toolkit\or~/Tools/mssql-mcp-toolkit/). On Linux/macOS, ensure the binary is executable (chmod +x mssql-mcp-toolkitif needed). -
Copy shipped
appsettings.jsontoappsettings.local.jsonbeside the binary (mssql-mcp-toolkit.exeon Windows,mssql-mcp-toolkiton Linux/macOS). -
Edit
appsettings.local.json— replace theYOUR_*placeholders forDatabase.ConnectionStringandSerilog.WriteTo[0].Args.path(use an OS-appropriate log path). -
Copy the MCP example for your OS into your Cursor MCP config (e.g.
.cursor/mcp.jsonor user settings) and setcommandto the full path of the binary:- Windows: mcp.release.example.json
- Linux / macOS: mcp.release.unix.example.json
-
Restart Cursor and enable the mssql-mcp-toolkit server.
Do not commit appsettings.local.json, .runsettings, mcp.json, publish profiles, or other files with real credentials or machine-specific paths (see .gitignore). Committed .mcp.json is the Cursor Directory listing: it starts mssql-mcp-toolkit with npx -y mssql-mcp-toolkit and contains no credentials.
Quick start (developers)
Clone and build
git clone https://github.com/darwijesinghe/mssql-mcp-toolkit.git
cd mssql-mcp-toolkit
dotnet build Mcp.sln
Default branch is main.
Configure locally
- Copy appsettings.json to
Mcp.Server/appsettings.local.json. - Edit
appsettings.local.json— replace theYOUR_*placeholders with your SQL Server connection string and log file path. - Leave appsettings.json as the masked shared template (local values override it).
Run locally (stdio)
dotnet run --project Mcp.Server/Mcp.Server.csproj
The server reads JSON-RPC from stdin and writes responses to stdout. Startup fails with exit code 1 if the database is unreachable or configuration is missing.
Run tests
# Unit tests only (matches CI)
dotnet test --solution Mcp.sln --filter "TestCategory!=Integration"
Or target the test project directly:
dotnet test --project Mcp.Test/Mcp.Test.csproj --filter "TestCategory!=Integration"
Unit tests use mocks and do not require SQL Server. Integration tests ([TestCategory("Integration")]) need a live database:
- Run integration-test-db.sql to create
mcp_test. - Copy
.runsettings.example->Mcp.Test/.runsettings, setDbConnectionString, then run with--settings.
CI skips integration tests.
Configure in Cursor (from source)
Copy mcp.example.json to your Cursor MCP config and fix the project path in args. Ensure appsettings.local.json exists beside the server project (or in the run output directory).
Create a release (maintainers)
Pushing a version tag triggers .github/workflows/release.yml, which runs unit tests (excludes Integration), publishes self-contained single-file binaries for win-x64, linux-x64, osx-arm64, and osx-x64, and attaches those archives to the GitHub Release.
git checkout main
git pull
git tag v1.0.0
git push origin v1.0.0
Replace v1.0.0 with your semver tag. Check the Actions tab for the workflow run, then the Releases tab for the download.
Configuration
Settings are loaded from JSON files in the server working directory (appsettings.json, then optional appsettings.local.json overrides).
| Section | Key | Description |
|---|---|---|
Database |
ConnectionString |
MSSQL Server connection string (required) |
Serilog |
WriteTo[].Args.path |
Log file path (required for file logging) |
QueryOptions |
MaxRows |
Maximum rows returned per query (default: 500) |
QueryOptions |
MaxCellLength |
Maximum string length per cell before truncation (default: 5000) |
QueryOptions |
CommandTimeoutSeconds |
MSSQL command timeout (default: 30) |
See appsettings.json for the masked committed template. Copy it to appsettings.local.json and replace the YOUR_* placeholders (never commit the local file).
MCP tools
Responses use JSON-RPC result / error. tools/call puts MCP content / isError inside result. See Project overview — Response shape and Tool results.
| Tool | Arguments | Description |
|---|---|---|
list_tables |
— | User base tables (SCHEMANAME, TABLENAME) |
list_views |
— | Views (SCHEMANAME, VIEWNAME) |
list_procedures |
— | Stored procedures (SCHEMANAME, PROCEDURENAME) |
list_triggers |
— | Triggers (PARENTOBJECT, TRIGGERNAME, ISDISABLED) |
list_functions |
— | User functions (SCHEMANAME, FUNCTIONNAME) |
describe_table |
tableName |
Column metadata for a table (schema.table or name) |
get_object_definition |
objectName |
T-SQL for procedure, view, function, or trigger |
search_definitions |
text |
Objects whose module body contains text |
find_references |
objectName |
Objects that reference a table or view |
execute_read_query |
sql |
Run a validated SELECT-only query |
Contributing
Contributions are welcome. See CONTRIBUTING.md for setup, coding conventions, testing, and how to submit a pull request.
License
This project is licensed under the MIT License.