@xcr1234/dbhub-fork 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.
Files changed (34) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/dist/chunk-6O5I6UAW.js +2150 -0
  4. package/dist/chunk-BRXZ5ZQB.js +127 -0
  5. package/dist/chunk-C7WEAPX4.js +485 -0
  6. package/dist/chunk-FAIJPBT5.js +40 -0
  7. package/dist/chunk-JFWX35TB.js +34 -0
  8. package/dist/chunk-RTB262PR.js +60 -0
  9. package/dist/chunk-WVVMH6FJ.js +49 -0
  10. package/dist/demo/employee-sqlite/employee.sql +117 -0
  11. package/dist/demo/employee-sqlite/load_department.sql +10 -0
  12. package/dist/demo/employee-sqlite/load_dept_emp.sql +1103 -0
  13. package/dist/demo/employee-sqlite/load_dept_manager.sql +17 -0
  14. package/dist/demo/employee-sqlite/load_employee.sql +1000 -0
  15. package/dist/demo/employee-sqlite/load_salary1.sql +9488 -0
  16. package/dist/demo/employee-sqlite/load_title.sql +1470 -0
  17. package/dist/demo-loader-WKQAEFSX.js +48 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +1584 -0
  20. package/dist/mariadb-QHRMVK47.js +468 -0
  21. package/dist/mysql-GOLPG2Q6.js +475 -0
  22. package/dist/oracle-3V2T7ZWF.js +27739 -0
  23. package/dist/postgres-CK6N5BXI.js +520 -0
  24. package/dist/public/assets/index-BiTHVJQj.js +144 -0
  25. package/dist/public/assets/index-CfPYb3wl.css +1 -0
  26. package/dist/public/assets/postgres-BpcazhJg.svg +22 -0
  27. package/dist/public/assets/sqlserver-ByfFYYpV.svg +11 -0
  28. package/dist/public/favicon.svg +57 -0
  29. package/dist/public/index.html +14 -0
  30. package/dist/public/logo-full-light.svg +58 -0
  31. package/dist/registry-KI3KJMRY.js +13 -0
  32. package/dist/sqlite-P6NXTMYE.js +2473 -0
  33. package/dist/sqlserver-5RM44GWI.js +493 -0
  34. package/package.json +99 -0
@@ -0,0 +1,493 @@
1
+ import {
2
+ isDriverNotInstalled
3
+ } from "./chunk-WVVMH6FJ.js";
4
+ import {
5
+ SQLRowLimiter
6
+ } from "./chunk-BRXZ5ZQB.js";
7
+ import {
8
+ ConnectorRegistry,
9
+ SafeURL,
10
+ obfuscateDSNPassword
11
+ } from "./chunk-C7WEAPX4.js";
12
+ import "./chunk-FAIJPBT5.js";
13
+
14
+ // src/connectors/sqlserver/index.ts
15
+ import sql from "mssql";
16
+ var SQLServerDSNParser = class {
17
+ async parse(dsn, config) {
18
+ const connectionTimeoutSeconds = config?.connectionTimeoutSeconds;
19
+ const queryTimeoutSeconds = config?.queryTimeoutSeconds;
20
+ if (!this.isValidDSN(dsn)) {
21
+ const obfuscatedDSN = obfuscateDSNPassword(dsn);
22
+ const expectedFormat = this.getSampleDSN();
23
+ throw new Error(
24
+ `Invalid SQL Server DSN format.
25
+ Provided: ${obfuscatedDSN}
26
+ Expected: ${expectedFormat}`
27
+ );
28
+ }
29
+ try {
30
+ const url = new SafeURL(dsn);
31
+ const options = {};
32
+ url.forEachSearchParam((value, key) => {
33
+ if (key === "authentication") {
34
+ options.authentication = value;
35
+ } else if (key === "sslmode") {
36
+ options.sslmode = value;
37
+ } else if (key === "instanceName") {
38
+ options.instanceName = value;
39
+ } else if (key === "domain") {
40
+ options.domain = value;
41
+ }
42
+ });
43
+ if (options.authentication === "ntlm" && !options.domain) {
44
+ throw new Error("NTLM authentication requires 'domain' parameter");
45
+ }
46
+ if (options.domain && options.authentication !== "ntlm") {
47
+ throw new Error("Parameter 'domain' requires 'authentication=ntlm'");
48
+ }
49
+ if (options.sslmode) {
50
+ if (options.sslmode === "disable") {
51
+ options.encrypt = false;
52
+ options.trustServerCertificate = false;
53
+ } else if (options.sslmode === "require") {
54
+ options.encrypt = true;
55
+ options.trustServerCertificate = true;
56
+ }
57
+ }
58
+ const config2 = {
59
+ server: url.hostname,
60
+ port: url.port ? parseInt(url.port) : 1433,
61
+ // Default SQL Server port
62
+ database: url.pathname ? url.pathname.substring(1) : "",
63
+ // Remove leading slash
64
+ options: {
65
+ encrypt: options.encrypt ?? false,
66
+ // Default to unencrypted for development
67
+ trustServerCertificate: options.trustServerCertificate ?? false,
68
+ ...connectionTimeoutSeconds !== void 0 && {
69
+ connectTimeout: connectionTimeoutSeconds * 1e3
70
+ },
71
+ ...queryTimeoutSeconds !== void 0 && {
72
+ requestTimeout: queryTimeoutSeconds * 1e3
73
+ },
74
+ instanceName: options.instanceName
75
+ // Add named instance support
76
+ }
77
+ };
78
+ switch (options.authentication) {
79
+ case "azure-active-directory-access-token": {
80
+ let DefaultAzureCredential;
81
+ try {
82
+ ({ DefaultAzureCredential } = await import("@azure/identity"));
83
+ } catch (importError) {
84
+ if (isDriverNotInstalled(importError, "@azure/identity")) {
85
+ throw new Error(
86
+ 'Azure AD authentication requires the "@azure/identity" package. Install it with: pnpm add @azure/identity'
87
+ );
88
+ }
89
+ throw importError;
90
+ }
91
+ try {
92
+ const credential = new DefaultAzureCredential();
93
+ const token = await credential.getToken("https://database.windows.net/");
94
+ config2.authentication = {
95
+ type: "azure-active-directory-access-token",
96
+ options: {
97
+ token: token.token
98
+ }
99
+ };
100
+ } catch (error) {
101
+ const errorMessage = error instanceof Error ? error.message : String(error);
102
+ throw new Error(`Failed to get Azure AD token: ${errorMessage}`);
103
+ }
104
+ break;
105
+ }
106
+ case "ntlm":
107
+ config2.authentication = {
108
+ type: "ntlm",
109
+ options: {
110
+ domain: options.domain,
111
+ userName: url.username,
112
+ password: url.password
113
+ }
114
+ };
115
+ break;
116
+ default:
117
+ config2.user = url.username;
118
+ config2.password = url.password;
119
+ break;
120
+ }
121
+ return config2;
122
+ } catch (error) {
123
+ throw new Error(
124
+ `Failed to parse SQL Server DSN: ${error instanceof Error ? error.message : String(error)}`
125
+ );
126
+ }
127
+ }
128
+ getSampleDSN() {
129
+ return "sqlserver://username:password@localhost:1433/database?sslmode=disable&instanceName=INSTANCE1";
130
+ }
131
+ isValidDSN(dsn) {
132
+ try {
133
+ return dsn.startsWith("sqlserver://");
134
+ } catch (error) {
135
+ return false;
136
+ }
137
+ }
138
+ };
139
+ var SQLServerConnector = class _SQLServerConnector {
140
+ constructor() {
141
+ this.id = "sqlserver";
142
+ this.name = "SQL Server";
143
+ this.dsnParser = new SQLServerDSNParser();
144
+ // Source ID is set by ConnectorManager after cloning
145
+ this.sourceId = "default";
146
+ }
147
+ getId() {
148
+ return this.sourceId;
149
+ }
150
+ clone() {
151
+ return new _SQLServerConnector();
152
+ }
153
+ async connect(dsn, initScript, config) {
154
+ try {
155
+ this.config = await this.dsnParser.parse(dsn, config);
156
+ if (!this.config.options) {
157
+ this.config.options = {};
158
+ }
159
+ this.connection = await new sql.ConnectionPool(this.config).connect();
160
+ } catch (error) {
161
+ throw error;
162
+ }
163
+ }
164
+ async disconnect() {
165
+ if (this.connection) {
166
+ await this.connection.close();
167
+ this.connection = void 0;
168
+ }
169
+ }
170
+ async getSchemas() {
171
+ if (!this.connection) {
172
+ throw new Error("Not connected to SQL Server database");
173
+ }
174
+ try {
175
+ const result = await this.connection.request().query(`
176
+ SELECT SCHEMA_NAME
177
+ FROM INFORMATION_SCHEMA.SCHEMATA
178
+ ORDER BY SCHEMA_NAME
179
+ `);
180
+ return result.recordset.map((row) => row.SCHEMA_NAME);
181
+ } catch (error) {
182
+ throw new Error(`Failed to get schemas: ${error.message}`);
183
+ }
184
+ }
185
+ async getTables(schema) {
186
+ if (!this.connection) {
187
+ throw new Error("Not connected to SQL Server database");
188
+ }
189
+ try {
190
+ const schemaToUse = schema || "dbo";
191
+ const request = this.connection.request().input("schema", sql.VarChar, schemaToUse);
192
+ const query = `
193
+ SELECT TABLE_NAME
194
+ FROM INFORMATION_SCHEMA.TABLES
195
+ WHERE TABLE_SCHEMA = @schema
196
+ ORDER BY TABLE_NAME
197
+ `;
198
+ const result = await request.query(query);
199
+ return result.recordset.map((row) => row.TABLE_NAME);
200
+ } catch (error) {
201
+ throw new Error(`Failed to get tables: ${error.message}`);
202
+ }
203
+ }
204
+ async tableExists(tableName, schema) {
205
+ if (!this.connection) {
206
+ throw new Error("Not connected to SQL Server database");
207
+ }
208
+ try {
209
+ const schemaToUse = schema || "dbo";
210
+ const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
211
+ const query = `
212
+ SELECT COUNT(*) as count
213
+ FROM INFORMATION_SCHEMA.TABLES
214
+ WHERE TABLE_NAME = @tableName
215
+ AND TABLE_SCHEMA = @schema
216
+ `;
217
+ const result = await request.query(query);
218
+ return result.recordset[0].count > 0;
219
+ } catch (error) {
220
+ throw new Error(`Failed to check if table exists: ${error.message}`);
221
+ }
222
+ }
223
+ async getTableIndexes(tableName, schema) {
224
+ if (!this.connection) {
225
+ throw new Error("Not connected to SQL Server database");
226
+ }
227
+ try {
228
+ const schemaToUse = schema || "dbo";
229
+ const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
230
+ const query = `
231
+ SELECT i.name AS index_name,
232
+ i.is_unique,
233
+ i.is_primary_key,
234
+ c.name AS column_name,
235
+ ic.key_ordinal
236
+ FROM sys.indexes i
237
+ INNER JOIN
238
+ sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
239
+ INNER JOIN
240
+ sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
241
+ INNER JOIN
242
+ sys.tables t ON i.object_id = t.object_id
243
+ INNER JOIN
244
+ sys.schemas s ON t.schema_id = s.schema_id
245
+ WHERE t.name = @tableName
246
+ AND s.name = @schema
247
+ ORDER BY i.name,
248
+ ic.key_ordinal
249
+ `;
250
+ const result = await request.query(query);
251
+ const indexMap = /* @__PURE__ */ new Map();
252
+ for (const row of result.recordset) {
253
+ const indexName = row.index_name;
254
+ const columnName = row.column_name;
255
+ const isUnique = !!row.is_unique;
256
+ const isPrimary = !!row.is_primary_key;
257
+ if (!indexMap.has(indexName)) {
258
+ indexMap.set(indexName, {
259
+ columns: [],
260
+ is_unique: isUnique,
261
+ is_primary: isPrimary
262
+ });
263
+ }
264
+ const indexInfo = indexMap.get(indexName);
265
+ indexInfo.columns.push(columnName);
266
+ }
267
+ const indexes = [];
268
+ indexMap.forEach((info, name) => {
269
+ indexes.push({
270
+ index_name: name,
271
+ column_names: info.columns,
272
+ is_unique: info.is_unique,
273
+ is_primary: info.is_primary
274
+ });
275
+ });
276
+ return indexes;
277
+ } catch (error) {
278
+ throw new Error(`Failed to get indexes for table ${tableName}: ${error.message}`);
279
+ }
280
+ }
281
+ async getTableSchema(tableName, schema) {
282
+ if (!this.connection) {
283
+ throw new Error("Not connected to SQL Server database");
284
+ }
285
+ try {
286
+ const schemaToUse = schema || "dbo";
287
+ const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
288
+ const query = `
289
+ SELECT c.COLUMN_NAME as column_name,
290
+ c.DATA_TYPE as data_type,
291
+ c.IS_NULLABLE as is_nullable,
292
+ c.COLUMN_DEFAULT as column_default,
293
+ ep.value as description
294
+ FROM INFORMATION_SCHEMA.COLUMNS c
295
+ LEFT JOIN sys.columns sc
296
+ ON sc.name = c.COLUMN_NAME
297
+ AND sc.object_id = OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME))
298
+ LEFT JOIN sys.extended_properties ep
299
+ ON ep.major_id = sc.object_id
300
+ AND ep.minor_id = sc.column_id
301
+ AND ep.name = 'MS_Description'
302
+ WHERE c.TABLE_NAME = @tableName
303
+ AND c.TABLE_SCHEMA = @schema
304
+ ORDER BY c.ORDINAL_POSITION
305
+ `;
306
+ const result = await request.query(query);
307
+ return result.recordset.map((row) => ({
308
+ ...row,
309
+ description: row.description || null
310
+ }));
311
+ } catch (error) {
312
+ throw new Error(`Failed to get schema for table ${tableName}: ${error.message}`);
313
+ }
314
+ }
315
+ async getTableComment(tableName, schema) {
316
+ if (!this.connection) {
317
+ throw new Error("Not connected to SQL Server database");
318
+ }
319
+ try {
320
+ const schemaToUse = schema || "dbo";
321
+ const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
322
+ const query = `
323
+ SELECT ep.value as table_comment
324
+ FROM sys.extended_properties ep
325
+ JOIN sys.tables t ON ep.major_id = t.object_id
326
+ JOIN sys.schemas s ON t.schema_id = s.schema_id
327
+ WHERE ep.minor_id = 0
328
+ AND ep.name = 'MS_Description'
329
+ AND t.name = @tableName
330
+ AND s.name = @schema
331
+ `;
332
+ const result = await request.query(query);
333
+ if (result.recordset.length > 0) {
334
+ return result.recordset[0].table_comment || null;
335
+ }
336
+ return null;
337
+ } catch (error) {
338
+ return null;
339
+ }
340
+ }
341
+ async getStoredProcedures(schema, routineType) {
342
+ if (!this.connection) {
343
+ throw new Error("Not connected to SQL Server database");
344
+ }
345
+ try {
346
+ const schemaToUse = schema || "dbo";
347
+ const request = this.connection.request().input("schema", sql.VarChar, schemaToUse);
348
+ let typeFilter;
349
+ if (routineType === "function") {
350
+ typeFilter = "AND ROUTINE_TYPE = 'FUNCTION'";
351
+ } else if (routineType === "procedure") {
352
+ typeFilter = "AND ROUTINE_TYPE = 'PROCEDURE'";
353
+ } else {
354
+ typeFilter = "AND (ROUTINE_TYPE = 'PROCEDURE' OR ROUTINE_TYPE = 'FUNCTION')";
355
+ }
356
+ const query = `
357
+ SELECT ROUTINE_NAME
358
+ FROM INFORMATION_SCHEMA.ROUTINES
359
+ WHERE ROUTINE_SCHEMA = @schema
360
+ ${typeFilter}
361
+ ORDER BY ROUTINE_NAME
362
+ `;
363
+ const result = await request.query(query);
364
+ return result.recordset.map((row) => row.ROUTINE_NAME);
365
+ } catch (error) {
366
+ throw new Error(`Failed to get stored procedures: ${error.message}`);
367
+ }
368
+ }
369
+ async getStoredProcedureDetail(procedureName, schema) {
370
+ if (!this.connection) {
371
+ throw new Error("Not connected to SQL Server database");
372
+ }
373
+ try {
374
+ const schemaToUse = schema || "dbo";
375
+ const request = this.connection.request().input("procedureName", sql.VarChar, procedureName).input("schema", sql.VarChar, schemaToUse);
376
+ const routineQuery = `
377
+ SELECT ROUTINE_NAME as procedure_name,
378
+ ROUTINE_TYPE,
379
+ DATA_TYPE as return_data_type
380
+ FROM INFORMATION_SCHEMA.ROUTINES
381
+ WHERE ROUTINE_NAME = @procedureName
382
+ AND ROUTINE_SCHEMA = @schema
383
+ `;
384
+ const routineResult = await request.query(routineQuery);
385
+ if (routineResult.recordset.length === 0) {
386
+ throw new Error(`Stored procedure '${procedureName}' not found in schema '${schemaToUse}'`);
387
+ }
388
+ const routine = routineResult.recordset[0];
389
+ const parameterQuery = `
390
+ SELECT PARAMETER_NAME,
391
+ PARAMETER_MODE,
392
+ DATA_TYPE,
393
+ CHARACTER_MAXIMUM_LENGTH,
394
+ ORDINAL_POSITION
395
+ FROM INFORMATION_SCHEMA.PARAMETERS
396
+ WHERE SPECIFIC_NAME = @procedureName
397
+ AND SPECIFIC_SCHEMA = @schema
398
+ ORDER BY ORDINAL_POSITION
399
+ `;
400
+ const parameterResult = await request.query(parameterQuery);
401
+ let parameterList = "";
402
+ if (parameterResult.recordset.length > 0) {
403
+ parameterList = parameterResult.recordset.map(
404
+ (param) => {
405
+ const lengthStr = param.CHARACTER_MAXIMUM_LENGTH > 0 ? `(${param.CHARACTER_MAXIMUM_LENGTH})` : "";
406
+ return `${param.PARAMETER_NAME} ${param.PARAMETER_MODE} ${param.DATA_TYPE}${lengthStr}`;
407
+ }
408
+ ).join(", ");
409
+ }
410
+ const definitionQuery = `
411
+ SELECT definition
412
+ FROM sys.sql_modules sm
413
+ JOIN sys.objects o ON sm.object_id = o.object_id
414
+ JOIN sys.schemas s ON o.schema_id = s.schema_id
415
+ WHERE o.name = @procedureName
416
+ AND s.name = @schema
417
+ `;
418
+ const definitionResult = await request.query(definitionQuery);
419
+ let definition = void 0;
420
+ if (definitionResult.recordset.length > 0) {
421
+ definition = definitionResult.recordset[0].definition;
422
+ }
423
+ return {
424
+ procedure_name: routine.procedure_name,
425
+ procedure_type: routine.ROUTINE_TYPE === "PROCEDURE" ? "procedure" : "function",
426
+ language: "sql",
427
+ // SQL Server procedures are typically in T-SQL
428
+ parameter_list: parameterList,
429
+ return_type: routine.ROUTINE_TYPE === "FUNCTION" ? routine.return_data_type : void 0,
430
+ definition
431
+ };
432
+ } catch (error) {
433
+ throw new Error(`Failed to get stored procedure details: ${error.message}`);
434
+ }
435
+ }
436
+ async executeSQL(sqlQuery, options, parameters) {
437
+ if (!this.connection) {
438
+ throw new Error("Not connected to SQL Server database");
439
+ }
440
+ try {
441
+ let processedSQL = sqlQuery;
442
+ if (options.maxRows) {
443
+ processedSQL = SQLRowLimiter.applyMaxRowsForSQLServer(sqlQuery, options.maxRows);
444
+ }
445
+ const request = this.connection.request();
446
+ if (parameters && parameters.length > 0) {
447
+ parameters.forEach((param, index) => {
448
+ const paramName = `p${index + 1}`;
449
+ if (typeof param === "string") {
450
+ request.input(paramName, sql.VarChar, param);
451
+ } else if (typeof param === "number") {
452
+ if (Number.isInteger(param)) {
453
+ request.input(paramName, sql.Int, param);
454
+ } else {
455
+ request.input(paramName, sql.Float, param);
456
+ }
457
+ } else if (typeof param === "boolean") {
458
+ request.input(paramName, sql.Bit, param);
459
+ } else if (param === null || param === void 0) {
460
+ request.input(paramName, sql.VarChar, param);
461
+ } else if (Array.isArray(param)) {
462
+ request.input(paramName, sql.VarChar, JSON.stringify(param));
463
+ } else {
464
+ request.input(paramName, sql.VarChar, JSON.stringify(param));
465
+ }
466
+ });
467
+ }
468
+ let result;
469
+ try {
470
+ result = await request.query(processedSQL);
471
+ } catch (error) {
472
+ if (parameters && parameters.length > 0) {
473
+ console.error(`[SQL Server executeSQL] ERROR: ${error.message}`);
474
+ console.error(`[SQL Server executeSQL] SQL: ${processedSQL}`);
475
+ console.error(`[SQL Server executeSQL] Parameters: ${JSON.stringify(parameters)}`);
476
+ }
477
+ throw error;
478
+ }
479
+ return {
480
+ rows: result.recordset || [],
481
+ rowCount: result.rowsAffected[0] || 0
482
+ };
483
+ } catch (error) {
484
+ throw new Error(`Failed to execute query: ${error.message}`);
485
+ }
486
+ }
487
+ };
488
+ var sqlServerConnector = new SQLServerConnector();
489
+ ConnectorRegistry.register(sqlServerConnector);
490
+ export {
491
+ SQLServerConnector,
492
+ SQLServerDSNParser
493
+ };
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@xcr1234/dbhub-fork",
3
+ "version": "1.0.0",
4
+ "mcpName": "io.github.xcr1234/dbhub",
5
+ "description": "Minimal, token-efficient Database MCP Server for PostgreSQL, MySQL, SQL Server, SQLite, MariaDB",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/xcr1234/dbhub.git"
9
+ },
10
+ "main": "dist/index.js",
11
+ "type": "module",
12
+ "bin": {
13
+ "dbhub": "dist/index.js"
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "LICENSE",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "pnpm run generate:api-types && tsup && cd frontend && pnpm run build",
22
+ "build:npm": "npm run generate:api-types && tsup && cd frontend && npm run build",
23
+ "build:backend": "pnpm run generate:api-types && tsup",
24
+ "build:frontend": "cd frontend && pnpm run build",
25
+ "start": "node dist/index.js",
26
+ "dev": "concurrently --kill-others \"pnpm run dev:backend\" \"pnpm run dev:frontend\"",
27
+ "dev:npm": "concurrently --kill-others \"npm run dev:backend\" \"npm run dev:frontend-npm\"",
28
+ "dev:backend": "NODE_ENV=development tsx src/index.ts --transport=http",
29
+ "dev:frontend": "cd frontend && pnpm run dev",
30
+ "dev:frontend-npm": "cd frontend && npm run dev",
31
+ "crossdev": "cross-env NODE_ENV=development tsx src/index.ts",
32
+ "generate:api-types": "openapi-typescript src/api/openapi.yaml -o src/api/openapi.d.ts",
33
+ "test": "vitest run",
34
+ "test:unit": "vitest run --project unit",
35
+ "test:watch": "vitest",
36
+ "test:integration": "vitest run --project integration",
37
+ "test:build": "node scripts/smoke-test-build.mjs"
38
+ },
39
+ "engines": {
40
+ "node": ">=20"
41
+ },
42
+ "keywords": [],
43
+ "author": "",
44
+ "license": "MIT",
45
+ "dependencies": {
46
+ "@iarna/toml": "^2.2.5",
47
+ "@modelcontextprotocol/sdk": "^1.25.1",
48
+ "dotenv": "^16.4.7",
49
+ "express": "^4.18.2",
50
+ "ssh-config": "^5.0.3",
51
+ "ssh2": "^1.16.0",
52
+ "zod": "^3.24.2"
53
+ },
54
+ "optionalDependencies": {
55
+ "@aws-sdk/rds-signer": "^3.1001.0",
56
+ "@azure/identity": "^4.8.0",
57
+ "mariadb": "^3.4.0",
58
+ "mssql": "^11.0.1",
59
+ "mysql2": "^3.13.0",
60
+ "oracledb": "^6.10.0",
61
+ "pg": "^8.13.3",
62
+ "sql.js": "^1.14.1"
63
+ },
64
+ "devDependencies": {
65
+ "@testcontainers/mariadb": "^11.0.3",
66
+ "@testcontainers/mssqlserver": "^11.0.3",
67
+ "@testcontainers/mysql": "^11.0.3",
68
+ "@testcontainers/postgresql": "^11.0.3",
69
+ "@types/express": "^4.17.21",
70
+ "@types/mssql": "^9.1.7",
71
+ "@types/node": "^22.13.10",
72
+ "@types/oracledb": "^6.10.4",
73
+ "@types/pg": "^8.11.11",
74
+ "@types/sqlite3": "^5.1.0",
75
+ "@types/ssh2": "^1.15.5",
76
+ "concurrently": "^9.2.1",
77
+ "cross-env": "^7.0.3",
78
+ "openapi-typescript": "^7.10.1",
79
+ "prettier": "^3.5.3",
80
+ "testcontainers": "^11.0.3",
81
+ "ts-node": "^10.9.2",
82
+ "tsup": "^8.4.0",
83
+ "tsx": "^4.19.3",
84
+ "typescript": "^5.8.2",
85
+ "vitest": "^4.0.6"
86
+ },
87
+ "compilerOptions": {
88
+ "target": "ES2020",
89
+ "module": "NodeNext",
90
+ "moduleResolution": "NodeNext",
91
+ "esModuleInterop": true,
92
+ "strict": true,
93
+ "outDir": "dist",
94
+ "rootDir": "src"
95
+ },
96
+ "include": [
97
+ "src/**/*"
98
+ ]
99
+ }