Repository navigation
First tagged release of the SQL Server MCP demo: a custom DBA-monitoring MCP server (34 tools over SQL Server DMVs, multi-instance) alongside Data API Builder for application data, all in Docker Compose.
Highlights
- Truncation is now reported, not silent. Every query tool caps its result set and tells you when it did: responses carry
truncatedandrow_limit. Previously the flag could never betrue, so an agent had no way to tell a complete result from a clipped one.execute_querynow returns{ rows, truncated, row_limit }instead of a bare array. - Four security & auditing tools:
get_security_config_drift,get_sysadmin_members,get_failed_logins,get_orphaned_users. - Passwords come from
.env, and stay off command lines. Thedba_monitoranddab_applogins are created fromMONITOR_PASSWORD/DAB_PASSWORD; everysqlcmdcall usesSQLCMDPASSWORD; the MCP container receives onlyINSTANCES.
Fixes
MCP server
- Row cap uses a sentinel row (
SET ROWCOUNT limit+1) sotruncatedis observable; the oldTOP (n)bypass, which never matched the server's own queries, is gone. A tool-levelTOPand the cap now compose correctly, soget_cpu_historyreturns its full 256 samples instead of being clipped at 200. get_index_usage_statsmanages its own row cap so the temp-table load is never clipped before the final select.fan_out_queryruns the same read-only validation asexecute_query.- Safety validation matches bare keywords (
INSERT dbo.T,DELETE dbo.T,EXECon a new line,SELECT … INTO dbo.Twere all slipping through), while string literals are ignored so audit queries such asWHERE permission_name = 'DELETE'still run. - Default instance is the first one registered;
instance_nameis matched case-insensitively; unknown names return the available list instead of failing on a hard-coded default. - Concurrent first calls to one instance share a single connection pool.
Environment
- Compose healthchecks use
sqlcmd -bexit codes (no shell pipeline), shared via one anchor for both SQL Server containers. - Init containers run with
-b, so a failed T-SQL batch fails the container instead of leaving a half-initialised database that downstream services start against. start.shusesdocker compose up --wait, runs from any working directory, and fails fast on a missingSA_PASSWORDinstead of hanging on asqlcmdpassword prompt.scripts/ag/setup-ag.shreads the sa password from.env, surfacessqlcmderrors instead of swallowing them, and no longer prints the password.- Removed a dead
docker-entrypoint-initdb.dmount and a redundant 10-second sleep from the startup path. - Test scripts fixed and extended: the MCP protocol suite now covers all 34 tools plus truncation, safety, and instance-routing cases (44 checks).
Upgrading from an untagged checkout
- Add
MONITOR_PASSWORDandDAB_PASSWORDto.env(see.env.example).MONITOR_PASSWORDmust match thepasswordfields inINSTANCES. Avoid single quotes and$(in these values. - Run
./start.sh. Existing volumes are fine: the init scripts re-sync the login passwords to.envon every start. - If you parse
execute_queryoutput, readrowsfrom the returned object.
Verification
Fresh-stack run on macOS / Docker Compose v5: endpoint tests 8/8, T-SQL smoke tests 19/19, MCP protocol tests 44/44, Always On AG setup script end to end (TestAG synchronized on both replicas).