@eamonboyle/mssql-mcp 1.0.0 → 1.2.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 (133) hide show
  1. package/README.md +153 -36
  2. package/dist/__tests__/ExplainQueryTool.test.d.ts +2 -0
  3. package/dist/__tests__/ExplainQueryTool.test.d.ts.map +1 -0
  4. package/dist/__tests__/ExplainQueryTool.test.js +96 -0
  5. package/dist/__tests__/ExplainQueryTool.test.js.map +1 -0
  6. package/dist/__tests__/config.test.d.ts +2 -0
  7. package/dist/__tests__/config.test.d.ts.map +1 -0
  8. package/dist/__tests__/config.test.js +29 -0
  9. package/dist/__tests__/config.test.js.map +1 -0
  10. package/dist/__tests__/db.test.d.ts +2 -0
  11. package/dist/__tests__/db.test.d.ts.map +1 -0
  12. package/dist/__tests__/db.test.js +204 -0
  13. package/dist/__tests__/db.test.js.map +1 -0
  14. package/dist/__tests__/promptRegistry.test.d.ts +2 -0
  15. package/dist/__tests__/promptRegistry.test.d.ts.map +1 -0
  16. package/dist/__tests__/promptRegistry.test.js +40 -0
  17. package/dist/__tests__/promptRegistry.test.js.map +1 -0
  18. package/dist/__tests__/resourceRegistry.test.d.ts +2 -0
  19. package/dist/__tests__/resourceRegistry.test.d.ts.map +1 -0
  20. package/dist/__tests__/resourceRegistry.test.js +40 -0
  21. package/dist/__tests__/resourceRegistry.test.js.map +1 -0
  22. package/dist/__tests__/schema.test.d.ts +2 -0
  23. package/dist/__tests__/schema.test.d.ts.map +1 -0
  24. package/dist/__tests__/schema.test.js +130 -0
  25. package/dist/__tests__/schema.test.js.map +1 -0
  26. package/dist/__tests__/sql.test.d.ts +2 -0
  27. package/dist/__tests__/sql.test.d.ts.map +1 -0
  28. package/dist/__tests__/sql.test.js +35 -0
  29. package/dist/__tests__/sql.test.js.map +1 -0
  30. package/dist/__tests__/toolRegistry.test.d.ts +2 -0
  31. package/dist/__tests__/toolRegistry.test.d.ts.map +1 -0
  32. package/dist/__tests__/toolRegistry.test.js +47 -0
  33. package/dist/__tests__/toolRegistry.test.js.map +1 -0
  34. package/dist/__tests__/validation.test.d.ts +2 -0
  35. package/dist/__tests__/validation.test.d.ts.map +1 -0
  36. package/dist/__tests__/validation.test.js +111 -0
  37. package/dist/__tests__/validation.test.js.map +1 -0
  38. package/dist/__tests__/writeTools.test.d.ts +2 -0
  39. package/dist/__tests__/writeTools.test.d.ts.map +1 -0
  40. package/dist/__tests__/writeTools.test.js +115 -0
  41. package/dist/__tests__/writeTools.test.js.map +1 -0
  42. package/dist/config.d.ts +5 -0
  43. package/dist/config.d.ts.map +1 -0
  44. package/dist/config.js +34 -0
  45. package/dist/config.js.map +1 -0
  46. package/dist/db.d.ts +28 -24
  47. package/dist/db.d.ts.map +1 -1
  48. package/dist/db.js +144 -89
  49. package/dist/db.js.map +1 -1
  50. package/dist/index.d.ts +2 -2
  51. package/dist/index.js +70 -105
  52. package/dist/index.js.map +1 -1
  53. package/dist/promptRegistry.d.ts +16 -0
  54. package/dist/promptRegistry.d.ts.map +1 -0
  55. package/dist/promptRegistry.js +107 -0
  56. package/dist/promptRegistry.js.map +1 -0
  57. package/dist/resourceRegistry.d.ts +12 -0
  58. package/dist/resourceRegistry.d.ts.map +1 -0
  59. package/dist/resourceRegistry.js +172 -0
  60. package/dist/resourceRegistry.js.map +1 -0
  61. package/dist/schema.d.ts +41 -0
  62. package/dist/schema.d.ts.map +1 -0
  63. package/dist/schema.js +211 -0
  64. package/dist/schema.js.map +1 -0
  65. package/dist/sql.d.ts +7 -0
  66. package/dist/sql.d.ts.map +1 -0
  67. package/dist/sql.js +73 -0
  68. package/dist/sql.js.map +1 -0
  69. package/dist/toolRegistry.d.ts +16 -0
  70. package/dist/toolRegistry.d.ts.map +1 -0
  71. package/dist/toolRegistry.js +401 -0
  72. package/dist/toolRegistry.js.map +1 -0
  73. package/dist/tools/CreateIndexTool.d.ts +30 -23
  74. package/dist/tools/CreateIndexTool.d.ts.map +1 -1
  75. package/dist/tools/CreateIndexTool.js +47 -71
  76. package/dist/tools/CreateIndexTool.js.map +1 -1
  77. package/dist/tools/CreateTableTool.d.ts +18 -11
  78. package/dist/tools/CreateTableTool.d.ts.map +1 -1
  79. package/dist/tools/CreateTableTool.js +37 -56
  80. package/dist/tools/CreateTableTool.js.map +1 -1
  81. package/dist/tools/DeleteDataTool.d.ts +22 -0
  82. package/dist/tools/DeleteDataTool.d.ts.map +1 -0
  83. package/dist/tools/DeleteDataTool.js +35 -0
  84. package/dist/tools/DeleteDataTool.js.map +1 -0
  85. package/dist/tools/DescribeObjectTool.d.ts +21 -0
  86. package/dist/tools/DescribeObjectTool.d.ts.map +1 -0
  87. package/dist/tools/DescribeObjectTool.js +31 -0
  88. package/dist/tools/DescribeObjectTool.js.map +1 -0
  89. package/dist/tools/DescribeTableTool.d.ts +19 -20
  90. package/dist/tools/DescribeTableTool.d.ts.map +1 -1
  91. package/dist/tools/DescribeTableTool.js +23 -41
  92. package/dist/tools/DescribeTableTool.js.map +1 -1
  93. package/dist/tools/DropTableTool.d.ts +13 -11
  94. package/dist/tools/DropTableTool.d.ts.map +1 -1
  95. package/dist/tools/DropTableTool.js +30 -44
  96. package/dist/tools/DropTableTool.js.map +1 -1
  97. package/dist/tools/ExplainQueryTool.d.ts +32 -0
  98. package/dist/tools/ExplainQueryTool.d.ts.map +1 -0
  99. package/dist/tools/ExplainQueryTool.js +102 -0
  100. package/dist/tools/ExplainQueryTool.js.map +1 -0
  101. package/dist/tools/InsertDataTool.d.ts +20 -16
  102. package/dist/tools/InsertDataTool.d.ts.map +1 -1
  103. package/dist/tools/InsertDataTool.js +91 -108
  104. package/dist/tools/InsertDataTool.js.map +1 -1
  105. package/dist/tools/ListObjectsTool.d.ts +20 -0
  106. package/dist/tools/ListObjectsTool.d.ts.map +1 -0
  107. package/dist/tools/ListObjectsTool.js +26 -0
  108. package/dist/tools/ListObjectsTool.js.map +1 -0
  109. package/dist/tools/ListTableTool.d.ts +20 -16
  110. package/dist/tools/ListTableTool.d.ts.map +1 -1
  111. package/dist/tools/ListTableTool.js +32 -49
  112. package/dist/tools/ListTableTool.js.map +1 -1
  113. package/dist/tools/ReadDataTool.d.ts +35 -41
  114. package/dist/tools/ReadDataTool.d.ts.map +1 -1
  115. package/dist/tools/ReadDataTool.js +92 -228
  116. package/dist/tools/ReadDataTool.js.map +1 -1
  117. package/dist/tools/SearchDataTool.d.ts +27 -0
  118. package/dist/tools/SearchDataTool.d.ts.map +1 -0
  119. package/dist/tools/SearchDataTool.js +61 -0
  120. package/dist/tools/SearchDataTool.js.map +1 -0
  121. package/dist/tools/UpdateDataTool.d.ts +21 -16
  122. package/dist/tools/UpdateDataTool.d.ts.map +1 -1
  123. package/dist/tools/UpdateDataTool.js +45 -65
  124. package/dist/tools/UpdateDataTool.js.map +1 -1
  125. package/dist/validation.d.ts +14 -0
  126. package/dist/validation.d.ts.map +1 -0
  127. package/dist/validation.js +134 -0
  128. package/dist/validation.js.map +1 -0
  129. package/dist/writeSafety.d.ts +21 -0
  130. package/dist/writeSafety.d.ts.map +1 -0
  131. package/dist/writeSafety.js +169 -0
  132. package/dist/writeSafety.js.map +1 -0
  133. package/package.json +17 -6
@@ -1,50 +1,33 @@
1
- import { getSqlRequest } from "../db.js";
2
- export class ListTableTool {
3
- constructor() {
4
- this.name = "list_table";
5
- this.description = "Lists tables in an MSSQL Database, or list tables in specific schemas";
6
- this.inputSchema = {
7
- type: "object",
8
- properties: {
9
- parameters: {
10
- type: "array",
11
- description: "Schemas to filter by (optional)",
12
- items: {
13
- type: "string"
14
- },
15
- minItems: 0
16
- },
17
- databaseName: {
18
- type: "string",
19
- description: "Name of the database to use (optional). Omit to use the default database."
20
- },
21
- },
22
- required: [],
23
- };
24
- }
25
- async run(params) {
26
- try {
27
- const { parameters, databaseName } = params || {};
28
- const { request, error } = await getSqlRequest(databaseName);
29
- if (error) {
30
- return { success: false, message: error };
31
- }
32
- const schemaFilter = parameters && parameters.length > 0 ? `AND TABLE_SCHEMA IN (${parameters.map((p) => `'${p}'`).join(", ")})` : "";
33
- const query = `SELECT TABLE_SCHEMA + '.' + TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' ${schemaFilter} ORDER BY TABLE_SCHEMA, TABLE_NAME`;
34
- const result = await request.query(query);
35
- return {
36
- success: true,
37
- message: `List tables executed successfully`,
38
- items: result.recordset,
39
- };
40
- }
41
- catch (error) {
42
- console.error("Error listing tables:", error);
43
- return {
44
- success: false,
45
- message: `Failed to list tables: ${error}`,
46
- };
47
- }
48
- }
49
- }
1
+ import { listDatabaseTables } from "../schema.js";
2
+ export class ListTableTool {
3
+ constructor() {
4
+ this.name = "list_table";
5
+ this.description = "Lists tables in an MSSQL Database, or list tables in specific schemas";
6
+ }
7
+ async run(params = {}) {
8
+ try {
9
+ const { parameters, databaseName } = params;
10
+ const schemaNames = Array.isArray(parameters)
11
+ ? parameters.filter((value) => typeof value === "string")
12
+ : [];
13
+ const tables = schemaNames.length > 0
14
+ ? (await Promise.all(schemaNames.map((schemaName) => listDatabaseTables(databaseName, schemaName)))).flat()
15
+ : await listDatabaseTables(databaseName);
16
+ return {
17
+ success: true,
18
+ message: `List tables executed successfully`,
19
+ items: tables.map((table) => ({
20
+ name: `${table.schemaName}.${table.tableName}`,
21
+ })),
22
+ };
23
+ }
24
+ catch (error) {
25
+ console.error("Error listing tables:", error);
26
+ return {
27
+ success: false,
28
+ message: `Failed to list tables: ${error}`,
29
+ };
30
+ }
31
+ }
32
+ }
50
33
  //# sourceMappingURL=ListTableTool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListTableTool.js","sourceRoot":"","sources":["../../src/tools/ListTableTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,OAAO,aAAa;IAA1B;QAEE,SAAI,GAAG,YAAY,CAAC;QACpB,gBAAW,GAAG,uEAAuE,CAAC;QACtF,gBAAW,GAAG;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,UAAU,EAAE;oBACV,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,iCAAiC;oBAC9C,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;qBACf;oBACD,QAAQ,EAAE,CAAC;iBACZ;gBACD,YAAY,EAAE;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,2EAA2E;iBACzF;aACF;YACD,QAAQ,EAAE,EAAE;SACN,CAAC;IA0BX,CAAC;IAxBC,KAAK,CAAC,GAAG,CAAC,MAAW;QACnB,IAAI;YACF,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;YAElD,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;YACD,MAAM,YAAY,GAAG,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,wBAAwB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9I,MAAM,KAAK,GAAG,yGAAyG,YAAY,oCAAoC,CAAC;YACxK,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,mCAAmC;gBAC5C,KAAK,EAAE,MAAM,CAAC,SAAS;aACxB,CAAC;SACH;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC9C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,0BAA0B,KAAK,EAAE;aAC3C,CAAC;SACH;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"ListTableTool.js","sourceRoot":"","sources":["../../src/tools/ListTableTool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOlD,MAAM,OAAO,aAAa;IAA1B;QACE,SAAI,GAAG,YAAY,CAAC;QACpB,gBAAW,GACT,uEAAuE,CAAC;IAmC5E,CAAC;IAjCC,KAAK,CAAC,GAAG,CAAC,SAA0B,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;YAC5C,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;gBAC3C,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;gBAClE,CAAC,CAAC,EAAE,CAAC;YAEP,MAAM,MAAM,GACV,WAAW,CAAC,MAAM,GAAG,CAAC;gBACpB,CAAC,CAAC,CACE,MAAM,OAAO,CAAC,GAAG,CACf,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAC7B,kBAAkB,CAAC,YAAY,EAAE,UAAU,CAAC,CAC7C,CACF,CACF,CAAC,IAAI,EAAE;gBACV,CAAC,CAAC,MAAM,kBAAkB,CAAC,YAAY,CAAC,CAAC;YAE7C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,mCAAmC;gBAC5C,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBAC5B,IAAI,EAAE,GAAG,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,SAAS,EAAE;iBAC/C,CAAC,CAAC;aACJ,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC9C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,0BAA0B,KAAK,EAAE;aAC3C,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -1,42 +1,36 @@
1
- import { Tool } from "@modelcontextprotocol/sdk/types.js";
2
- export declare class ReadDataTool implements Tool {
3
- [key: string]: any;
4
- name: string;
5
- description: string;
6
- inputSchema: any;
7
- private static readonly DANGEROUS_KEYWORDS;
8
- private static readonly DANGEROUS_PATTERNS;
9
- /**
10
- * Validates the SQL query for security issues
11
- * @param query The SQL query to validate
12
- * @returns Validation result with success flag and error message if invalid
13
- */
14
- private validateQuery;
15
- /**
16
- * Sanitizes the query result to prevent any potential security issues
17
- * @param data The query result data
18
- * @returns Sanitized data
19
- */
20
- private sanitizeResult;
21
- /**
22
- * Executes the validated SQL query
23
- * @param params Query parameters
24
- * @returns Query execution result
25
- */
26
- run(params: any): Promise<{
27
- success: boolean;
28
- message: string;
29
- error: string;
30
- data?: undefined;
31
- recordCount?: undefined;
32
- totalRecords?: undefined;
33
- } | {
34
- success: boolean;
35
- message: string;
36
- data: any[];
37
- recordCount: number;
38
- totalRecords: number;
39
- error?: undefined;
40
- }>;
41
- }
1
+ interface ReadDataParams {
2
+ query: string;
3
+ databaseName?: string;
4
+ }
5
+ export declare class ReadDataTool {
6
+ name: string;
7
+ description: string;
8
+ /**
9
+ * Sanitizes the query result to prevent any potential security issues
10
+ * @param data The query result data
11
+ * @returns Sanitized data
12
+ */
13
+ private sanitizeResult;
14
+ /**
15
+ * Executes the validated SQL query
16
+ * @param params Query parameters
17
+ * @returns Query execution result
18
+ */
19
+ run(params: ReadDataParams): Promise<{
20
+ success: boolean;
21
+ message: string;
22
+ error: string;
23
+ data?: undefined;
24
+ recordCount?: undefined;
25
+ totalRecords?: undefined;
26
+ } | {
27
+ success: boolean;
28
+ message: string;
29
+ data: unknown[];
30
+ recordCount: number;
31
+ totalRecords: number;
32
+ error?: undefined;
33
+ }>;
34
+ }
35
+ export {};
42
36
  //# sourceMappingURL=ReadDataTool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReadDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/ReadDataTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG1D,qBAAa,YAAa,YAAW,IAAI;IACvC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,IAAI,SAAe;IACnB,WAAW,SAAkK;IAE7K,WAAW,MAaF;IAGT,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAOxC;IAGF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CA+CxC;IAEF;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAkFrB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IA6BtB;;;;OAIG;IACG,GAAG,CAAC,MAAM,EAAE,GAAG;;;;;;;;;;;;;;;CAyDtB"}
1
+ {"version":3,"file":"ReadDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/ReadDataTool.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,YAAY;IACvB,IAAI,SAAe;IACnB,WAAW,SACsJ;IAEjK;;;;OAIG;IACH,OAAO,CAAC,cAAc;IA+BtB;;;;OAIG;IACG,GAAG,CAAC,MAAM,EAAE,cAAc;;;;;;;;;;;;;;;CA6DjC"}
@@ -1,229 +1,93 @@
1
- import { getSqlRequest } from "../db.js";
2
- export class ReadDataTool {
3
- constructor() {
4
- this.name = "read_data";
5
- this.description = "Executes a SELECT query on an MSSQL Database table. The query must start with SELECT and cannot contain any destructive SQL operations for security reasons.";
6
- this.inputSchema = {
7
- type: "object",
8
- properties: {
9
- query: {
10
- 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
- },
13
- databaseName: {
14
- type: "string",
15
- description: "Name of the database to query (optional). Omit to use the default database."
16
- },
17
- },
18
- required: ["query"],
19
- };
20
- }
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
- /**
98
- * Sanitizes the query result to prevent any potential security issues
99
- * @param data The query result data
100
- * @returns Sanitized data
101
- */
102
- sanitizeResult(data) {
103
- if (!Array.isArray(data)) {
104
- return [];
105
- }
106
- // Limit the number of returned records to prevent memory issues
107
- const maxRecords = 10000;
108
- if (data.length > maxRecords) {
109
- console.warn(`Query returned ${data.length} records, limiting to ${maxRecords}`);
110
- return data.slice(0, maxRecords);
111
- }
112
- return data.map(record => {
113
- if (typeof record === 'object' && record !== null) {
114
- const sanitized = {};
115
- for (const [key, value] of Object.entries(record)) {
116
- // Sanitize column names (remove any suspicious characters)
117
- const sanitizedKey = key.replace(/[^\w\s-_.]/g, '');
118
- if (sanitizedKey !== key) {
119
- console.warn(`Column name sanitized: ${key} -> ${sanitizedKey}`);
120
- }
121
- sanitized[sanitizedKey] = value;
122
- }
123
- return sanitized;
124
- }
125
- return record;
126
- });
127
- }
128
- /**
129
- * Executes the validated SQL query
130
- * @param params Query parameters
131
- * @returns Query execution result
132
- */
133
- async run(params) {
134
- try {
135
- const { query, databaseName } = params;
136
- const { request, error } = await getSqlRequest(databaseName);
137
- if (error) {
138
- return { success: false, message: error, error: "INVALID_DATABASE" };
139
- }
140
- // Validate the query for security issues
141
- const validation = this.validateQuery(query);
142
- if (!validation.isValid) {
143
- console.warn(`Security validation failed for query: ${query.substring(0, 100)}...`);
144
- return {
145
- success: false,
146
- message: `Security validation failed: ${validation.error}`,
147
- error: 'SECURITY_VALIDATION_FAILED'
148
- };
149
- }
150
- // 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 ? '...' : ''}`);
152
- // Execute the query
153
- const result = await request.query(query);
154
- // Sanitize the result
155
- const sanitizedData = this.sanitizeResult(result.recordset);
156
- return {
157
- success: true,
158
- message: `Query executed successfully. Retrieved ${sanitizedData.length} record(s)${result.recordset.length !== sanitizedData.length
159
- ? ` (limited from ${result.recordset.length} total records)`
160
- : ''}`,
161
- data: sanitizedData,
162
- recordCount: sanitizedData.length,
163
- totalRecords: result.recordset.length
164
- };
165
- }
166
- catch (error) {
167
- console.error("Error executing query:", error);
168
- // 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')
171
- ? errorMessage
172
- : 'Database query execution failed';
173
- return {
174
- success: false,
175
- message: `Failed to execute query: ${safeErrorMessage}`,
176
- error: 'QUERY_EXECUTION_FAILED'
177
- };
178
- }
179
- }
180
- }
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
- ];
1
+ import { getMaxRows } from "../config.js";
2
+ import { getSqlRequest } from "../db.js";
3
+ import { validateReadQuery } from "../validation.js";
4
+ export class ReadDataTool {
5
+ constructor() {
6
+ this.name = "read_data";
7
+ this.description = "Executes a SELECT query on an MSSQL Database table. The query must start with SELECT and cannot contain any destructive SQL operations for security reasons.";
8
+ }
9
+ /**
10
+ * Sanitizes the query result to prevent any potential security issues
11
+ * @param data The query result data
12
+ * @returns Sanitized data
13
+ */
14
+ sanitizeResult(data) {
15
+ if (!Array.isArray(data)) {
16
+ return [];
17
+ }
18
+ // Limit the number of returned records to prevent memory issues
19
+ const maxRecords = getMaxRows();
20
+ if (data.length > maxRecords) {
21
+ console.warn(`Query returned ${data.length} records, limiting to ${maxRecords}`);
22
+ return data.slice(0, maxRecords);
23
+ }
24
+ return data.map((record) => {
25
+ if (typeof record === "object" && record !== null) {
26
+ const sanitized = {};
27
+ for (const [key, value] of Object.entries(record)) {
28
+ // Sanitize column names (remove any suspicious characters)
29
+ const sanitizedKey = key.replace(/[^\w\s-_.]/g, "");
30
+ if (sanitizedKey !== key) {
31
+ console.warn(`Column name sanitized: ${key} -> ${sanitizedKey}`);
32
+ }
33
+ sanitized[sanitizedKey] = value;
34
+ }
35
+ return sanitized;
36
+ }
37
+ return record;
38
+ });
39
+ }
40
+ /**
41
+ * Executes the validated SQL query
42
+ * @param params Query parameters
43
+ * @returns Query execution result
44
+ */
45
+ async run(params) {
46
+ try {
47
+ const { query, databaseName } = params;
48
+ const { request, error } = await getSqlRequest(databaseName);
49
+ if (error) {
50
+ return { success: false, message: error, error: "INVALID_DATABASE" };
51
+ }
52
+ // Validate the query for security issues
53
+ const validation = validateReadQuery(query);
54
+ if (!validation.isValid) {
55
+ console.warn(`Security validation failed for query: ${query.substring(0, 100)}...`);
56
+ return {
57
+ success: false,
58
+ message: `Security validation failed: ${validation.error}`,
59
+ error: "SECURITY_VALIDATION_FAILED",
60
+ };
61
+ }
62
+ // Log the query for audit purposes (in production, consider more secure logging)
63
+ console.log(`Executing validated SELECT query: ${query.substring(0, 200)}${query.length > 200 ? "..." : ""}`);
64
+ // Execute the query
65
+ const result = await request.query(query);
66
+ // Sanitize the result
67
+ const sanitizedData = this.sanitizeResult(result.recordset);
68
+ return {
69
+ success: true,
70
+ message: `Query executed successfully. Retrieved ${sanitizedData.length} record(s)${result.recordset.length !== sanitizedData.length
71
+ ? ` (limited from ${result.recordset.length} total records)`
72
+ : ""}`,
73
+ data: sanitizedData,
74
+ recordCount: sanitizedData.length,
75
+ totalRecords: result.recordset.length,
76
+ };
77
+ }
78
+ catch (error) {
79
+ console.error("Error executing query:", error);
80
+ // Don't expose internal error details to prevent information leakage
81
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
82
+ const safeErrorMessage = errorMessage.includes("Invalid object name")
83
+ ? errorMessage
84
+ : "Database query execution failed";
85
+ return {
86
+ success: false,
87
+ message: `Failed to execute query: ${safeErrorMessage}`,
88
+ error: "QUERY_EXECUTION_FAILED",
89
+ };
90
+ }
91
+ }
92
+ }
229
93
  //# 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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"}
@@ -0,0 +1,27 @@
1
+ interface SearchDataParams {
2
+ tableName: string;
3
+ schemaName?: string;
4
+ columns: string[];
5
+ searchTerm: string;
6
+ limit?: number;
7
+ databaseName?: string;
8
+ }
9
+ export declare class SearchDataTool {
10
+ name: string;
11
+ description: string;
12
+ run(params: SearchDataParams): Promise<{
13
+ success: boolean;
14
+ message: string;
15
+ data?: undefined;
16
+ recordCount?: undefined;
17
+ limit?: undefined;
18
+ } | {
19
+ success: boolean;
20
+ message: string;
21
+ data: import("mssql").IRecordSet<any>;
22
+ recordCount: number;
23
+ limit: number;
24
+ }>;
25
+ }
26
+ export {};
27
+ //# sourceMappingURL=SearchDataTool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/SearchDataTool.ts"],"names":[],"mappings":"AAIA,UAAU,gBAAgB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,cAAc;IACzB,IAAI,SAAiB;IACrB,WAAW,SACsF;IAE3F,GAAG,CAAC,MAAM,EAAE,gBAAgB;;;;;;;;;;;;;CA+DnC"}
@@ -0,0 +1,61 @@
1
+ import { clampRowLimit, getDefaultSearchLimit } from "../config.js";
2
+ import { getSqlRequest } from "../db.js";
3
+ import { buildQualifiedName, quoteIdentifier } from "../sql.js";
4
+ export class SearchDataTool {
5
+ constructor() {
6
+ this.name = "search_data";
7
+ this.description = "Searches rows in a table by applying a parameterized LIKE filter across one or more columns.";
8
+ }
9
+ async run(params) {
10
+ try {
11
+ const { tableName, schemaName, columns, searchTerm, limit, databaseName, } = params;
12
+ if (!Array.isArray(columns) || columns.length === 0) {
13
+ return {
14
+ success: false,
15
+ message: "The 'columns' field must be a non-empty array.",
16
+ };
17
+ }
18
+ if (typeof searchTerm !== "string" || searchTerm.trim() === "") {
19
+ return {
20
+ success: false,
21
+ message: "The 'searchTerm' field must be a non-empty string.",
22
+ };
23
+ }
24
+ const { request, error } = await getSqlRequest(databaseName);
25
+ if (error) {
26
+ return { success: false, message: error };
27
+ }
28
+ const qualifiedTableName = buildQualifiedName(tableName, schemaName);
29
+ const safeColumns = columns.map((column) => quoteIdentifier(column));
30
+ const top = clampRowLimit(limit, getDefaultSearchLimit());
31
+ const whereClause = safeColumns
32
+ .map((columnName, index) => {
33
+ const parameterName = `search_${index}`;
34
+ request.input(parameterName, `%${searchTerm.trim()}%`);
35
+ return `${columnName} LIKE @${parameterName}`;
36
+ })
37
+ .join(" OR ");
38
+ const query = `
39
+ SELECT TOP (${top}) *
40
+ FROM ${qualifiedTableName}
41
+ WHERE ${whereClause}
42
+ `;
43
+ const result = await request.query(query);
44
+ return {
45
+ success: true,
46
+ message: `Search completed successfully. Retrieved ${result.recordset.length} row(s).`,
47
+ data: result.recordset,
48
+ recordCount: result.recordset.length,
49
+ limit: top,
50
+ };
51
+ }
52
+ catch (error) {
53
+ console.error("Error searching data:", error);
54
+ return {
55
+ success: false,
56
+ message: `Failed to search data: ${error}`,
57
+ };
58
+ }
59
+ }
60
+ }
61
+ //# sourceMappingURL=SearchDataTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchDataTool.js","sourceRoot":"","sources":["../../src/tools/SearchDataTool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAWhE,MAAM,OAAO,cAAc;IAA3B;QACE,SAAI,GAAG,aAAa,CAAC;QACrB,gBAAW,GACT,8FAA8F,CAAC;IAiEnG,CAAC;IA/DC,KAAK,CAAC,GAAG,CAAC,MAAwB;QAChC,IAAI,CAAC;YACH,MAAM,EACJ,SAAS,EACT,UAAU,EACV,OAAO,EACP,UAAU,EACV,KAAK,EACL,YAAY,GACb,GAAG,MAAM,CAAC;YAEX,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpD,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,gDAAgD;iBAC1D,CAAC;YACJ,CAAC;YAED,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBAC/D,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,oDAAoD;iBAC9D,CAAC;YACJ,CAAC;YAED,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;YAC7D,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAC5C,CAAC;YAED,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;YACrE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7E,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;YAC1D,MAAM,WAAW,GAAG,WAAW;iBAC5B,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;gBACzB,MAAM,aAAa,GAAG,UAAU,KAAK,EAAE,CAAC;gBACxC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACvD,OAAO,GAAG,UAAU,UAAU,aAAa,EAAE,CAAC;YAChD,CAAC,CAAC;iBACD,IAAI,CAAC,MAAM,CAAC,CAAC;YAEhB,MAAM,KAAK,GAAG;sBACE,GAAG;eACV,kBAAkB;gBACjB,WAAW;OACpB,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAE1C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,4CAA4C,MAAM,CAAC,SAAS,CAAC,MAAM,UAAU;gBACtF,IAAI,EAAE,MAAM,CAAC,SAAS;gBACtB,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM;gBACpC,KAAK,EAAE,GAAG;aACX,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC9C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,0BAA0B,KAAK,EAAE;aAC3C,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}