mcp-migration-advisor 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
@@ -153,6 +153,13 @@ Returns a conflict report with severity levels, affected tables/columns, and whe
153
153
  - **No execution**: The advisor analyzes but never executes migrations. All recommendations are advisory.
154
154
  - **Database-specific DDL**: Parser targets PostgreSQL/MySQL DDL syntax. Oracle PL/SQL or SQL Server T-SQL may not be fully recognized.
155
155
 
156
+ ## Part of the MCP Java Backend Suite
157
+
158
+ - [mcp-db-analyzer](https://www.npmjs.com/package/mcp-db-analyzer) — PostgreSQL/MySQL/SQLite schema analysis
159
+ - [mcp-spring-boot-actuator](https://www.npmjs.com/package/mcp-spring-boot-actuator) — Spring Boot health, metrics, and bean analysis
160
+ - [mcp-jvm-diagnostics](https://www.npmjs.com/package/mcp-jvm-diagnostics) — Thread dump and GC log analysis
161
+ - [mcp-redis-diagnostics](https://www.npmjs.com/package/mcp-redis-diagnostics) — Redis memory, slowlog, and client diagnostics
162
+
156
163
  ## License
157
164
 
158
165
  MIT
@@ -8,16 +8,6 @@
8
8
  * - Table drops
9
9
  * - CASCADE operations
10
10
  */
11
- // Types that lose precision when converted
12
- const NARROWING_CONVERSIONS = {
13
- "BIGINT": ["INTEGER", "SMALLINT", "TINYINT"],
14
- "INTEGER": ["SMALLINT", "TINYINT"],
15
- "DOUBLE PRECISION": ["REAL", "FLOAT4", "NUMERIC"],
16
- "TEXT": ["VARCHAR", "CHAR"],
17
- "VARCHAR": ["CHAR"],
18
- "TIMESTAMP": ["DATE", "TIME"],
19
- "TIMESTAMPTZ": ["DATE", "TIME", "TIMESTAMP"],
20
- };
21
11
  /**
22
12
  * Analyze a migration for data loss risks.
23
13
  */
@@ -147,6 +147,17 @@ function analyzeStatement(stmt) {
147
147
  recommendation: "Avoid explicit locks in migrations. Use row-level locking or redesign the migration.",
148
148
  });
149
149
  }
150
+ // TRUNCATE acquires ACCESS EXCLUSIVE lock — same severity as DROP TABLE
151
+ if (stmt.type === "OTHER" && /\bTRUNCATE\b/i.test(stmt.raw)) {
152
+ const tableMatch = stmt.raw.match(/TRUNCATE\s+(?:TABLE\s+)?(?:`|"|)?(\w+)/i);
153
+ risks.push({
154
+ severity: "HIGH",
155
+ statement: truncate(stmt.raw),
156
+ tableName: tableMatch?.[1] || null,
157
+ risk: "TRUNCATE acquires ACCESS EXCLUSIVE lock, blocking all concurrent reads and writes for the duration.",
158
+ recommendation: "On large tables, prefer DELETE with a WHERE clause in batches. If speed is critical, ensure a maintenance window.",
159
+ });
160
+ }
150
161
  return risks;
151
162
  }
152
163
  function truncate(s, max = 120) {
package/build/index.js CHANGED
@@ -33,7 +33,7 @@ function formatParserWarnings(migration) {
33
33
  }
34
34
  // Handle --help
35
35
  if (process.argv.includes("--help") || process.argv.includes("-h")) {
36
- console.log(`mcp-migration-advisor v0.1.0 — MCP server for database migration risk analysis
36
+ console.log(`mcp-migration-advisor v0.2.5 — MCP server for database migration risk analysis
37
37
 
38
38
  Usage:
39
39
  mcp-migration-advisor [options]
@@ -52,7 +52,7 @@ Tools provided:
52
52
  }
53
53
  const server = new McpServer({
54
54
  name: "mcp-migration-advisor",
55
- version: "0.1.0",
55
+ version: "0.2.5",
56
56
  });
57
57
  // Tool 1: analyze_migration
58
58
  server.tool("analyze_migration", "Analyze a SQL migration file for lock risks, data loss potential, and unsafe patterns. Supports Flyway (V__*.sql) and plain SQL.", {
@@ -202,29 +202,34 @@ server.tool("score_risk", "Calculate the overall risk score (0-100) for a SQL mi
202
202
  const highCount = lockRisks.filter(r => r.severity === "HIGH").length;
203
203
  const dataLossCertain = dataLossIssues.filter(i => i.risk === "CERTAIN").length;
204
204
  const dataLossLikely = dataLossIssues.filter(i => i.risk === "LIKELY").length;
205
+ const dataLossPossible = dataLossIssues.filter(i => i.risk === "POSSIBLE").length;
206
+ // Combine lock risk score with data loss severity for a complete picture
207
+ const dataLossScore = Math.min(100, dataLossCertain * 25 + dataLossLikely * 15 + dataLossPossible * 5);
208
+ const combinedScore = Math.min(100, riskScore + dataLossScore);
205
209
  let verdict;
206
- if (riskScore >= 60 || dataLossCertain > 0) {
210
+ if (combinedScore >= 60 || dataLossCertain > 0) {
207
211
  verdict = "HIGH RISK — requires careful review and testing before deployment";
208
212
  }
209
- else if (riskScore >= 30 || dataLossLikely > 0) {
213
+ else if (combinedScore >= 30 || dataLossLikely > 0) {
210
214
  verdict = "MODERATE RISK — review lock duration and test on staging";
211
215
  }
212
216
  else {
213
217
  verdict = "LOW RISK — standard migration, proceed with normal deployment";
214
218
  }
215
- const output = `## Risk Score: ${riskScore}/100
219
+ const output = `## Risk Score: ${combinedScore}/100
216
220
 
217
221
  **Verdict**: ${verdict}
218
222
 
219
223
  ### Breakdown
220
224
 
221
- | Category | Count |
222
- |----------|-------|
223
- | CRITICAL lock risks | ${criticalCount} |
224
- | HIGH lock risks | ${highCount} |
225
- | Certain data loss | ${dataLossCertain} |
226
- | Likely data loss | ${dataLossLikely} |
227
- | Total statements | ${migration.statements.length} |
225
+ | Category | Count | Score contribution |
226
+ |----------|-------|--------------------|
227
+ | CRITICAL lock risks | ${criticalCount} | ${criticalCount * 30} |
228
+ | HIGH lock risks | ${highCount} | ${highCount * 20} |
229
+ | Certain data loss | ${dataLossCertain} | ${dataLossCertain * 25} |
230
+ | Likely data loss | ${dataLossLikely} | ${dataLossLikely * 15} |
231
+ | Possible data loss | ${dataLossPossible} | ${dataLossPossible * 5} |
232
+ | Total statements | ${migration.statements.length} | — |
228
233
  `;
229
234
  return {
230
235
  content: [{ type: "text", text: output }],
@@ -31,7 +31,8 @@ export function parseFlywayFilename(filename) {
31
31
  }
32
32
  /**
33
33
  * Split SQL text into individual statements.
34
- * Handles semicolons, ignoring those inside strings and comments.
34
+ * Handles semicolons, ignoring those inside string literals and comments.
35
+ * Single-quoted strings are tracked; escaped quotes ('') are handled correctly.
35
36
  */
36
37
  function splitStatements(sql) {
37
38
  // Remove block comments
@@ -40,16 +41,38 @@ function splitStatements(sql) {
40
41
  cleaned = cleaned.replace(/--.*$/gm, "");
41
42
  const stmts = [];
42
43
  let current = "";
43
- for (const char of cleaned) {
44
- if (char === ";") {
44
+ let inString = false;
45
+ let i = 0;
46
+ while (i < cleaned.length) {
47
+ const char = cleaned[i];
48
+ if (char === "'" && !inString) {
49
+ inString = true;
50
+ current += char;
51
+ i++;
52
+ }
53
+ else if (char === "'" && inString) {
54
+ current += char;
55
+ i++;
56
+ // '' is the SQL escape for a literal single quote inside a string
57
+ if (i < cleaned.length && cleaned[i] === "'") {
58
+ current += cleaned[i];
59
+ i++;
60
+ }
61
+ else {
62
+ inString = false;
63
+ }
64
+ }
65
+ else if (char === ";" && !inString) {
45
66
  const trimmed = current.trim();
46
67
  if (trimmed.length > 0) {
47
68
  stmts.push(trimmed);
48
69
  }
49
70
  current = "";
71
+ i++;
50
72
  }
51
73
  else {
52
74
  current += char;
75
+ i++;
53
76
  }
54
77
  }
55
78
  const last = current.trim();
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "mcp-migration-advisor",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "MCP server for database migration risk analysis — Flyway and Liquibase XML/YAML/SQL support with lock detection and conflict analysis",
5
+ "mcpName": "io.github.dmitriusan/mcp-migration-advisor",
5
6
  "main": "build/index.js",
6
7
  "bin": {
7
8
  "mcp-migration-advisor": "build/index.js"