@eamonboyle/mssql-mcp 1.0.0 → 1.1.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.
Files changed (44) hide show
  1. package/README.md +31 -26
  2. package/dist/__tests__/db.test.d.ts +2 -0
  3. package/dist/__tests__/db.test.d.ts.map +1 -0
  4. package/dist/__tests__/db.test.js +204 -0
  5. package/dist/__tests__/db.test.js.map +1 -0
  6. package/dist/__tests__/validation.test.d.ts +2 -0
  7. package/dist/__tests__/validation.test.d.ts.map +1 -0
  8. package/dist/__tests__/validation.test.js +111 -0
  9. package/dist/__tests__/validation.test.js.map +1 -0
  10. package/dist/db.d.ts.map +1 -1
  11. package/dist/db.js +30 -7
  12. package/dist/db.js.map +1 -1
  13. package/dist/index.js +39 -22
  14. package/dist/index.js.map +1 -1
  15. package/dist/tools/CreateIndexTool.d.ts.map +1 -1
  16. package/dist/tools/CreateIndexTool.js +15 -9
  17. package/dist/tools/CreateIndexTool.js.map +1 -1
  18. package/dist/tools/CreateTableTool.d.ts.map +1 -1
  19. package/dist/tools/CreateTableTool.js +12 -7
  20. package/dist/tools/CreateTableTool.js.map +1 -1
  21. package/dist/tools/DescribeTableTool.d.ts.map +1 -1
  22. package/dist/tools/DescribeTableTool.js +5 -2
  23. package/dist/tools/DescribeTableTool.js.map +1 -1
  24. package/dist/tools/DropTableTool.d.ts.map +1 -1
  25. package/dist/tools/DropTableTool.js +3 -3
  26. package/dist/tools/DropTableTool.js.map +1 -1
  27. package/dist/tools/InsertDataTool.d.ts.map +1 -1
  28. package/dist/tools/InsertDataTool.js +8 -8
  29. package/dist/tools/InsertDataTool.js.map +1 -1
  30. package/dist/tools/ListTableTool.d.ts.map +1 -1
  31. package/dist/tools/ListTableTool.js +6 -4
  32. package/dist/tools/ListTableTool.js.map +1 -1
  33. package/dist/tools/ReadDataTool.d.ts +0 -8
  34. package/dist/tools/ReadDataTool.d.ts.map +1 -1
  35. package/dist/tools/ReadDataTool.js +15 -138
  36. package/dist/tools/ReadDataTool.js.map +1 -1
  37. package/dist/tools/UpdateDataTool.d.ts.map +1 -1
  38. package/dist/tools/UpdateDataTool.js +5 -5
  39. package/dist/tools/UpdateDataTool.js.map +1 -1
  40. package/dist/validation.d.ts +14 -0
  41. package/dist/validation.d.ts.map +1 -0
  42. package/dist/validation.js +134 -0
  43. package/dist/validation.js.map +1 -0
  44. package/package.json +14 -4
@@ -1,4 +1,5 @@
1
1
  import { getSqlRequest } from "../db.js";
2
+ import { validateReadQuery } from "../validation.js";
2
3
  export class ReadDataTool {
3
4
  constructor() {
4
5
  this.name = "read_data";
@@ -8,92 +9,16 @@ export class ReadDataTool {
8
9
  properties: {
9
10
  query: {
10
11
  type: "string",
11
- description: "SQL SELECT query to execute (must start with SELECT and cannot contain destructive operations). Example: SELECT * FROM movies WHERE genre = 'comedy'"
12
+ description: "SQL SELECT query to execute (must start with SELECT and cannot contain destructive operations). Example: SELECT * FROM movies WHERE genre = 'comedy'",
12
13
  },
13
14
  databaseName: {
14
15
  type: "string",
15
- description: "Name of the database to query (optional). Omit to use the default database."
16
+ description: "Name of the database to query (optional). Omit to use the default configured database.",
16
17
  },
17
18
  },
18
19
  required: ["query"],
19
20
  };
20
21
  }
21
- /**
22
- * Validates the SQL query for security issues
23
- * @param query The SQL query to validate
24
- * @returns Validation result with success flag and error message if invalid
25
- */
26
- validateQuery(query) {
27
- if (!query || typeof query !== 'string') {
28
- return {
29
- isValid: false,
30
- error: 'Query must be a non-empty string'
31
- };
32
- }
33
- // Remove comments and normalize whitespace for analysis
34
- const cleanQuery = query
35
- .replace(/--.*$/gm, '') // Remove line comments
36
- .replace(/\/\*[\s\S]*?\*\//g, '') // Remove block comments
37
- .replace(/\s+/g, ' ') // Normalize whitespace
38
- .trim();
39
- if (!cleanQuery) {
40
- return {
41
- isValid: false,
42
- error: 'Query cannot be empty after removing comments'
43
- };
44
- }
45
- const upperQuery = cleanQuery.toUpperCase();
46
- // Must start with SELECT
47
- if (!upperQuery.startsWith('SELECT')) {
48
- return {
49
- isValid: false,
50
- error: 'Query must start with SELECT for security reasons'
51
- };
52
- }
53
- // Check for dangerous keywords in the cleaned query using word boundaries
54
- for (const keyword of ReadDataTool.DANGEROUS_KEYWORDS) {
55
- // Use word boundary regex to match only complete keywords, not parts of words
56
- const keywordRegex = new RegExp(`(^|\\s|[^A-Za-z0-9_])${keyword}($|\\s|[^A-Za-z0-9_])`, 'i');
57
- if (keywordRegex.test(upperQuery)) {
58
- return {
59
- isValid: false,
60
- error: `Dangerous keyword '${keyword}' detected in query. Only SELECT operations are allowed.`
61
- };
62
- }
63
- }
64
- // Check for dangerous patterns using regex
65
- for (const pattern of ReadDataTool.DANGEROUS_PATTERNS) {
66
- if (pattern.test(query)) {
67
- return {
68
- isValid: false,
69
- error: 'Potentially malicious SQL pattern detected. Only simple SELECT queries are allowed.'
70
- };
71
- }
72
- }
73
- // Additional validation: Check for multiple statements
74
- const statements = cleanQuery.split(';').filter(stmt => stmt.trim().length > 0);
75
- if (statements.length > 1) {
76
- return {
77
- isValid: false,
78
- error: 'Multiple SQL statements are not allowed. Use only a single SELECT statement.'
79
- };
80
- }
81
- // Check for suspicious string patterns that might indicate obfuscation
82
- if (query.includes('CHAR(') || query.includes('NCHAR(') || query.includes('ASCII(')) {
83
- return {
84
- isValid: false,
85
- error: 'Character conversion functions are not allowed as they may be used for obfuscation.'
86
- };
87
- }
88
- // Limit query length to prevent potential DoS
89
- if (query.length > 10000) {
90
- return {
91
- isValid: false,
92
- error: 'Query is too long. Maximum allowed length is 10,000 characters.'
93
- };
94
- }
95
- return { isValid: true };
96
- }
97
22
  /**
98
23
  * Sanitizes the query result to prevent any potential security issues
99
24
  * @param data The query result data
@@ -109,12 +34,12 @@ export class ReadDataTool {
109
34
  console.warn(`Query returned ${data.length} records, limiting to ${maxRecords}`);
110
35
  return data.slice(0, maxRecords);
111
36
  }
112
- return data.map(record => {
113
- if (typeof record === 'object' && record !== null) {
37
+ return data.map((record) => {
38
+ if (typeof record === "object" && record !== null) {
114
39
  const sanitized = {};
115
40
  for (const [key, value] of Object.entries(record)) {
116
41
  // Sanitize column names (remove any suspicious characters)
117
- const sanitizedKey = key.replace(/[^\w\s-_.]/g, '');
42
+ const sanitizedKey = key.replace(/[^\w\s-_.]/g, "");
118
43
  if (sanitizedKey !== key) {
119
44
  console.warn(`Column name sanitized: ${key} -> ${sanitizedKey}`);
120
45
  }
@@ -138,17 +63,17 @@ export class ReadDataTool {
138
63
  return { success: false, message: error, error: "INVALID_DATABASE" };
139
64
  }
140
65
  // Validate the query for security issues
141
- const validation = this.validateQuery(query);
66
+ const validation = validateReadQuery(query);
142
67
  if (!validation.isValid) {
143
68
  console.warn(`Security validation failed for query: ${query.substring(0, 100)}...`);
144
69
  return {
145
70
  success: false,
146
71
  message: `Security validation failed: ${validation.error}`,
147
- error: 'SECURITY_VALIDATION_FAILED'
72
+ error: "SECURITY_VALIDATION_FAILED",
148
73
  };
149
74
  }
150
75
  // Log the query for audit purposes (in production, consider more secure logging)
151
- console.log(`Executing validated SELECT query: ${query.substring(0, 200)}${query.length > 200 ? '...' : ''}`);
76
+ console.log(`Executing validated SELECT query: ${query.substring(0, 200)}${query.length > 200 ? "..." : ""}`);
152
77
  // Execute the query
153
78
  const result = await request.query(query);
154
79
  // Sanitize the result
@@ -157,73 +82,25 @@ export class ReadDataTool {
157
82
  success: true,
158
83
  message: `Query executed successfully. Retrieved ${sanitizedData.length} record(s)${result.recordset.length !== sanitizedData.length
159
84
  ? ` (limited from ${result.recordset.length} total records)`
160
- : ''}`,
85
+ : ""}`,
161
86
  data: sanitizedData,
162
87
  recordCount: sanitizedData.length,
163
- totalRecords: result.recordset.length
88
+ totalRecords: result.recordset.length,
164
89
  };
165
90
  }
166
91
  catch (error) {
167
92
  console.error("Error executing query:", error);
168
93
  // Don't expose internal error details to prevent information leakage
169
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
170
- const safeErrorMessage = errorMessage.includes('Invalid object name')
94
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
95
+ const safeErrorMessage = errorMessage.includes("Invalid object name")
171
96
  ? errorMessage
172
- : 'Database query execution failed';
97
+ : "Database query execution failed";
173
98
  return {
174
99
  success: false,
175
100
  message: `Failed to execute query: ${safeErrorMessage}`,
176
- error: 'QUERY_EXECUTION_FAILED'
101
+ error: "QUERY_EXECUTION_FAILED",
177
102
  };
178
103
  }
179
104
  }
180
105
  }
181
- // List of dangerous SQL keywords that should not be allowed
182
- ReadDataTool.DANGEROUS_KEYWORDS = [
183
- 'DELETE', 'DROP', 'UPDATE', 'INSERT', 'ALTER', 'CREATE',
184
- 'TRUNCATE', 'EXEC', 'EXECUTE', 'MERGE', 'REPLACE',
185
- 'GRANT', 'REVOKE', 'COMMIT', 'ROLLBACK', 'TRANSACTION',
186
- 'BEGIN', 'DECLARE', 'SET', 'USE', 'BACKUP',
187
- 'RESTORE', 'KILL', 'SHUTDOWN', 'WAITFOR', 'OPENROWSET',
188
- 'OPENDATASOURCE', 'OPENQUERY', 'OPENXML', 'BULK', 'INTO'
189
- ];
190
- // Regex patterns to detect common SQL injection techniques
191
- ReadDataTool.DANGEROUS_PATTERNS = [
192
- // SELECT INTO operations that create new tables
193
- /SELECT\s+.*?\s+INTO\s+/i,
194
- // Semicolon followed by dangerous keywords
195
- /;\s*(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE|MERGE|REPLACE|GRANT|REVOKE)/i,
196
- // UNION injection attempts with dangerous keywords
197
- /UNION\s+(?:ALL\s+)?SELECT.*?(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)/i,
198
- // Comment-based injection attempts
199
- /--.*?(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)/i,
200
- /\/\*.*?(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE).*?\*\//i,
201
- // Stored procedure execution patterns
202
- /EXEC\s*\(/i,
203
- /EXECUTE\s*\(/i,
204
- /sp_/i,
205
- /xp_/i,
206
- // Dynamic SQL construction
207
- /EXEC\s*\(/i,
208
- /EXECUTE\s*\(/i,
209
- // Bulk operations
210
- /BULK\s+INSERT/i,
211
- /OPENROWSET/i,
212
- /OPENDATASOURCE/i,
213
- // System functions that could be dangerous
214
- /@@/,
215
- /SYSTEM_USER/i,
216
- /USER_NAME/i,
217
- /DB_NAME/i,
218
- /HOST_NAME/i,
219
- // Time delay attacks
220
- /WAITFOR\s+DELAY/i,
221
- /WAITFOR\s+TIME/i,
222
- // Multiple statements (semicolon not at end)
223
- /;\s*\w/,
224
- // String concatenation that might hide malicious code
225
- /\+\s*CHAR\s*\(/i,
226
- /\+\s*NCHAR\s*\(/i,
227
- /\+\s*ASCII\s*\(/i,
228
- ];
229
106
  //# sourceMappingURL=ReadDataTool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReadDataTool.js","sourceRoot":"","sources":["../../src/tools/ReadDataTool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ReadDataTool.js","sourceRoot":"","sources":["../../src/tools/ReadDataTool.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"UpdateDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/UpdateDataTool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG1D,qBAAa,cAAe,YAAW,IAAI;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,IAAI,SAAiB;IACrB,WAAW,SAAmH;IAC9H,WAAW,MAqBF;IAEH,GAAG,CAAC,MAAM,EAAE,GAAG;;;;;;;;;CAwCtB"}
1
+ {"version":3,"file":"UpdateDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/UpdateDataTool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG1D,qBAAa,cAAe,YAAW,IAAI;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,IAAI,SAAiB;IACrB,WAAW,SACuG;IAClH,WAAW,MAwBF;IAEH,GAAG,CAAC,MAAM,EAAE,GAAG;;;;;;;;;CAwCtB"}
@@ -8,7 +8,7 @@ export class UpdateDataTool {
8
8
  properties: {
9
9
  tableName: {
10
10
  type: "string",
11
- description: "Name of the table to update"
11
+ description: "Name of the table to update",
12
12
  },
13
13
  updates: {
14
14
  type: "object",
@@ -16,11 +16,11 @@ export class UpdateDataTool {
16
16
  },
17
17
  whereClause: {
18
18
  type: "string",
19
- description: "WHERE clause to identify which records to update. Example: \"genre = 'comedy' AND created_date <= '2025-07-05'\""
19
+ description: "WHERE clause to identify which records to update. Example: \"genre = 'comedy' AND created_date <= '2025-07-05'\"",
20
20
  },
21
21
  databaseName: {
22
22
  type: "string",
23
- description: "Name of the database to use (optional). Omit to use the default database."
23
+ description: "Name of the database to use (optional). Omit to use the default configured database.",
24
24
  },
25
25
  },
26
26
  required: ["tableName", "updates", "whereClause"],
@@ -35,7 +35,7 @@ export class UpdateDataTool {
35
35
  return { success: false, message: error };
36
36
  }
37
37
  // Basic validation: ensure whereClause is not empty
38
- if (!whereClause || whereClause.trim() === '') {
38
+ if (!whereClause || whereClause.trim() === "") {
39
39
  throw new Error("WHERE clause is required for security reasons");
40
40
  }
41
41
  // Build SET clause with parameterized queries for security
@@ -58,7 +58,7 @@ export class UpdateDataTool {
58
58
  console.error("Error updating data:", error);
59
59
  return {
60
60
  success: false,
61
- message: `Failed to update data ${query ? ` with '${query}'` : ''}: ${error}`,
61
+ message: `Failed to update data ${query ? ` with '${query}'` : ""}: ${error}`,
62
62
  };
63
63
  }
64
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"UpdateDataTool.js","sourceRoot":"","sources":["../../src/tools/UpdateDataTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,OAAO,cAAc;IAA3B;QAEE,SAAI,GAAG,aAAa,CAAC;QACrB,gBAAW,GAAG,+GAA+G,CAAC;QAC9H,gBAAW,GAAG;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,6BAA6B;iBAC3C;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,qGAAqG;iBACnH;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,kHAAkH;iBAChI;gBACD,YAAY,EAAE;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,2EAA2E;iBACzF;aACF;YACD,QAAQ,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC;SAC3C,CAAC;IA0CX,CAAC;IAxCC,KAAK,CAAC,GAAG,CAAC,MAAW;QACnB,IAAI,KAAyB,CAAC;QAC9B,IAAI;YACF,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;YAEjE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;YAC7D,IAAI,KAAK,EAAE;gBACT,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;aAC3C;YAED,oDAAoD;YACpD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBAC7C,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;aAClE;YAED,2DAA2D;YAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;iBACnC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBAClB,MAAM,SAAS,GAAG,UAAU,KAAK,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;gBACvC,OAAO,IAAI,GAAG,QAAQ,SAAS,EAAE,CAAC;YACpC,CAAC,CAAC;iBACD,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,KAAK,GAAG,UAAU,SAAS,QAAQ,SAAS,UAAU,WAAW,EAAE,CAAC;YACpE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAE1C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,kCAAkC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,kBAAkB;gBACnF,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;aACrC,CAAC;SACH;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,yBAAyB,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,EAAE;aAC9E,CAAC;SACH;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"UpdateDataTool.js","sourceRoot":"","sources":["../../src/tools/UpdateDataTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,OAAO,cAAc;IAA3B;QAEE,SAAI,GAAG,aAAa,CAAC;QACrB,gBAAW,GACT,+GAA+G,CAAC;QAClH,gBAAW,GAAG;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,6BAA6B;iBAC3C;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,qGAAqG;iBACxG;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,kHAAkH;iBACrH;gBACD,YAAY,EAAE;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,sFAAsF;iBACzF;aACF;YACD,QAAQ,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC;SAC3C,CAAC;IA0CX,CAAC;IAxCC,KAAK,CAAC,GAAG,CAAC,MAAW;QACnB,IAAI,KAAyB,CAAC;QAC9B,IAAI;YACF,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;YAEjE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;YAC7D,IAAI,KAAK,EAAE;gBACT,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;aAC3C;YAED,oDAAoD;YACpD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBAC7C,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;aAClE;YAED,2DAA2D;YAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;iBACnC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBAClB,MAAM,SAAS,GAAG,UAAU,KAAK,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;gBACvC,OAAO,IAAI,GAAG,QAAQ,SAAS,EAAE,CAAC;YACpC,CAAC,CAAC;iBACD,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,KAAK,GAAG,UAAU,SAAS,QAAQ,SAAS,UAAU,WAAW,EAAE,CAAC;YACpE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAE1C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,kCAAkC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,kBAAkB;gBACnF,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;aACrC,CAAC;SACH;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,yBAAyB,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,EAAE;aAC9E,CAAC;SACH;IACH,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * SQL query validation for read-only operations.
3
+ * Extracted for testability and reuse.
4
+ */
5
+ export interface ValidationResult {
6
+ isValid: boolean;
7
+ error?: string;
8
+ }
9
+ /**
10
+ * Validates a SQL query for read-only (SELECT) operations.
11
+ * Rejects dangerous keywords, injection patterns, and multi-statement queries.
12
+ */
13
+ export declare function validateReadQuery(query: string): ValidationResult;
14
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA8DH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAoFjE"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * SQL query validation for read-only operations.
3
+ * Extracted for testability and reuse.
4
+ */
5
+ const DANGEROUS_KEYWORDS = [
6
+ "DELETE",
7
+ "DROP",
8
+ "UPDATE",
9
+ "INSERT",
10
+ "ALTER",
11
+ "CREATE",
12
+ "TRUNCATE",
13
+ "EXEC",
14
+ "EXECUTE",
15
+ "MERGE",
16
+ "REPLACE",
17
+ "GRANT",
18
+ "REVOKE",
19
+ "COMMIT",
20
+ "ROLLBACK",
21
+ "TRANSACTION",
22
+ "BEGIN",
23
+ "DECLARE",
24
+ "SET",
25
+ "USE",
26
+ "BACKUP",
27
+ "RESTORE",
28
+ "KILL",
29
+ "SHUTDOWN",
30
+ "WAITFOR",
31
+ "OPENROWSET",
32
+ "OPENDATASOURCE",
33
+ "OPENQUERY",
34
+ "OPENXML",
35
+ "BULK",
36
+ "INTO",
37
+ ];
38
+ const DANGEROUS_PATTERNS = [
39
+ /SELECT\s+.*?\s+INTO\s+/i,
40
+ /;\s*(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE|MERGE|REPLACE|GRANT|REVOKE)/i,
41
+ /UNION\s+(?:ALL\s+)?SELECT.*?(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)/i,
42
+ /--.*?(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)/i,
43
+ /\/\*.*?(DELETE|DROP|UPDATE|INSERT|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE).*?\*\//i,
44
+ /EXEC\s*\(/i,
45
+ /EXECUTE\s*\(/i,
46
+ /sp_/i,
47
+ /xp_/i,
48
+ /BULK\s+INSERT/i,
49
+ /OPENROWSET/i,
50
+ /OPENDATASOURCE/i,
51
+ /@@/,
52
+ /SYSTEM_USER/i,
53
+ /USER_NAME/i,
54
+ /DB_NAME/i,
55
+ /HOST_NAME/i,
56
+ /WAITFOR\s+DELAY/i,
57
+ /WAITFOR\s+TIME/i,
58
+ /;\s*\w/,
59
+ /\+\s*CHAR\s*\(/i,
60
+ /\+\s*NCHAR\s*\(/i,
61
+ /\+\s*ASCII\s*\(/i,
62
+ ];
63
+ /**
64
+ * Validates a SQL query for read-only (SELECT) operations.
65
+ * Rejects dangerous keywords, injection patterns, and multi-statement queries.
66
+ */
67
+ export function validateReadQuery(query) {
68
+ if (!query || typeof query !== "string") {
69
+ return {
70
+ isValid: false,
71
+ error: "Query must be a non-empty string",
72
+ };
73
+ }
74
+ const cleanQuery = query
75
+ .replace(/--.*$/gm, "")
76
+ .replace(/\/\*[\s\S]*?\*\//g, "")
77
+ .replace(/\s+/g, " ")
78
+ .trim();
79
+ if (!cleanQuery) {
80
+ return {
81
+ isValid: false,
82
+ error: "Query cannot be empty after removing comments",
83
+ };
84
+ }
85
+ const upperQuery = cleanQuery.toUpperCase();
86
+ if (!upperQuery.startsWith("SELECT")) {
87
+ return {
88
+ isValid: false,
89
+ error: "Query must start with SELECT for security reasons",
90
+ };
91
+ }
92
+ for (const keyword of DANGEROUS_KEYWORDS) {
93
+ const keywordRegex = new RegExp(`(^|\\s|[^A-Za-z0-9_])${keyword}($|\\s|[^A-Za-z0-9_])`, "i");
94
+ if (keywordRegex.test(upperQuery)) {
95
+ return {
96
+ isValid: false,
97
+ error: `Dangerous keyword '${keyword}' detected in query. Only SELECT operations are allowed.`,
98
+ };
99
+ }
100
+ }
101
+ for (const pattern of DANGEROUS_PATTERNS) {
102
+ if (pattern.test(query)) {
103
+ return {
104
+ isValid: false,
105
+ error: "Potentially malicious SQL pattern detected. Only simple SELECT queries are allowed.",
106
+ };
107
+ }
108
+ }
109
+ const statements = cleanQuery
110
+ .split(";")
111
+ .filter((stmt) => stmt.trim().length > 0);
112
+ if (statements.length > 1) {
113
+ return {
114
+ isValid: false,
115
+ error: "Multiple SQL statements are not allowed. Use only a single SELECT statement.",
116
+ };
117
+ }
118
+ if (query.includes("CHAR(") ||
119
+ query.includes("NCHAR(") ||
120
+ query.includes("ASCII(")) {
121
+ return {
122
+ isValid: false,
123
+ error: "Character conversion functions are not allowed as they may be used for obfuscation.",
124
+ };
125
+ }
126
+ if (query.length > 10000) {
127
+ return {
128
+ isValid: false,
129
+ error: "Query is too long. Maximum allowed length is 10,000 characters.",
130
+ };
131
+ }
132
+ return { isValid: true };
133
+ }
134
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eamonboyle/mssql-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server for Microsoft SQL Server - query and manage your database with natural language in Cursor, Claude, and VS Code",
5
5
  "keywords": [
6
6
  "mcp",
@@ -29,7 +29,11 @@
29
29
  "build": "tsc && shx chmod +x dist/*.js",
30
30
  "prepare": "npm run build",
31
31
  "watch": "tsc --watch",
32
- "start": "node dist/index.js"
32
+ "start": "node dist/index.js",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "lint": "eslint src",
36
+ "format": "prettier --write src"
33
37
  },
34
38
  "files": [
35
39
  "dist"
@@ -38,10 +42,16 @@
38
42
  "node": ">=18.0.0"
39
43
  },
40
44
  "devDependencies": {
45
+ "@eslint/js": "^9.39.2",
41
46
  "@types/mssql": "^9.1.7",
42
- "@types/node": "^16.7.13",
47
+ "@types/node": "^20.0.0",
48
+ "eslint": "^9.39.2",
49
+ "eslint-config-prettier": "^10.1.8",
50
+ "prettier": "^3.8.1",
43
51
  "shx": "^0.3.4",
44
- "typescript": "^4.9.5"
52
+ "typescript": "^4.9.5",
53
+ "typescript-eslint": "^8.55.0",
54
+ "vitest": "^2.1.0"
45
55
  },
46
56
  "dependencies": {
47
57
  "@modelcontextprotocol/sdk": "^1.0.0",