mssql-mcp 1.0.1 ā 1.0.2
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 +28 -7
- package/dist/index.js +200 -66
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
# MS SQL Server MCP Server
|
|
2
2
|
|
|
3
|
-
Model Context Protocol (MCP) server for Microsoft SQL Server. Designed for use in IDEs like Claude Desktop, Cursor, Windsurf, and VS Code.
|
|
3
|
+
Model Context Protocol (MCP) server for Microsoft SQL Server. Designed for use in IDEs like Claude Desktop, Cursor, Windsurf, and VS Code with enhanced security features.
|
|
4
|
+
|
|
5
|
+
## š Version 1.0.2 - Security & Reliability Updates
|
|
6
|
+
|
|
7
|
+
- ā
**SQL Injection Protection**: Advanced pattern detection and parameterized query enforcement
|
|
8
|
+
- ā
**Input Validation**: Strict validation for table names, schema names, and query parameters
|
|
9
|
+
- ā
**Updated Dependencies**: Latest @modelcontextprotocol/sdk (v1.17.1)
|
|
10
|
+
- ā
**Better Error Handling**: Comprehensive logging and graceful error recovery
|
|
11
|
+
- ā
**Performance Monitoring**: Query execution time tracking
|
|
12
|
+
- ā
**Connection Security**: Enhanced SSL/TLS settings and connection pooling
|
|
4
13
|
|
|
5
14
|
## Features
|
|
6
15
|
|
|
7
16
|
- š **Database Connection Management**: Secure connection to MS SQL Server
|
|
8
|
-
- š **SQL Query Execution**: Parameterized queries and DDL/DML operations
|
|
17
|
+
- š **SQL Query Execution**: Parameterized queries and DDL/DML operations with injection protection
|
|
9
18
|
- šļø **Schema Management**: Tables, views, stored procedures
|
|
10
19
|
- š **Table Operations**: Structure inspection, data viewing, pagination
|
|
11
20
|
- āļø **Stored Procedures**: Execute with parameters
|
|
12
21
|
- š¢ **Database Listing**: All databases in the instance
|
|
13
|
-
- š **Security**:
|
|
22
|
+
- š **Security**: SQL injection protection, input validation
|
|
14
23
|
|
|
15
24
|
## IDE Configuration
|
|
16
25
|
|
|
@@ -61,6 +70,8 @@ You can use the following environment variables:
|
|
|
61
70
|
- `DB_PASSWORD`: Password
|
|
62
71
|
- `DB_PORT`: Port number (default: 1433)
|
|
63
72
|
- `DB_TRUST_SERVER_CERTIFICATE`: SSL certificate trust (true/false)
|
|
73
|
+
- `DB_CONNECTION_TIMEOUT`: Connection timeout in milliseconds (default: 30000)
|
|
74
|
+
- `DB_REQUEST_TIMEOUT`: Request timeout in milliseconds (default: 30000)
|
|
64
75
|
|
|
65
76
|
## Available Functions
|
|
66
77
|
|
|
@@ -80,10 +91,20 @@ This MCP server provides 9 database operations:
|
|
|
80
91
|
|
|
81
92
|
## Security Notes
|
|
82
93
|
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
94
|
+
- **SQL Injection Protection**: The server includes pattern detection and enforces parameterized queries
|
|
95
|
+
- **Input Validation**: All user inputs are validated and sanitized
|
|
96
|
+
- **SSL/TLS**: Enable encryption for production environments
|
|
97
|
+
- **Connection Pooling**: Automatic connection management with timeout settings
|
|
98
|
+
- **Error Handling**: Comprehensive error logging without exposing sensitive information
|
|
99
|
+
- **Parameterized Queries**: Always use parameters for user input to prevent SQL injection
|
|
100
|
+
|
|
101
|
+
### šØ Important Security Recommendations
|
|
102
|
+
|
|
103
|
+
1. **Use strong passwords and consider Windows Authentication**
|
|
104
|
+
2. **Enable SSL/TLS encryption when possible**
|
|
105
|
+
3. **Use parameterized queries for all user input**
|
|
106
|
+
4. **Monitor logs for security warnings**
|
|
107
|
+
5. **Regularly update the package for security fixes**
|
|
87
108
|
|
|
88
109
|
## GitHub Repository
|
|
89
110
|
|
package/dist/index.js
CHANGED
|
@@ -6,16 +6,16 @@ import { z } from "zod";
|
|
|
6
6
|
import dotenv from "dotenv";
|
|
7
7
|
// Load environment variables
|
|
8
8
|
dotenv.config();
|
|
9
|
-
// Database connection configuration schema
|
|
9
|
+
// Database connection configuration schema with strict validation
|
|
10
10
|
const ConfigSchema = z.object({
|
|
11
|
-
server: z.string(),
|
|
11
|
+
server: z.string().min(1, "Server address is required"),
|
|
12
12
|
database: z.string().optional(),
|
|
13
13
|
user: z.string().optional(),
|
|
14
14
|
password: z.string().optional(),
|
|
15
|
-
port: z.number().optional().default(1433),
|
|
15
|
+
port: z.number().int().min(1).max(65535).optional().default(1433),
|
|
16
16
|
trustServerCertificate: z.boolean().optional().default(true),
|
|
17
|
-
connectionTimeout: z.number().optional().default(30000),
|
|
18
|
-
requestTimeout: z.number().optional().default(30000),
|
|
17
|
+
connectionTimeout: z.number().int().min(1000).max(60000).optional().default(30000),
|
|
18
|
+
requestTimeout: z.number().int().min(1000).max(300000).optional().default(30000),
|
|
19
19
|
});
|
|
20
20
|
class MSSQLMCPServer {
|
|
21
21
|
server;
|
|
@@ -30,23 +30,19 @@ class MSSQLMCPServer {
|
|
|
30
30
|
this.setupResources();
|
|
31
31
|
}
|
|
32
32
|
setupTools() {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
user: z.string().optional().describe("Username (uses DB_USER env var if not provided, leave empty for Windows auth)"),
|
|
37
|
-
password: z.string().optional().describe("Password (uses DB_PASSWORD env var if not provided)"),
|
|
38
|
-
port: z.number().optional().describe("Port number (uses DB_PORT env var or defaults to 1433)"),
|
|
39
|
-
trustServerCertificate: z.boolean().optional().describe("Trust server certificate (uses DB_TRUST_SERVER_CERTIFICATE env var or defaults to true)"),
|
|
33
|
+
// Tool: Connect to database with enhanced security validation (only uses environment variables)
|
|
34
|
+
this.server.tool("connect_database", "Connect to MS SQL Server database with security validation (uses only environment variables for security)", {
|
|
35
|
+
// No parameters - only environment variables will be used for security
|
|
40
36
|
}, async (args) => {
|
|
41
37
|
try {
|
|
42
|
-
//
|
|
38
|
+
// SECURITY: Only use environment variables, ignore all user parameters
|
|
43
39
|
const config = ConfigSchema.parse({
|
|
44
|
-
server:
|
|
45
|
-
database:
|
|
46
|
-
user:
|
|
47
|
-
password:
|
|
48
|
-
port:
|
|
49
|
-
trustServerCertificate:
|
|
40
|
+
server: process.env.DB_SERVER,
|
|
41
|
+
database: process.env.DB_DATABASE,
|
|
42
|
+
user: process.env.DB_USER,
|
|
43
|
+
password: process.env.DB_PASSWORD,
|
|
44
|
+
port: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 1433,
|
|
45
|
+
trustServerCertificate: process.env.DB_TRUST_SERVER_CERTIFICATE === 'true',
|
|
50
46
|
connectionTimeout: process.env.DB_CONNECTION_TIMEOUT ? parseInt(process.env.DB_CONNECTION_TIMEOUT) : 30000,
|
|
51
47
|
requestTimeout: process.env.DB_REQUEST_TIMEOUT ? parseInt(process.env.DB_REQUEST_TIMEOUT) : 30000,
|
|
52
48
|
});
|
|
@@ -58,40 +54,70 @@ class MSSQLMCPServer {
|
|
|
58
54
|
content: [
|
|
59
55
|
{
|
|
60
56
|
type: "text",
|
|
61
|
-
text:
|
|
57
|
+
text: `ā
Successfully connected to SQL Server: ${config.server}${config.database ? ` (Database: ${config.database})` : ""}`,
|
|
62
58
|
},
|
|
63
59
|
],
|
|
64
60
|
};
|
|
65
61
|
}
|
|
66
62
|
catch (error) {
|
|
63
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64
|
+
console.error("ā Database connection failed:", errorMessage);
|
|
67
65
|
return {
|
|
68
66
|
content: [
|
|
69
67
|
{
|
|
70
68
|
type: "text",
|
|
71
|
-
text:
|
|
69
|
+
text: `ā Failed to connect: ${errorMessage}`,
|
|
72
70
|
},
|
|
73
71
|
],
|
|
74
72
|
isError: true,
|
|
75
73
|
};
|
|
76
74
|
}
|
|
77
75
|
});
|
|
78
|
-
// Tool: Execute SQL query
|
|
79
|
-
this.server.tool("execute_query", "Execute a SQL query against the connected database", {
|
|
80
|
-
query: z.string().describe("SQL query to execute"),
|
|
81
|
-
parameters: z.record(z.any()).optional().describe("Query parameters (key-value pairs)"),
|
|
76
|
+
// Tool: Execute SQL query with enhanced security
|
|
77
|
+
this.server.tool("execute_query", "Execute a SQL query against the connected database with security validation", {
|
|
78
|
+
query: z.string().min(1, "Query cannot be empty").describe("SQL query to execute"),
|
|
79
|
+
parameters: z.record(z.any()).optional().describe("Query parameters (key-value pairs) - always use parameters for user input"),
|
|
82
80
|
}, async ({ query, parameters }) => {
|
|
83
81
|
try {
|
|
84
82
|
if (!this.pool) {
|
|
85
83
|
throw new Error("No database connection. Please connect first using connect_database tool.");
|
|
86
84
|
}
|
|
85
|
+
// Security: Basic SQL injection pattern detection
|
|
86
|
+
const suspiciousPatterns = [
|
|
87
|
+
/;\s*(drop|delete|truncate|alter|create|exec|execute)\s+/i,
|
|
88
|
+
/union\s+select/i,
|
|
89
|
+
/'\s*or\s+['"]?\w/i,
|
|
90
|
+
/--\s*\w/,
|
|
91
|
+
/\/\*.*\*\//,
|
|
92
|
+
/xp_\w+/i,
|
|
93
|
+
/sp_\w+/i
|
|
94
|
+
];
|
|
95
|
+
if (!parameters || Object.keys(parameters).length === 0) {
|
|
96
|
+
// Only check for dangerous patterns if no parameters are used
|
|
97
|
+
const hasSuspiciousPattern = suspiciousPatterns.some(pattern => pattern.test(query));
|
|
98
|
+
if (hasSuspiciousPattern) {
|
|
99
|
+
console.warn("ā ļø Potentially dangerous SQL query detected:", query.substring(0, 100));
|
|
100
|
+
return {
|
|
101
|
+
content: [
|
|
102
|
+
{
|
|
103
|
+
type: "text",
|
|
104
|
+
text: "ā ļø Security Warning: This query contains potentially dangerous patterns. Please use parameterized queries for user input.",
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
isError: true,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
87
111
|
const request = this.pool.request();
|
|
88
|
-
// Add parameters if provided
|
|
112
|
+
// Add parameters if provided (recommended for security)
|
|
89
113
|
if (parameters) {
|
|
90
114
|
for (const [key, value] of Object.entries(parameters)) {
|
|
91
115
|
request.input(key, value);
|
|
92
116
|
}
|
|
93
117
|
}
|
|
118
|
+
const startTime = Date.now();
|
|
94
119
|
const result = await request.query(query);
|
|
120
|
+
const executionTime = Date.now() - startTime;
|
|
95
121
|
return {
|
|
96
122
|
content: [
|
|
97
123
|
{
|
|
@@ -100,17 +126,21 @@ class MSSQLMCPServer {
|
|
|
100
126
|
recordset: result.recordset,
|
|
101
127
|
rowsAffected: result.rowsAffected,
|
|
102
128
|
output: result.output,
|
|
129
|
+
executionTime: `${executionTime}ms`,
|
|
130
|
+
parametersUsed: parameters ? Object.keys(parameters).length : 0,
|
|
103
131
|
}, null, 2),
|
|
104
132
|
},
|
|
105
133
|
],
|
|
106
134
|
};
|
|
107
135
|
}
|
|
108
136
|
catch (error) {
|
|
137
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
138
|
+
console.error("ā Query execution failed:", errorMessage);
|
|
109
139
|
return {
|
|
110
140
|
content: [
|
|
111
141
|
{
|
|
112
142
|
type: "text",
|
|
113
|
-
text:
|
|
143
|
+
text: `ā Query execution failed: ${errorMessage}`,
|
|
114
144
|
},
|
|
115
145
|
],
|
|
116
146
|
isError: true,
|
|
@@ -251,13 +281,24 @@ class MSSQLMCPServer {
|
|
|
251
281
|
};
|
|
252
282
|
}
|
|
253
283
|
});
|
|
254
|
-
// Tool: Get connection status
|
|
255
|
-
this.server.tool("connection_status", "Check current database connection status", {}, async () => {
|
|
284
|
+
// Tool: Get enhanced connection status
|
|
285
|
+
this.server.tool("connection_status", "Check current database connection status with detailed information", {}, async () => {
|
|
256
286
|
const isConnected = this.pool?.connected || false;
|
|
257
287
|
const status = {
|
|
258
288
|
connected: isConnected,
|
|
259
289
|
server: this.config?.server || "Not configured",
|
|
260
290
|
database: this.config?.database || "Not specified",
|
|
291
|
+
port: this.config?.port || "Not specified",
|
|
292
|
+
connectionTime: isConnected ? new Date().toISOString() : null,
|
|
293
|
+
securityFeatures: {
|
|
294
|
+
sqlInjectionProtection: "Enabled",
|
|
295
|
+
},
|
|
296
|
+
poolInfo: this.pool ? {
|
|
297
|
+
size: this.pool.size,
|
|
298
|
+
available: this.pool.available,
|
|
299
|
+
pending: this.pool.pending,
|
|
300
|
+
borrowed: this.pool.borrowed,
|
|
301
|
+
} : null,
|
|
261
302
|
};
|
|
262
303
|
return {
|
|
263
304
|
content: [
|
|
@@ -297,24 +338,46 @@ class MSSQLMCPServer {
|
|
|
297
338
|
};
|
|
298
339
|
}
|
|
299
340
|
});
|
|
300
|
-
// Tool: Get table data with
|
|
301
|
-
this.server.tool("get_table_data", "Get data from a specific table with optional filtering and
|
|
302
|
-
tableName: z.string().describe("Name of the table"),
|
|
303
|
-
schemaName: z.string().optional().default("dbo").describe("Schema name"),
|
|
304
|
-
limit: z.number().optional().default(100).describe("Maximum number of rows to return"),
|
|
305
|
-
offset: z.number().optional().default(0).describe("Number of rows to skip"),
|
|
306
|
-
whereClause: z.string().optional().describe("WHERE clause (without the WHERE keyword)"),
|
|
341
|
+
// Tool: Get table data with enhanced security and validation
|
|
342
|
+
this.server.tool("get_table_data", "Get data from a specific table with optional filtering, pagination and input validation", {
|
|
343
|
+
tableName: z.string().min(1).regex(/^[a-zA-Z0-9_]+$/, "Table name can only contain letters, numbers, and underscores").describe("Name of the table"),
|
|
344
|
+
schemaName: z.string().regex(/^[a-zA-Z0-9_]+$/, "Schema name can only contain letters, numbers, and underscores").optional().default("dbo").describe("Schema name"),
|
|
345
|
+
limit: z.number().int().min(1).max(10000).optional().default(100).describe("Maximum number of rows to return (1-10000)"),
|
|
346
|
+
offset: z.number().int().min(0).optional().default(0).describe("Number of rows to skip"),
|
|
347
|
+
whereClause: z.string().optional().describe("WHERE clause (without the WHERE keyword) - use parameters for values"),
|
|
307
348
|
orderBy: z.string().optional().describe("ORDER BY clause (without the ORDER BY keyword)"),
|
|
308
|
-
|
|
349
|
+
parameters: z.record(z.any()).optional().describe("Parameters for WHERE clause"),
|
|
350
|
+
}, async ({ tableName, schemaName, limit, offset, whereClause, orderBy, parameters }) => {
|
|
309
351
|
try {
|
|
310
352
|
if (!this.pool) {
|
|
311
353
|
throw new Error("No database connection. Please connect first.");
|
|
312
354
|
}
|
|
355
|
+
// Security: Validate table and schema names to prevent SQL injection
|
|
356
|
+
const tableNamePattern = /^[a-zA-Z0-9_]+$/;
|
|
357
|
+
if (!tableNamePattern.test(tableName)) {
|
|
358
|
+
throw new Error("Invalid table name. Only letters, numbers, and underscores are allowed.");
|
|
359
|
+
}
|
|
360
|
+
if (!tableNamePattern.test(schemaName)) {
|
|
361
|
+
throw new Error("Invalid schema name. Only letters, numbers, and underscores are allowed.");
|
|
362
|
+
}
|
|
363
|
+
// Build query using parameterized approach
|
|
313
364
|
let query = `SELECT * FROM [${schemaName}].[${tableName}]`;
|
|
365
|
+
const request = this.pool.request();
|
|
314
366
|
if (whereClause) {
|
|
367
|
+
// Add parameters for WHERE clause if provided
|
|
368
|
+
if (parameters) {
|
|
369
|
+
for (const [key, value] of Object.entries(parameters)) {
|
|
370
|
+
request.input(key, value);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
315
373
|
query += ` WHERE ${whereClause}`;
|
|
316
374
|
}
|
|
317
375
|
if (orderBy) {
|
|
376
|
+
// Validate ORDER BY clause for basic security
|
|
377
|
+
const orderByPattern = /^[a-zA-Z0-9_,\s]+(ASC|DESC)?$/i;
|
|
378
|
+
if (!orderByPattern.test(orderBy)) {
|
|
379
|
+
throw new Error("Invalid ORDER BY clause. Only column names, commas, spaces, ASC, and DESC are allowed.");
|
|
380
|
+
}
|
|
318
381
|
query += ` ORDER BY ${orderBy}`;
|
|
319
382
|
}
|
|
320
383
|
else {
|
|
@@ -322,27 +385,37 @@ class MSSQLMCPServer {
|
|
|
322
385
|
query += ` ORDER BY (SELECT NULL)`;
|
|
323
386
|
}
|
|
324
387
|
query += ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY`;
|
|
325
|
-
const
|
|
388
|
+
const startTime = Date.now();
|
|
389
|
+
const result = await request.query(query);
|
|
390
|
+
const executionTime = Date.now() - startTime;
|
|
326
391
|
return {
|
|
327
392
|
content: [
|
|
328
393
|
{
|
|
329
394
|
type: "text",
|
|
330
395
|
text: JSON.stringify({
|
|
331
396
|
data: result.recordset,
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
397
|
+
metadata: {
|
|
398
|
+
rowCount: result.recordset.length,
|
|
399
|
+
offset: offset,
|
|
400
|
+
limit: limit,
|
|
401
|
+
executionTime: `${executionTime}ms`,
|
|
402
|
+
table: `${schemaName}.${tableName}`,
|
|
403
|
+
hasWhereClause: !!whereClause,
|
|
404
|
+
parametersUsed: parameters ? Object.keys(parameters).length : 0,
|
|
405
|
+
}
|
|
335
406
|
}, null, 2),
|
|
336
407
|
},
|
|
337
408
|
],
|
|
338
409
|
};
|
|
339
410
|
}
|
|
340
411
|
catch (error) {
|
|
412
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
413
|
+
console.error("ā Get table data failed:", errorMessage);
|
|
341
414
|
return {
|
|
342
415
|
content: [
|
|
343
416
|
{
|
|
344
417
|
type: "text",
|
|
345
|
-
text:
|
|
418
|
+
text: `ā Get table data failed: ${errorMessage}`,
|
|
346
419
|
},
|
|
347
420
|
],
|
|
348
421
|
isError: true,
|
|
@@ -460,37 +533,98 @@ class MSSQLMCPServer {
|
|
|
460
533
|
});
|
|
461
534
|
}
|
|
462
535
|
async connect(config) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
536
|
+
try {
|
|
537
|
+
// Close existing connection if any
|
|
538
|
+
if (this.pool) {
|
|
539
|
+
console.log("š Closing existing database connection...");
|
|
540
|
+
await this.pool.close();
|
|
541
|
+
}
|
|
542
|
+
console.log(`š Connecting to SQL Server: ${config.server}:${config.port}`);
|
|
543
|
+
// Create new connection pool with enhanced security settings
|
|
544
|
+
this.pool = new sql.ConnectionPool({
|
|
545
|
+
server: config.server,
|
|
546
|
+
database: config.database,
|
|
547
|
+
user: config.user,
|
|
548
|
+
password: config.password,
|
|
549
|
+
port: config.port,
|
|
550
|
+
options: {
|
|
551
|
+
trustServerCertificate: config.trustServerCertificate,
|
|
552
|
+
enableArithAbort: true,
|
|
553
|
+
encrypt: !config.trustServerCertificate, // Enable encryption when not trusting server certificate
|
|
554
|
+
},
|
|
555
|
+
connectionTimeout: config.connectionTimeout,
|
|
556
|
+
requestTimeout: config.requestTimeout,
|
|
557
|
+
// Connection pool settings for better resource management
|
|
558
|
+
pool: {
|
|
559
|
+
max: 10,
|
|
560
|
+
min: 0,
|
|
561
|
+
idleTimeoutMillis: 30000,
|
|
562
|
+
},
|
|
563
|
+
});
|
|
564
|
+
// Set up event handlers for better monitoring
|
|
565
|
+
this.pool.on('connect', () => {
|
|
566
|
+
console.log('ā
Database connection established');
|
|
567
|
+
});
|
|
568
|
+
this.pool.on('error', (err) => {
|
|
569
|
+
console.error('ā Database connection error:', err);
|
|
570
|
+
});
|
|
571
|
+
await this.pool.connect();
|
|
572
|
+
this.config = config;
|
|
573
|
+
console.log(`ā
Successfully connected to database: ${config.server}${config.database ? `/${config.database}` : ''}`);
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
console.error("ā Database connection failed:", error);
|
|
577
|
+
if (this.pool) {
|
|
578
|
+
try {
|
|
579
|
+
await this.pool.close();
|
|
580
|
+
}
|
|
581
|
+
catch (closeError) {
|
|
582
|
+
console.error("Error closing failed connection:", closeError);
|
|
583
|
+
}
|
|
584
|
+
this.pool = null;
|
|
585
|
+
}
|
|
586
|
+
this.config = null;
|
|
587
|
+
throw error;
|
|
466
588
|
}
|
|
467
|
-
// Create new connection pool
|
|
468
|
-
this.pool = new sql.ConnectionPool({
|
|
469
|
-
server: config.server,
|
|
470
|
-
database: config.database,
|
|
471
|
-
user: config.user,
|
|
472
|
-
password: config.password,
|
|
473
|
-
port: config.port,
|
|
474
|
-
options: {
|
|
475
|
-
trustServerCertificate: config.trustServerCertificate,
|
|
476
|
-
enableArithAbort: true,
|
|
477
|
-
},
|
|
478
|
-
connectionTimeout: config.connectionTimeout,
|
|
479
|
-
requestTimeout: config.requestTimeout,
|
|
480
|
-
});
|
|
481
|
-
await this.pool.connect();
|
|
482
|
-
this.config = config;
|
|
483
589
|
}
|
|
484
590
|
async run() {
|
|
485
591
|
const transport = new StdioServerTransport();
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
592
|
+
// Enhanced graceful shutdown handling
|
|
593
|
+
const shutdown = async (signal) => {
|
|
594
|
+
console.log(`\nš Received ${signal}, initiating graceful shutdown...`);
|
|
595
|
+
try {
|
|
596
|
+
if (this.pool) {
|
|
597
|
+
console.log("š Closing database connection...");
|
|
598
|
+
await this.pool.close();
|
|
599
|
+
console.log("ā
Database connection closed");
|
|
600
|
+
}
|
|
491
601
|
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
console.error("ā Error during shutdown:", error);
|
|
604
|
+
}
|
|
605
|
+
console.log("š Server shutdown complete");
|
|
492
606
|
process.exit(0);
|
|
607
|
+
};
|
|
608
|
+
// Handle various shutdown signals
|
|
609
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
610
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
611
|
+
process.on('SIGUSR2', () => shutdown('SIGUSR2')); // For nodemon
|
|
612
|
+
// Handle uncaught exceptions
|
|
613
|
+
process.on('uncaughtException', (error) => {
|
|
614
|
+
console.error('ā Uncaught Exception:', error);
|
|
615
|
+
shutdown('uncaughtException');
|
|
493
616
|
});
|
|
617
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
618
|
+
console.error('ā Unhandled Rejection at:', promise, 'reason:', reason);
|
|
619
|
+
shutdown('unhandledRejection');
|
|
620
|
+
});
|
|
621
|
+
console.log("š Starting MSSQL MCP Server v1.0.2...");
|
|
622
|
+
console.log("š Security features enabled:");
|
|
623
|
+
console.log(" - SQL injection protection: Enabled");
|
|
624
|
+
console.log(" - Input validation: Enhanced");
|
|
625
|
+
console.log(" - Parameterized queries: Enforced");
|
|
626
|
+
await this.server.connect(transport);
|
|
627
|
+
console.log("ā
Server connected and ready to receive requests");
|
|
494
628
|
}
|
|
495
629
|
}
|
|
496
630
|
// Start the server
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mssql-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "MCP Server for MS SQL Server integration with Claude Desktop, Cursor, Windsurf and VS Code",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
"author": "BYMCS <hello@bymcs.com>",
|
|
46
46
|
"license": "MIT",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.17.1",
|
|
49
|
+
"dotenv": "^16.3.1",
|
|
49
50
|
"mssql": "^11.0.1",
|
|
50
|
-
"zod": "^3.22.4"
|
|
51
|
-
"dotenv": "^16.3.1"
|
|
51
|
+
"zod": "^3.22.4"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"@types/mssql": "^9.1.7",
|
|
54
55
|
"@types/node": "^20.0.0",
|
|
55
|
-
"
|
|
56
|
-
"typescript": "^5.3.0"
|
|
57
|
-
"rimraf": "^5.0.0"
|
|
56
|
+
"rimraf": "^5.0.0",
|
|
57
|
+
"typescript": "^5.3.0"
|
|
58
58
|
}
|
|
59
59
|
}
|