This server wraps SQL Server Extended Events in MCP tools so Claude can monitor production databases without ODBC. You get session lifecycle control, query fingerprinting, deadlock and blocking analysis, wait stats from sys.dm_os_wait_stats, and real-time event streaming. It also handles basic database operations like listing tables, describing schemas, and running SELECT/INSERT/UPDATE queries. Built on Microsoft.Data.SqlClient with native TDS protocol. Ships as a Docker container or .NET global tool. Useful when you need to diagnose slow queries, trace execution sequences, or let an agent interact with SQL Server metadata and performance counters directly from chat.
A production-ready MCP (Model Context Protocol) server for SQL Server monitoring, diagnostics, and database operations. Built with .NET 9 and Microsoft.Data.SqlClient for native SQL Server connectivity — no ODBC drivers required.
sys.dm_os_wait_stats directly, categorized by type (CPU, I/O, Lock, Memory, etc.)sp_reset_connection, SET statements, trace queries)GRANT ALTER ANY EVENT SESSION TO [your_login];
GRANT VIEW SERVER STATE TO [your_login];
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'blocked process threshold', 5;
RECONFIGURE;
No .NET SDK required. Works on any system with Docker installed.
docker pull ghcr.io/tkmawarire/sql-sentinel-mcp:latest
claude_desktop_config.json){
"mcpServers": {
"sql-sentinel": {
"command": "docker",
"args": ["run", "-i", "--rm", "--network", "host",
"-e", "SQL_SENTINEL_CONNECTION_STRING=Server=localhost;Database=master;User Id=sa;Password=YourPassword;TrustServerCertificate=true",
"ghcr.io/tkmawarire/sql-sentinel-mcp:latest"]
}
}
}
claude mcp add sql-sentinel \
-e SQL_SENTINEL_CONNECTION_STRING="Server=localhost;Database=master;User Id=sa;Password=YourPassword;TrustServerCertificate=true" \
-- docker run -i --rm --network host \
-e SQL_SENTINEL_CONNECTION_STRING \
ghcr.io/tkmawarire/sql-sentinel-mcp:latest
Network access: The
-iflag is required for stdio transport. Use--network hostso the container can reach SQL Server on your host machine. For remote SQL Server, omit--network hostand use the accessible hostname in your connection string.Connection string: Set
SQL_SENTINEL_CONNECTION_STRINGvia-e. All tools read the connection string from this environment variable.
Requires .NET 9 SDK or later.
dotnet tool install -g Neofenyx.SqlSentinel.Mcp
{
"mcpServers": {
"sql-sentinel": {
"command": "sql-sentinel-mcp",
"env": {
"SQL_SENTINEL_CONNECTION_STRING": "Server=localhost;Database=master;User Id=sa;Password=YourPassword;TrustServerCertificate=true"
}
}
}
}
git clone https://github.com/tkmawarire/sql-sentinel.git
cd sql-sentinel
dotnet build
Run directly:
dotnet run --project SqlServer.Profiler.Mcp/
Or publish a self-contained single binary:
# Windows
dotnet publish SqlServer.Profiler.Mcp/ -c Release -r win-x64 --self-contained
# Linux
dotnet publish SqlServer.Profiler.Mcp/ -c Release -r linux-x64 --self-contained
# macOS (Apple Silicon)
dotnet publish SqlServer.Profiler.Mcp/ -c Release -r osx-arm64 --self-contained
# macOS (Intel)
dotnet publish SqlServer.Profiler.Mcp/ -c Release -r osx-x64 --self-contained
Output will be in bin/Release/net9.0/{runtime}/publish/
All tools read the connection string from the SQL_SENTINEL_CONNECTION_STRING environment variable. Set it once before starting the server:
export SQL_SENTINEL_CONNECTION_STRING="Server=localhost;Database=master;User Id=sa;Password=YourPassword;TrustServerCertificate=false;Encrypt=true"
SQL Authentication:
Server=localhost;Database=master;User Id=sa;Password=YourPassword;TrustServerCertificate=false;Encrypt=true
Windows Authentication:
Server=localhost;Database=master;Integrated Security=true;TrustServerCertificate=false;Encrypt=true
Note: Only use
TrustServerCertificate=truein development environments with self-signed certificates. For production, always useTrustServerCertificate=falsewith a valid SSL certificate.
Azure SQL:
Server=yourserver.database.windows.net;Database=yourdb;User Id=user;Password=password;Encrypt=true
| Tool | Description |
|---|---|
sqlsentinel_create_session | Create an Extended Events session with filters (not started) |
sqlsentinel_start_session | Start capturing events for an existing session |
sqlsentinel_stop_session | Stop capturing; events are retained |
sqlsentinel_drop_session | Drop session and discard all events |
sqlsentinel_list_sessions | List all MCP-created sessions with state and buffer usage |
sqlsentinel_quick_capture | Create and start a session in one step |
| Tool | Description |
|---|---|
sqlsentinel_get_events | Retrieve captured events with filtering, sorting, and deduplication |
sqlsentinel_get_stats | Aggregate statistics grouped by fingerprint, database, app, or login |
sqlsentinel_analyze_sequence | Analyze query execution sequence with timing and gaps |
sqlsentinel_get_connection_info | List databases, applications, logins, sessions, and blocking info |
sqlsentinel_stream_events | Real-time event capture for a specified duration (1–300s) |
| Tool | Description |
|---|---|
sqlsentinel_get_deadlocks | Retrieve deadlock events with victim, processes, locks, and SQL text |
sqlsentinel_get_blocking | Retrieve blocked process events with wait resources and SQL text |
sqlsentinel_get_wait_stats | Query sys.dm_os_wait_stats categorized by type (no session required) |
sqlsentinel_health_check | Comprehensive report: slow queries, deadlocks, blocking, wait stats, insights |
| Tool | Description |
|---|---|
sqlsentinel_check_permissions | Check current login permissions and blocked process threshold config |
sqlsentinel_grant_permissions | Grant required permissions to a login (requires sysadmin) |
| Tool | Description |
|---|---|
sqlsentinel_list_tables | List all user tables in the database (schema-qualified) |
sqlsentinel_describe_table | Detailed table schema: columns, indexes, constraints, foreign keys |
sqlsentinel_create_table | Create a new table via CREATE TABLE statement |
sqlsentinel_insert_data | Insert data via INSERT statement |
sqlsentinel_read_data | Execute SELECT queries and return results |
sqlsentinel_update_data | Update data via UPDATE statement |
sqlsentinel_drop_table | Drop a table via DROP TABLE statement |
Agent: sqlsentinel_quick_capture(
sessionName: "debug_api",
applications: "MyWebApp",
minDurationMs: 100
)
// User triggers the slow operation
Agent: sqlsentinel_get_events(
sessionName: "debug_api",
sortBy: "DurationDesc",
limit: 20
)
Agent: sqlsentinel_drop_session(sessionName: "debug_api")
Agent: sqlsentinel_quick_capture(
sessionName: "n_plus_one_check",
databases: "OrdersDB"
)
// User loads a page
Agent: sqlsentinel_get_stats(
sessionName: "n_plus_one_check",
groupBy: "QueryFingerprint"
)
// Look for queries with high execution counts
Agent: sqlsentinel_analyze_sequence(
sessionName: "my_session",
correlationId: "order-12345",
responseFormat: "Markdown"
)
Agent: sqlsentinel_quick_capture(
sessionName: "deadlock_monitor",
eventTypes: "Deadlock"
)
// Wait for deadlocks to occur
Agent: sqlsentinel_get_deadlocks(
sessionName: "deadlock_monitor",
responseFormat: "Markdown"
)
Agent: sqlsentinel_quick_capture(
sessionName: "blocking_check",
eventTypes: "BlockedProcess"
)
// Requires: sp_configure 'blocked process threshold', 5
Agent: sqlsentinel_get_blocking(
sessionName: "blocking_check",
responseFormat: "Markdown"
)
Agent: sqlsentinel_health_check(
sessionName: "my_session",
slowQueryThresholdMs: 1000,
responseFormat: "Markdown"
)
Agent: sqlsentinel_list_tables()
Agent: sqlsentinel_describe_table(
name: "dbo.Products"
)
Agent: sqlsentinel_read_data(
sql: "SELECT TOP 10 * FROM dbo.Products ORDER BY CreatedDate DESC"
)
Agent: sqlsentinel_get_wait_stats(
topN: 20,
responseFormat: "Markdown"
)
Queries are normalized to group similar ones:
-- These become one fingerprint:
SELECT * FROM Users WHERE id = 123
SELECT * FROM Users WHERE id = 456
-- Fingerprint: abc123:SELECT * FROM Users WHERE id = ?
-- Execution count: 2
Default excluded patterns (when excludeNoise=true):
sp_reset_connection — Connection pool resetSET TRANSACTION ISOLATION LEVEL — Session setupSET NOCOUNT, SET ANSI_* — Client configurationsp_trace_*, fn_trace_* — Trace system queriesSqlBatchCompleted, RpcCompleted, SqlStatementCompleted, SpStatementCompleted, Attention, ErrorReported, Deadlock, BlockedProcess, LoginEvent, SchemaChange, Recompile, AutoStats
sql-profiler-mcp/
├── .github/
│ └── workflows/
│ ├── docker.yml # Build & push multi-arch Docker images
│ └── publish-mcp-registry.yml # Publish NuGet + MCP registry
├── .mcp/
│ └── server.json # MCP manifest (NuGet + OCI packages)
├── SqlServer.Profiler.Mcp/ # Main MCP server (stdio transport)
│ ├── SqlServer.Profiler.Mcp.csproj
│ ├── Program.cs # Entry point, DI setup, MCP config
│ ├── Models/
│ │ ├── ProfilerModels.cs # Records, enums, data models
│ │ └── DbOperationResult.cs # Result model for CRUD operations
│ ├── Services/
│ │ ├── ProfilerService.cs # Core Extended Events logic
│ │ ├── QueryFingerprintService.cs # SQL normalization & fingerprinting
│ │ ├── WaitStatsService.cs # DMV-based wait stats analysis
│ │ ├── SessionConfigStore.cs # In-memory session config storage
│ │ └── EventStreamingService.cs # Real-time event streaming
│ ├── Utilities/
│ │ └── SqlInputValidator.cs # SQL input validation & escaping
│ └── Tools/
│ ├── SessionManagementTools.cs # Session lifecycle tools (6)
│ ├── EventRetrievalTools.cs # Event retrieval tools (5)
│ ├── DiagnosticTools.cs # Diagnostic tools (4)
│ ├── PermissionTools.cs # Permission tools (2)
│ └── DatabaseTools.cs # Database CRUD tools (7)
├── SqlServer.Profiler.Mcp.Api/ # Debug REST API (Swagger on port 5100)
│ ├── SqlServer.Profiler.Mcp.Api.csproj
│ ├── Program.cs
│ ├── Controllers/
│ │ └── ProfilerController.cs
│ ├── Models/
│ │ └── RequestModels.cs
│ └── appsettings.json
├── SqlServer.Profiler.Mcp.Cli/ # Debug CLI (REPL + script mode)
│ ├── SqlServer.Profiler.Mcp.Cli.csproj
│ └── Program.cs
├── SqlServer.Profiler.Mcp.Tests/ # xUnit tests for core MCP library (228 tests)
│ └── ...
├── SqlServer.Profiler.Mcp.Api.Tests/ # xUnit tests for API project (29 tests)
│ └── ...
├── Dockerfile # Multi-stage build (bookworm-slim)
├── .dockerignore
├── SqlServer.Profiler.Mcp.slnx # Solution file
├── CLAUDE.md
├── CONTRIBUTING.md
└── README.md
git clone https://github.com/tkmawarire/sql-sentinel.git
cd sql-sentinel
dotnet restore
dotnet build
dotnet run --project SqlServer.Profiler.Mcp/
The server communicates over stdio using the MCP protocol. Connect it to an MCP client (Claude Desktop, Claude Code, etc.) for interactive use.
The API project provides a REST wrapper around all MCP tools with Swagger UI for manual testing.
dotnet run --project SqlServer.Profiler.Mcp.Api/
http://localhost:5100/SQL_SENTINEL_CONNECTION_STRINGThe CLI project provides an interactive REPL and script mode for testing tools directly.
# Interactive REPL mode
dotnet run --project SqlServer.Profiler.Mcp.Cli/
# List all available tools
dotnet run --project SqlServer.Profiler.Mcp.Cli/ list
# Get help for a specific tool
dotnet run --project SqlServer.Profiler.Mcp.Cli/ help sqlsentinel_quick_capture
# Execute a single tool
dotnet run --project SqlServer.Profiler.Mcp.Cli/ call sqlsentinel_list_sessions
Set the SQL_SENTINEL_CONNECTION_STRING environment variable before running.
docker build -t sql-sentinel-mcp:test .
docker run -i --rm --network host sql-sentinel-mcp:test
Microsoft.Extensions.HostingWithToolsFromAssembly()mcp_sentinel_public static method in the appropriate file under Tools/ (or create a new file)[McpServerTool(Name = "sqlsentinel_your_tool")] and [Description("...")][Description("...")] attributes — they become the tool's input schemaIProfilerService, IWaitStatsService)[McpServerTool(Name = "sqlsentinel_example")]
[Description("Description shown to AI agents")]
public static async Task<string> Example(
IProfilerService profilerService,
[Description("Optional filter")] string? filter = null)
{
var connectionString = ConnectionStringResolver.Resolve();
// Implementation
return JsonSerializer.Serialize(result);
}
GRANT ALTER ANY EVENT SESSION TO [your_login];
GRANT VIEW SERVER STATE TO [your_login];
sqlsentinel_list_sessions)minDurationMs isn't filtering everythingeventTypes: "Deadlock"blocked process threshold is configured: sp_configure 'blocked process threshold', 5eventTypes: "BlockedProcess"Large ring buffers with many events can be slow to parse. Use:
SQL_SENTINEL_CONNECTION_STRING environment variable contains credentials — secure appropriatelySee CONTRIBUTING.md for guidelines on submitting issues and pull requests.
MIT
hovecapital/read-only-local-postgres-mcp-server
cocaxcode/database-mcp
io.github.infoinlet-marketplace/mcp-mysql
io.github.cybeleri/database-admin
io.github.yash-0620/postgres-mcp-secured