taurusdb-mcp 0.1.0 → 0.2.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/README.md +39 -2
- package/dist/tools/common/public-formatters.d.ts +0 -1
- package/dist/tools/common/public-formatters.js +0 -1
- package/dist/tools/error-handling.js +5 -1
- package/dist/tools/query.js +0 -1
- package/dist/tools/registry.d.ts +1 -0
- package/dist/tools/registry.js +14 -14
- package/dist/tools/taurus/cloud-context.d.ts +4 -0
- package/dist/tools/taurus/cloud-context.js +233 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
TaurusDB MCP server for MCP clients such as:
|
|
4
4
|
|
|
5
|
-
- Claude
|
|
5
|
+
- Claude Code
|
|
6
|
+
- Codex
|
|
6
7
|
- Cursor
|
|
7
8
|
- VS Code
|
|
8
9
|
|
|
@@ -15,7 +16,43 @@ npm install taurusdb-mcp
|
|
|
15
16
|
Run directly with:
|
|
16
17
|
|
|
17
18
|
```bash
|
|
18
|
-
npx taurusdb-mcp --version
|
|
19
|
+
npx -y taurusdb-mcp --version
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Use this command in MCP client configs:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["-y", "taurusdb-mcp"]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Claude Code:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
claude mcp add huaweicloud-taurusdb \
|
|
35
|
+
--transport stdio \
|
|
36
|
+
-e TAURUSDB_CLOUD_REGION=<your-region> \
|
|
37
|
+
-e TAURUSDB_CLOUD_ACCESS_KEY_ID=<your-ak> \
|
|
38
|
+
-e TAURUSDB_CLOUD_SECRET_ACCESS_KEY=<your-sk> \
|
|
39
|
+
-e TAURUSDB_SQL_DATABASE=<your-database> \
|
|
40
|
+
-e TAURUSDB_SQL_USER=<your-readonly-user> \
|
|
41
|
+
-e TAURUSDB_SQL_PASSWORD=<your-readonly-password> \
|
|
42
|
+
-- npx -y taurusdb-mcp
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Codex:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
codex mcp add huaweicloud-taurusdb \
|
|
49
|
+
--env TAURUSDB_CLOUD_REGION=<your-region> \
|
|
50
|
+
--env TAURUSDB_CLOUD_ACCESS_KEY_ID=<your-ak> \
|
|
51
|
+
--env TAURUSDB_CLOUD_SECRET_ACCESS_KEY=<your-sk> \
|
|
52
|
+
--env TAURUSDB_SQL_DATABASE=<your-database> \
|
|
53
|
+
--env TAURUSDB_SQL_USER=<your-readonly-user> \
|
|
54
|
+
--env TAURUSDB_SQL_PASSWORD=<your-readonly-password> \
|
|
55
|
+
-- npx -y taurusdb-mcp
|
|
19
56
|
```
|
|
20
57
|
|
|
21
58
|
Initialize local MCP client config:
|
|
@@ -75,15 +75,19 @@ export function formatToolError(error, context) {
|
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
if (error instanceof UnsupportedFeatureError) {
|
|
78
|
+
const parameterHint = error.parameterHint
|
|
79
|
+
? ` Enable or verify ${error.parameterHint} on the target instance if this feature should be available.`
|
|
80
|
+
: "";
|
|
78
81
|
return formatError({
|
|
79
82
|
code: ErrorCode.UNSUPPORTED_FEATURE,
|
|
80
|
-
message: error.message
|
|
83
|
+
message: `${error.message}${parameterHint}`,
|
|
81
84
|
summary: "The requested TaurusDB feature is not available on this instance.",
|
|
82
85
|
metadata: context.metadata,
|
|
83
86
|
details: {
|
|
84
87
|
feature: error.feature,
|
|
85
88
|
required_version: error.requiredVersion,
|
|
86
89
|
current_version: error.currentVersion,
|
|
90
|
+
parameter_hint: error.parameterHint,
|
|
87
91
|
},
|
|
88
92
|
});
|
|
89
93
|
}
|
package/dist/tools/query.js
CHANGED
|
@@ -163,7 +163,6 @@ export const executeSqlTool = {
|
|
|
163
163
|
sql: requiredSqlSchema("Mutation SQL to execute."),
|
|
164
164
|
confirmation_token: optionalTokenSchema(),
|
|
165
165
|
},
|
|
166
|
-
exposeWhen: (config) => config.enableMutations,
|
|
167
166
|
async handler(input, deps, context) {
|
|
168
167
|
const sql = asRequiredString(input.sql, "sql");
|
|
169
168
|
const statementType = statementTypeFromSql(sql);
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -19,4 +19,5 @@ export interface ToolDefinition<I extends Record<string, unknown> = Record<strin
|
|
|
19
19
|
}
|
|
20
20
|
export declare const commonToolDefinitions: ToolDefinition[];
|
|
21
21
|
export declare const capabilityToolDefinitions: ToolDefinition[];
|
|
22
|
+
export declare const taurusToolDefinitions: ToolDefinition[];
|
|
22
23
|
export declare function registerTools(server: McpServer, deps: ToolDeps, config: Config, probeOrTools?: ToolRegistrationProbe | ToolDefinition[], maybeTools?: ToolDefinition[]): void;
|
package/dist/tools/registry.js
CHANGED
|
@@ -4,7 +4,7 @@ import { describeTableTool, listDatabasesTool, listTablesTool, } from "./discove
|
|
|
4
4
|
import { showProcesslistTool } from "./processlist.js";
|
|
5
5
|
import { pingTool } from "./ping.js";
|
|
6
6
|
import { getKernelInfoTool, listTaurusFeaturesTool } from "./taurus/capability.js";
|
|
7
|
-
import { selectCloudTaurusInstanceTool, setCloudAccessKeysTool, setCloudRegionTool, } from "./taurus/cloud-context.js";
|
|
7
|
+
import { clearSqlCredentialsTool, getSessionBindingTool, selectCloudTaurusInstanceTool, setCloudAccessKeysTool, setCloudRegionTool, setDefaultDatabaseTool, setSqlCredentialsTool, } from "./taurus/cloud-context.js";
|
|
8
8
|
import { listCloudTaurusInstancesTool } from "./taurus/cloud-instances.js";
|
|
9
9
|
import { diagnosticToolDefinitions } from "./taurus/diagnostics.js";
|
|
10
10
|
import { explainSqlEnhancedTool } from "./taurus/explain.js";
|
|
@@ -68,27 +68,27 @@ export const capabilityToolDefinitions = [
|
|
|
68
68
|
listTaurusFeaturesTool,
|
|
69
69
|
setCloudRegionTool,
|
|
70
70
|
setCloudAccessKeysTool,
|
|
71
|
+
getSessionBindingTool,
|
|
72
|
+
setSqlCredentialsTool,
|
|
73
|
+
clearSqlCredentialsTool,
|
|
74
|
+
setDefaultDatabaseTool,
|
|
71
75
|
listCloudTaurusInstancesTool,
|
|
72
76
|
selectCloudTaurusInstanceTool,
|
|
73
77
|
];
|
|
78
|
+
export const taurusToolDefinitions = [
|
|
79
|
+
explainSqlEnhancedTool,
|
|
80
|
+
flashbackQueryTool,
|
|
81
|
+
listRecycleBinTool,
|
|
82
|
+
restoreRecycleBinTableTool,
|
|
83
|
+
];
|
|
74
84
|
function buildDefaultToolDefinitions(_config, probe) {
|
|
75
|
-
|
|
85
|
+
void probe;
|
|
86
|
+
return [
|
|
76
87
|
...commonToolDefinitions,
|
|
77
88
|
...capabilityToolDefinitions,
|
|
78
89
|
...diagnosticToolDefinitions,
|
|
90
|
+
...taurusToolDefinitions,
|
|
79
91
|
];
|
|
80
|
-
if (probe?.features) {
|
|
81
|
-
if (probe.features.ndp_pushdown.available || probe.features.parallel_query.available) {
|
|
82
|
-
tools.push(explainSqlEnhancedTool);
|
|
83
|
-
}
|
|
84
|
-
if (probe.features.flashback_query.available) {
|
|
85
|
-
tools.push(flashbackQueryTool);
|
|
86
|
-
}
|
|
87
|
-
if (probe.features.recycle_bin.available) {
|
|
88
|
-
tools.push(listRecycleBinTool, restoreRecycleBinTableTool);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return tools;
|
|
92
92
|
}
|
|
93
93
|
function isToolDefinitionArray(value) {
|
|
94
94
|
return Array.isArray(value);
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { ToolDefinition } from "../registry.js";
|
|
2
2
|
export declare const setCloudRegionTool: ToolDefinition;
|
|
3
3
|
export declare const setCloudAccessKeysTool: ToolDefinition;
|
|
4
|
+
export declare const setDefaultDatabaseTool: ToolDefinition;
|
|
5
|
+
export declare const setSqlCredentialsTool: ToolDefinition;
|
|
6
|
+
export declare const clearSqlCredentialsTool: ToolDefinition;
|
|
7
|
+
export declare const getSessionBindingTool: ToolDefinition;
|
|
4
8
|
export declare const selectCloudTaurusInstanceTool: ToolDefinition;
|
|
@@ -50,6 +50,15 @@ function normalizePort(port) {
|
|
|
50
50
|
}
|
|
51
51
|
return undefined;
|
|
52
52
|
}
|
|
53
|
+
function maskUsername(username) {
|
|
54
|
+
if (!username) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
if (username.length <= 2) {
|
|
58
|
+
return `${username[0]}*`;
|
|
59
|
+
}
|
|
60
|
+
return `${username.slice(0, 1)}***${username.slice(-1)}`;
|
|
61
|
+
}
|
|
53
62
|
export const setCloudRegionTool = {
|
|
54
63
|
name: "set_cloud_region",
|
|
55
64
|
description: "Update the active Huawei Cloud region for the current MCP session and reset any stale cloud project or instance selections.",
|
|
@@ -129,6 +138,230 @@ export const setCloudAccessKeysTool = {
|
|
|
129
138
|
}
|
|
130
139
|
},
|
|
131
140
|
};
|
|
141
|
+
export const setDefaultDatabaseTool = {
|
|
142
|
+
name: "set_default_database",
|
|
143
|
+
description: "Set the default database for a datasource in the current MCP session so later tool calls can omit input.database.",
|
|
144
|
+
inputSchema: {
|
|
145
|
+
database: z
|
|
146
|
+
.string()
|
|
147
|
+
.trim()
|
|
148
|
+
.min(1)
|
|
149
|
+
.describe("Database name to bind as the session default for the selected datasource."),
|
|
150
|
+
datasource: z
|
|
151
|
+
.string()
|
|
152
|
+
.trim()
|
|
153
|
+
.min(1)
|
|
154
|
+
.optional()
|
|
155
|
+
.describe("Optional datasource template to bind. Defaults to the current default datasource."),
|
|
156
|
+
},
|
|
157
|
+
async handler(input, deps, context) {
|
|
158
|
+
try {
|
|
159
|
+
const database = typeof input.database === "string" ? input.database.trim() : "";
|
|
160
|
+
if (!database) {
|
|
161
|
+
throw new ToolInputError("database is required.");
|
|
162
|
+
}
|
|
163
|
+
const datasource = await resolveBindingDatasource(deps, typeof input.datasource === "string" ? input.datasource : undefined);
|
|
164
|
+
if (!datasource) {
|
|
165
|
+
throw new ToolInputError("No datasource selected. Configure a default datasource or pass datasource explicitly.");
|
|
166
|
+
}
|
|
167
|
+
const ctx = await deps.engine.resolveContext({
|
|
168
|
+
datasource,
|
|
169
|
+
readonly: true,
|
|
170
|
+
}, context.taskId);
|
|
171
|
+
const databases = await deps.engine.listDatabases(ctx);
|
|
172
|
+
if (!databases.some((item) => item.name === database)) {
|
|
173
|
+
throw new ToolInputError(`Database "${database}" was not found on datasource "${datasource}". Run list_databases first and choose one of the returned names.`);
|
|
174
|
+
}
|
|
175
|
+
const profile = await deps.profileLoader.get(datasource);
|
|
176
|
+
if (!profile) {
|
|
177
|
+
throw new ToolInputError(`Datasource "${datasource}" was not found.`);
|
|
178
|
+
}
|
|
179
|
+
const currentTarget = deps.profileLoader.getRuntimeTarget(datasource);
|
|
180
|
+
deps.profileLoader.setRuntimeTarget(datasource, {
|
|
181
|
+
host: currentTarget?.host ?? profile.host,
|
|
182
|
+
port: currentTarget?.port ?? profile.port,
|
|
183
|
+
instanceId: currentTarget?.instanceId,
|
|
184
|
+
nodeId: currentTarget?.nodeId,
|
|
185
|
+
database,
|
|
186
|
+
});
|
|
187
|
+
await reloadEngine(deps);
|
|
188
|
+
return formatSuccess({
|
|
189
|
+
datasource,
|
|
190
|
+
database,
|
|
191
|
+
}, {
|
|
192
|
+
summary: `Default database for ${datasource} set to ${database} in the current session.`,
|
|
193
|
+
metadata: metadata(context.taskId),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return formatToolError(error, {
|
|
198
|
+
action: "set_default_database",
|
|
199
|
+
metadata: metadata(context.taskId),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
export const setSqlCredentialsTool = {
|
|
205
|
+
name: "set_sql_credentials",
|
|
206
|
+
description: "Set the SQL username and password for a datasource in the current MCP session without writing credentials to disk.",
|
|
207
|
+
inputSchema: {
|
|
208
|
+
username: z
|
|
209
|
+
.string()
|
|
210
|
+
.trim()
|
|
211
|
+
.min(1)
|
|
212
|
+
.describe("Database username to use for the selected datasource in this session."),
|
|
213
|
+
password: z
|
|
214
|
+
.string()
|
|
215
|
+
.trim()
|
|
216
|
+
.min(1)
|
|
217
|
+
.describe("Database password to use for the selected datasource in this session."),
|
|
218
|
+
datasource: z
|
|
219
|
+
.string()
|
|
220
|
+
.trim()
|
|
221
|
+
.min(1)
|
|
222
|
+
.optional()
|
|
223
|
+
.describe("Optional datasource template to bind. Defaults to the current default datasource."),
|
|
224
|
+
},
|
|
225
|
+
async handler(input, deps, context) {
|
|
226
|
+
try {
|
|
227
|
+
const username = typeof input.username === "string" ? input.username.trim() : "";
|
|
228
|
+
const password = typeof input.password === "string" ? input.password.trim() : "";
|
|
229
|
+
if (!username || !password) {
|
|
230
|
+
throw new ToolInputError("username and password are required.");
|
|
231
|
+
}
|
|
232
|
+
const datasource = await resolveBindingDatasource(deps, typeof input.datasource === "string" ? input.datasource : undefined);
|
|
233
|
+
if (!datasource) {
|
|
234
|
+
throw new ToolInputError("No datasource selected. Configure a default datasource or pass datasource explicitly.");
|
|
235
|
+
}
|
|
236
|
+
const profile = await deps.profileLoader.get(datasource);
|
|
237
|
+
if (!profile) {
|
|
238
|
+
throw new ToolInputError(`Datasource "${datasource}" was not found.`);
|
|
239
|
+
}
|
|
240
|
+
const currentTarget = deps.profileLoader.getRuntimeTarget(datasource);
|
|
241
|
+
deps.profileLoader.setRuntimeTarget(datasource, {
|
|
242
|
+
host: currentTarget?.host ?? profile.host,
|
|
243
|
+
port: currentTarget?.port ?? profile.port,
|
|
244
|
+
database: currentTarget?.database ?? profile.database,
|
|
245
|
+
instanceId: currentTarget?.instanceId,
|
|
246
|
+
nodeId: currentTarget?.nodeId,
|
|
247
|
+
user: {
|
|
248
|
+
username,
|
|
249
|
+
password: { type: "plain", value: password },
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
await reloadEngine(deps);
|
|
253
|
+
return formatSuccess({
|
|
254
|
+
datasource,
|
|
255
|
+
username,
|
|
256
|
+
}, {
|
|
257
|
+
summary: `SQL credentials for ${datasource} updated in the current session.`,
|
|
258
|
+
metadata: metadata(context.taskId),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
return formatToolError(error, {
|
|
263
|
+
action: "set_sql_credentials",
|
|
264
|
+
metadata: metadata(context.taskId),
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
export const clearSqlCredentialsTool = {
|
|
270
|
+
name: "clear_sql_credentials",
|
|
271
|
+
description: "Clear any session-scoped SQL credential override for a datasource and fall back to the configured profile credentials.",
|
|
272
|
+
inputSchema: {
|
|
273
|
+
datasource: z
|
|
274
|
+
.string()
|
|
275
|
+
.trim()
|
|
276
|
+
.min(1)
|
|
277
|
+
.optional()
|
|
278
|
+
.describe("Optional datasource template to clear. Defaults to the current default datasource."),
|
|
279
|
+
},
|
|
280
|
+
async handler(input, deps, context) {
|
|
281
|
+
try {
|
|
282
|
+
const datasource = await resolveBindingDatasource(deps, typeof input.datasource === "string" ? input.datasource : undefined);
|
|
283
|
+
if (!datasource) {
|
|
284
|
+
throw new ToolInputError("No datasource selected. Configure a default datasource or pass datasource explicitly.");
|
|
285
|
+
}
|
|
286
|
+
const profile = await deps.profileLoader.get(datasource);
|
|
287
|
+
if (!profile) {
|
|
288
|
+
throw new ToolInputError(`Datasource "${datasource}" was not found.`);
|
|
289
|
+
}
|
|
290
|
+
const currentTarget = deps.profileLoader.getRuntimeTarget(datasource);
|
|
291
|
+
deps.profileLoader.setRuntimeTarget(datasource, {
|
|
292
|
+
host: currentTarget?.host ?? profile.host,
|
|
293
|
+
port: currentTarget?.port ?? profile.port,
|
|
294
|
+
database: currentTarget?.database ?? profile.database,
|
|
295
|
+
instanceId: currentTarget?.instanceId,
|
|
296
|
+
nodeId: currentTarget?.nodeId,
|
|
297
|
+
user: profile.user,
|
|
298
|
+
});
|
|
299
|
+
await reloadEngine(deps);
|
|
300
|
+
return formatSuccess({
|
|
301
|
+
datasource,
|
|
302
|
+
}, {
|
|
303
|
+
summary: `Session SQL credential override cleared for ${datasource}.`,
|
|
304
|
+
metadata: metadata(context.taskId),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
return formatToolError(error, {
|
|
309
|
+
action: "clear_sql_credentials",
|
|
310
|
+
metadata: metadata(context.taskId),
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
export const getSessionBindingTool = {
|
|
316
|
+
name: "get_session_binding",
|
|
317
|
+
description: "Return the current session binding for a datasource, including selected instance, host, database, and whether SQL credentials are overridden in memory.",
|
|
318
|
+
inputSchema: {
|
|
319
|
+
datasource: z
|
|
320
|
+
.string()
|
|
321
|
+
.trim()
|
|
322
|
+
.min(1)
|
|
323
|
+
.optional()
|
|
324
|
+
.describe("Optional datasource template to inspect. Defaults to the current default datasource."),
|
|
325
|
+
},
|
|
326
|
+
async handler(input, deps, context) {
|
|
327
|
+
try {
|
|
328
|
+
const datasource = await resolveBindingDatasource(deps, typeof input.datasource === "string" ? input.datasource : undefined);
|
|
329
|
+
if (!datasource) {
|
|
330
|
+
throw new ToolInputError("No datasource selected. Configure a default datasource or pass datasource explicitly.");
|
|
331
|
+
}
|
|
332
|
+
const profile = await deps.profileLoader.get(datasource);
|
|
333
|
+
if (!profile) {
|
|
334
|
+
throw new ToolInputError(`Datasource "${datasource}" was not found.`);
|
|
335
|
+
}
|
|
336
|
+
const target = deps.profileLoader.getRuntimeTarget(datasource);
|
|
337
|
+
return formatSuccess({
|
|
338
|
+
datasource,
|
|
339
|
+
host: profile.host,
|
|
340
|
+
port: profile.port,
|
|
341
|
+
database: profile.database,
|
|
342
|
+
username_masked: maskUsername(profile.user.username),
|
|
343
|
+
runtime_override: {
|
|
344
|
+
instance_id: target?.instanceId,
|
|
345
|
+
node_id: target?.nodeId,
|
|
346
|
+
host: target?.host,
|
|
347
|
+
port: target?.port,
|
|
348
|
+
database: target?.database,
|
|
349
|
+
has_sql_credentials_override: Boolean(target?.user),
|
|
350
|
+
username_masked: maskUsername(target?.user?.username),
|
|
351
|
+
},
|
|
352
|
+
}, {
|
|
353
|
+
summary: `Returned current session binding for ${datasource}.`,
|
|
354
|
+
metadata: metadata(context.taskId),
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
return formatToolError(error, {
|
|
359
|
+
action: "get_session_binding",
|
|
360
|
+
metadata: metadata(context.taskId),
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
};
|
|
132
365
|
export const selectCloudTaurusInstanceTool = {
|
|
133
366
|
name: "select_cloud_taurus_instance",
|
|
134
367
|
description: "Select the default TaurusDB cloud instance for the current session so diagnostics can reuse its instance id and default node id.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taurusdb-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "TaurusDB MCP server for Claude, Cursor, VS Code, and other MCP clients.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"test": "node --test tests/*.test.mjs"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"taurusdb-core": "0.
|
|
35
|
+
"taurusdb-core": "0.2.0",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.17.0",
|
|
37
37
|
"mysql2": "^3.22.1",
|
|
38
38
|
"zod": "^3.24.1"
|