@bytebase/dbhub 0.21.0 → 0.21.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 +7 -1
- package/dist/{chunk-GRGEI5QT.js → chunk-7D6RKVK2.js} +14 -1
- package/dist/chunk-WVVMH6FJ.js +49 -0
- package/dist/index.js +86 -44
- package/dist/{mariadb-VGTS4WXE.js → mariadb-4IBCPIEV.js} +7 -2
- package/dist/{mysql-I35IQ2GH.js → mysql-M4INQQ46.js} +7 -2
- package/dist/{postgres-B7YSSZMH.js → postgres-4PCNQDGV.js} +1 -1
- package/dist/{registry-XSMMLRC4.js → registry-Y755MTUO.js} +2 -1
- package/dist/{sqlserver-FDBRUELV.js → sqlserver-YV3KVJ3B.js} +14 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -117,4 +117,10 @@ See [Testing](.claude/skills/testing/SKILL.md) and [Debug](https://dbhub.ai/conf
|
|
|
117
117
|
|
|
118
118
|
## Star History
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
<a href="https://www.star-history.com/?repos=bytebase%2Fdbhub&type=date&legend=top-left">
|
|
121
|
+
<picture>
|
|
122
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=bytebase/dbhub&type=date&theme=dark&legend=top-left" />
|
|
123
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=bytebase/dbhub&type=date&legend=top-left" />
|
|
124
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=bytebase/dbhub&type=date&legend=top-left" />
|
|
125
|
+
</picture>
|
|
126
|
+
</a>
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isDriverNotInstalled
|
|
3
|
+
} from "./chunk-WVVMH6FJ.js";
|
|
1
4
|
import {
|
|
2
5
|
ConnectorRegistry,
|
|
3
6
|
SafeURL,
|
|
@@ -1314,8 +1317,18 @@ function buildDSNFromSource(source) {
|
|
|
1314
1317
|
}
|
|
1315
1318
|
|
|
1316
1319
|
// src/utils/aws-rds-signer.ts
|
|
1317
|
-
import { Signer } from "@aws-sdk/rds-signer";
|
|
1318
1320
|
async function generateRdsAuthToken(params) {
|
|
1321
|
+
let Signer;
|
|
1322
|
+
try {
|
|
1323
|
+
({ Signer } = await import("@aws-sdk/rds-signer"));
|
|
1324
|
+
} catch (error) {
|
|
1325
|
+
if (isDriverNotInstalled(error, "@aws-sdk/rds-signer")) {
|
|
1326
|
+
throw new Error(
|
|
1327
|
+
'AWS IAM authentication requires the "@aws-sdk/rds-signer" package. Install it with: pnpm add @aws-sdk/rds-signer'
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
throw error;
|
|
1331
|
+
}
|
|
1319
1332
|
const signer = new Signer({
|
|
1320
1333
|
hostname: params.hostname,
|
|
1321
1334
|
port: params.port,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// src/utils/module-loader.ts
|
|
2
|
+
var MISSING_MODULE_RE = /Cannot find (?:package|module) '([^']+)'/;
|
|
3
|
+
function isDriverNotInstalled(err, driver) {
|
|
4
|
+
if (!(err instanceof Error) || !("code" in err) || err.code !== "ERR_MODULE_NOT_FOUND") {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const match = err.message.match(MISSING_MODULE_RE);
|
|
8
|
+
if (!match) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const missingSpecifier = match[1];
|
|
12
|
+
return missingSpecifier === driver || missingSpecifier.startsWith(`${driver}/`);
|
|
13
|
+
}
|
|
14
|
+
function isModuleNotFound(err) {
|
|
15
|
+
if (!(err instanceof Error) || !("code" in err)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const code = err.code;
|
|
19
|
+
return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND";
|
|
20
|
+
}
|
|
21
|
+
async function loadConnectors(connectorModules) {
|
|
22
|
+
await Promise.all(
|
|
23
|
+
connectorModules.map(async ({ load, name, driver }) => {
|
|
24
|
+
try {
|
|
25
|
+
await load();
|
|
26
|
+
} catch (err) {
|
|
27
|
+
if (isDriverNotInstalled(err, driver)) {
|
|
28
|
+
console.error(
|
|
29
|
+
`Skipping ${name} connector: driver package "${driver}" not installed.`
|
|
30
|
+
);
|
|
31
|
+
} else if (isModuleNotFound(err)) {
|
|
32
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
33
|
+
const match = msg.match(MISSING_MODULE_RE);
|
|
34
|
+
const missing = match ? match[1] : "unknown";
|
|
35
|
+
console.error(
|
|
36
|
+
`Skipping ${name} connector: required dependency "${missing}" not installed.`
|
|
37
|
+
);
|
|
38
|
+
} else {
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
isDriverNotInstalled,
|
|
48
|
+
loadConnectors
|
|
49
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,10 @@ import {
|
|
|
12
12
|
resolveSourceConfigs,
|
|
13
13
|
resolveTomlConfigPath,
|
|
14
14
|
resolveTransport
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-7D6RKVK2.js";
|
|
16
|
+
import {
|
|
17
|
+
loadConnectors
|
|
18
|
+
} from "./chunk-WVVMH6FJ.js";
|
|
16
19
|
import {
|
|
17
20
|
quoteQualifiedIdentifier
|
|
18
21
|
} from "./chunk-JFWX35TB.js";
|
|
@@ -90,20 +93,76 @@ function createToolSuccessResponse(data, meta = {}) {
|
|
|
90
93
|
|
|
91
94
|
// src/utils/allowed-keywords.ts
|
|
92
95
|
var allowedKeywords = {
|
|
93
|
-
postgres: ["select", "with", "explain", "
|
|
94
|
-
mysql: ["select", "with", "explain", "
|
|
95
|
-
mariadb: ["select", "with", "explain", "
|
|
96
|
-
sqlite: ["select", "with", "explain", "
|
|
96
|
+
postgres: ["select", "with", "explain", "show"],
|
|
97
|
+
mysql: ["select", "with", "explain", "show", "describe", "desc"],
|
|
98
|
+
mariadb: ["select", "with", "explain", "show", "describe", "desc"],
|
|
99
|
+
sqlite: ["select", "with", "explain", "pragma"],
|
|
97
100
|
sqlserver: ["select", "with", "explain", "showplan"]
|
|
98
101
|
};
|
|
102
|
+
var mutatingKeywords = [
|
|
103
|
+
"insert",
|
|
104
|
+
"update",
|
|
105
|
+
"delete",
|
|
106
|
+
"drop",
|
|
107
|
+
"alter",
|
|
108
|
+
"create",
|
|
109
|
+
"truncate",
|
|
110
|
+
"merge",
|
|
111
|
+
"grant",
|
|
112
|
+
"revoke",
|
|
113
|
+
"rename"
|
|
114
|
+
];
|
|
115
|
+
var mutatingPattern = new RegExp(
|
|
116
|
+
`\\b(?:${mutatingKeywords.join("|")})\\b`,
|
|
117
|
+
"i"
|
|
118
|
+
);
|
|
119
|
+
var mutatingPatternWithReplace = new RegExp(
|
|
120
|
+
`\\b(?:${mutatingKeywords.join("|")}|replace\\s+(?:(?:low_priority|delayed)\\s+)?into)\\b`,
|
|
121
|
+
"i"
|
|
122
|
+
);
|
|
123
|
+
var mutatingPatterns = {
|
|
124
|
+
postgres: mutatingPattern,
|
|
125
|
+
mysql: mutatingPatternWithReplace,
|
|
126
|
+
mariadb: mutatingPatternWithReplace,
|
|
127
|
+
sqlite: mutatingPatternWithReplace,
|
|
128
|
+
sqlserver: mutatingPattern
|
|
129
|
+
};
|
|
130
|
+
var selectIntoPattern = /\bselect\b[\s\S]+\binto\b/i;
|
|
131
|
+
var explainAnalyzePattern = /^explain\s+(?:\([^)]*\banalyze\b(?!\s*(?:=\s*)?(?:false|off|0)\b)[^)]*\)|\banalyze\b(?!\s*(?:=\s*)?(?:false|off|0)\b)(?:\s+verbose\b)?)/i;
|
|
99
132
|
function isReadOnlySQL(sql, connectorType) {
|
|
100
|
-
|
|
133
|
+
return checkReadOnly(
|
|
134
|
+
stripCommentsAndStrings(sql, connectorType).trim().toLowerCase(),
|
|
135
|
+
connectorType
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
function checkReadOnly(cleanedSQL, connectorType) {
|
|
101
139
|
if (!cleanedSQL) {
|
|
102
140
|
return false;
|
|
103
141
|
}
|
|
104
|
-
const firstWord = cleanedSQL.
|
|
142
|
+
const firstWord = cleanedSQL.match(/\S+/)?.[0] ?? "";
|
|
105
143
|
const keywordList = allowedKeywords[connectorType] || [];
|
|
106
|
-
|
|
144
|
+
if (!keywordList.includes(firstWord)) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (firstWord === "with") {
|
|
148
|
+
const pattern = mutatingPatterns[connectorType] ?? mutatingPattern;
|
|
149
|
+
if (pattern.test(cleanedSQL)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if ((firstWord === "select" || firstWord === "with") && selectIntoPattern.test(cleanedSQL)) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
if (firstWord === "explain") {
|
|
157
|
+
const m = explainAnalyzePattern.exec(cleanedSQL);
|
|
158
|
+
if (m) {
|
|
159
|
+
const afterExplain = cleanedSQL.slice(m[0].length).trim();
|
|
160
|
+
if (afterExplain && !checkReadOnly(afterExplain, connectorType)) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
107
166
|
}
|
|
108
167
|
|
|
109
168
|
// src/requests/store.ts
|
|
@@ -1362,7 +1421,7 @@ See documentation for more details on configuring database connections.
|
|
|
1362
1421
|
const sources = sourceConfigsData.sources;
|
|
1363
1422
|
console.error(`Configuration source: ${sourceConfigsData.source}`);
|
|
1364
1423
|
await connectorManager.connectWithSources(sources);
|
|
1365
|
-
const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-
|
|
1424
|
+
const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-Y755MTUO.js");
|
|
1366
1425
|
initializeToolRegistry2({
|
|
1367
1426
|
sources: sourceConfigsData.sources,
|
|
1368
1427
|
tools: sourceConfigsData.tools
|
|
@@ -1407,6 +1466,20 @@ See documentation for more details on configuring database connections.
|
|
|
1407
1466
|
app.use(express.json());
|
|
1408
1467
|
app.use((req, res, next) => {
|
|
1409
1468
|
const origin = req.headers.origin;
|
|
1469
|
+
if (origin) {
|
|
1470
|
+
const host = (req.headers.host ?? "").split(":")[0].toLowerCase();
|
|
1471
|
+
try {
|
|
1472
|
+
const originHost = new URL(origin).hostname.toLowerCase();
|
|
1473
|
+
if (originHost !== host) {
|
|
1474
|
+
return res.status(403).json({
|
|
1475
|
+
error: "Forbidden",
|
|
1476
|
+
message: "Origin does not match Host header (DNS rebinding protection)"
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
} catch {
|
|
1480
|
+
return res.status(400).json({ error: "Bad Request", message: "Malformed Origin header" });
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1410
1483
|
res.header("Access-Control-Allow-Origin", origin || "http://localhost");
|
|
1411
1484
|
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
1412
1485
|
res.header("Access-Control-Allow-Headers", "Content-Type, Mcp-Session-Id");
|
|
@@ -1488,44 +1561,13 @@ See documentation for more details on configuring database connections.
|
|
|
1488
1561
|
}
|
|
1489
1562
|
}
|
|
1490
1563
|
|
|
1491
|
-
// src/utils/module-loader.ts
|
|
1492
|
-
var MISSING_MODULE_RE = /Cannot find (?:package|module) '([^']+)'/;
|
|
1493
|
-
function isDriverNotInstalled(err, driver) {
|
|
1494
|
-
if (!(err instanceof Error) || !("code" in err) || err.code !== "ERR_MODULE_NOT_FOUND") {
|
|
1495
|
-
return false;
|
|
1496
|
-
}
|
|
1497
|
-
const match = err.message.match(MISSING_MODULE_RE);
|
|
1498
|
-
if (!match) {
|
|
1499
|
-
return false;
|
|
1500
|
-
}
|
|
1501
|
-
const missingSpecifier = match[1];
|
|
1502
|
-
return missingSpecifier === driver || missingSpecifier.startsWith(`${driver}/`);
|
|
1503
|
-
}
|
|
1504
|
-
async function loadConnectors(connectorModules2) {
|
|
1505
|
-
await Promise.all(
|
|
1506
|
-
connectorModules2.map(async ({ load, name, driver }) => {
|
|
1507
|
-
try {
|
|
1508
|
-
await load();
|
|
1509
|
-
} catch (err) {
|
|
1510
|
-
if (isDriverNotInstalled(err, driver)) {
|
|
1511
|
-
console.error(
|
|
1512
|
-
`Skipping ${name} connector: driver package "${driver}" not installed.`
|
|
1513
|
-
);
|
|
1514
|
-
} else {
|
|
1515
|
-
throw err;
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
})
|
|
1519
|
-
);
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
1564
|
// src/index.ts
|
|
1523
1565
|
var connectorModules = [
|
|
1524
|
-
{ load: () => import("./postgres-
|
|
1525
|
-
{ load: () => import("./sqlserver-
|
|
1566
|
+
{ load: () => import("./postgres-4PCNQDGV.js"), name: "PostgreSQL", driver: "pg" },
|
|
1567
|
+
{ load: () => import("./sqlserver-YV3KVJ3B.js"), name: "SQL Server", driver: "mssql" },
|
|
1526
1568
|
{ load: () => import("./sqlite-FSCLCRIH.js"), name: "SQLite", driver: "better-sqlite3" },
|
|
1527
|
-
{ load: () => import("./mysql-
|
|
1528
|
-
{ load: () => import("./mariadb-
|
|
1569
|
+
{ load: () => import("./mysql-M4INQQ46.js"), name: "MySQL", driver: "mysql2" },
|
|
1570
|
+
{ load: () => import("./mariadb-4IBCPIEV.js"), name: "MariaDB", driver: "mariadb" }
|
|
1529
1571
|
];
|
|
1530
1572
|
loadConnectors(connectorModules).then(() => main()).catch((error) => {
|
|
1531
1573
|
console.error("Fatal error:", error);
|
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
extractAffectedRows,
|
|
3
3
|
parseQueryResults
|
|
4
4
|
} from "./chunk-RTB262PR.js";
|
|
5
|
+
import {
|
|
6
|
+
quoteIdentifier
|
|
7
|
+
} from "./chunk-JFWX35TB.js";
|
|
5
8
|
import {
|
|
6
9
|
SQLRowLimiter
|
|
7
10
|
} from "./chunk-BRXZ5ZQB.js";
|
|
@@ -352,10 +355,12 @@ var MariaDBConnector = class _MariaDBConnector {
|
|
|
352
355
|
let definition = procedure.ROUTINE_DEFINITION;
|
|
353
356
|
try {
|
|
354
357
|
const schemaValue = schema || await this.getCurrentSchema();
|
|
358
|
+
const quotedSchema = quoteIdentifier(schemaValue, "mariadb");
|
|
359
|
+
const quotedProcName = quoteIdentifier(procedureName, "mariadb");
|
|
355
360
|
if (procedure.procedure_type === "procedure") {
|
|
356
361
|
try {
|
|
357
362
|
const defRows = await this.pool.query(`
|
|
358
|
-
SHOW CREATE PROCEDURE ${
|
|
363
|
+
SHOW CREATE PROCEDURE ${quotedSchema}.${quotedProcName}
|
|
359
364
|
`);
|
|
360
365
|
if (defRows && defRows.length > 0) {
|
|
361
366
|
definition = defRows[0]["Create Procedure"];
|
|
@@ -366,7 +371,7 @@ var MariaDBConnector = class _MariaDBConnector {
|
|
|
366
371
|
} else {
|
|
367
372
|
try {
|
|
368
373
|
const defRows = await this.pool.query(`
|
|
369
|
-
SHOW CREATE FUNCTION ${
|
|
374
|
+
SHOW CREATE FUNCTION ${quotedSchema}.${quotedProcName}
|
|
370
375
|
`);
|
|
371
376
|
if (defRows && defRows.length > 0) {
|
|
372
377
|
definition = defRows[0]["Create Function"];
|
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
extractAffectedRows,
|
|
3
3
|
parseQueryResults
|
|
4
4
|
} from "./chunk-RTB262PR.js";
|
|
5
|
+
import {
|
|
6
|
+
quoteIdentifier
|
|
7
|
+
} from "./chunk-JFWX35TB.js";
|
|
5
8
|
import {
|
|
6
9
|
SQLRowLimiter
|
|
7
10
|
} from "./chunk-BRXZ5ZQB.js";
|
|
@@ -358,10 +361,12 @@ var MySQLConnector = class _MySQLConnector {
|
|
|
358
361
|
let definition = procedure.ROUTINE_DEFINITION;
|
|
359
362
|
try {
|
|
360
363
|
const schemaValue = schema || await this.getCurrentSchema();
|
|
364
|
+
const quotedSchema = quoteIdentifier(schemaValue, "mysql");
|
|
365
|
+
const quotedProcName = quoteIdentifier(procedureName, "mysql");
|
|
361
366
|
if (procedure.procedure_type === "procedure") {
|
|
362
367
|
try {
|
|
363
368
|
const [defRows] = await this.pool.query(`
|
|
364
|
-
SHOW CREATE PROCEDURE ${
|
|
369
|
+
SHOW CREATE PROCEDURE ${quotedSchema}.${quotedProcName}
|
|
365
370
|
`);
|
|
366
371
|
if (defRows && defRows.length > 0) {
|
|
367
372
|
definition = defRows[0]["Create Procedure"];
|
|
@@ -372,7 +377,7 @@ var MySQLConnector = class _MySQLConnector {
|
|
|
372
377
|
} else {
|
|
373
378
|
try {
|
|
374
379
|
const [defRows] = await this.pool.query(`
|
|
375
|
-
SHOW CREATE FUNCTION ${
|
|
380
|
+
SHOW CREATE FUNCTION ${quotedSchema}.${quotedProcName}
|
|
376
381
|
`);
|
|
377
382
|
if (defRows && defRows.length > 0) {
|
|
378
383
|
definition = defRows[0]["Create Function"];
|
|
@@ -303,7 +303,7 @@ var PostgresConnector = class _PostgresConnector {
|
|
|
303
303
|
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
304
304
|
WHERE c.relname = $1
|
|
305
305
|
AND n.nspname = $2
|
|
306
|
-
AND c.relkind IN ('r','p','m','f')
|
|
306
|
+
AND c.relkind IN ('r','p','m','f','v')
|
|
307
307
|
`,
|
|
308
308
|
[tableName, schemaToUse]
|
|
309
309
|
);
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isDriverNotInstalled
|
|
3
|
+
} from "./chunk-WVVMH6FJ.js";
|
|
1
4
|
import {
|
|
2
5
|
SQLRowLimiter
|
|
3
6
|
} from "./chunk-BRXZ5ZQB.js";
|
|
@@ -9,7 +12,6 @@ import {
|
|
|
9
12
|
|
|
10
13
|
// src/connectors/sqlserver/index.ts
|
|
11
14
|
import sql from "mssql";
|
|
12
|
-
import { DefaultAzureCredential } from "@azure/identity";
|
|
13
15
|
var SQLServerDSNParser = class {
|
|
14
16
|
async parse(dsn, config) {
|
|
15
17
|
const connectionTimeoutSeconds = config?.connectionTimeoutSeconds;
|
|
@@ -74,6 +76,17 @@ Expected: ${expectedFormat}`
|
|
|
74
76
|
};
|
|
75
77
|
switch (options.authentication) {
|
|
76
78
|
case "azure-active-directory-access-token": {
|
|
79
|
+
let DefaultAzureCredential;
|
|
80
|
+
try {
|
|
81
|
+
({ DefaultAzureCredential } = await import("@azure/identity"));
|
|
82
|
+
} catch (importError) {
|
|
83
|
+
if (isDriverNotInstalled(importError, "@azure/identity")) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
'Azure AD authentication requires the "@azure/identity" package. Install it with: pnpm add @azure/identity'
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
throw importError;
|
|
89
|
+
}
|
|
77
90
|
try {
|
|
78
91
|
const credential = new DefaultAzureCredential();
|
|
79
92
|
const token = await credential.getToken("https://database.windows.net/");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytebase/dbhub",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.2",
|
|
4
4
|
"mcpName": "io.github.bytebase/dbhub",
|
|
5
5
|
"description": "Minimal, token-efficient Database MCP Server for PostgreSQL, MySQL, SQL Server, SQLite, MariaDB",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"test": "vitest run",
|
|
31
31
|
"test:unit": "vitest run --project unit",
|
|
32
32
|
"test:watch": "vitest",
|
|
33
|
-
"test:integration": "vitest run --project integration"
|
|
33
|
+
"test:integration": "vitest run --project integration",
|
|
34
|
+
"test:build": "node scripts/smoke-test-build.mjs"
|
|
34
35
|
},
|
|
35
36
|
"engines": {
|
|
36
37
|
"node": ">=20"
|
|
@@ -39,8 +40,6 @@
|
|
|
39
40
|
"author": "",
|
|
40
41
|
"license": "MIT",
|
|
41
42
|
"dependencies": {
|
|
42
|
-
"@aws-sdk/rds-signer": "^3.1001.0",
|
|
43
|
-
"@azure/identity": "^4.8.0",
|
|
44
43
|
"@iarna/toml": "^2.2.5",
|
|
45
44
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
46
45
|
"dotenv": "^16.4.7",
|
|
@@ -50,6 +49,8 @@
|
|
|
50
49
|
"zod": "^3.24.2"
|
|
51
50
|
},
|
|
52
51
|
"optionalDependencies": {
|
|
52
|
+
"@aws-sdk/rds-signer": "^3.1001.0",
|
|
53
|
+
"@azure/identity": "^4.8.0",
|
|
53
54
|
"better-sqlite3": "^11.9.0",
|
|
54
55
|
"mariadb": "^3.4.0",
|
|
55
56
|
"mssql": "^11.0.1",
|