mcp-db-analyzer 0.2.10 → 0.2.12

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
@@ -30,7 +30,7 @@ Other analytical MCP servers (CrystalDBA, pg-dash, MCP-PostgreSQL-Ops) cover Pos
30
30
  - Priority support
31
31
 
32
32
  <!-- TODO: replace placeholder Stripe Payment Link once STRIPE_SECRET_KEY is configured -->
33
- **$9.99/month** — [Get Pro License](https://buy.stripe.com/PLACEHOLDER)
33
+ **$9.00/month** — [Get Pro License](https://buy.stripe.com/PLACEHOLDER)
34
34
 
35
35
  Pro license key activates the `generate_report` MCP tool in mcp-jvm-diagnostics.
36
36
 
@@ -162,6 +162,23 @@ async function analyzeMysqlConnections() {
162
162
  }
163
163
  lines.push(`| **Total** | **${total}** |`);
164
164
  lines.push("");
165
+ // 2. Max connections utilization
166
+ try {
167
+ const maxConn = await query(`SELECT @@max_connections AS max_connections`);
168
+ if (maxConn.rows.length > 0) {
169
+ const max = parseInt(maxConn.rows[0].max_connections, 10);
170
+ const utilization = total / max;
171
+ lines.push(`**Max connections**: ${max}`);
172
+ lines.push(`**Utilization**: ${(utilization * 100).toFixed(1)}%`);
173
+ if (utilization > 0.8) {
174
+ lines.push(`\n**WARNING**: Connection pool is ${(utilization * 100).toFixed(0)}% utilized. Consider increasing max_connections or using a connection pooler (e.g. ProxySQL).`);
175
+ }
176
+ lines.push("");
177
+ }
178
+ }
179
+ catch {
180
+ // Supplemental info — skip silently if unavailable
181
+ }
165
182
  const longQueries = await query(`SELECT ID AS id, USER AS user, TIME AS time, STATE AS state, LEFT(INFO, 100) AS info
166
183
  FROM information_schema.PROCESSLIST
167
184
  WHERE COMMAND = 'Query' AND TIME > 30
@@ -177,7 +194,14 @@ async function analyzeMysqlConnections() {
177
194
  }
178
195
  lines.push("");
179
196
  }
180
- if (longQueries.rows.length === 0) {
197
+ if (longQueries.rows.length > 0) {
198
+ lines.push("### Recommendations\n");
199
+ lines.push("- Set `max_execution_time` (per-session) or `innodb_lock_wait_timeout` to limit runaway queries");
200
+ lines.push("- Investigate long-running queries with `EXPLAIN` and optimize or add indexes");
201
+ lines.push("- Use `KILL <id>` to terminate a blocking query if needed");
202
+ lines.push("");
203
+ }
204
+ else {
181
205
  lines.push("### No connection issues detected.\n");
182
206
  }
183
207
  return lines.join("\n");
@@ -72,8 +72,9 @@ async function analyzeIndexUsageMysql(schema) {
72
72
  `, [schema]);
73
73
  return formatIndexUsage(result.rows, schema);
74
74
  }
75
- catch {
76
- return `## Index Usage Analysis schema '${schema}'\n\nUnable to query performance_schema. Ensure performance_schema is enabled (it is ON by default in MySQL 5.7+) and the user has SELECT privilege on performance_schema tables.`;
75
+ catch (err) {
76
+ const detail = err instanceof Error ? err.message : String(err);
77
+ return `## Index Usage Analysis — schema '${schema}'\n\nUnable to query performance_schema. Ensure performance_schema is enabled (it is ON by default in MySQL 5.7+) and the user has SELECT privilege on performance_schema tables.\n\nDetails: ${detail}`;
77
78
  }
78
79
  }
79
80
  function formatIndexUsage(rows, schema) {
@@ -226,8 +227,9 @@ async function findMissingIndexesMysql(schema) {
226
227
  }
227
228
  return lines.join("\n");
228
229
  }
229
- catch {
230
- return "## Missing Index Analysis\n\nUnable to query performance_schema. Ensure performance_schema is enabled (it is ON by default in MySQL 5.7+) and the user has SELECT privilege on performance_schema tables.";
230
+ catch (err) {
231
+ const detail = err instanceof Error ? err.message : String(err);
232
+ return `## Missing Index Analysis\n\nUnable to query performance_schema. Ensure performance_schema is enabled (it is ON by default in MySQL 5.7+) and the user has SELECT privilege on performance_schema tables.\n\nDetails: ${detail}`;
231
233
  }
232
234
  }
233
235
  function formatMissingIndexes(rows, schema) {
@@ -41,10 +41,23 @@ async function explainQuerySqlite(sql) {
41
41
  if (result.rows.length === 0) {
42
42
  return "Could not parse query plan.";
43
43
  }
44
+ // Build a depth map from the parent chain. SQLite's id field is a node
45
+ // identifier (can be 2, 4, 10...), not a depth — depth must be computed
46
+ // by following parent references.
47
+ const depthMap = new Map();
48
+ for (const row of result.rows) {
49
+ if (row.parent === 0 || row.parent === row.id) {
50
+ depthMap.set(row.id, 0);
51
+ }
52
+ else {
53
+ depthMap.set(row.id, (depthMap.get(row.parent) ?? 0) + 1);
54
+ }
55
+ }
44
56
  const lines = ["## Query Plan Analysis (SQLite)\n"];
45
57
  lines.push("```");
46
58
  for (const row of result.rows) {
47
- const indent = " ".repeat(Math.max(0, row.id));
59
+ const depth = depthMap.get(row.id) ?? 0;
60
+ const indent = " ".repeat(depth);
48
61
  lines.push(`${indent}${row.detail}`);
49
62
  }
50
63
  lines.push("```\n");
@@ -127,8 +127,9 @@ async function suggestMissingIndexesMysql(schema) {
127
127
  `, [schema]);
128
128
  return formatSuggestions(needsIndex.rows, unused.rows, schema);
129
129
  }
130
- catch {
131
- return "## Index Suggestions\n\nUnable to query performance_schema. Ensure performance_schema is enabled (it is ON by default in MySQL 5.7+) and the user has SELECT privilege on performance_schema tables.";
130
+ catch (err) {
131
+ const detail = err instanceof Error ? err.message : String(err);
132
+ return `## Index Suggestions\n\nUnable to query performance_schema. Ensure performance_schema is enabled (it is ON by default in MySQL 5.7+) and the user has SELECT privilege on performance_schema tables.\n\nDetails: ${detail}`;
132
133
  }
133
134
  }
134
135
  function formatSuggestions(needsIndex, unused, schema) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-db-analyzer",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "MCP server for PostgreSQL, MySQL, and SQLite schema analysis, index optimization, and query plan inspection",
5
5
  "mcpName": "io.github.dmitriusan/mcp-db-analyzer",
6
6
  "author": "Dmytro Lisnichenko",