@berthojoris/mcp-mysql-server 1.28.0 → 1.30.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@ All notable changes to the MySQL MCP Server will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.30.0] - 2025-12-22
9
+
10
+ ### Fixed
11
+ - **Security Layer Comment Detection** - Fixed overly aggressive regex patterns that incorrectly flagged legitimate SQL syntax:
12
+ - Fixed `/\/*/` pattern that incorrectly matched forward slashes in function calls like `YEAR(start_date)`
13
+ - Improved `--` pattern to `--\s` to avoid false positives with date formats
14
+ - Now properly detects actual comment patterns while allowing legitimate SQL syntax
15
+ - Resolves issue where valid SELECT queries with date functions were being rejected
16
+
17
+ ## [1.29.0] - 2025-12-21
18
+
19
+ ### Enhanced
20
+ - **`get_database_summary` tool** - Significantly improved output format and functionality:
21
+ - Added database **Overview section** displaying total tables, tables shown, and total estimated rows with thousands separators
22
+ - Enhanced **column display**: now one per line with data type, nullable status, and key indicators (PK, UNI, FK with target table)
23
+ - Added **Primary Key section** per table showing all PK columns
24
+ - Included **Foreign Key relationships** section showing all FK connections across tables (can be disabled with `include_relationships: false`)
25
+ - Added `max_tables` parameter (max 500) to limit output for large databases
26
+ - Added `include_relationships` parameter (default: true) to control FK relationships display
27
+ - Improved **markdown formatting** with clear hierarchy using H1, H2, H3 headings
28
+ - Enhanced **foreign key tracking**: shows FK targets inline per column and in dedicated relationships summary
29
+ - Added footer note when tables are truncated due to `max_tables` limit
30
+ - Better **readability** for AI context consumption and human review
31
+
8
32
  ## [1.28.0] - 2025-12-21
9
33
 
10
34
  ### Changed
package/DOCUMENTATIONS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MySQL MCP Server - Detailed Documentation
2
2
 
3
- **Last Updated:** 2025-12-21 17:00:00
3
+ **Last Updated:** 2025-12-22 15:30:00
4
4
 
5
5
  This file contains detailed documentation for all features of the MySQL MCP Server. For quick start and basic information, see [README.md](README.md).
6
6
 
@@ -439,11 +439,19 @@ This section provides a comprehensive reference of all 145 available tools organ
439
439
 
440
440
  | Tool | Description | Requires |
441
441
  |------|-------------|----------|
442
- | `get_database_summary` | High-level overview (tables, columns, rows) for AI context | `list` |
442
+ | `get_database_summary` | Enhanced database overview with overview section, per-table breakdown (PKs, columns with nullable info, FK references), optional relationships summary, and configurable table limits | `list` |
443
443
  | `get_schema_erd` | Generate Mermaid.js ER diagram for visualization | `list` |
444
444
  | `get_schema_rag_context` | Condensed schema snapshot (tables, PK/FK, row estimates) for RAG prompts | `list` |
445
445
  | `get_column_statistics` | Profile data (min, max, nulls, distinct) for analysis | `read` |
446
446
 
447
+ #### Database Summary Enhancement
448
+ - **Better readability**: Columns displayed one per line with type, nullable status, and key indicators (PK, UNI, FK with target)
449
+ - **Overview section**: Shows total tables, tables displayed, and total estimated rows
450
+ - **Configurable limits**: Use `max_tables` parameter (max 500) to limit output for large databases
451
+ - **Relationship tracking**: Automatically includes foreign key relationships (set `include_relationships: false` to disable)
452
+ - **Formatted output**: Uses markdown headings for clear hierarchy, number formatting with thousands separators
453
+ - **Foreign key details**: Shows FK targets inline per column and in dedicated relationships section
454
+
447
455
  #### Schema-Aware RAG Context Pack
448
456
  - Purpose-built for embeddings: returns a `context_text` block plus structured `tables` and `relationships` so agents can self-orient without pulling a full ERD.
449
457
  - Tunable size: `max_tables` (default 50, max 200) and `max_columns` (default 12) to control output length; set `include_relationships` to `false` to omit FK lines.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **A production-ready Model Context Protocol (MCP) server for MySQL database integration with AI agents**
6
6
 
7
- **Last Updated:** 2025-12-21 17:00:00
7
+ **Last Updated:** 2025-12-22 15:30:00
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/@berthojoris/mcp-mysql-server)](https://www.npmjs.com/package/@berthojoris/mysql-mcp)
10
10
  [![npm downloads](https://img.shields.io/npm/dm/@berthojoris/mysql-mcp)](https://www.npmjs.com/package/@berthojoris/mysql-mcp)
package/dist/index.d.ts CHANGED
@@ -61,6 +61,8 @@ export declare class MySQLMCP {
61
61
  }>;
62
62
  getDatabaseSummary(params: {
63
63
  database?: string;
64
+ max_tables?: number;
65
+ include_relationships?: boolean;
64
66
  }): Promise<{
65
67
  status: string;
66
68
  data?: string;
@@ -37,7 +37,7 @@ const TOOLS = [
37
37
  },
38
38
  {
39
39
  name: "get_database_summary",
40
- description: "📊 Returns a high-level overview of the database including all tables, their columns, data types, and row counts. RECOMMENDED: Use this first when exploring a new database to understand its structure quickly. Optimized for AI context with concise formatting.",
40
+ description: "📊 Returns a high-level overview of the database including all tables, their columns, data types, row counts, and relationships. RECOMMENDED: Use this first when exploring a new database to understand its structure quickly. Features: database overview, per-table breakdown with primary keys, columns with nullable info and foreign key references, optional relationship summary, and configurable table limits.",
41
41
  inputSchema: {
42
42
  type: "object",
43
43
  properties: {
@@ -45,6 +45,14 @@ const TOOLS = [
45
45
  type: "string",
46
46
  description: "Optional: specific database name",
47
47
  },
48
+ max_tables: {
49
+ type: "number",
50
+ description: "Optional: maximum number of tables to include (default: all tables, max 500)",
51
+ },
52
+ include_relationships: {
53
+ type: "boolean",
54
+ description: "Optional: include foreign key relationships section (default: true)",
55
+ },
48
56
  },
49
57
  },
50
58
  },
@@ -201,9 +201,9 @@ class SecurityLayer {
201
201
  }
202
202
  // Check for comment-like sequences that could be used for injection
203
203
  const suspiciousPatterns = [
204
- /\/*/, // Potential comment start
205
- /\*\//, // Potential comment end
206
- /--/, // Potential comment
204
+ /\/\*/, // Potential comment start (literal /*)
205
+ /\*\//, // Potential comment end (literal */)
206
+ /--\s/, // Potential comment (-- followed by space, not -- in dates)
207
207
  /#/, // Potential comment
208
208
  ];
209
209
  for (const pattern of suspiciousPatterns) {
@@ -33,10 +33,12 @@ export declare class DatabaseTools {
33
33
  }>;
34
34
  /**
35
35
  * Get a high-level summary of the database (tables, columns, row counts)
36
- * Optimized for AI context window
36
+ * Optimized for AI context window with better formatting and optional limits
37
37
  */
38
38
  getDatabaseSummary(params: {
39
39
  database?: string;
40
+ max_tables?: number;
41
+ include_relationships?: boolean;
40
42
  }): Promise<{
41
43
  status: string;
42
44
  data?: string;
@@ -141,7 +141,7 @@ class DatabaseTools {
141
141
  }
142
142
  /**
143
143
  * Get a high-level summary of the database (tables, columns, row counts)
144
- * Optimized for AI context window
144
+ * Optimized for AI context window with better formatting and optional limits
145
145
  */
146
146
  async getDatabaseSummary(params) {
147
147
  try {
@@ -159,37 +159,112 @@ class DatabaseTools {
159
159
  error: "No database specified and none connected.",
160
160
  };
161
161
  }
162
- // Get tables and row counts
162
+ const maxTables = params.max_tables ? Math.min(Math.max(params.max_tables, 1), 500) : undefined;
163
+ const includeRelationships = params.include_relationships ?? true;
164
+ // Get total table count first
165
+ const totalCountQuery = `
166
+ SELECT COUNT(*) as total
167
+ FROM INFORMATION_SCHEMA.TABLES
168
+ WHERE TABLE_SCHEMA = ?
169
+ `;
170
+ const totalCountResult = await this.db.query(totalCountQuery, [database]);
171
+ const totalTables = totalCountResult[0]?.total || 0;
172
+ // Get tables and row counts with optional limit
163
173
  const tablesQuery = `
164
174
  SELECT TABLE_NAME, TABLE_ROWS
165
175
  FROM INFORMATION_SCHEMA.TABLES
166
176
  WHERE TABLE_SCHEMA = ?
177
+ ORDER BY TABLE_NAME
178
+ ${maxTables ? `LIMIT ${maxTables}` : ''}
167
179
  `;
168
180
  const tables = await this.db.query(tablesQuery, [database]);
169
- // Get columns for all tables
181
+ if (tables.length === 0) {
182
+ return {
183
+ status: "success",
184
+ data: `# Database Summary: ${database}\n\nNo tables found in this database.`
185
+ };
186
+ }
187
+ // Get columns for displayed tables
188
+ const tableNames = tables.map(t => t.TABLE_NAME);
189
+ const placeholders = tableNames.map(() => '?').join(',');
170
190
  const columnsQuery = `
171
- SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, COLUMN_KEY
191
+ SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, COLUMN_KEY, IS_NULLABLE
172
192
  FROM INFORMATION_SCHEMA.COLUMNS
173
- WHERE TABLE_SCHEMA = ?
193
+ WHERE TABLE_SCHEMA = ? AND TABLE_NAME IN (${placeholders})
174
194
  ORDER BY TABLE_NAME, ORDINAL_POSITION
175
195
  `;
176
- const columns = await this.db.query(columnsQuery, [database]);
177
- // Build text summary
196
+ const columns = await this.db.query(columnsQuery, [database, ...tableNames]);
197
+ // Get foreign key relationships if requested
198
+ let foreignKeys = [];
199
+ if (includeRelationships) {
200
+ const fkQuery = `
201
+ SELECT
202
+ TABLE_NAME,
203
+ COLUMN_NAME,
204
+ REFERENCED_TABLE_NAME,
205
+ REFERENCED_COLUMN_NAME
206
+ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
207
+ WHERE TABLE_SCHEMA = ?
208
+ AND TABLE_NAME IN (${placeholders})
209
+ AND REFERENCED_TABLE_NAME IS NOT NULL
210
+ `;
211
+ foreignKeys = await this.db.query(fkQuery, [database, ...tableNames]);
212
+ }
213
+ // Build enhanced summary
178
214
  let summary = `# Database Summary: ${database}\n\n`;
215
+ // Overview section
216
+ summary += `## Overview\n`;
217
+ summary += `- **Total Tables**: ${totalTables}\n`;
218
+ summary += `- **Tables Shown**: ${tables.length}${maxTables && totalTables > maxTables ? ` (limited to ${maxTables})` : ''}\n`;
219
+ const totalRows = tables.reduce((sum, t) => sum + (parseInt(t.TABLE_ROWS) || 0), 0);
220
+ summary += `- **Total Estimated Rows**: ~${totalRows.toLocaleString()}\n\n`;
221
+ // Tables section
222
+ summary += `## Tables\n\n`;
179
223
  for (const table of tables) {
180
- summary += `## Table: ${table.TABLE_NAME} (~${table.TABLE_ROWS || 0} rows)\n`;
224
+ const rowCount = parseInt(table.TABLE_ROWS) || 0;
225
+ summary += `### ${table.TABLE_NAME}\n`;
226
+ summary += `**Rows**: ~${rowCount.toLocaleString()}\n\n`;
181
227
  const tableColumns = columns.filter(c => c.TABLE_NAME === table.TABLE_NAME);
182
- const columnDefs = tableColumns.map(c => {
183
- let def = `${c.COLUMN_NAME} (${c.DATA_TYPE})`;
184
- if (c.COLUMN_KEY === 'PRI')
185
- def += " [PK]";
186
- if (c.COLUMN_KEY === 'MUL')
187
- def += " [FK/Index]";
188
- if (c.COLUMN_KEY === 'UNI')
189
- def += " [Unique]";
190
- return def;
191
- });
192
- summary += `Columns: ${columnDefs.join(", ")}\n\n`;
228
+ const tableFKs = foreignKeys.filter(fk => fk.TABLE_NAME === table.TABLE_NAME);
229
+ // Primary keys
230
+ const primaryKeys = tableColumns.filter(c => c.COLUMN_KEY === 'PRI');
231
+ if (primaryKeys.length > 0) {
232
+ summary += `**Primary Key(s)**: ${primaryKeys.map(c => c.COLUMN_NAME).join(', ')}\n\n`;
233
+ }
234
+ // Columns
235
+ summary += `**Columns** (${tableColumns.length}):\n`;
236
+ for (const col of tableColumns) {
237
+ const nullable = col.IS_NULLABLE === 'YES' ? 'nullable' : 'not null';
238
+ let keys = [];
239
+ if (col.COLUMN_KEY === 'PRI')
240
+ keys.push('PK');
241
+ else if (col.COLUMN_KEY === 'UNI')
242
+ keys.push('UNI');
243
+ // Check if this column is a foreign key
244
+ const fk = tableFKs.find(f => f.COLUMN_NAME === col.COLUMN_NAME);
245
+ if (fk) {
246
+ keys.push(`FK → ${fk.REFERENCED_TABLE_NAME}.${fk.REFERENCED_COLUMN_NAME}`);
247
+ }
248
+ else if (col.COLUMN_KEY === 'MUL') {
249
+ keys.push('Index');
250
+ }
251
+ const keyInfo = keys.length > 0 ? ` [${keys.join(', ')}]` : '';
252
+ summary += ` - ${col.COLUMN_NAME}: ${col.DATA_TYPE} (${nullable})${keyInfo}\n`;
253
+ }
254
+ summary += `\n`;
255
+ }
256
+ // Relationships summary if included and exists
257
+ if (includeRelationships && foreignKeys.length > 0) {
258
+ summary += `## Foreign Key Relationships (${foreignKeys.length})\n\n`;
259
+ for (const fk of foreignKeys) {
260
+ summary += `- ${fk.TABLE_NAME}.${fk.COLUMN_NAME} → ${fk.REFERENCED_TABLE_NAME}.${fk.REFERENCED_COLUMN_NAME}\n`;
261
+ }
262
+ summary += `\n`;
263
+ }
264
+ // Footer note if tables were limited
265
+ if (maxTables && totalTables > maxTables) {
266
+ summary += `\n---\n`;
267
+ summary += `*Note: ${totalTables - maxTables} table(s) not shown. Increase \`max_tables\` parameter to see more.*\n`;
193
268
  }
194
269
  return {
195
270
  status: "success",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berthojoris/mcp-mysql-server",
3
- "version": "1.28.0",
3
+ "version": "1.30.0",
4
4
  "description": "Model Context Protocol server for MySQL database integration with dynamic per-project permissions, backup/restore, data import/export, and data migration capabilities",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",