@eamonboyle/mssql-mcp 1.1.0 → 1.3.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/README.md +169 -22
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/db.d.ts +29 -24
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +144 -112
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +382 -122
- package/dist/index.js.map +1 -1
- package/dist/mcpResults.d.ts +49 -0
- package/dist/mcpResults.d.ts.map +1 -0
- package/dist/mcpResults.js +246 -0
- package/dist/mcpResults.js.map +1 -0
- package/dist/promptRegistry.d.ts +16 -0
- package/dist/promptRegistry.d.ts.map +1 -0
- package/dist/promptRegistry.js +112 -0
- package/dist/promptRegistry.js.map +1 -0
- package/dist/resourceRegistry.d.ts +14 -0
- package/dist/resourceRegistry.d.ts.map +1 -0
- package/dist/resourceRegistry.js +311 -0
- package/dist/resourceRegistry.js.map +1 -0
- package/dist/schema.d.ts +57 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +390 -0
- package/dist/schema.js.map +1 -0
- package/dist/serverState.d.ts +28 -0
- package/dist/serverState.d.ts.map +1 -0
- package/dist/serverState.js +99 -0
- package/dist/serverState.js.map +1 -0
- package/dist/sql.d.ts +7 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +73 -0
- package/dist/sql.js.map +1 -0
- package/dist/toolRegistry.d.ts +20 -0
- package/dist/toolRegistry.d.ts.map +1 -0
- package/dist/toolRegistry.js +547 -0
- package/dist/toolRegistry.js.map +1 -0
- package/dist/tools/AnalyzeTableTool.d.ts +37 -0
- package/dist/tools/AnalyzeTableTool.d.ts.map +1 -0
- package/dist/tools/AnalyzeTableTool.js +81 -0
- package/dist/tools/AnalyzeTableTool.js.map +1 -0
- package/dist/tools/CreateIndexTool.d.ts +30 -23
- package/dist/tools/CreateIndexTool.d.ts.map +1 -1
- package/dist/tools/CreateIndexTool.js +47 -77
- package/dist/tools/CreateIndexTool.js.map +1 -1
- package/dist/tools/CreateTableTool.d.ts +18 -11
- package/dist/tools/CreateTableTool.d.ts.map +1 -1
- package/dist/tools/CreateTableTool.js +37 -61
- package/dist/tools/CreateTableTool.js.map +1 -1
- package/dist/tools/DeleteDataTool.d.ts +22 -0
- package/dist/tools/DeleteDataTool.d.ts.map +1 -0
- package/dist/tools/DeleteDataTool.js +38 -0
- package/dist/tools/DeleteDataTool.js.map +1 -0
- package/dist/tools/DescribeObjectTool.d.ts +21 -0
- package/dist/tools/DescribeObjectTool.d.ts.map +1 -0
- package/dist/tools/DescribeObjectTool.js +31 -0
- package/dist/tools/DescribeObjectTool.js.map +1 -0
- package/dist/tools/DescribeRelationshipsTool.d.ts +20 -0
- package/dist/tools/DescribeRelationshipsTool.d.ts.map +1 -0
- package/dist/tools/DescribeRelationshipsTool.js +24 -0
- package/dist/tools/DescribeRelationshipsTool.js.map +1 -0
- package/dist/tools/DescribeTableTool.d.ts +19 -20
- package/dist/tools/DescribeTableTool.d.ts.map +1 -1
- package/dist/tools/DescribeTableTool.js +23 -44
- package/dist/tools/DescribeTableTool.js.map +1 -1
- package/dist/tools/DropTableTool.d.ts +13 -11
- package/dist/tools/DropTableTool.d.ts.map +1 -1
- package/dist/tools/DropTableTool.js +30 -44
- package/dist/tools/DropTableTool.js.map +1 -1
- package/dist/tools/ExplainQueryTool.d.ts +32 -0
- package/dist/tools/ExplainQueryTool.d.ts.map +1 -0
- package/dist/tools/ExplainQueryTool.js +102 -0
- package/dist/tools/ExplainQueryTool.js.map +1 -0
- package/dist/tools/InsertDataTool.d.ts +20 -16
- package/dist/tools/InsertDataTool.d.ts.map +1 -1
- package/dist/tools/InsertDataTool.js +91 -108
- package/dist/tools/InsertDataTool.js.map +1 -1
- package/dist/tools/ListDatabasesTool.d.ts +16 -0
- package/dist/tools/ListDatabasesTool.d.ts.map +1 -0
- package/dist/tools/ListDatabasesTool.js +26 -0
- package/dist/tools/ListDatabasesTool.js.map +1 -0
- package/dist/tools/ListForeignKeysTool.d.ts +19 -0
- package/dist/tools/ListForeignKeysTool.d.ts.map +1 -0
- package/dist/tools/ListForeignKeysTool.js +24 -0
- package/dist/tools/ListForeignKeysTool.js.map +1 -0
- package/dist/tools/ListObjectsTool.d.ts +20 -0
- package/dist/tools/ListObjectsTool.d.ts.map +1 -0
- package/dist/tools/ListObjectsTool.js +26 -0
- package/dist/tools/ListObjectsTool.js.map +1 -0
- package/dist/tools/ListTableTool.d.ts +20 -16
- package/dist/tools/ListTableTool.d.ts.map +1 -1
- package/dist/tools/ListTableTool.js +32 -51
- package/dist/tools/ListTableTool.js.map +1 -1
- package/dist/tools/PreviewDeleteTool.d.ts +28 -0
- package/dist/tools/PreviewDeleteTool.d.ts.map +1 -0
- package/dist/tools/PreviewDeleteTool.js +31 -0
- package/dist/tools/PreviewDeleteTool.js.map +1 -0
- package/dist/tools/PreviewUpdateTool.d.ts +30 -0
- package/dist/tools/PreviewUpdateTool.d.ts.map +1 -0
- package/dist/tools/PreviewUpdateTool.js +34 -0
- package/dist/tools/PreviewUpdateTool.js.map +1 -0
- package/dist/tools/ReadDataTool.d.ts +35 -33
- package/dist/tools/ReadDataTool.d.ts.map +1 -1
- package/dist/tools/ReadDataTool.js +92 -105
- package/dist/tools/ReadDataTool.js.map +1 -1
- package/dist/tools/SearchDataTool.d.ts +27 -0
- package/dist/tools/SearchDataTool.d.ts.map +1 -0
- package/dist/tools/SearchDataTool.js +61 -0
- package/dist/tools/SearchDataTool.js.map +1 -0
- package/dist/tools/UpdateDataTool.d.ts +22 -16
- package/dist/tools/UpdateDataTool.d.ts.map +1 -1
- package/dist/tools/UpdateDataTool.js +48 -65
- package/dist/tools/UpdateDataTool.js.map +1 -1
- package/dist/validation.d.ts +13 -13
- package/dist/validation.js +133 -133
- package/dist/validation.js.map +1 -1
- package/dist/writePreview.d.ts +20 -0
- package/dist/writePreview.d.ts.map +1 -0
- package/dist/writePreview.js +27 -0
- package/dist/writePreview.js.map +1 -0
- package/dist/writePreviewGrant.d.ts +18 -0
- package/dist/writePreviewGrant.d.ts.map +1 -0
- package/dist/writePreviewGrant.js +71 -0
- package/dist/writePreviewGrant.js.map +1 -0
- package/dist/writePreviewGrantStore.d.ts +10 -0
- package/dist/writePreviewGrantStore.d.ts.map +1 -0
- package/dist/writePreviewGrantStore.js +47 -0
- package/dist/writePreviewGrantStore.js.map +1 -0
- package/dist/writeSafety.d.ts +21 -0
- package/dist/writeSafety.d.ts.map +1 -0
- package/dist/writeSafety.js +169 -0
- package/dist/writeSafety.js.map +1 -0
- package/package.json +6 -5
- package/dist/__tests__/db.test.d.ts +0 -2
- package/dist/__tests__/db.test.d.ts.map +0 -1
- package/dist/__tests__/db.test.js +0 -204
- package/dist/__tests__/db.test.js.map +0 -1
- package/dist/__tests__/validation.test.d.ts +0 -2
- package/dist/__tests__/validation.test.d.ts.map +0 -1
- package/dist/__tests__/validation.test.js +0 -111
- package/dist/__tests__/validation.test.js.map +0 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SqlFilter } from "../writeSafety.js";
|
|
2
|
+
interface PreviewUpdateParams {
|
|
3
|
+
tableName: string;
|
|
4
|
+
schemaName?: string;
|
|
5
|
+
filters: SqlFilter[];
|
|
6
|
+
updates: Record<string, unknown>;
|
|
7
|
+
previewLimit?: number;
|
|
8
|
+
databaseName?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class PreviewUpdateTool {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
run(params: PreviewUpdateParams): Promise<{
|
|
14
|
+
success: boolean;
|
|
15
|
+
message: string;
|
|
16
|
+
data: {
|
|
17
|
+
updates: Record<string, unknown>;
|
|
18
|
+
query: string;
|
|
19
|
+
countQuery: string;
|
|
20
|
+
rows: import("mssql").IRecordSet<any>;
|
|
21
|
+
affectedRowCount: any;
|
|
22
|
+
};
|
|
23
|
+
} | {
|
|
24
|
+
success: boolean;
|
|
25
|
+
message: string;
|
|
26
|
+
data?: undefined;
|
|
27
|
+
}>;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=PreviewUpdateTool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreviewUpdateTool.d.ts","sourceRoot":"","sources":["../../src/tools/PreviewUpdateTool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,iBAAiB;IAC5B,IAAI,SAAoB;IACxB,WAAW,SAC0D;IAE/D,GAAG,CAAC,MAAM,EAAE,mBAAmB;;;;;;;;;;;;;;;CAyBtC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { clampRowLimit } from "../config.js";
|
|
2
|
+
import { previewFilteredRows } from "../writePreview.js";
|
|
3
|
+
export class PreviewUpdateTool {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = "preview_update";
|
|
6
|
+
this.description = "Previews which rows would be updated before running update_data.";
|
|
7
|
+
}
|
|
8
|
+
async run(params) {
|
|
9
|
+
try {
|
|
10
|
+
const preview = await previewFilteredRows({
|
|
11
|
+
tableName: params.tableName,
|
|
12
|
+
schemaName: params.schemaName,
|
|
13
|
+
filters: params.filters,
|
|
14
|
+
databaseName: params.databaseName,
|
|
15
|
+
limit: clampRowLimit(params.previewLimit, 25),
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
success: true,
|
|
19
|
+
message: `Previewed ${preview.rows.length} row(s) for update; ${preview.affectedRowCount} row(s) would be affected.`,
|
|
20
|
+
data: {
|
|
21
|
+
...preview,
|
|
22
|
+
updates: params.updates,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return {
|
|
28
|
+
success: false,
|
|
29
|
+
message: `Failed to preview update: ${error}`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=PreviewUpdateTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreviewUpdateTool.js","sourceRoot":"","sources":["../../src/tools/PreviewUpdateTool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAYzD,MAAM,OAAO,iBAAiB;IAA9B;QACE,SAAI,GAAG,gBAAgB,CAAC;QACxB,gBAAW,GACT,kEAAkE,CAAC;IA2BvE,CAAC;IAzBC,KAAK,CAAC,GAAG,CAAC,MAA2B;QACnC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC;gBACxC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;aAC9C,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,aAAa,OAAO,CAAC,IAAI,CAAC,MAAM,uBAAuB,OAAO,CAAC,gBAAgB,4BAA4B;gBACpH,IAAI,EAAE;oBACJ,GAAG,OAAO;oBACV,OAAO,EAAE,MAAM,CAAC,OAAO;iBACxB;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,6BAA6B,KAAK,EAAE;aAC9C,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
* @
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
* @
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
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 {};
|
|
34
36
|
//# sourceMappingURL=ReadDataTool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReadDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/ReadDataTool.ts"],"names":[],"mappings":"
|
|
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,106 +1,93 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// Don't expose internal error details to prevent information leakage
|
|
94
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
95
|
-
const safeErrorMessage = errorMessage.includes("Invalid object name")
|
|
96
|
-
? errorMessage
|
|
97
|
-
: "Database query execution failed";
|
|
98
|
-
return {
|
|
99
|
-
success: false,
|
|
100
|
-
message: `Failed to execute query: ${safeErrorMessage}`,
|
|
101
|
-
error: "QUERY_EXECUTION_FAILED",
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
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
|
+
}
|
|
106
93
|
//# sourceMappingURL=ReadDataTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReadDataTool.js","sourceRoot":"","sources":["../../src/tools/ReadDataTool.ts"],"names":[],"mappings":"
|
|
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"}
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
1
|
+
import { type SqlFilter } from "../writeSafety.js";
|
|
2
|
+
interface UpdateDataParams {
|
|
3
|
+
tableName: string;
|
|
4
|
+
schemaName?: string;
|
|
5
|
+
updates: Record<string, unknown>;
|
|
6
|
+
filters: SqlFilter[];
|
|
7
|
+
databaseName?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class UpdateDataTool {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
run(params: UpdateDataParams): Promise<{
|
|
13
|
+
success: boolean;
|
|
14
|
+
message: string;
|
|
15
|
+
rowsAffected?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
success: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
rowsAffected: number;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
17
23
|
//# sourceMappingURL=UpdateDataTool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UpdateDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/UpdateDataTool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UpdateDataTool.d.ts","sourceRoot":"","sources":["../../src/tools/UpdateDataTool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAElF,UAAU,gBAAgB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,cAAc;IACzB,IAAI,SAAiB;IACrB,WAAW,SACoE;IAEzE,GAAG,CAAC,MAAM,EAAE,gBAAgB;;;;;;;;;CAiDnC"}
|
|
@@ -1,66 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
query = `UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;
|
|
50
|
-
const result = await request.query(query);
|
|
51
|
-
return {
|
|
52
|
-
success: true,
|
|
53
|
-
message: `Update completed successfully. ${result.rowsAffected[0]} row(s) affected`,
|
|
54
|
-
rowsAffected: result.rowsAffected[0],
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
console.error("Error updating data:", error);
|
|
59
|
-
return {
|
|
60
|
-
success: false,
|
|
61
|
-
message: `Failed to update data ${query ? ` with '${query}'` : ""}: ${error}`,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
import { getMaxWriteRows } from "../config.js";
|
|
2
|
+
import { getSqlRequest } from "../db.js";
|
|
3
|
+
import { buildQualifiedName, quoteIdentifier } from "../sql.js";
|
|
4
|
+
import { buildParameterizedWhereClause } from "../writeSafety.js";
|
|
5
|
+
export class UpdateDataTool {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = "update_data";
|
|
8
|
+
this.description = "Updates data in an MSSQL Database table using required structured filters.";
|
|
9
|
+
}
|
|
10
|
+
async run(params) {
|
|
11
|
+
let query;
|
|
12
|
+
try {
|
|
13
|
+
const { tableName, schemaName, updates, filters, databaseName } = params;
|
|
14
|
+
const { request, error } = await getSqlRequest(databaseName);
|
|
15
|
+
if (error) {
|
|
16
|
+
return { success: false, message: error };
|
|
17
|
+
}
|
|
18
|
+
const updateColumns = Object.keys(updates);
|
|
19
|
+
if (updateColumns.length === 0) {
|
|
20
|
+
throw new Error("At least one column update is required.");
|
|
21
|
+
}
|
|
22
|
+
const setClause = updateColumns
|
|
23
|
+
.map((key, index) => {
|
|
24
|
+
const paramName = `update_${index}`;
|
|
25
|
+
request.input(paramName, updates[key]);
|
|
26
|
+
return `${quoteIdentifier(key)} = @${paramName}`;
|
|
27
|
+
})
|
|
28
|
+
.join(", ");
|
|
29
|
+
const whereClause = buildParameterizedWhereClause(filters, (name, value) => request.input(name, value), "update_filter");
|
|
30
|
+
query = `UPDATE ${buildQualifiedName(tableName, schemaName)} SET ${setClause} WHERE ${whereClause}`;
|
|
31
|
+
const maxRows = getMaxWriteRows();
|
|
32
|
+
request.input("mcp_rowcap", maxRows);
|
|
33
|
+
const result = await request.query(`SET ROWCOUNT @mcp_rowcap;\n${query}\nSET ROWCOUNT 0;`);
|
|
34
|
+
return {
|
|
35
|
+
success: true,
|
|
36
|
+
message: `Update completed successfully. ${result.rowsAffected[0]} row(s) affected`,
|
|
37
|
+
rowsAffected: result.rowsAffected[0],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error("Error updating data:", error);
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
message: `Failed to update data ${query ? ` with '${query}'` : ""}: ${error}`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
66
49
|
//# sourceMappingURL=UpdateDataTool.js.map
|