Sql Sentinel — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Sql Sentinel (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<!-- mcp-name: io.github.tkmawarire/sql-sentinel -->
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 (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 Code
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:latestNetwork 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: SetSQL_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 buildRun 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-containedOutput 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=trueWindows Authentication:
Server=localhost;Database=master;Integrated Security=true;TrustServerCertificate=false;Encrypt=trueNote: Only useTrustServerCertificate=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 countsAgent: 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: 2Default 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.mdgit clone https://github.com/tkmawarire/sql-sentinel.git
cd sql-sentinel
dotnet restore
dotnet builddotnet 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_sessionsSet 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:testMicrosoft.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
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.