← Discover MCPs and Agents
D
MCPAI & MLGitHub

DBPilot

Self-hosted database performance diagnostics for SQL Server, MySQL & PostgreSQL: trends, AAS insight, Top SQL, plan-change tracking, blocking & deadlock analysis. Single-process deploy, built-in MCP server for AI agents.

Links

README

From the repo.

DBPilot

Self-hosted database autonomous diagnostics platform.

NuGet NuGet downloads License: Apache-2.0 .NET Engines

DBPilot continuously samples your instances and serves the day-to-day DBA workflow in one web console: performance trends and insight (AAS load decomposition), Top SQL, query plan change tracking, missing-index advice, index usage & fragmentation, blocking analysis, deadlock analysis, and slow query logs.

简体中文

Overview

Contents

Highlights

  • Single-process deployment — one .NET process (8.0+) + one metadata DB, schema auto-created on startup (SQL Server / MySQL / PostgreSQL / SQLite).
  • Monitors three engines — SQL Server 2008–2022, MySQL 8.0+, PostgreSQL 13+. Monitoring and metadata-store engines are independent axes: any combination works.
  • <1% CPU overhead — collectors read only in-memory metadata views (DMVs / pg_stat_* / performance_schema); business tables are never scanned.
  • AI-ready — built-in read-only MCP Server exposes 11 diagnostic tools to AI agents (Claude Code, Codex CLI). Just ask: "did any SQL slow down in the last hour?"
  • Capability-driven UI — features without an equivalent data source hide or degrade per engine (PostgreSQL gets deadlock trends instead of event details); APIs answer with actionable messages.

Screenshots

Performance insight (AAS)Performance trends
Performance insightPerformance trends
Deadlock analysisDeadlock event detail
DeadlocksDeadlock event detail
Blocking analysisBlocking chain detail
BlockingBlocking chain detail
Index usageSlow query log
Index usageSlow SQL

Quick start

Fastest path: NuGet packages (frontend embedded — no Node.js). Requires .NET SDK 8.0+ — packages run on .NET 8 or later.

  1. Create a host project and add the metapackage:
mkdir dbpilot-demo && cd dbpilot-demo
dotnet new web
dotnet add package DBPilot

Don't name the host project dbpilot or DBPilot.* — it collides with the NuGet package and restore fails (NU1108).

  1. Replace Program.cs with:
using DBPilot.AspNetCore.Extension;
using DBPilot.Core.Providers;

var builder = WebApplication.CreateBuilder(args);
builder.AddDBPilot(o => o.PlatformEngine = DbpilotEngine.Sqlite);  // metadata store: SQLite, zero dependencies

var app = builder.Build();
app.UseDBPilot();
app.Run();
  1. Replace appsettings.json with (SQLite flavor):
{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": { "Microsoft": "Warning", "System": "Warning" }
    }
  },
  "DBPilot": {
    "ConnectionString": "Data Source=dbpilot_platform.db",
    "Mcp": { "ApiKey": "<random key; non-empty enables MCP, empty = off>" },
    "Auth": {
      "Username": "admin",
      "PasswordHash": "pbkdf2$100000$IOaBWezPYRnzEbBWYwLxZA==$xBWm8jjDfanDmyRttfnZoG4MIk8lcF0UnDbpjJuWaEU=",
      "Secret": "<your master key (>= 32-char random string)>"
    }
  },
  "AllowedHosts": "*"
}
  • ConnectionString and Auth:Secret are required — the SQLite file and schema are created on startup; the master key is generated as shown below.
  • PasswordHash is the hash of the default password dbpilot@2026; keep it to log in with the default.
  1. Run:
dotnet run    # → http://localhost:5000
  1. Log in with admin / dbpilot@2026 (change it after deployment), then register your first instance: Instances → Add → Test connection → Enable. Real-time pages work immediately; history accumulates.

Metadata store: for SQL Server / MySQL / PostgreSQL, switch PlatformEngine and the connection string — that's all; registered instances are unaffected. SQLite suits evaluation and single-machine use; prefer a server engine for production (and multi-process roles). Ready-made hosts: samples/ (SqlServer :5200 / MySql :5201 / Sqlite :5203 / PostgreSql :5204).

Password and master key

Change the login password: passwords are PBKDF2 hashes in DBPilot:Auth:PasswordHash — replace the hash to change the password.

  1. Create a two-line hash.cs outside any project directory (your home dir works). Inside a project, dotnet run would treat it as an argument. File-based apps with #:package need .NET SDK 10; on SDK 8 use the repo-clone alternative below:
#:package DBPilot.Core@0.5.5
Console.WriteLine(DBPilot.Core.Auth.PasswordHasher.Hash(args[0]));
  1. Run it — the whole output line is the new hash:
dotnet run hash.cs <new-password>
  1. Paste it into DBPilot:Auth:PasswordHash, restart.

Repo clones can skip the steps: dotnet run --project samples/DBPilot.Sample.SqlServer -- --hash <new-password>.

Master key (Auth:Secret, or env DBPILOT_MASTER_KEY) — required, exactly two uses:

PurposeWhat it doesIf you change it
Login-cookie signingissues/validates login tickets (HMAC-SHA256)all sessions logged out; log in again
Instance-credential encryptioninstance passwords stored AES-256-GCM-encrypted in the metadata DBold ciphertext is undecryptable, no recovery — re-enter each instance's password in the UI

Hence startup fails without it, and you should not change it once in use. Generate one:

openssl rand -base64 32      # Linux / macOS / Git Bash
# PowerShell: [guid]::NewGuid().ToString("N") + [guid]::NewGuid().ToString("N")

Configuration (appsettings.json)

Two required keys + one required value — DBPilot:ConnectionString, DBPilot:PlatformEngine, and a master key (Auth:Secret or env DBPILOT_MASTER_KEY). Missing → startup error; everything else is optional with defaults.

KeyRequiredNotes
DBPilot:ConnectionStringyesmetadata DB connection string; schema auto-created on startup
DBPilot:PlatformEngineyessqlserver / mysql / postgresql / sqlite; in code: o.PlatformEngine = DbpilotEngine.SqlServer. Independent of which engines you monitor
DBPilot:Auth:Secretyes (or env)master key — signs login cookies, encrypts instance credentials; ≥32-char random string
DBPILOT_MASTER_KEY (env)yes (or Secret)env form of the master key, container-friendly; config value takes precedence
DBPilot:Auth:Username / PasswordHashnologin account (default admin) / password hash (default dbpilot@2026)
DBPilot:Mcp:ApiKeynoMCP Server switch (non-empty = on)
DBPilot:Rolesnoprocess roles (Web / Collector, both by default); multi-process = 1 collector + N web fronts — two collectors on one metadata DB double-collect
DBPilot:Jobsnoper-collector switch & cron; empty value = disable that collector
DBPilot:Retention / DBPilot:Collectnoretention days (auto-clean) / parallelism & backoff
DBPilot:AutoInitSchemanoauto-create schema on startup (default true; set false when DBAs own the schema); versioned incremental migrations (dbpilot_schema_version) run alongside on upgrade
DBPilot:TopSqlExcludePatternsnoTop SQL noise filter (LIKE patterns); default set built in, explicit empty array clears it

Monitored instances are never configured here — they live in the UI, credentials encrypted in the metadata DB.

Building from source

Additionally requires Node.js 20+ (the embedded web UI comes from the frontend build; NuGet packages ship it prebuilt).

git clone https://github.com/SkyChenSky/DBPilot.git
cd DBPilot
scripts\run\setup.bat      # frontend build + compile + sample appsettings.json (default SqlServer host; pass MySql / Sqlite / PostgreSql to switch)
# edit samples/DBPilot.Sample.SqlServer/appsettings.json — fill in the connection string and Auth:Secret
dotnet run --project samples/DBPilot.Sample.SqlServer    # → http://localhost:5200

Non-Windows / manual equivalent:

cd web && npm install && npm run build
cd .. && dotnet build
cp samples/DBPilot.Sample.SqlServer/appsettings.template.json samples/DBPilot.Sample.SqlServer/appsettings.json

Day-to-day dev: scripts\run\dev.bat, or two terminals — dotnet watch --project samples/DBPilot.Sample.SqlServer (backend, Swagger at /swagger) + cd web && npm run dev (frontend → http://localhost:5173). Tests: scripts\run\test.bat (compile + unit tests + frontend build). Self-test load scripts in scripts/test/ — never run them against production databases.

Architecture

flowchart LR
    subgraph browser["Browser"]
        ui["Web console"]
    end

    subgraph host["DBPilot service (single process)"]
        api["Web API + MCP Server"]
        sched["Background collectors (Quartz)"]
        webhost["Static UI hosting"]
    end

    subgraph platform["Metadata DB (schema auto-created)"]
        tables["Historical data"]
    end

    subgraph monitored["Monitored instances (any number)"]
        dmv["DMV / XE / pg_stat_* / performance_schema"]
    end

    ui --> webhost
    ui -->|API| api
    sched -->|scheduled sampling| dmv
    sched --> tables
    api --> tables
    api -->|real-time queries| dmv

The browser talks only to the DBPilot service: real-time pages query instances directly, history pages read the metadata DB — both share the same data conventions (noise exclusion, fingerprinting, time windows).

Features

PageWhat it answers
Overviewinstance health at a glance — metric cards with sparklines, recent events, Top SQL digest
Performance trendsCPU / memory / PLE / QPS·TPS / IO / disk, 10s granularity (30-day retention, auto down-sampling); event overlay for deadlocks / slow SQL / plan changes
Performance insightAverage Active Sessions decomposed into CPU / lock / IO / waits — which resource is saturated, and the SQL statements contributing the load
Top SQLreal-time leaderboard + history trends, merged by fingerprint; one-click noise exclusion
Query plansplan versions snapshotted automatically; changes raise events with before/after comparison, plan tree and XML
Missing indexesoptimizer recommendations ranked by impact, with CREATE scripts and overlap hints
Index usage / fragmentationunused-index detection with drop scripts; fragmentation scan with REBUILD / REORGANIZE scripts
Blocking analysisreal-time blocking tree (head blocker, chain, wait times) + historical statistics
Deadlock analysiscaptured automatically; graph view of the cycle, statements and lock relationships
Slow query logabove-threshold statements archived automatically — full text, duration, IO, fingerprint

Engine support matrix

CapabilitySQL ServerMySQL 8.0+PostgreSQL 13+
Sessions / blocking (real-time tree + history)✅ (pg_stat_activity + pg_blocking_pids)
Top SQL (fingerprinted)✅ (performance_schema digest)✅ (pg_stat_statements)
Slow query log✅ (XE events)✅ (mysql.slow_log table)◐ template leaderboard
Performance trends◐ (no OS CPU/memory, PLE, compile counters)◐ (QPS is transaction-scope)
Deadlock analysis✅ event details + graph◐ trend only
Query plan snapshots / change tracking
Missing index advice
Index usage◐ (unused-index detection conservative)◐ (unused indexes reliably detectable)
Fragmentation scan
Index disable script✅ (INVISIBLE)
Disk usage✅ volume-level◐ database-level◐ database-level

Metadata store: SQL Server / MySQL / PostgreSQL / SQLite — independent from the monitored engines, any combination (SQLite = single-executable + single-file embedded deployment).

Prerequisites are minimal and self-checked by the connection-test wizard: MySQL needs performance_schema + slow-log settings; PostgreSQL needs the pg_stat_statements extension; SQL Server works from 2008 up (deadlock capture rides the built-in system_health session). The wizard tells you exactly what to change when something is missing.

AI diagnostics (MCP Server)

A read-only MCP Server (/mcp, Streamable HTTP + API key) hands the platform's evidence — metrics, slow SQL, deadlocks, blocking, indexes — to AI agents as 11 read-only tools. Agents never connect to your databases directly; every call is audit-logged.

Enable (off by default; non-empty ApiKey = on):

"DBPilot": { "Mcp": { "ApiKey": "a sufficiently random key" } }
claude mcp add --transport http dbpilot http://localhost:5200/mcp --header "X-Api-Key: <your-key>"

Then just ask: "use dbpilot to check the instance load over the last hour — any SQL getting slower?" Add --scope user to make it global.

Codex CLI (~/.codex/config.toml):

[mcp_servers.dbpilot]
url = "http://localhost:5200/mcp"

[mcp_servers.dbpilot.http_headers]
X-Api-Key = "<your-key>"

Example projects live in examples/: DBPilot.McpConsole (command-line diagnostic console) and DBPilot.Scenarios (fault-drill project), both referencing the official NuGet packages.

Overhead on monitored instances

<1% CPU, zero disk pressure. Collectors read in-memory metadata views only — no business-table scans, no physical IO, no locks on user objects.

CollectorFrequencyCost
Sessions / metrics / Top SQL delta / deadlocks / slow SQL10–60smillisecond-level metadata queries; XE cursors near zero when idle
Query plan snapshots5 minplan XML fetched once per fingerprint (XML generation is the expensive part)
Index snapshots (incl. fragmentation)daily 03:10heaviest tick, scheduled at night
History writesalways to the metadata DB, never to monitored instances

Built-in mitigations: XE predicates exclude the platform's own traffic, every cron is configurable, instances disable individually, failed connections back off. Same DMV-polling path as SQL Server's own system_health and AWS Performance Insights.

Verify it yourself — after a day of running, the monitoring account's accumulated CPU seconds is the true cost:

SELECT login_name, SUM(cpu_time)/1000 AS cpu_seconds_total
FROM sys.dm_exec_sessions
WHERE host_process_id IS NOT NULL
GROUP BY login_name;

Embedding via NuGet

Published on nuget.org:

dotnet add package DBPilot            # metapackage: AspNetCore + all engines, one line
# or pick what you need:
dotnet add package DBPilot.AspNetCore # API / MCP / auth / scheduling / embedded frontend
dotnet add package DBPilot.SqlServer  # engines — SqlServer / MySql / PostgreSql (monitor + storage)
dotnet add package DBPilot.MySql      #   and Sqlite (storage only, embedded deployments)
dotnet add package DBPilot.Sqlite
using DBPilot.AspNetCore.Extension;
using DBPilot.Core.Providers;

var builder = WebApplication.CreateBuilder(args);
builder.AddDBPilot(o =>
{
    o.PlatformEngine = DbpilotEngine.SqlServer;  // no default — set explicitly (or via DBPilot:PlatformEngine)
    // o.WebOnly();                               // delegate sets only what you want to change
});

var app = builder.Build();
app.UseDBPilot();
app.Run();
  • Zero wiring — referenced engine packages register themselves (output-directory scan); instances route by their engine column. Explicit registration (AddDbpilotSqlServer()) mixes in and is required for single-file publishes.
  • Package graph: DBPilot.AspNetCore → Core → Storage → Common; engine packages depend on Core + Storage.
  • Frontend assets ship twice — buildTransitive targets copy into wwwroot, plus an embedded-manifest fallback so the UI works even with an empty wwwroot.
  • Fine-grained methods (AddDbpilotWeb / AddDbpilotMcp / AddDbpilotQuartz / ...) remain available.

FAQ

SymptomFix
Startup warning 平台库结构初始化失败 (schema init failed)check DBPilot:ConnectionString and DB reachability; ignorable without persistence
Home page 404 / stale UIfrontend not built — cd web && npm install && npm run build, rebuild, restart
Startup error "DBPilot 主密钥未配置" (master key missing)set DBPilot:Auth:Secret or env DBPILOT_MASTER_KEY
Collector error The computed authentication tag did not match...master key doesn't match the stored credential ciphertext (changed after instances were registered) — re-enter each instance's password in the UI
Performance insight emptyinstance enabled and collecting? Insights need ~1 minute of samples
Deadlock / slow SQL events not showing yetevent files buffer ~1 minute — wait and refresh

License

Apache-2.0

Collected info

  • 75 stars
  • 16 forks
  • Language: C#
  • Source updated: 9/24/2026

Config for your environment

Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.

Tool

OS

Config file: ~/.cursor/mcp.json

{
  "mcpServers": {
    "mcp-server": {
      "url": "{MCP_ENDPOINT_URL}"
    }
  }
}

Paste into mcpServers in the config file. Restart Cursor after saving.

If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.