Offline PostgreSQL query, migration and EXPLAIN diagnostics for AI agents.
Runs on your machine from its package; the steps are below.
Not assessed yet.
Odel charges nothing per call. The publisher may charge for its own service.
Runs locally over stdio
This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).
Run
npx -y mcp-database-doctor
MCP client config
{
"mcpServers": {
"mcp-database-doctor": {
"command": "npx",
"args": [
"-y",
"mcp-database-doctor"
]
}
}
}Offline PostgreSQL diagnostics for AI coding agents. Review SQL, risky migrations, candidate indexes and supplied EXPLAIN JSON plans without database credentials or executing statements.
Status: 0.1.0 MVP. Static rules are heuristic: no_rules_triggered does not mean safe, performant or valid PostgreSQL. No telemetry, remote analysis, credentials or automatic fixes.
Works with any MCP client over stdio; no account or API key needed for the local server.
Claude Code
claude mcp add database-doctor -- npx -y mcp-database-doctor
Codex CLI
codex mcp add database-doctor -- npx -y mcp-database-doctor
Claude Desktop, Cursor, Windsurf, Cline, Gemini CLI — add to the client's MCP config (claude_desktop_config.json, ~/.cursor/mcp.json, ~/.codeium/windsurf/mcp_config.json, Cline MCP settings, ~/.gemini/settings.json):
{
"mcpServers": {
"database-doctor": {
"command": "npx",
"args": [
"-y",
"mcp-database-doctor"
]
}
}
}
VS Code / GitHub Copilot — .vscode/mcp.json:
{
"servers": {
"database-doctor": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"mcp-database-doctor"
]
}
}
}
Zed — settings.json:
{
"context_servers": {
"database-doctor": {
"command": "npx",
"args": [
"-y",
"mcp-database-doctor"
]
}
}
}
| Tool | Input | Output |
|---|---|---|
analyze_query | sql | SQL anti-patterns with severity and recommendations |
check_migration | sql | Destructive DDL, index locking, constraints, rewrite and transaction risks |
suggest_indexes | sql, optional existingIndexes: [{table, columns}] | Conservative DDL candidates; not applied |
explain_plan | plan as a JSON string | Large sequential scans, row estimate errors, sort spills, high loops |
health_report | optional queries, migrations, plans arrays; at least one required | Aggregate review of supplied artifacts only |
Reports include code, severity, message, recommendation, and statement numbers for SQL. No synthetic database health score.
Node.js >=22.18 (Node 24 recommended).
npm install
npm run check
npm test
npm run build
npm run test:integration
npm pack --dry-run
Core tests run without installed dependencies using Node's native TypeScript stripping. Vitest integration tests exercise the official MCP client over stdio after build. CI runs both. Generate and commit a package-lock.json after the first successful dependency installation; current checkout does not include one because npm access was blocked in the implementation environment.
Build locally first. Copy examples/mcp.json into your client's MCP configuration and replace the absolute checkout path:
{
"mcpServers": {
"database-doctor": {
"command": "node",
"args": ["/absolute/path/mcp-database-doctor/dist/server.js"]
}
}
}
Claude Code CLI alternative:
claude mcp add database-doctor -- node /absolute/path/mcp-database-doctor/dist/server.js
Launch with npx -y mcp-database-doctor.
Suggested agent instruction: "Before proposing database changes, call check_migration. Review slow queries with analyze_query and supplied EXPLAIN JSON. Treat index DDL as candidates requiring workload validation."
check_migration({"sql":"BEGIN; CREATE INDEX CONCURRENTLY ON users(email); COMMIT;"}) identifies an invalid transaction context.
analyze_query({"sql":"SELECT * FROM users OFFSET 50000"}) flags projection and deep pagination.
explain_plan({"plan":"[{\"Plan\":{\"Node Type\":\"Seq Scan\",\"Plan Rows\":20000}}]"}) flags a scan for review; it does not claim an index is necessarily better.
For a real database, obtain plans yourself on a safe test environment: EXPLAIN (FORMAT JSON) SELECT .... EXPLAIN ANALYZE executes the statement; this server never runs it.
Local MCP stays free and offline. Quotas apply only on a hosted HTTP process that reserves units on mcp-control-plane before analysis. Build first (npm run build), then:
cp .env.example .env # set CONTROL_PLANE_URL
npm run start:hosted # default 127.0.0.1:3103
| Method | Path | Body |
|---|---|---|
| GET | /health | Liveness |
| POST | /v1/analyze-query | { "requestId", "sql" } |
| POST | /v1/check-migration | { "requestId", "sql" } |
| POST | /v1/suggest-indexes | { "requestId", "sql", "existingIndexes"? } |
| POST | /v1/explain-plan | { "requestId", "plan" } |
| POST | /v1/health-report | { "requestId", "queries"?, "migrations"?, "plans"? } |
Requires Authorization: Bearer mcp_…. SQL and plans stay on the hosted host; control-plane sees only product, requestId, and units. No database credentials are accepted.
Free: local query/migration/plan analysis. Pro later: history, before/after comparisons, CI policies and advanced recommendations. Team later: shared policies and centralized reports. Hosted quotas use the control-plane path above; local counters are not used for paid enforcement.
MIT license.