@kingsnow129/database-mcp 0.4.0 → 0.4.1
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 +13 -5
- package/dist/server.js +41 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,11 +13,17 @@ It provides tools for:
|
|
|
13
13
|
## Release
|
|
14
14
|
|
|
15
15
|
Current release:
|
|
16
|
-
- NPM package: `@kingsnow129/database-mcp@0.4.
|
|
16
|
+
- NPM package: `@kingsnow129/database-mcp@0.4.1`
|
|
17
17
|
- MCP server name: `database-mcp`
|
|
18
|
-
- VSIX helper: `database-mcp-helper@0.4.
|
|
18
|
+
- VSIX helper: `database-mcp-helper@0.4.1`
|
|
19
19
|
|
|
20
|
-
## What Is New In 0.4.
|
|
20
|
+
## What Is New In 0.4.1
|
|
21
|
+
|
|
22
|
+
- Enforced hard read-only mode for all connections (no override).
|
|
23
|
+
- Added stronger query safety blocks for execution patterns.
|
|
24
|
+
- Allowed spaces in server profile names in VSIX manager (e.g. `QA EUD`).
|
|
25
|
+
|
|
26
|
+
## What Was Introduced In 0.4.0
|
|
21
27
|
|
|
22
28
|
- Multi-database profile model (`servers` + `databases`) is now the primary config.
|
|
23
29
|
- Automatic profile resolution during `connect`:
|
|
@@ -111,14 +117,16 @@ Build and install locally:
|
|
|
111
117
|
cd vscode-extension
|
|
112
118
|
npm install
|
|
113
119
|
npm run package
|
|
114
|
-
code --install-extension database-mcp-helper-0.4.
|
|
120
|
+
code --install-extension database-mcp-helper-0.4.1.vsix --force
|
|
115
121
|
```
|
|
116
122
|
|
|
117
123
|
## Safety Defaults
|
|
118
124
|
|
|
119
|
-
- Read-only mode
|
|
125
|
+
- Read-only mode is hard-enforced (`connect.readOnly` overrides are ignored)
|
|
120
126
|
- Query tool only accepts one SELECT statement
|
|
121
127
|
- Semicolons are blocked
|
|
128
|
+
- Stored procedure execution (`exec`, `execute`, `sp_*`, `xp_*`) is blocked
|
|
129
|
+
- Function-call style execution patterns like `schema.fn(...)` are blocked
|
|
122
130
|
- Returned rows are capped (default `200`)
|
|
123
131
|
|
|
124
132
|
## Development
|
package/dist/server.js
CHANGED
|
@@ -20,6 +20,7 @@ const {Pool: PostgresPool}=pg;
|
|
|
20
20
|
const SUPPORTED_ENGINES=new Set(["sqlserver","postgres","mysql"]);
|
|
21
21
|
|
|
22
22
|
const CLI_OPTION_MAP={
|
|
23
|
+
target: "target",
|
|
23
24
|
alias: "alias",
|
|
24
25
|
serverName: "serverName",
|
|
25
26
|
defaultAlias: "defaultAlias",
|
|
@@ -68,7 +69,7 @@ function parseCliArgs(argv) {
|
|
|
68
69
|
|
|
69
70
|
const rawToken=String(token).slice(2);
|
|
70
71
|
if(rawToken==="help") {
|
|
71
|
-
console.error("Supported flags: --alias --serverName --defaultAlias --profilesFile --currentServer --currentDatabase --engine --host --connectionString --server --port --database --user --password --encrypt --ssl --trustServerCertificate --readOnly --maxRows");
|
|
72
|
+
console.error("Supported flags: --target --alias --serverName --defaultAlias --profilesFile --currentServer --currentDatabase --engine --host --connectionString --server --port --database --user --password --encrypt --ssl --trustServerCertificate --readOnly --maxRows");
|
|
72
73
|
process.exit(0);
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -194,6 +195,16 @@ function resolveSavedProfile(overrides={}) {
|
|
|
194
195
|
const profiles=loadProfiles();
|
|
195
196
|
const {servers,aliases}=profiles;
|
|
196
197
|
|
|
198
|
+
const requestedTarget=firstDefined(overrides.target,cliOptions.target);
|
|
199
|
+
const matchServerByHost=(hostOrServer) => {
|
|
200
|
+
const wanted=normalizeHostForCompare(hostOrServer);
|
|
201
|
+
return Object.entries(servers).find(([,cfg]) => {
|
|
202
|
+
const hostA=normalizeHostForCompare(cfg?.host);
|
|
203
|
+
const hostB=normalizeHostForCompare(cfg?.server);
|
|
204
|
+
return wanted===hostA||wanted===hostB;
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
|
|
197
208
|
const requestedAlias=firstDefined(overrides.alias,cliOptions.alias,process.env.DB_ALIAS);
|
|
198
209
|
const requestedServerName=firstDefined(
|
|
199
210
|
overrides.serverName,
|
|
@@ -209,6 +220,26 @@ function resolveSavedProfile(overrides={}) {
|
|
|
209
220
|
let serverName;
|
|
210
221
|
let serverProfile;
|
|
211
222
|
|
|
223
|
+
if(requestedTarget) {
|
|
224
|
+
const targetKey=String(requestedTarget).trim();
|
|
225
|
+
if(aliases[targetKey]&&typeof aliases[targetKey]==="object") {
|
|
226
|
+
source="target:alias";
|
|
227
|
+
aliasName=targetKey;
|
|
228
|
+
serverProfile=aliases[targetKey];
|
|
229
|
+
} else if(servers[targetKey]&&typeof servers[targetKey]==="object") {
|
|
230
|
+
source="target:serverName";
|
|
231
|
+
serverName=targetKey;
|
|
232
|
+
serverProfile=servers[targetKey];
|
|
233
|
+
} else {
|
|
234
|
+
const foundByTargetHost=matchServerByHost(targetKey);
|
|
235
|
+
if(foundByTargetHost) {
|
|
236
|
+
source="target:host";
|
|
237
|
+
serverName=foundByTargetHost[0];
|
|
238
|
+
serverProfile=foundByTargetHost[1];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
212
243
|
if(requestedAlias) {
|
|
213
244
|
const aliasKey=String(requestedAlias).trim();
|
|
214
245
|
if(aliases[aliasKey]&&typeof aliases[aliasKey]==="object") {
|
|
@@ -232,12 +263,7 @@ function resolveSavedProfile(overrides={}) {
|
|
|
232
263
|
}
|
|
233
264
|
|
|
234
265
|
if(!serverProfile&&requestedHost) {
|
|
235
|
-
const
|
|
236
|
-
const found=Object.entries(servers).find(([,cfg]) => {
|
|
237
|
-
const hostA=normalizeHostForCompare(cfg?.host);
|
|
238
|
-
const hostB=normalizeHostForCompare(cfg?.server);
|
|
239
|
-
return wanted===hostA||wanted===hostB;
|
|
240
|
-
});
|
|
266
|
+
const found=matchServerByHost(requestedHost);
|
|
241
267
|
if(found) {
|
|
242
268
|
source="host";
|
|
243
269
|
serverName=found[0];
|
|
@@ -402,7 +428,8 @@ function buildConfig(overrides={}) {
|
|
|
402
428
|
user: integratedAuth? "":user,
|
|
403
429
|
password: integratedAuth? "":password,
|
|
404
430
|
connectionString,
|
|
405
|
-
|
|
431
|
+
// Enforce hard read-only mode regardless of caller overrides.
|
|
432
|
+
readOnly: true,
|
|
406
433
|
maxRows: intFromEnv(firstDefined(overrides.maxRows,dbConfig?.maxRows,serverProfile?.maxRows),getMaxRowsDefault()),
|
|
407
434
|
trustServerCertificate: boolFromEnv(
|
|
408
435
|
firstDefined(
|
|
@@ -739,6 +766,9 @@ function validateQuerySafety(sqlText) {
|
|
|
739
766
|
|
|
740
767
|
const blockedPatterns=[
|
|
741
768
|
/\b(insert|update|delete|drop|alter|create|truncate|merge|exec|execute|grant|revoke)\b/i,
|
|
769
|
+
/\b(call|declare)\b/i,
|
|
770
|
+
/\b(?:sp_|xp_)[A-Za-z0-9_]*\b/i,
|
|
771
|
+
/\b[A-Za-z0-9_]+\.[A-Za-z0-9_]+\s*\(/i,
|
|
742
772
|
/--/,
|
|
743
773
|
/\/\*/
|
|
744
774
|
];
|
|
@@ -756,7 +786,9 @@ async function handleToolCall(name,args={}) {
|
|
|
756
786
|
switch(name) {
|
|
757
787
|
case TOOL_NAMES.CONNECT: {
|
|
758
788
|
const overrides={
|
|
789
|
+
...(args.target? {target: args.target}:{}),
|
|
759
790
|
...(args.alias? {alias: args.alias}:{}),
|
|
791
|
+
...(args.serverName? {serverName: args.serverName}:{}),
|
|
760
792
|
...(args.engine? {engine: args.engine}:{}),
|
|
761
793
|
...(args.connectionString? {connectionString: args.connectionString}:{}),
|
|
762
794
|
...(args.host? {host: args.host}:{}),
|
|
@@ -765,7 +797,6 @@ async function handleToolCall(name,args={}) {
|
|
|
765
797
|
...(args.database? {database: args.database}:{}),
|
|
766
798
|
...(args.user? {user: args.user}:{}),
|
|
767
799
|
...(args.password? {password: args.password}:{}),
|
|
768
|
-
...(args.readOnly!==undefined? {readOnly: Boolean(args.readOnly)}:{}),
|
|
769
800
|
...(args.maxRows!==undefined? {maxRows: Number(args.maxRows)}:{}),
|
|
770
801
|
...(args.encrypt!==undefined? {encrypt: Boolean(args.encrypt)}:{}),
|
|
771
802
|
...(args.ssl!==undefined? {ssl: Boolean(args.ssl)}:{}),
|
|
@@ -969,6 +1000,7 @@ server.setRequestHandler(ListToolsRequestSchema,async () => {
|
|
|
969
1000
|
inputSchema: {
|
|
970
1001
|
type: "object",
|
|
971
1002
|
properties: {
|
|
1003
|
+
target: {type: "string"},
|
|
972
1004
|
alias: {type: "string"},
|
|
973
1005
|
serverName: {type: "string"},
|
|
974
1006
|
engine: {type: "string",enum: ["sqlserver","postgres","mysql"]},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kingsnow129/database-mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"mcpName": "io.github.kingsnow129/database-mcp",
|
|
5
5
|
"description": "Database MCP server for SQL Server, PostgreSQL, and MySQL with profile-based auto resolution",
|
|
6
6
|
"author": "kingsnow129",
|