@connorbritain/mssql-mcp-reader 0.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.
- package/README.md +106 -0
- package/dist/audit/AuditLogger.d.ts +37 -0
- package/dist/audit/AuditLogger.d.ts.map +1 -0
- package/dist/audit/AuditLogger.js +145 -0
- package/dist/audit/AuditLogger.js.map +1 -0
- package/dist/config/EnvironmentManager.d.ts +70 -0
- package/dist/config/EnvironmentManager.d.ts.map +1 -0
- package/dist/config/EnvironmentManager.js +301 -0
- package/dist/config/EnvironmentManager.js.map +1 -0
- package/dist/config/ScriptManager.d.ts +69 -0
- package/dist/config/ScriptManager.d.ts.map +1 -0
- package/dist/config/ScriptManager.js +166 -0
- package/dist/config/ScriptManager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +569 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/DescribeTableTool.d.ts +32 -0
- package/dist/tools/DescribeTableTool.d.ts.map +1 -0
- package/dist/tools/DescribeTableTool.js +108 -0
- package/dist/tools/DescribeTableTool.js.map +1 -0
- package/dist/tools/ExplainQueryTool.d.ts +24 -0
- package/dist/tools/ExplainQueryTool.d.ts.map +1 -0
- package/dist/tools/ExplainQueryTool.js +98 -0
- package/dist/tools/ExplainQueryTool.js.map +1 -0
- package/dist/tools/InspectDependenciesTool.d.ts +45 -0
- package/dist/tools/InspectDependenciesTool.d.ts.map +1 -0
- package/dist/tools/InspectDependenciesTool.js +215 -0
- package/dist/tools/InspectDependenciesTool.js.map +1 -0
- package/dist/tools/ListDatabasesTool.d.ts +27 -0
- package/dist/tools/ListDatabasesTool.d.ts.map +1 -0
- package/dist/tools/ListDatabasesTool.js +107 -0
- package/dist/tools/ListDatabasesTool.js.map +1 -0
- package/dist/tools/ListEnvironmentsTool.d.ts +49 -0
- package/dist/tools/ListEnvironmentsTool.d.ts.map +1 -0
- package/dist/tools/ListEnvironmentsTool.js +73 -0
- package/dist/tools/ListEnvironmentsTool.js.map +1 -0
- package/dist/tools/ListScriptsTool.d.ts +41 -0
- package/dist/tools/ListScriptsTool.d.ts.map +1 -0
- package/dist/tools/ListScriptsTool.js +86 -0
- package/dist/tools/ListScriptsTool.js.map +1 -0
- package/dist/tools/ListTableTool.d.ts +24 -0
- package/dist/tools/ListTableTool.d.ts.map +1 -0
- package/dist/tools/ListTableTool.js +85 -0
- package/dist/tools/ListTableTool.js.map +1 -0
- package/dist/tools/ProfileTableTool.d.ts +78 -0
- package/dist/tools/ProfileTableTool.d.ts.map +1 -0
- package/dist/tools/ProfileTableTool.js +372 -0
- package/dist/tools/ProfileTableTool.js.map +1 -0
- package/dist/tools/ReadDataTool.d.ts +61 -0
- package/dist/tools/ReadDataTool.d.ts.map +1 -0
- package/dist/tools/ReadDataTool.js +299 -0
- package/dist/tools/ReadDataTool.js.map +1 -0
- package/dist/tools/RelationshipInspectorTool.d.ts +46 -0
- package/dist/tools/RelationshipInspectorTool.d.ts.map +1 -0
- package/dist/tools/RelationshipInspectorTool.js +155 -0
- package/dist/tools/RelationshipInspectorTool.js.map +1 -0
- package/dist/tools/RunScriptTool.d.ts +215 -0
- package/dist/tools/RunScriptTool.d.ts.map +1 -0
- package/dist/tools/RunScriptTool.js +177 -0
- package/dist/tools/RunScriptTool.js.map +1 -0
- package/dist/tools/SearchSchemaTool.d.ts +88 -0
- package/dist/tools/SearchSchemaTool.d.ts.map +1 -0
- package/dist/tools/SearchSchemaTool.js +236 -0
- package/dist/tools/SearchSchemaTool.js.map +1 -0
- package/dist/tools/TestConnectionTool.d.ts +36 -0
- package/dist/tools/TestConnectionTool.d.ts.map +1 -0
- package/dist/tools/TestConnectionTool.js +155 -0
- package/dist/tools/TestConnectionTool.js.map +1 -0
- package/dist/tools/ValidateEnvironmentConfigTool.d.ts +37 -0
- package/dist/tools/ValidateEnvironmentConfigTool.d.ts.map +1 -0
- package/dist/tools/ValidateEnvironmentConfigTool.js +230 -0
- package/dist/tools/ValidateEnvironmentConfigTool.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import sql from "mssql";
|
|
2
|
+
import { getEnvironmentManager } from "../config/EnvironmentManager.js";
|
|
3
|
+
export class DescribeTableTool {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = "describe_table";
|
|
6
|
+
this.description = "Describes the schema (columns and types) of a specified MSSQL Database table. " +
|
|
7
|
+
"For server-level access environments, you can specify a database to target.";
|
|
8
|
+
this.inputSchema = {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
tableName: {
|
|
12
|
+
type: "string",
|
|
13
|
+
description: "Name of the table to describe (can include schema: 'dbo.TableName')",
|
|
14
|
+
},
|
|
15
|
+
database: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "Optional: Target database name for server-level access environments.",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
required: ["tableName"],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async run(params) {
|
|
24
|
+
try {
|
|
25
|
+
const { tableName, database, environment } = params;
|
|
26
|
+
// Validate database access if specified
|
|
27
|
+
if (database) {
|
|
28
|
+
const envManager = getEnvironmentManager();
|
|
29
|
+
const dbCheck = envManager.isDatabaseAllowed(environment, database);
|
|
30
|
+
if (!dbCheck.allowed) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
message: dbCheck.reason || `Access to database '${database}' is not allowed.`,
|
|
34
|
+
error: "DATABASE_ACCESS_DENIED",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Parse schema and table name
|
|
39
|
+
let schemaName = "dbo";
|
|
40
|
+
let actualTableName = tableName;
|
|
41
|
+
if (tableName.includes(".")) {
|
|
42
|
+
const parts = tableName.split(".");
|
|
43
|
+
schemaName = parts[0];
|
|
44
|
+
actualTableName = parts[1];
|
|
45
|
+
}
|
|
46
|
+
const request = new sql.Request();
|
|
47
|
+
// Build query with optional database context
|
|
48
|
+
let query;
|
|
49
|
+
if (database) {
|
|
50
|
+
const safeDbName = database.replace(/]/g, "]]");
|
|
51
|
+
query = `
|
|
52
|
+
USE [${safeDbName}];
|
|
53
|
+
SELECT
|
|
54
|
+
COLUMN_NAME as name,
|
|
55
|
+
DATA_TYPE as type,
|
|
56
|
+
CHARACTER_MAXIMUM_LENGTH as max_length,
|
|
57
|
+
IS_NULLABLE as nullable,
|
|
58
|
+
COLUMN_DEFAULT as default_value,
|
|
59
|
+
ORDINAL_POSITION as position
|
|
60
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
61
|
+
WHERE TABLE_NAME = @tableName AND TABLE_SCHEMA = @schemaName
|
|
62
|
+
ORDER BY ORDINAL_POSITION
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
query = `
|
|
67
|
+
SELECT
|
|
68
|
+
COLUMN_NAME as name,
|
|
69
|
+
DATA_TYPE as type,
|
|
70
|
+
CHARACTER_MAXIMUM_LENGTH as max_length,
|
|
71
|
+
IS_NULLABLE as nullable,
|
|
72
|
+
COLUMN_DEFAULT as default_value,
|
|
73
|
+
ORDINAL_POSITION as position
|
|
74
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
75
|
+
WHERE TABLE_NAME = @tableName AND TABLE_SCHEMA = @schemaName
|
|
76
|
+
ORDER BY ORDINAL_POSITION
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
request.input("tableName", sql.NVarChar, actualTableName);
|
|
80
|
+
request.input("schemaName", sql.NVarChar, schemaName);
|
|
81
|
+
const result = await request.query(query);
|
|
82
|
+
if (result.recordset.length === 0) {
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
message: `Table '${schemaName}.${actualTableName}' not found${database ? ` in database [${database}]` : ""}.`,
|
|
86
|
+
error: "TABLE_NOT_FOUND",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
message: `Described table '${schemaName}.${actualTableName}'${database ? ` in [${database}]` : ""}`,
|
|
92
|
+
database: database || undefined,
|
|
93
|
+
schema: schemaName,
|
|
94
|
+
tableName: actualTableName,
|
|
95
|
+
columnCount: result.recordset.length,
|
|
96
|
+
columns: result.recordset,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
message: `Failed to describe table: ${error}`,
|
|
103
|
+
error: "QUERY_FAILED",
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=DescribeTableTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DescribeTableTool.js","sourceRoot":"","sources":["../../src/tools/DescribeTableTool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export declare class ExplainQueryTool implements Tool {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: any;
|
|
7
|
+
run(params: any): Promise<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
message: string;
|
|
10
|
+
hasPlanXml: boolean;
|
|
11
|
+
} | {
|
|
12
|
+
success: boolean;
|
|
13
|
+
message: string;
|
|
14
|
+
error: string;
|
|
15
|
+
} | {
|
|
16
|
+
planXml: string;
|
|
17
|
+
success: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
hasPlanXml: boolean;
|
|
20
|
+
error?: undefined;
|
|
21
|
+
}>;
|
|
22
|
+
private extractPlanXml;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=ExplainQueryTool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExplainQueryTool.d.ts","sourceRoot":"","sources":["../../src/tools/ExplainQueryTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG1D,qBAAa,gBAAiB,YAAW,IAAI;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,IAAI,SAAmB;IACvB,WAAW,SAAgG;IAE3G,WAAW,EAiBN,GAAG,CAAC;IAEH,GAAG,CAAC,MAAM,EAAE,GAAG;;;;;;;;;;;;;;;IA4DrB,OAAO,CAAC,cAAc;CAuBvB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import sql from "mssql";
|
|
2
|
+
import { getEnvironmentManager } from "../config/EnvironmentManager.js";
|
|
3
|
+
export class ExplainQueryTool {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = "explain_query";
|
|
6
|
+
this.description = "Generates an estimated execution plan (SHOWPLAN_XML) for a SQL query without executing it.";
|
|
7
|
+
this.inputSchema = {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {
|
|
10
|
+
query: {
|
|
11
|
+
type: "string",
|
|
12
|
+
description: "SQL statement to analyze (typically SELECT/UPDATE/INSERT/DELETE).",
|
|
13
|
+
},
|
|
14
|
+
environment: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "Optional environment name to target (prod, staging, etc).",
|
|
17
|
+
},
|
|
18
|
+
includePlanXml: {
|
|
19
|
+
type: "boolean",
|
|
20
|
+
description: "If true (default), returns the raw SHOWPLAN XML. Set false for summary only.",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
required: ["query"],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async run(params) {
|
|
27
|
+
const { query, includePlanXml = true, environment } = params ?? {};
|
|
28
|
+
if (typeof query !== "string" || !query.trim()) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
message: "explain_query requires a non-empty SQL string.",
|
|
32
|
+
error: "INVALID_QUERY",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const sanitizedQuery = query.trim();
|
|
36
|
+
const envManager = getEnvironmentManager();
|
|
37
|
+
const pool = await envManager.getConnection(environment);
|
|
38
|
+
let showplanEnabled = false;
|
|
39
|
+
try {
|
|
40
|
+
const planRequest = new sql.Request(pool);
|
|
41
|
+
await planRequest.batch("SET SHOWPLAN_XML ON;");
|
|
42
|
+
showplanEnabled = true;
|
|
43
|
+
const explainRequest = new sql.Request(pool);
|
|
44
|
+
const result = await explainRequest.query(sanitizedQuery);
|
|
45
|
+
const planOutput = result.recordset?.[0];
|
|
46
|
+
const planXml = this.extractPlanXml(planOutput);
|
|
47
|
+
const summary = {
|
|
48
|
+
success: true,
|
|
49
|
+
message: "Generated estimated execution plan.",
|
|
50
|
+
hasPlanXml: Boolean(planXml),
|
|
51
|
+
};
|
|
52
|
+
if (includePlanXml && planXml) {
|
|
53
|
+
return {
|
|
54
|
+
...summary,
|
|
55
|
+
planXml,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return summary;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
message: `Failed to generate plan: ${errorMessage}`,
|
|
65
|
+
error: "SHOWPLAN_FAILED",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
if (showplanEnabled) {
|
|
70
|
+
try {
|
|
71
|
+
const resetRequest = new sql.Request(pool);
|
|
72
|
+
await resetRequest.batch("SET SHOWPLAN_XML OFF;");
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// ignore
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
extractPlanXml(row) {
|
|
81
|
+
if (!row) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const knownColumns = [
|
|
85
|
+
"ShowPlanXML",
|
|
86
|
+
"Microsoft SQL Server 2005 XML Showplan",
|
|
87
|
+
"Plan",
|
|
88
|
+
];
|
|
89
|
+
for (const column of knownColumns) {
|
|
90
|
+
if (row[column]) {
|
|
91
|
+
return row[column];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const firstXml = Object.values(row).find((value) => typeof value === "string" && value.trim().startsWith("<?xml"));
|
|
95
|
+
return firstXml ?? null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=ExplainQueryTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExplainQueryTool.js","sourceRoot":"","sources":["../../src/tools/ExplainQueryTool.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,OAAO,CAAC;AAExB,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,OAAO,gBAAgB;IAA7B;QAEE,SAAI,GAAG,eAAe,CAAC;QACvB,gBAAW,GAAG,4FAA4F,CAAC;QAE3G,gBAAW,GAAG;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,mEAAmE;iBACjF;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,2DAA2D;iBACzE;gBACD,cAAc,EAAE;oBACd,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,8EAA8E;iBAC5F;aACF;YACD,QAAQ,EAAE,CAAC,OAAO,CAAC;SACb,CAAC;IAqFX,CAAC;IAnFC,KAAK,CAAC,GAAG,CAAC,MAAW;QACnB,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;QAEnE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,gDAAgD;gBACzD,KAAK,EAAE,eAAe;aACvB,CAAC;QACJ,CAAC;QAED,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,qBAAqB,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAEzD,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,WAAW,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAChD,eAAe,GAAG,IAAI,CAAC;YAEvB,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAE1D,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;YAEhD,MAAM,OAAO,GAAG;gBACd,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,qCAAqC;gBAC9C,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC;aAC7B,CAAC;YAEF,IAAI,cAAc,IAAI,OAAO,EAAE,CAAC;gBAC9B,OAAO;oBACL,GAAG,OAAO;oBACV,OAAO;iBACR,CAAC;YACJ,CAAC;YAED,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,4BAA4B,YAAY,EAAE;gBACnD,KAAK,EAAE,iBAAiB;aACzB,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,IAAI,eAAe,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAC3C,MAAM,YAAY,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;gBACpD,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,GAAQ;QAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,YAAY,GAAG;YACnB,aAAa;YACb,wCAAwC;YACxC,MAAM;SACP,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;YAClC,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChB,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACjD,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAC9D,CAAC;QAEF,OAAQ,QAA+B,IAAI,IAAI,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
interface DependencyReference {
|
|
3
|
+
name: string;
|
|
4
|
+
schema: string;
|
|
5
|
+
type: string;
|
|
6
|
+
columns?: string[];
|
|
7
|
+
}
|
|
8
|
+
interface DependencyResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
object: string;
|
|
11
|
+
objectType?: string;
|
|
12
|
+
referencedBy?: {
|
|
13
|
+
views: DependencyReference[];
|
|
14
|
+
storedProcedures: DependencyReference[];
|
|
15
|
+
functions: DependencyReference[];
|
|
16
|
+
triggers: DependencyReference[];
|
|
17
|
+
foreignKeys: {
|
|
18
|
+
table: string;
|
|
19
|
+
schema: string;
|
|
20
|
+
column: string;
|
|
21
|
+
constraint: string;
|
|
22
|
+
}[];
|
|
23
|
+
};
|
|
24
|
+
references?: {
|
|
25
|
+
tables: DependencyReference[];
|
|
26
|
+
views: DependencyReference[];
|
|
27
|
+
functions: DependencyReference[];
|
|
28
|
+
};
|
|
29
|
+
message?: string;
|
|
30
|
+
error?: string;
|
|
31
|
+
hint?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare class InspectDependenciesTool implements Tool {
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
inputSchema: any;
|
|
38
|
+
run(params: {
|
|
39
|
+
objectName: string;
|
|
40
|
+
includeColumns?: boolean;
|
|
41
|
+
environment?: string;
|
|
42
|
+
}): Promise<DependencyResult>;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=InspectDependenciesTool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InspectDependenciesTool.d.ts","sourceRoot":"","sources":["../../src/tools/InspectDependenciesTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE1D,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE;QACb,KAAK,EAAE,mBAAmB,EAAE,CAAC;QAC7B,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;QACxC,SAAS,EAAE,mBAAmB,EAAE,CAAC;QACjC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;QAChC,WAAW,EAAE;YACX,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,MAAM,CAAC;SACpB,EAAE,CAAC;KACL,CAAC;IACF,UAAU,CAAC,EAAE;QACX,MAAM,EAAE,mBAAmB,EAAE,CAAC;QAC9B,KAAK,EAAE,mBAAmB,EAAE,CAAC;QAC7B,SAAS,EAAE,mBAAmB,EAAE,CAAC;KAClC,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,uBAAwB,YAAW,IAAI;IAClD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,IAAI,SAA0B;IAC9B,WAAW,SAA0H;IAErI,WAAW,EAaN,GAAG,CAAC;IAEH,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;CAsNzF"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import sql from "mssql";
|
|
2
|
+
export class InspectDependenciesTool {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.name = "inspect_dependencies";
|
|
5
|
+
this.description = "Shows what database objects depend on a table, view, or other object. Use for impact analysis before schema changes.";
|
|
6
|
+
this.inputSchema = {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
objectName: {
|
|
10
|
+
type: "string",
|
|
11
|
+
description: "Name of the object to inspect (e.g., 'dbo.Customers' or 'Customers')",
|
|
12
|
+
},
|
|
13
|
+
includeColumns: {
|
|
14
|
+
type: "boolean",
|
|
15
|
+
description: "Include column-level dependency details. Default: false",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
required: ["objectName"],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async run(params) {
|
|
22
|
+
const { objectName, includeColumns = false } = params;
|
|
23
|
+
try {
|
|
24
|
+
// Parse schema and object name
|
|
25
|
+
const parts = objectName.split(".");
|
|
26
|
+
let schemaName = "dbo";
|
|
27
|
+
let objName = objectName;
|
|
28
|
+
if (parts.length === 2) {
|
|
29
|
+
schemaName = parts[0];
|
|
30
|
+
objName = parts[1];
|
|
31
|
+
}
|
|
32
|
+
const pool = sql.globalPool;
|
|
33
|
+
if (!pool) {
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
object: objectName,
|
|
37
|
+
error: "NO_CONNECTION",
|
|
38
|
+
message: "No database connection available.",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// First, get the object type
|
|
42
|
+
const objectTypeResult = await pool.request()
|
|
43
|
+
.input("schema", sql.NVarChar, schemaName)
|
|
44
|
+
.input("name", sql.NVarChar, objName)
|
|
45
|
+
.query(`
|
|
46
|
+
SELECT
|
|
47
|
+
o.type_desc AS objectType,
|
|
48
|
+
o.object_id AS objectId
|
|
49
|
+
FROM sys.objects o
|
|
50
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
51
|
+
WHERE s.name = @schema AND o.name = @name
|
|
52
|
+
`);
|
|
53
|
+
if (objectTypeResult.recordset.length === 0) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
object: objectName,
|
|
57
|
+
error: "OBJECT_NOT_FOUND",
|
|
58
|
+
message: `Object '${schemaName}.${objName}' not found.`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const objectType = objectTypeResult.recordset[0].objectType;
|
|
62
|
+
const objectId = objectTypeResult.recordset[0].objectId;
|
|
63
|
+
// Get objects that reference this object (what depends on this)
|
|
64
|
+
const referencedByResult = await pool.request()
|
|
65
|
+
.input("schema", sql.NVarChar, schemaName)
|
|
66
|
+
.input("name", sql.NVarChar, objName)
|
|
67
|
+
.query(`
|
|
68
|
+
SELECT DISTINCT
|
|
69
|
+
OBJECT_SCHEMA_NAME(d.referencing_id) AS referencingSchema,
|
|
70
|
+
OBJECT_NAME(d.referencing_id) AS referencingName,
|
|
71
|
+
o.type_desc AS referencingType
|
|
72
|
+
FROM sys.sql_expression_dependencies d
|
|
73
|
+
INNER JOIN sys.objects o ON d.referencing_id = o.object_id
|
|
74
|
+
WHERE d.referenced_schema_name = @schema
|
|
75
|
+
AND d.referenced_entity_name = @name
|
|
76
|
+
AND d.referencing_id != d.referenced_id
|
|
77
|
+
ORDER BY o.type_desc, referencingName
|
|
78
|
+
`);
|
|
79
|
+
// Get foreign keys pointing to this table (if it's a table)
|
|
80
|
+
let foreignKeys = [];
|
|
81
|
+
if (objectType === "USER_TABLE") {
|
|
82
|
+
const fkResult = await pool.request()
|
|
83
|
+
.input("objectId", sql.Int, objectId)
|
|
84
|
+
.query(`
|
|
85
|
+
SELECT
|
|
86
|
+
OBJECT_SCHEMA_NAME(fk.parent_object_id) AS referencingSchema,
|
|
87
|
+
OBJECT_NAME(fk.parent_object_id) AS referencingTable,
|
|
88
|
+
COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS referencingColumn,
|
|
89
|
+
fk.name AS constraintName
|
|
90
|
+
FROM sys.foreign_keys fk
|
|
91
|
+
INNER JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
|
|
92
|
+
WHERE fk.referenced_object_id = @objectId
|
|
93
|
+
ORDER BY referencingTable, referencingColumn
|
|
94
|
+
`);
|
|
95
|
+
foreignKeys = fkResult.recordset;
|
|
96
|
+
}
|
|
97
|
+
// Get objects that this object references (what this depends on)
|
|
98
|
+
const referencesResult = await pool.request()
|
|
99
|
+
.input("schema", sql.NVarChar, schemaName)
|
|
100
|
+
.input("name", sql.NVarChar, objName)
|
|
101
|
+
.query(`
|
|
102
|
+
SELECT DISTINCT
|
|
103
|
+
d.referenced_schema_name AS referencedSchema,
|
|
104
|
+
d.referenced_entity_name AS referencedName,
|
|
105
|
+
COALESCE(o.type_desc, 'UNKNOWN') AS referencedType
|
|
106
|
+
FROM sys.sql_expression_dependencies d
|
|
107
|
+
LEFT JOIN sys.objects o ON d.referenced_id = o.object_id
|
|
108
|
+
WHERE OBJECT_SCHEMA_NAME(d.referencing_id) = @schema
|
|
109
|
+
AND OBJECT_NAME(d.referencing_id) = @name
|
|
110
|
+
AND d.referenced_entity_name IS NOT NULL
|
|
111
|
+
ORDER BY referencedType, referencedName
|
|
112
|
+
`);
|
|
113
|
+
// Categorize referencing objects
|
|
114
|
+
const views = [];
|
|
115
|
+
const storedProcedures = [];
|
|
116
|
+
const functions = [];
|
|
117
|
+
const triggers = [];
|
|
118
|
+
for (const row of referencedByResult.recordset) {
|
|
119
|
+
const ref = {
|
|
120
|
+
name: row.referencingName,
|
|
121
|
+
schema: row.referencingSchema,
|
|
122
|
+
type: row.referencingType,
|
|
123
|
+
};
|
|
124
|
+
switch (row.referencingType) {
|
|
125
|
+
case "VIEW":
|
|
126
|
+
views.push(ref);
|
|
127
|
+
break;
|
|
128
|
+
case "SQL_STORED_PROCEDURE":
|
|
129
|
+
storedProcedures.push(ref);
|
|
130
|
+
break;
|
|
131
|
+
case "SQL_SCALAR_FUNCTION":
|
|
132
|
+
case "SQL_TABLE_VALUED_FUNCTION":
|
|
133
|
+
case "SQL_INLINE_TABLE_VALUED_FUNCTION":
|
|
134
|
+
functions.push(ref);
|
|
135
|
+
break;
|
|
136
|
+
case "SQL_TRIGGER":
|
|
137
|
+
triggers.push(ref);
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
// Other types go to functions as catch-all
|
|
141
|
+
functions.push(ref);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Categorize referenced objects
|
|
145
|
+
const referencedTables = [];
|
|
146
|
+
const referencedViews = [];
|
|
147
|
+
const referencedFunctions = [];
|
|
148
|
+
for (const row of referencesResult.recordset) {
|
|
149
|
+
const ref = {
|
|
150
|
+
name: row.referencedName,
|
|
151
|
+
schema: row.referencedSchema || "dbo",
|
|
152
|
+
type: row.referencedType,
|
|
153
|
+
};
|
|
154
|
+
switch (row.referencedType) {
|
|
155
|
+
case "USER_TABLE":
|
|
156
|
+
referencedTables.push(ref);
|
|
157
|
+
break;
|
|
158
|
+
case "VIEW":
|
|
159
|
+
referencedViews.push(ref);
|
|
160
|
+
break;
|
|
161
|
+
default:
|
|
162
|
+
referencedFunctions.push(ref);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const result = {
|
|
166
|
+
success: true,
|
|
167
|
+
object: `${schemaName}.${objName}`,
|
|
168
|
+
objectType,
|
|
169
|
+
referencedBy: {
|
|
170
|
+
views,
|
|
171
|
+
storedProcedures,
|
|
172
|
+
functions,
|
|
173
|
+
triggers,
|
|
174
|
+
foreignKeys: foreignKeys.map((fk) => ({
|
|
175
|
+
table: fk.referencingTable,
|
|
176
|
+
schema: fk.referencingSchema,
|
|
177
|
+
column: fk.referencingColumn,
|
|
178
|
+
constraint: fk.constraintName,
|
|
179
|
+
})),
|
|
180
|
+
},
|
|
181
|
+
references: {
|
|
182
|
+
tables: referencedTables,
|
|
183
|
+
views: referencedViews,
|
|
184
|
+
functions: referencedFunctions,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
// Add summary counts
|
|
188
|
+
const totalReferencedBy = views.length +
|
|
189
|
+
storedProcedures.length +
|
|
190
|
+
functions.length +
|
|
191
|
+
triggers.length +
|
|
192
|
+
foreignKeys.length;
|
|
193
|
+
const totalReferences = referencedTables.length + referencedViews.length + referencedFunctions.length;
|
|
194
|
+
if (totalReferencedBy === 0 && totalReferences === 0) {
|
|
195
|
+
result.message = `No dependencies found for '${schemaName}.${objName}'.`;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
result.message = `Found ${totalReferencedBy} object(s) that reference this ${objectType.toLowerCase().replace(/_/g, " ")}, and ${totalReferences} object(s) that it references.`;
|
|
199
|
+
}
|
|
200
|
+
if (totalReferencedBy > 0) {
|
|
201
|
+
result.hint = "Modifying or dropping this object may affect the listed dependents.";
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
object: objectName,
|
|
209
|
+
error: "QUERY_ERROR",
|
|
210
|
+
message: `Failed to inspect dependencies: ${error.message}`,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=InspectDependenciesTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InspectDependenciesTool.js","sourceRoot":"","sources":["../../src/tools/InspectDependenciesTool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export declare class ListDatabasesTool implements Tool {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: any;
|
|
7
|
+
run(params: any): Promise<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
message: string;
|
|
10
|
+
error: string;
|
|
11
|
+
environment?: undefined;
|
|
12
|
+
accessLevel?: undefined;
|
|
13
|
+
totalDatabases?: undefined;
|
|
14
|
+
accessibleDatabases?: undefined;
|
|
15
|
+
databases?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
success: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
environment: string;
|
|
20
|
+
accessLevel: "server";
|
|
21
|
+
totalDatabases: number;
|
|
22
|
+
accessibleDatabases: number;
|
|
23
|
+
databases: any[];
|
|
24
|
+
error?: undefined;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=ListDatabasesTool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListDatabasesTool.d.ts","sourceRoot":"","sources":["../../src/tools/ListDatabasesTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG1D,qBAAa,iBAAkB,YAAW,IAAI;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,IAAI,SAAoB;IACxB,WAAW,SAAiH;IAC5H,WAAW,EAkBN,GAAG,CAAC;IAEH,GAAG,CAAC,MAAM,EAAE,GAAG;;;;;;;;;;;;;;;;;;;CAyFtB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import sql from "mssql";
|
|
2
|
+
import { getEnvironmentManager } from "../config/EnvironmentManager.js";
|
|
3
|
+
export class ListDatabasesTool {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = "list_databases";
|
|
6
|
+
this.description = "Lists databases on the SQL Server instance. Requires server-level access. Filtered by environment policies.";
|
|
7
|
+
this.inputSchema = {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {
|
|
10
|
+
environment: {
|
|
11
|
+
type: "string",
|
|
12
|
+
description: "Target environment name (optional, uses default if not specified)",
|
|
13
|
+
},
|
|
14
|
+
includeSystemDbs: {
|
|
15
|
+
type: "boolean",
|
|
16
|
+
description: "Include system databases (master, msdb, model, tempdb). Default: false",
|
|
17
|
+
},
|
|
18
|
+
stateFilter: {
|
|
19
|
+
type: "string",
|
|
20
|
+
enum: ["ONLINE", "OFFLINE", "RESTORING", "RECOVERING", "SUSPECT", "ALL"],
|
|
21
|
+
description: "Filter by database state. Default: ONLINE",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
required: [],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
async run(params) {
|
|
28
|
+
const { environment, includeSystemDbs = false, stateFilter = "ONLINE" } = params ?? {};
|
|
29
|
+
try {
|
|
30
|
+
const envManager = getEnvironmentManager();
|
|
31
|
+
const envConfig = envManager.getEnvironment(environment);
|
|
32
|
+
// Check if environment has server-level access
|
|
33
|
+
const accessLevel = envConfig.accessLevel ?? "database";
|
|
34
|
+
if (accessLevel !== "server") {
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
message: `Environment '${envConfig.name}' has database-level access only. ` +
|
|
38
|
+
`list_databases requires server-level access (accessLevel: "server").`,
|
|
39
|
+
error: "ACCESS_LEVEL_DENIED",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const request = new sql.Request();
|
|
43
|
+
// Build the query
|
|
44
|
+
let query = `
|
|
45
|
+
SELECT
|
|
46
|
+
d.name AS database_name,
|
|
47
|
+
d.database_id,
|
|
48
|
+
d.state_desc AS state,
|
|
49
|
+
d.recovery_model_desc AS recovery_model,
|
|
50
|
+
d.compatibility_level,
|
|
51
|
+
d.collation_name,
|
|
52
|
+
d.create_date,
|
|
53
|
+
d.is_read_only,
|
|
54
|
+
CAST(SUM(mf.size) * 8.0 / 1024 AS DECIMAL(10,2)) AS size_mb
|
|
55
|
+
FROM sys.databases d
|
|
56
|
+
LEFT JOIN sys.master_files mf ON d.database_id = mf.database_id
|
|
57
|
+
WHERE 1=1
|
|
58
|
+
`;
|
|
59
|
+
// Filter by state
|
|
60
|
+
if (stateFilter && stateFilter !== "ALL") {
|
|
61
|
+
query += ` AND d.state_desc = '${stateFilter}'`;
|
|
62
|
+
}
|
|
63
|
+
// Exclude system databases if not requested
|
|
64
|
+
if (!includeSystemDbs) {
|
|
65
|
+
query += ` AND d.database_id > 4`; // System DBs have IDs 1-4
|
|
66
|
+
}
|
|
67
|
+
query += `
|
|
68
|
+
GROUP BY d.name, d.database_id, d.state_desc, d.recovery_model_desc,
|
|
69
|
+
d.compatibility_level, d.collation_name, d.create_date, d.is_read_only
|
|
70
|
+
ORDER BY d.name
|
|
71
|
+
`;
|
|
72
|
+
const result = await request.query(query);
|
|
73
|
+
// Filter results by allowedDatabases/deniedDatabases policies
|
|
74
|
+
const filteredDatabases = result.recordset.filter((db) => {
|
|
75
|
+
const check = envManager.isDatabaseAllowed(environment, db.database_name);
|
|
76
|
+
return check.allowed;
|
|
77
|
+
});
|
|
78
|
+
// Mark which databases are accessible vs restricted
|
|
79
|
+
const databases = result.recordset.map((db) => {
|
|
80
|
+
const check = envManager.isDatabaseAllowed(environment, db.database_name);
|
|
81
|
+
return {
|
|
82
|
+
...db,
|
|
83
|
+
accessible: check.allowed,
|
|
84
|
+
restriction_reason: check.reason,
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
return {
|
|
88
|
+
success: true,
|
|
89
|
+
message: `Found ${result.recordset.length} database(s), ${filteredDatabases.length} accessible`,
|
|
90
|
+
environment: envConfig.name,
|
|
91
|
+
accessLevel: accessLevel,
|
|
92
|
+
totalDatabases: result.recordset.length,
|
|
93
|
+
accessibleDatabases: filteredDatabases.length,
|
|
94
|
+
databases: databases,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error("Error listing databases:", error);
|
|
99
|
+
return {
|
|
100
|
+
success: false,
|
|
101
|
+
message: `Failed to list databases: ${error}`,
|
|
102
|
+
error: "QUERY_FAILED",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=ListDatabasesTool.js.map
|