@elad-nofy/mssql-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/mssqlClient.d.ts +17 -0
- package/dist/mssqlClient.d.ts.map +1 -0
- package/dist/mssqlClient.js +78 -0
- package/dist/mssqlClient.js.map +1 -0
- package/dist/tools/availability.d.ts +50 -0
- package/dist/tools/availability.d.ts.map +1 -0
- package/dist/tools/availability.js +153 -0
- package/dist/tools/availability.js.map +1 -0
- package/dist/tools/connection.d.ts +32 -0
- package/dist/tools/connection.d.ts.map +1 -0
- package/dist/tools/connection.js +63 -0
- package/dist/tools/connection.js.map +1 -0
- package/dist/tools/health.d.ts +89 -0
- package/dist/tools/health.d.ts.map +1 -0
- package/dist/tools/health.js +189 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +7 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/jobs.d.ts +53 -0
- package/dist/tools/jobs.d.ts.map +1 -0
- package/dist/tools/jobs.js +161 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/performance.d.ts +60 -0
- package/dist/tools/performance.d.ts.map +1 -0
- package/dist/tools/performance.js +162 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/tools/queries.d.ts +59 -0
- package/dist/tools/queries.d.ts.map +1 -0
- package/dist/tools/queries.js +125 -0
- package/dist/tools/queries.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const jobTools = {
|
|
3
|
+
list_jobs: {
|
|
4
|
+
description: 'List all SQL Server Agent jobs with their status and schedule',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
enabledOnly: z.boolean().optional().default(false).describe('Only show enabled jobs'),
|
|
7
|
+
}),
|
|
8
|
+
handler: async (client, args) => {
|
|
9
|
+
const enabledFilter = args.enabledOnly ? 'AND j.enabled = 1' : '';
|
|
10
|
+
const query = `
|
|
11
|
+
SELECT
|
|
12
|
+
j.job_id,
|
|
13
|
+
j.name as job_name,
|
|
14
|
+
j.description,
|
|
15
|
+
CASE j.enabled WHEN 1 THEN 'Enabled' ELSE 'Disabled' END as status,
|
|
16
|
+
c.name as category,
|
|
17
|
+
SUSER_SNAME(j.owner_sid) as owner,
|
|
18
|
+
j.date_created,
|
|
19
|
+
j.date_modified,
|
|
20
|
+
CASE
|
|
21
|
+
WHEN ja.run_requested_date IS NOT NULL AND ja.stop_execution_date IS NULL THEN 'Running'
|
|
22
|
+
ELSE 'Idle'
|
|
23
|
+
END as current_status,
|
|
24
|
+
h.last_run_date,
|
|
25
|
+
h.last_run_time,
|
|
26
|
+
h.last_run_outcome,
|
|
27
|
+
h.last_run_duration_seconds
|
|
28
|
+
FROM msdb.dbo.sysjobs j
|
|
29
|
+
LEFT JOIN msdb.dbo.syscategories c ON j.category_id = c.category_id
|
|
30
|
+
LEFT JOIN msdb.dbo.sysjobactivity ja ON j.job_id = ja.job_id
|
|
31
|
+
AND ja.session_id = (SELECT MAX(session_id) FROM msdb.dbo.sysjobactivity)
|
|
32
|
+
LEFT JOIN (
|
|
33
|
+
SELECT
|
|
34
|
+
job_id,
|
|
35
|
+
MAX(CAST(
|
|
36
|
+
CAST(run_date AS VARCHAR) + ' ' +
|
|
37
|
+
STUFF(STUFF(RIGHT('000000' + CAST(run_time AS VARCHAR), 6), 5, 0, ':'), 3, 0, ':')
|
|
38
|
+
AS DATETIME)) as last_run_date,
|
|
39
|
+
MAX(run_time) as last_run_time,
|
|
40
|
+
(SELECT TOP 1 CASE run_status
|
|
41
|
+
WHEN 0 THEN 'Failed'
|
|
42
|
+
WHEN 1 THEN 'Succeeded'
|
|
43
|
+
WHEN 2 THEN 'Retry'
|
|
44
|
+
WHEN 3 THEN 'Canceled'
|
|
45
|
+
WHEN 4 THEN 'In Progress'
|
|
46
|
+
END FROM msdb.dbo.sysjobhistory h2
|
|
47
|
+
WHERE h2.job_id = h.job_id AND h2.step_id = 0
|
|
48
|
+
ORDER BY run_date DESC, run_time DESC) as last_run_outcome,
|
|
49
|
+
(SELECT TOP 1
|
|
50
|
+
((run_duration / 10000) * 3600) +
|
|
51
|
+
(((run_duration % 10000) / 100) * 60) +
|
|
52
|
+
(run_duration % 100)
|
|
53
|
+
FROM msdb.dbo.sysjobhistory h2
|
|
54
|
+
WHERE h2.job_id = h.job_id AND h2.step_id = 0
|
|
55
|
+
ORDER BY run_date DESC, run_time DESC) as last_run_duration_seconds
|
|
56
|
+
FROM msdb.dbo.sysjobhistory h
|
|
57
|
+
WHERE step_id = 0
|
|
58
|
+
GROUP BY job_id
|
|
59
|
+
) h ON j.job_id = h.job_id
|
|
60
|
+
WHERE 1=1
|
|
61
|
+
${enabledFilter}
|
|
62
|
+
ORDER BY j.name
|
|
63
|
+
`;
|
|
64
|
+
return await client.query(query);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
get_running_jobs: {
|
|
68
|
+
description: 'Get currently executing SQL Server Agent jobs',
|
|
69
|
+
inputSchema: z.object({}),
|
|
70
|
+
handler: async (client) => {
|
|
71
|
+
const query = `
|
|
72
|
+
SELECT
|
|
73
|
+
j.name as job_name,
|
|
74
|
+
j.job_id,
|
|
75
|
+
ja.start_execution_date,
|
|
76
|
+
DATEDIFF(SECOND, ja.start_execution_date, GETDATE()) as running_seconds,
|
|
77
|
+
ISNULL(ja.last_executed_step_id, 0) as current_step,
|
|
78
|
+
js.step_name as current_step_name,
|
|
79
|
+
js.subsystem,
|
|
80
|
+
js.command as step_command
|
|
81
|
+
FROM msdb.dbo.sysjobactivity ja
|
|
82
|
+
INNER JOIN msdb.dbo.sysjobs j ON ja.job_id = j.job_id
|
|
83
|
+
LEFT JOIN msdb.dbo.sysjobsteps js ON j.job_id = js.job_id
|
|
84
|
+
AND ja.last_executed_step_id + 1 = js.step_id
|
|
85
|
+
WHERE ja.session_id = (SELECT MAX(session_id) FROM msdb.dbo.syssessions)
|
|
86
|
+
AND ja.start_execution_date IS NOT NULL
|
|
87
|
+
AND ja.stop_execution_date IS NULL
|
|
88
|
+
ORDER BY ja.start_execution_date
|
|
89
|
+
`;
|
|
90
|
+
return await client.query(query);
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
get_failed_jobs: {
|
|
94
|
+
description: 'Get jobs that failed in their last execution or recent history',
|
|
95
|
+
inputSchema: z.object({
|
|
96
|
+
hours: z.number().optional().default(24).describe('Look back this many hours for failures'),
|
|
97
|
+
}),
|
|
98
|
+
handler: async (client, args) => {
|
|
99
|
+
const query = `
|
|
100
|
+
SELECT
|
|
101
|
+
j.name as job_name,
|
|
102
|
+
j.job_id,
|
|
103
|
+
h.step_id,
|
|
104
|
+
h.step_name,
|
|
105
|
+
CAST(
|
|
106
|
+
CAST(h.run_date AS VARCHAR) + ' ' +
|
|
107
|
+
STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR), 6), 5, 0, ':'), 3, 0, ':')
|
|
108
|
+
AS DATETIME) as run_datetime,
|
|
109
|
+
((h.run_duration / 10000) * 3600) +
|
|
110
|
+
(((h.run_duration % 10000) / 100) * 60) +
|
|
111
|
+
(h.run_duration % 100) as duration_seconds,
|
|
112
|
+
h.message as error_message
|
|
113
|
+
FROM msdb.dbo.sysjobhistory h
|
|
114
|
+
INNER JOIN msdb.dbo.sysjobs j ON h.job_id = j.job_id
|
|
115
|
+
WHERE h.run_status = 0 -- Failed
|
|
116
|
+
AND CAST(
|
|
117
|
+
CAST(h.run_date AS VARCHAR) + ' ' +
|
|
118
|
+
STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR), 6), 5, 0, ':'), 3, 0, ':')
|
|
119
|
+
AS DATETIME) > DATEADD(HOUR, -${args.hours || 24}, GETDATE())
|
|
120
|
+
ORDER BY h.run_date DESC, h.run_time DESC
|
|
121
|
+
`;
|
|
122
|
+
return await client.query(query);
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
get_job_history: {
|
|
126
|
+
description: 'Get execution history for a specific job',
|
|
127
|
+
inputSchema: z.object({
|
|
128
|
+
jobName: z.string().describe('Name of the job'),
|
|
129
|
+
top: z.number().optional().default(50).describe('Number of history records to return'),
|
|
130
|
+
}),
|
|
131
|
+
handler: async (client, args) => {
|
|
132
|
+
const query = `
|
|
133
|
+
SELECT TOP ${args.top || 50}
|
|
134
|
+
j.name as job_name,
|
|
135
|
+
h.step_id,
|
|
136
|
+
h.step_name,
|
|
137
|
+
CASE h.run_status
|
|
138
|
+
WHEN 0 THEN 'Failed'
|
|
139
|
+
WHEN 1 THEN 'Succeeded'
|
|
140
|
+
WHEN 2 THEN 'Retry'
|
|
141
|
+
WHEN 3 THEN 'Canceled'
|
|
142
|
+
WHEN 4 THEN 'In Progress'
|
|
143
|
+
END as status,
|
|
144
|
+
CAST(
|
|
145
|
+
CAST(h.run_date AS VARCHAR) + ' ' +
|
|
146
|
+
STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR), 6), 5, 0, ':'), 3, 0, ':')
|
|
147
|
+
AS DATETIME) as run_datetime,
|
|
148
|
+
((h.run_duration / 10000) * 3600) +
|
|
149
|
+
(((h.run_duration % 10000) / 100) * 60) +
|
|
150
|
+
(h.run_duration % 100) as duration_seconds,
|
|
151
|
+
h.message
|
|
152
|
+
FROM msdb.dbo.sysjobhistory h
|
|
153
|
+
INNER JOIN msdb.dbo.sysjobs j ON h.job_id = j.job_id
|
|
154
|
+
WHERE j.name = @jobName
|
|
155
|
+
ORDER BY h.run_date DESC, h.run_time DESC, h.step_id
|
|
156
|
+
`;
|
|
157
|
+
return await client.query(query, { jobName: args.jobName });
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=jobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../src/tools/jobs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,SAAS,EAAE;QACT,WAAW,EAAE,+DAA+D;QAC5E,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;SACtF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,IAA+B,EAAE,EAAE;YACtE,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;YAElE,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAmDV,aAAa;;OAEhB,CAAC;YAEF,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;KACF;IAED,gBAAgB,EAAE;QAChB,WAAW,EAAE,+CAA+C;QAC5D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;OAkBb,CAAC;YAEF,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;KACF;IAED,eAAe,EAAE;QACf,WAAW,EAAE,gEAAgE;QAC7E,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;SAC5F,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,IAAwB,EAAE,EAAE;YAC/D,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;wCAoBoB,IAAI,CAAC,KAAK,IAAI,EAAE;;OAEjD,CAAC;YAEF,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;KACF;IAED,eAAe,EAAE;QACf,WAAW,EAAE,0CAA0C;QACvD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC/C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;SACvF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,IAAuC,EAAE,EAAE;YAC9E,MAAM,KAAK,GAAG;qBACC,IAAI,CAAC,GAAG,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;OAuB5B,CAAC;YAEF,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { MssqlClient } from '../mssqlClient.js';
|
|
3
|
+
export declare const performanceTools: {
|
|
4
|
+
get_blocking: {
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
7
|
+
handler: (client: MssqlClient) => Promise<{
|
|
8
|
+
blockingCount: number;
|
|
9
|
+
chains: import("mssql").IRecordSet<unknown>[];
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
get_wait_stats: {
|
|
13
|
+
description: string;
|
|
14
|
+
inputSchema: z.ZodObject<{
|
|
15
|
+
top: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
16
|
+
excludeIdle: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
top: number;
|
|
19
|
+
excludeIdle: boolean;
|
|
20
|
+
}, {
|
|
21
|
+
top?: number | undefined;
|
|
22
|
+
excludeIdle?: boolean | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
handler: (client: MssqlClient, args: {
|
|
25
|
+
top?: number;
|
|
26
|
+
excludeIdle?: boolean;
|
|
27
|
+
}) => Promise<import("mssql").IRecordSet<unknown>[]>;
|
|
28
|
+
};
|
|
29
|
+
get_cpu_usage: {
|
|
30
|
+
description: string;
|
|
31
|
+
inputSchema: z.ZodObject<{
|
|
32
|
+
minutes: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
minutes: number;
|
|
35
|
+
}, {
|
|
36
|
+
minutes?: number | undefined;
|
|
37
|
+
}>;
|
|
38
|
+
handler: (client: MssqlClient, args: {
|
|
39
|
+
minutes?: number;
|
|
40
|
+
}) => Promise<import("mssql").IRecordSet<unknown>[]>;
|
|
41
|
+
};
|
|
42
|
+
get_index_usage: {
|
|
43
|
+
description: string;
|
|
44
|
+
inputSchema: z.ZodObject<{
|
|
45
|
+
database: z.ZodString;
|
|
46
|
+
showUnused: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
database: string;
|
|
49
|
+
showUnused: boolean;
|
|
50
|
+
}, {
|
|
51
|
+
database: string;
|
|
52
|
+
showUnused?: boolean | undefined;
|
|
53
|
+
}>;
|
|
54
|
+
handler: (client: MssqlClient, args: {
|
|
55
|
+
database: string;
|
|
56
|
+
showUnused?: boolean;
|
|
57
|
+
}) => Promise<import("mssql").IRecordSet<unknown>[]>;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=performance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../../src/tools/performance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,eAAO,MAAM,gBAAgB;;;;0BAID,WAAW;;;;;;;;;;;;;;;;;0BAoDX,WAAW,QAAQ;YAAE,GAAG,CAAC,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,OAAO,CAAA;SAAE;;;;;;;;;;;0BA2C1D,WAAW,QAAQ;YAAE,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE;;;;;;;;;;;;;;0BAmCvC,WAAW,QAAQ;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE;;CAkCxF,CAAC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const performanceTools = {
|
|
3
|
+
get_blocking: {
|
|
4
|
+
description: 'Get current blocking chains showing blocked and blocking sessions',
|
|
5
|
+
inputSchema: z.object({}),
|
|
6
|
+
handler: async (client) => {
|
|
7
|
+
const query = `
|
|
8
|
+
WITH BlockingTree AS (
|
|
9
|
+
SELECT
|
|
10
|
+
r.session_id as blocked_session_id,
|
|
11
|
+
r.blocking_session_id,
|
|
12
|
+
s.login_name as blocked_login,
|
|
13
|
+
s.host_name as blocked_host,
|
|
14
|
+
s.program_name as blocked_program,
|
|
15
|
+
DB_NAME(r.database_id) as database_name,
|
|
16
|
+
r.wait_type,
|
|
17
|
+
r.wait_time / 1000.0 as wait_time_seconds,
|
|
18
|
+
r.wait_resource,
|
|
19
|
+
SUBSTRING(st.text, (r.statement_start_offset/2)+1,
|
|
20
|
+
((CASE r.statement_end_offset
|
|
21
|
+
WHEN -1 THEN DATALENGTH(st.text)
|
|
22
|
+
ELSE r.statement_end_offset
|
|
23
|
+
END - r.statement_start_offset)/2)+1) as blocked_query
|
|
24
|
+
FROM sys.dm_exec_requests r
|
|
25
|
+
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
|
|
26
|
+
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) st
|
|
27
|
+
WHERE r.blocking_session_id > 0
|
|
28
|
+
)
|
|
29
|
+
SELECT
|
|
30
|
+
bt.*,
|
|
31
|
+
bs.login_name as blocking_login,
|
|
32
|
+
bs.host_name as blocking_host,
|
|
33
|
+
bs.program_name as blocking_program,
|
|
34
|
+
COALESCE(
|
|
35
|
+
(SELECT TOP 1 text FROM sys.dm_exec_sql_text(bc.most_recent_sql_handle)),
|
|
36
|
+
'No query available'
|
|
37
|
+
) as blocking_query
|
|
38
|
+
FROM BlockingTree bt
|
|
39
|
+
LEFT JOIN sys.dm_exec_sessions bs ON bt.blocking_session_id = bs.session_id
|
|
40
|
+
LEFT JOIN sys.dm_exec_connections bc ON bt.blocking_session_id = bc.session_id
|
|
41
|
+
ORDER BY bt.wait_time_seconds DESC
|
|
42
|
+
`;
|
|
43
|
+
const result = await client.query(query);
|
|
44
|
+
return {
|
|
45
|
+
blockingCount: result.length,
|
|
46
|
+
chains: result,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
get_wait_stats: {
|
|
51
|
+
description: 'Get aggregated wait statistics to identify performance bottlenecks',
|
|
52
|
+
inputSchema: z.object({
|
|
53
|
+
top: z.number().optional().default(20).describe('Number of top waits to return'),
|
|
54
|
+
excludeIdle: z.boolean().optional().default(true).describe('Exclude idle and benign waits'),
|
|
55
|
+
}),
|
|
56
|
+
handler: async (client, args) => {
|
|
57
|
+
const excludeFilter = args.excludeIdle
|
|
58
|
+
? `WHERE wait_type NOT IN (
|
|
59
|
+
'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
|
|
60
|
+
'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
|
|
61
|
+
'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',
|
|
62
|
+
'BROKER_TO_FLUSH', 'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT',
|
|
63
|
+
'CLR_AUTO_EVENT', 'DISPATCHER_QUEUE_SEMAPHORE', 'FT_IFTS_SCHEDULER_IDLE_WAIT',
|
|
64
|
+
'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
|
|
65
|
+
'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
|
|
66
|
+
'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
|
|
67
|
+
'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
|
|
68
|
+
'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK', 'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
|
|
69
|
+
'DIRTY_PAGE_POLL', 'SP_SERVER_DIAGNOSTICS_SLEEP'
|
|
70
|
+
)
|
|
71
|
+
AND wait_type NOT LIKE 'PREEMPTIVE_%'
|
|
72
|
+
AND wait_type NOT LIKE 'BROKER_%'
|
|
73
|
+
AND wait_type NOT LIKE 'SLEEP_%'`
|
|
74
|
+
: '';
|
|
75
|
+
const query = `
|
|
76
|
+
SELECT TOP ${args.top || 20}
|
|
77
|
+
wait_type,
|
|
78
|
+
waiting_tasks_count,
|
|
79
|
+
wait_time_ms,
|
|
80
|
+
max_wait_time_ms,
|
|
81
|
+
signal_wait_time_ms,
|
|
82
|
+
wait_time_ms - signal_wait_time_ms as resource_wait_time_ms,
|
|
83
|
+
CAST(100.0 * wait_time_ms / SUM(wait_time_ms) OVER() AS DECIMAL(5,2)) as pct_of_total
|
|
84
|
+
FROM sys.dm_os_wait_stats
|
|
85
|
+
${excludeFilter}
|
|
86
|
+
ORDER BY wait_time_ms DESC
|
|
87
|
+
`;
|
|
88
|
+
return await client.query(query);
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
get_cpu_usage: {
|
|
92
|
+
description: 'Get CPU usage history for SQL Server from ring buffer',
|
|
93
|
+
inputSchema: z.object({
|
|
94
|
+
minutes: z.number().optional().default(30).describe('Minutes of history to retrieve'),
|
|
95
|
+
}),
|
|
96
|
+
handler: async (client, args) => {
|
|
97
|
+
const query = `
|
|
98
|
+
DECLARE @ts_now BIGINT = (SELECT cpu_ticks/(cpu_ticks/ms_ticks) FROM sys.dm_os_sys_info);
|
|
99
|
+
|
|
100
|
+
SELECT TOP ${args.minutes || 30}
|
|
101
|
+
DATEADD(ms, -1 * (@ts_now - [timestamp]), GETDATE()) as event_time,
|
|
102
|
+
SQLProcessUtilization as sql_cpu_percent,
|
|
103
|
+
SystemIdle as system_idle_percent,
|
|
104
|
+
100 - SystemIdle - SQLProcessUtilization as other_cpu_percent
|
|
105
|
+
FROM (
|
|
106
|
+
SELECT
|
|
107
|
+
record.value('(./Record/@id)[1]', 'int') as record_id,
|
|
108
|
+
record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') as SystemIdle,
|
|
109
|
+
record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int') as SQLProcessUtilization,
|
|
110
|
+
[timestamp]
|
|
111
|
+
FROM (
|
|
112
|
+
SELECT [timestamp], CONVERT(xml, record) as record
|
|
113
|
+
FROM sys.dm_os_ring_buffers
|
|
114
|
+
WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
|
|
115
|
+
AND record LIKE '%<SystemHealth>%'
|
|
116
|
+
) AS x
|
|
117
|
+
) AS y
|
|
118
|
+
ORDER BY record_id DESC
|
|
119
|
+
`;
|
|
120
|
+
return await client.query(query);
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
get_index_usage: {
|
|
124
|
+
description: 'Get index usage statistics to identify unused or missing indexes',
|
|
125
|
+
inputSchema: z.object({
|
|
126
|
+
database: z.string().describe('Database name to analyze'),
|
|
127
|
+
showUnused: z.boolean().optional().default(true).describe('Include unused indexes'),
|
|
128
|
+
}),
|
|
129
|
+
handler: async (client, args) => {
|
|
130
|
+
const unusedFilter = args.showUnused
|
|
131
|
+
? ''
|
|
132
|
+
: 'AND (user_seeks + user_scans + user_lookups) > 0';
|
|
133
|
+
const query = `
|
|
134
|
+
USE [${args.database}];
|
|
135
|
+
|
|
136
|
+
SELECT
|
|
137
|
+
OBJECT_SCHEMA_NAME(i.object_id) as schema_name,
|
|
138
|
+
OBJECT_NAME(i.object_id) as table_name,
|
|
139
|
+
i.name as index_name,
|
|
140
|
+
i.type_desc as index_type,
|
|
141
|
+
ISNULL(s.user_seeks, 0) as user_seeks,
|
|
142
|
+
ISNULL(s.user_scans, 0) as user_scans,
|
|
143
|
+
ISNULL(s.user_lookups, 0) as user_lookups,
|
|
144
|
+
ISNULL(s.user_updates, 0) as user_updates,
|
|
145
|
+
ISNULL(s.last_user_seek, '1900-01-01') as last_user_seek,
|
|
146
|
+
ISNULL(s.last_user_scan, '1900-01-01') as last_user_scan,
|
|
147
|
+
CAST(ps.used_page_count * 8.0 / 1024 AS DECIMAL(10,2)) as size_mb
|
|
148
|
+
FROM sys.indexes i
|
|
149
|
+
LEFT JOIN sys.dm_db_index_usage_stats s
|
|
150
|
+
ON i.object_id = s.object_id AND i.index_id = s.index_id AND s.database_id = DB_ID()
|
|
151
|
+
LEFT JOIN sys.dm_db_partition_stats ps
|
|
152
|
+
ON i.object_id = ps.object_id AND i.index_id = ps.index_id
|
|
153
|
+
WHERE OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1
|
|
154
|
+
AND i.index_id > 0
|
|
155
|
+
${unusedFilter}
|
|
156
|
+
ORDER BY (ISNULL(s.user_seeks, 0) + ISNULL(s.user_scans, 0) + ISNULL(s.user_lookups, 0)) ASC
|
|
157
|
+
`;
|
|
158
|
+
return await client.query(query);
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=performance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.js","sourceRoot":"","sources":["../../src/tools/performance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,YAAY,EAAE;QACZ,WAAW,EAAE,mEAAmE;QAChF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCb,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzC,OAAO;gBACL,aAAa,EAAE,MAAM,CAAC,MAAM;gBAC5B,MAAM,EAAE,MAAM;aACf,CAAC;QACJ,CAAC;KACF;IAED,cAAc,EAAE;QACd,WAAW,EAAE,oEAAoE;QACjF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAChF,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;SAC5F,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,IAA6C,EAAE,EAAE;YACpF,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW;gBACpC,CAAC,CAAC;;;;;;;;;;;;;;;2CAeiC;gBACnC,CAAC,CAAC,EAAE,CAAC;YAEP,MAAM,KAAK,GAAG;qBACC,IAAI,CAAC,GAAG,IAAI,EAAE;;;;;;;;;UASzB,aAAa;;OAEhB,CAAC;YAEF,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;KACF;IAED,aAAa,EAAE;QACb,WAAW,EAAE,uDAAuD;QACpE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,gCAAgC,CAAC;SACtF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,IAA0B,EAAE,EAAE;YACjE,MAAM,KAAK,GAAG;;;qBAGC,IAAI,CAAC,OAAO,IAAI,EAAE;;;;;;;;;;;;;;;;;;;OAmBhC,CAAC;YAEF,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;KACF;IAED,eAAe,EAAE;QACf,WAAW,EAAE,kEAAkE;QAC/E,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;YACzD,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;SACpF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,MAAmB,EAAE,IAAgD,EAAE,EAAE;YACvF,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU;gBAClC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,kDAAkD,CAAC;YAEvD,MAAM,KAAK,GAAG;eACL,IAAI,CAAC,QAAQ;;;;;;;;;;;;;;;;;;;;;UAqBlB,YAAY;;OAEf,CAAC;YAEF,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { MssqlClient } from '../mssqlClient.js';
|
|
3
|
+
export declare const queryTools: {
|
|
4
|
+
execute_query: {
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{
|
|
7
|
+
query: z.ZodString;
|
|
8
|
+
database: z.ZodOptional<z.ZodString>;
|
|
9
|
+
maxRows: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
query: string;
|
|
12
|
+
maxRows: number;
|
|
13
|
+
database?: string | undefined;
|
|
14
|
+
}, {
|
|
15
|
+
query: string;
|
|
16
|
+
database?: string | undefined;
|
|
17
|
+
maxRows?: number | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
handler: (client: MssqlClient, args: {
|
|
20
|
+
query: string;
|
|
21
|
+
database?: string;
|
|
22
|
+
maxRows?: number;
|
|
23
|
+
}) => Promise<{
|
|
24
|
+
rowCount: number;
|
|
25
|
+
rows: import("mssql").IRecordSet<unknown>[];
|
|
26
|
+
}>;
|
|
27
|
+
};
|
|
28
|
+
get_expensive_queries: {
|
|
29
|
+
description: string;
|
|
30
|
+
inputSchema: z.ZodObject<{
|
|
31
|
+
metric: z.ZodDefault<z.ZodOptional<z.ZodEnum<["cpu", "reads", "writes", "duration", "executions"]>>>;
|
|
32
|
+
top: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
metric: "cpu" | "reads" | "writes" | "duration" | "executions";
|
|
35
|
+
top: number;
|
|
36
|
+
}, {
|
|
37
|
+
metric?: "cpu" | "reads" | "writes" | "duration" | "executions" | undefined;
|
|
38
|
+
top?: number | undefined;
|
|
39
|
+
}>;
|
|
40
|
+
handler: (client: MssqlClient, args: {
|
|
41
|
+
metric?: string;
|
|
42
|
+
top?: number;
|
|
43
|
+
}) => Promise<import("mssql").IRecordSet<unknown>[]>;
|
|
44
|
+
};
|
|
45
|
+
get_running_queries: {
|
|
46
|
+
description: string;
|
|
47
|
+
inputSchema: z.ZodObject<{
|
|
48
|
+
includeSystem: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
49
|
+
}, "strip", z.ZodTypeAny, {
|
|
50
|
+
includeSystem: boolean;
|
|
51
|
+
}, {
|
|
52
|
+
includeSystem?: boolean | undefined;
|
|
53
|
+
}>;
|
|
54
|
+
handler: (client: MssqlClient, args: {
|
|
55
|
+
includeSystem?: boolean;
|
|
56
|
+
}) => Promise<import("mssql").IRecordSet<unknown>[]>;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/tools/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;0BAQK,WAAW,QAAQ;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE;;;;;;;;;;;;;;;;;0BA0CzE,WAAW,QAAQ;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE;;;;;;;;;;;0BA2CpD,WAAW,QAAQ;YAAE,aAAa,CAAC,EAAE,OAAO,CAAA;SAAE;;CAyCzE,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const queryTools = {
|
|
3
|
+
execute_query: {
|
|
4
|
+
description: 'Execute a read-only SQL query. Only SELECT statements are allowed for safety.',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
query: z.string().describe('The SQL SELECT query to execute'),
|
|
7
|
+
database: z.string().optional().describe('Database to run the query against (optional, uses default if not specified)'),
|
|
8
|
+
maxRows: z.number().optional().default(1000).describe('Maximum rows to return (default: 1000)'),
|
|
9
|
+
}),
|
|
10
|
+
handler: async (client, args) => {
|
|
11
|
+
// Safety check: only allow SELECT statements
|
|
12
|
+
const trimmedQuery = args.query.trim().toUpperCase();
|
|
13
|
+
if (!trimmedQuery.startsWith('SELECT') && !trimmedQuery.startsWith('WITH')) {
|
|
14
|
+
throw new Error('Only SELECT queries are allowed. For safety, INSERT/UPDATE/DELETE/EXEC are not permitted.');
|
|
15
|
+
}
|
|
16
|
+
// Check for dangerous keywords
|
|
17
|
+
const dangerous = ['INSERT', 'UPDATE', 'DELETE', 'DROP', 'TRUNCATE', 'ALTER', 'CREATE', 'EXEC', 'EXECUTE', 'XP_', 'SP_'];
|
|
18
|
+
for (const keyword of dangerous) {
|
|
19
|
+
if (trimmedQuery.includes(keyword) && !trimmedQuery.startsWith('WITH')) {
|
|
20
|
+
throw new Error(`Query contains forbidden keyword: ${keyword}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
let finalQuery = args.query;
|
|
24
|
+
// Add TOP clause if not present and maxRows specified
|
|
25
|
+
if (args.maxRows && !trimmedQuery.includes('TOP')) {
|
|
26
|
+
finalQuery = args.query.replace(/^SELECT/i, `SELECT TOP ${args.maxRows}`);
|
|
27
|
+
}
|
|
28
|
+
// Switch database if specified
|
|
29
|
+
if (args.database) {
|
|
30
|
+
finalQuery = `USE [${args.database}]; ${finalQuery}`;
|
|
31
|
+
}
|
|
32
|
+
const result = await client.query(finalQuery);
|
|
33
|
+
return {
|
|
34
|
+
rowCount: result.length,
|
|
35
|
+
rows: result,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
get_expensive_queries: {
|
|
40
|
+
description: 'Get the most resource-intensive queries from the query store or plan cache',
|
|
41
|
+
inputSchema: z.object({
|
|
42
|
+
metric: z.enum(['cpu', 'reads', 'writes', 'duration', 'executions']).optional().default('cpu')
|
|
43
|
+
.describe('Metric to sort by'),
|
|
44
|
+
top: z.number().optional().default(20).describe('Number of queries to return'),
|
|
45
|
+
}),
|
|
46
|
+
handler: async (client, args) => {
|
|
47
|
+
const orderByMap = {
|
|
48
|
+
cpu: 'total_worker_time',
|
|
49
|
+
reads: 'total_logical_reads',
|
|
50
|
+
writes: 'total_logical_writes',
|
|
51
|
+
duration: 'total_elapsed_time',
|
|
52
|
+
executions: 'execution_count',
|
|
53
|
+
};
|
|
54
|
+
const orderBy = orderByMap[args.metric || 'cpu'];
|
|
55
|
+
const query = `
|
|
56
|
+
SELECT TOP ${args.top || 20}
|
|
57
|
+
qs.execution_count,
|
|
58
|
+
qs.total_worker_time / 1000 as total_cpu_ms,
|
|
59
|
+
qs.total_worker_time / qs.execution_count / 1000 as avg_cpu_ms,
|
|
60
|
+
qs.total_elapsed_time / 1000 as total_duration_ms,
|
|
61
|
+
qs.total_elapsed_time / qs.execution_count / 1000 as avg_duration_ms,
|
|
62
|
+
qs.total_logical_reads,
|
|
63
|
+
qs.total_logical_reads / qs.execution_count as avg_logical_reads,
|
|
64
|
+
qs.total_logical_writes,
|
|
65
|
+
qs.last_execution_time,
|
|
66
|
+
SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
|
|
67
|
+
((CASE qs.statement_end_offset
|
|
68
|
+
WHEN -1 THEN DATALENGTH(st.text)
|
|
69
|
+
ELSE qs.statement_end_offset
|
|
70
|
+
END - qs.statement_start_offset)/2)+1) as query_text,
|
|
71
|
+
DB_NAME(st.dbid) as database_name
|
|
72
|
+
FROM sys.dm_exec_query_stats qs
|
|
73
|
+
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
|
|
74
|
+
WHERE qs.execution_count > 0
|
|
75
|
+
ORDER BY ${orderBy} DESC
|
|
76
|
+
`;
|
|
77
|
+
return await client.query(query);
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
get_running_queries: {
|
|
81
|
+
description: 'Get currently executing queries with their status and resource usage',
|
|
82
|
+
inputSchema: z.object({
|
|
83
|
+
includeSystem: z.boolean().optional().default(false).describe('Include system processes'),
|
|
84
|
+
}),
|
|
85
|
+
handler: async (client, args) => {
|
|
86
|
+
const systemFilter = args.includeSystem ? '' : 'AND s.is_user_process = 1';
|
|
87
|
+
const query = `
|
|
88
|
+
SELECT
|
|
89
|
+
r.session_id,
|
|
90
|
+
r.request_id,
|
|
91
|
+
r.start_time,
|
|
92
|
+
DATEDIFF(SECOND, r.start_time, GETDATE()) as duration_seconds,
|
|
93
|
+
r.status,
|
|
94
|
+
r.command,
|
|
95
|
+
r.database_id,
|
|
96
|
+
DB_NAME(r.database_id) as database_name,
|
|
97
|
+
r.wait_type,
|
|
98
|
+
r.wait_time,
|
|
99
|
+
r.blocking_session_id,
|
|
100
|
+
r.cpu_time,
|
|
101
|
+
r.total_elapsed_time,
|
|
102
|
+
r.reads,
|
|
103
|
+
r.writes,
|
|
104
|
+
r.logical_reads,
|
|
105
|
+
s.login_name,
|
|
106
|
+
s.host_name,
|
|
107
|
+
s.program_name,
|
|
108
|
+
SUBSTRING(st.text, (r.statement_start_offset/2)+1,
|
|
109
|
+
((CASE r.statement_end_offset
|
|
110
|
+
WHEN -1 THEN DATALENGTH(st.text)
|
|
111
|
+
ELSE r.statement_end_offset
|
|
112
|
+
END - r.statement_start_offset)/2)+1) as current_statement,
|
|
113
|
+
st.text as full_query
|
|
114
|
+
FROM sys.dm_exec_requests r
|
|
115
|
+
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
|
|
116
|
+
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) st
|
|
117
|
+
WHERE r.session_id != @@SPID
|
|
118
|
+
${systemFilter}
|
|
119
|
+
ORDER BY r.total_elapsed_time DESC
|
|
120
|
+
`;
|
|
121
|
+
return await client.query(query);
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/tools/queries.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elad-nofy/mssql-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for Microsoft SQL Server - Query execution, performance analysis, health monitoring",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mssql-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"mssql",
|
|
22
|
+
"sql-server",
|
|
23
|
+
"database",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"claude",
|
|
26
|
+
"ai",
|
|
27
|
+
"observability",
|
|
28
|
+
"monitoring"
|
|
29
|
+
],
|
|
30
|
+
"author": "Nof Yonany",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/elad-nofy/mssql-mcp"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/elad-nofy/mssql-mcp/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/elad-nofy/mssql-mcp#readme",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
42
|
+
"mssql": "^11.0.1",
|
|
43
|
+
"zod": "^3.24.1",
|
|
44
|
+
"zod-to-json-schema": "^3.25.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/mssql": "^9.1.5",
|
|
48
|
+
"@types/node": "^22.10.5",
|
|
49
|
+
"typescript": "^5.7.2"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|