@berthojoris/mcp-mysql-server 1.0.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.
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DdlTools = void 0;
7
+ const connection_1 = __importDefault(require("../db/connection"));
8
+ class DdlTools {
9
+ constructor() {
10
+ this.db = connection_1.default.getInstance();
11
+ }
12
+ /**
13
+ * Create a new table
14
+ */
15
+ async createTable(params) {
16
+ try {
17
+ const { table_name, columns, indexes } = params;
18
+ // Build column definitions
19
+ const columnDefs = columns.map(col => {
20
+ let def = `\`${col.name}\` ${col.type}`;
21
+ if (col.nullable === false) {
22
+ def += ' NOT NULL';
23
+ }
24
+ if (col.auto_increment) {
25
+ def += ' AUTO_INCREMENT';
26
+ }
27
+ if (col.default !== undefined) {
28
+ def += ` DEFAULT ${col.default}`;
29
+ }
30
+ if (col.primary_key) {
31
+ def += ' PRIMARY KEY';
32
+ }
33
+ return def;
34
+ }).join(', ');
35
+ // Build the CREATE TABLE query
36
+ let query = `CREATE TABLE \`${table_name}\` (${columnDefs})`;
37
+ // Execute the query
38
+ await this.db.query(query);
39
+ // Create indexes if specified
40
+ if (indexes && indexes.length > 0) {
41
+ for (const index of indexes) {
42
+ const indexType = index.unique ? 'UNIQUE INDEX' : 'INDEX';
43
+ const indexColumns = index.columns.map(c => `\`${c}\``).join(', ');
44
+ const indexQuery = `CREATE ${indexType} \`${index.name}\` ON \`${table_name}\` (${indexColumns})`;
45
+ await this.db.query(indexQuery);
46
+ }
47
+ }
48
+ return {
49
+ status: 'success',
50
+ data: {
51
+ message: `Table '${table_name}' created successfully`,
52
+ table_name
53
+ }
54
+ };
55
+ }
56
+ catch (error) {
57
+ return {
58
+ status: 'error',
59
+ error: error.message
60
+ };
61
+ }
62
+ }
63
+ /**
64
+ * Alter an existing table
65
+ */
66
+ async alterTable(params) {
67
+ try {
68
+ const { table_name, operations } = params;
69
+ for (const op of operations) {
70
+ let query = `ALTER TABLE \`${table_name}\``;
71
+ switch (op.type) {
72
+ case 'add_column':
73
+ if (!op.column_name || !op.column_type) {
74
+ return { status: 'error', error: 'column_name and column_type required for add_column' };
75
+ }
76
+ query += ` ADD COLUMN \`${op.column_name}\` ${op.column_type}`;
77
+ if (op.nullable === false)
78
+ query += ' NOT NULL';
79
+ if (op.default !== undefined)
80
+ query += ` DEFAULT ${op.default}`;
81
+ break;
82
+ case 'drop_column':
83
+ if (!op.column_name) {
84
+ return { status: 'error', error: 'column_name required for drop_column' };
85
+ }
86
+ query += ` DROP COLUMN \`${op.column_name}\``;
87
+ break;
88
+ case 'modify_column':
89
+ if (!op.column_name || !op.column_type) {
90
+ return { status: 'error', error: 'column_name and column_type required for modify_column' };
91
+ }
92
+ query += ` MODIFY COLUMN \`${op.column_name}\` ${op.column_type}`;
93
+ if (op.nullable === false)
94
+ query += ' NOT NULL';
95
+ if (op.default !== undefined)
96
+ query += ` DEFAULT ${op.default}`;
97
+ break;
98
+ case 'rename_column':
99
+ if (!op.column_name || !op.new_column_name || !op.column_type) {
100
+ return { status: 'error', error: 'column_name, new_column_name, and column_type required for rename_column' };
101
+ }
102
+ query += ` CHANGE COLUMN \`${op.column_name}\` \`${op.new_column_name}\` ${op.column_type}`;
103
+ break;
104
+ case 'add_index':
105
+ if (!op.index_name || !op.index_columns) {
106
+ return { status: 'error', error: 'index_name and index_columns required for add_index' };
107
+ }
108
+ const indexType = op.unique ? 'UNIQUE INDEX' : 'INDEX';
109
+ const columns = op.index_columns.map(c => `\`${c}\``).join(', ');
110
+ query += ` ADD ${indexType} \`${op.index_name}\` (${columns})`;
111
+ break;
112
+ case 'drop_index':
113
+ if (!op.index_name) {
114
+ return { status: 'error', error: 'index_name required for drop_index' };
115
+ }
116
+ query += ` DROP INDEX \`${op.index_name}\``;
117
+ break;
118
+ default:
119
+ return { status: 'error', error: `Unknown operation type: ${op.type}` };
120
+ }
121
+ await this.db.query(query);
122
+ }
123
+ return {
124
+ status: 'success',
125
+ data: {
126
+ message: `Table '${table_name}' altered successfully`,
127
+ table_name,
128
+ operations_count: operations.length
129
+ }
130
+ };
131
+ }
132
+ catch (error) {
133
+ return {
134
+ status: 'error',
135
+ error: error.message
136
+ };
137
+ }
138
+ }
139
+ /**
140
+ * Drop a table
141
+ */
142
+ async dropTable(params) {
143
+ try {
144
+ const { table_name, if_exists } = params;
145
+ const ifExistsClause = if_exists ? 'IF EXISTS ' : '';
146
+ const query = `DROP TABLE ${ifExistsClause}\`${table_name}\``;
147
+ await this.db.query(query);
148
+ return {
149
+ status: 'success',
150
+ data: {
151
+ message: `Table '${table_name}' dropped successfully`,
152
+ table_name
153
+ }
154
+ };
155
+ }
156
+ catch (error) {
157
+ return {
158
+ status: 'error',
159
+ error: error.message
160
+ };
161
+ }
162
+ }
163
+ /**
164
+ * Execute raw DDL SQL
165
+ */
166
+ async executeDdl(params) {
167
+ try {
168
+ const { query } = params;
169
+ // Basic validation - ensure it's a DDL query
170
+ const upperQuery = query.trim().toUpperCase();
171
+ const isDdl = upperQuery.startsWith('CREATE') ||
172
+ upperQuery.startsWith('ALTER') ||
173
+ upperQuery.startsWith('DROP') ||
174
+ upperQuery.startsWith('TRUNCATE') ||
175
+ upperQuery.startsWith('RENAME');
176
+ if (!isDdl) {
177
+ return {
178
+ status: 'error',
179
+ error: 'Only DDL operations (CREATE, ALTER, DROP, TRUNCATE, RENAME) are allowed with executeDdl'
180
+ };
181
+ }
182
+ const result = await this.db.query(query);
183
+ return {
184
+ status: 'success',
185
+ data: {
186
+ message: 'DDL query executed successfully',
187
+ affected_rows: result.affectedRows || 0
188
+ }
189
+ };
190
+ }
191
+ catch (error) {
192
+ return {
193
+ status: 'error',
194
+ error: error.message
195
+ };
196
+ }
197
+ }
198
+ }
199
+ exports.DdlTools = DdlTools;
@@ -0,0 +1,29 @@
1
+ import SecurityLayer from '../security/securityLayer';
2
+ export declare class QueryTools {
3
+ private db;
4
+ private security;
5
+ constructor(security: SecurityLayer);
6
+ /**
7
+ * Execute a safe read-only SELECT query
8
+ */
9
+ runQuery(queryParams: {
10
+ query: string;
11
+ params?: any[];
12
+ }): Promise<{
13
+ status: string;
14
+ data?: any[];
15
+ error?: string;
16
+ }>;
17
+ /**
18
+ * Execute write operations (INSERT, UPDATE, DELETE) with validation
19
+ * Note: DDL operations are blocked by the security layer for safety
20
+ */
21
+ executeSql(queryParams: {
22
+ query: string;
23
+ params?: any[];
24
+ }): Promise<{
25
+ status: string;
26
+ data?: any;
27
+ error?: string;
28
+ }>;
29
+ }
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.QueryTools = void 0;
7
+ const connection_1 = __importDefault(require("../db/connection"));
8
+ const schemas_1 = require("../validation/schemas");
9
+ class QueryTools {
10
+ constructor(security) {
11
+ this.db = connection_1.default.getInstance();
12
+ this.security = security;
13
+ }
14
+ /**
15
+ * Execute a safe read-only SELECT query
16
+ */
17
+ async runQuery(queryParams) {
18
+ // Validate input schema
19
+ if (!(0, schemas_1.validateRunQuery)(queryParams)) {
20
+ return {
21
+ status: 'error',
22
+ error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateRunQuery.errors)
23
+ };
24
+ }
25
+ try {
26
+ const { query, params = [] } = queryParams;
27
+ // Validate query using security layer
28
+ const queryValidation = this.security.validateQuery(query);
29
+ if (!queryValidation.valid) {
30
+ return {
31
+ status: 'error',
32
+ error: `Query validation failed: ${queryValidation.error}`
33
+ };
34
+ }
35
+ // Ensure it's a SELECT query
36
+ if (queryValidation.queryType !== 'SELECT') {
37
+ return {
38
+ status: 'error',
39
+ error: 'Only SELECT queries are allowed with runQuery. Use executeSql for other operations.'
40
+ };
41
+ }
42
+ // Validate parameters
43
+ const paramValidation = this.security.validateParameters(params);
44
+ if (!paramValidation.valid) {
45
+ return {
46
+ status: 'error',
47
+ error: `Parameter validation failed: ${paramValidation.error}`
48
+ };
49
+ }
50
+ // Execute the query with sanitized parameters
51
+ const results = await this.db.query(query, paramValidation.sanitizedParams);
52
+ return {
53
+ status: 'success',
54
+ data: results
55
+ };
56
+ }
57
+ catch (error) {
58
+ return {
59
+ status: 'error',
60
+ error: error.message
61
+ };
62
+ }
63
+ }
64
+ /**
65
+ * Execute write operations (INSERT, UPDATE, DELETE) with validation
66
+ * Note: DDL operations are blocked by the security layer for safety
67
+ */
68
+ async executeSql(queryParams) {
69
+ // Validate input schema
70
+ if (!(0, schemas_1.validateRunQuery)(queryParams)) {
71
+ return {
72
+ status: 'error',
73
+ error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateRunQuery.errors)
74
+ };
75
+ }
76
+ try {
77
+ const { query, params = [] } = queryParams;
78
+ // Validate query using security layer
79
+ const queryValidation = this.security.validateQuery(query);
80
+ if (!queryValidation.valid) {
81
+ return {
82
+ status: 'error',
83
+ error: `Query validation failed: ${queryValidation.error}`
84
+ };
85
+ }
86
+ // Ensure it's not a SELECT query (use runQuery for that)
87
+ if (queryValidation.queryType === 'SELECT') {
88
+ return {
89
+ status: 'error',
90
+ error: 'SELECT queries should use runQuery method instead of executeSql.'
91
+ };
92
+ }
93
+ // Validate parameters
94
+ const paramValidation = this.security.validateParameters(params);
95
+ if (!paramValidation.valid) {
96
+ return {
97
+ status: 'error',
98
+ error: `Parameter validation failed: ${paramValidation.error}`
99
+ };
100
+ }
101
+ // Execute the query with sanitized parameters
102
+ const result = await this.db.query(query, paramValidation.sanitizedParams);
103
+ return {
104
+ status: 'success',
105
+ data: {
106
+ affectedRows: result.affectedRows || 0,
107
+ insertId: result.insertId || null
108
+ }
109
+ };
110
+ }
111
+ catch (error) {
112
+ return {
113
+ status: 'error',
114
+ error: error.message
115
+ };
116
+ }
117
+ }
118
+ }
119
+ exports.QueryTools = QueryTools;
@@ -0,0 +1,80 @@
1
+ import { SecurityLayer } from '../security/securityLayer';
2
+ export declare class StoredProcedureTools {
3
+ private db;
4
+ private security;
5
+ constructor(security: SecurityLayer);
6
+ /**
7
+ * List all stored procedures in the current database
8
+ */
9
+ listStoredProcedures(params: {
10
+ database?: string;
11
+ }): Promise<{
12
+ status: string;
13
+ data?: any[];
14
+ error?: string;
15
+ }>;
16
+ /**
17
+ * Get detailed information about a specific stored procedure
18
+ */
19
+ getStoredProcedureInfo(params: {
20
+ procedure_name: string;
21
+ database?: string;
22
+ }): Promise<{
23
+ status: string;
24
+ data?: any;
25
+ error?: string;
26
+ }>;
27
+ /**
28
+ * Execute a stored procedure with parameters
29
+ */
30
+ executeStoredProcedure(params: {
31
+ procedure_name: string;
32
+ parameters?: any[];
33
+ database?: string;
34
+ }): Promise<{
35
+ status: string;
36
+ data?: any;
37
+ error?: string;
38
+ }>;
39
+ /**
40
+ * Create a new stored procedure
41
+ */
42
+ createStoredProcedure(params: {
43
+ procedure_name: string;
44
+ parameters?: Array<{
45
+ name: string;
46
+ mode: 'IN' | 'OUT' | 'INOUT';
47
+ data_type: string;
48
+ }>;
49
+ body: string;
50
+ comment?: string;
51
+ database?: string;
52
+ }): Promise<{
53
+ status: string;
54
+ data?: any;
55
+ error?: string;
56
+ }>;
57
+ /**
58
+ * Drop a stored procedure
59
+ */
60
+ dropStoredProcedure(params: {
61
+ procedure_name: string;
62
+ if_exists?: boolean;
63
+ database?: string;
64
+ }): Promise<{
65
+ status: string;
66
+ message?: string;
67
+ error?: string;
68
+ }>;
69
+ /**
70
+ * Show the CREATE statement for a stored procedure
71
+ */
72
+ showCreateProcedure(params: {
73
+ procedure_name: string;
74
+ database?: string;
75
+ }): Promise<{
76
+ status: string;
77
+ data?: any;
78
+ error?: string;
79
+ }>;
80
+ }