mcp-db-analyzer 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -376,6 +376,13 @@ Analyze PostgreSQL VACUUM maintenance status. Checks dead tuple ratios, vacuum s
376
376
  - **Connection analysis**: `analyze_connections` is PostgreSQL/MySQL only. Not available for SQLite databases.
377
377
  - **Vacuum analysis**: `analyze_vacuum` is PostgreSQL only. For MySQL, use `OPTIMIZE TABLE` or `analyze_table_bloat`.
378
378
 
379
+ ## Part of the MCP Java Backend Suite
380
+
381
+ - [mcp-spring-boot-actuator](https://www.npmjs.com/package/mcp-spring-boot-actuator) — Spring Boot health, metrics, and bean analysis
382
+ - [mcp-jvm-diagnostics](https://www.npmjs.com/package/mcp-jvm-diagnostics) — Thread dump and GC log analysis
383
+ - [mcp-redis-diagnostics](https://www.npmjs.com/package/mcp-redis-diagnostics) — Redis memory, slowlog, and client diagnostics
384
+ - [mcp-migration-advisor](https://www.npmjs.com/package/mcp-migration-advisor) — Flyway/Liquibase migration risk analysis
385
+
379
386
  ## License
380
387
 
381
388
  MIT
@@ -3,6 +3,9 @@ import { queryUnsafe, getDriverType } from "../db.js";
3
3
  * Run EXPLAIN on a query and return a formatted analysis.
4
4
  */
5
5
  export async function explainQuery(sql, analyze = false) {
6
+ if (!sql || !sql.trim()) {
7
+ return "**Error**: SQL query cannot be empty.";
8
+ }
6
9
  // Safety: in ANALYZE mode, only allow pure SELECT statements.
7
10
  // EXPLAIN ANALYZE actually executes the query, so we must reject anything
8
11
  // that could modify data — including CTEs with write operations.
@@ -232,6 +235,16 @@ function collectWarnings(node) {
232
235
  if (node["Sort Method"] === "external merge") {
233
236
  warnings.push(`**Disk sort** detected. Increase \`work_mem\` or add an index to avoid sorting.`);
234
237
  }
238
+ // Stale statistics: actual rows deviate significantly from planner estimate
239
+ if (node["Actual Rows"] !== undefined &&
240
+ node["Plan Rows"] > 0 &&
241
+ node["Actual Rows"] > 0) {
242
+ const ratio = node["Actual Rows"] / node["Plan Rows"];
243
+ if (ratio > 10 || ratio < 0.1) {
244
+ const relation = node["Relation Name"] ?? node["Node Type"];
245
+ warnings.push(`**Stale statistics** on \`${relation}\`: planner estimated ${node["Plan Rows"]} rows but got ${node["Actual Rows"]} (${ratio > 1 ? ratio.toFixed(0) + "× over" : (1 / ratio).toFixed(0) + "× under"}estimate). Run \`ANALYZE ${node["Relation Name"] ?? ""}\` to refresh table statistics.`);
246
+ }
247
+ }
235
248
  if (node.Plans) {
236
249
  for (const child of node.Plans) {
237
250
  warnings.push(...collectWarnings(child));
@@ -84,7 +84,7 @@ async function analyzeSqliteRelationships() {
84
84
  // Get FK info per table
85
85
  const fks = [];
86
86
  for (const table of tablesResult.rows) {
87
- const fkInfo = await query(`PRAGMA foreign_key_list('${table.name}')`);
87
+ const fkInfo = await query(`PRAGMA foreign_key_list("${table.name.replace(/"/g, '""')}")`);
88
88
  for (const fk of fkInfo.rows) {
89
89
  fks.push({
90
90
  source_table: table.name,
package/build/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "module";
2
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
5
  import { z } from "zod";
6
+ const require = createRequire(import.meta.url);
7
+ const { version: PKG_VERSION } = require("../package.json");
5
8
  import { listTables, inspectTable } from "./analyzers/schema.js";
6
9
  import { analyzeIndexUsage, findMissingIndexes } from "./analyzers/indexes.js";
7
10
  import { explainQuery } from "./analyzers/query.js";
@@ -15,7 +18,7 @@ import { closePool, initDriver, setConnectionTimeoutMs } from "./db.js";
15
18
  import { formatToolError } from "./errors.js";
16
19
  // Handle --help
17
20
  if (process.argv.includes("--help") || process.argv.includes("-h")) {
18
- console.log(`mcp-db-analyzer v0.1.0 — MCP server for database analysis
21
+ console.log(`mcp-db-analyzer v${PKG_VERSION} — MCP server for database analysis
19
22
 
20
23
  Usage:
21
24
  mcp-db-analyzer [options]
@@ -68,7 +71,7 @@ function detectDriver() {
68
71
  }
69
72
  const server = new McpServer({
70
73
  name: "mcp-db-analyzer",
71
- version: "0.1.0",
74
+ version: PKG_VERSION,
72
75
  });
73
76
  // Shared Zod parameter for connection timeout
74
77
  const timeoutParam = z
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "mcp-db-analyzer",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "MCP server for PostgreSQL, MySQL, and SQLite schema analysis, index optimization, and query plan inspection",
5
+ "mcpName": "io.github.dmitriusan/mcp-db-analyzer",
5
6
  "author": "Dmytro Lisnichenko",
6
7
  "type": "module",
7
8
  "main": "./build/index.js",