taurusdb-mcp 0.3.0 → 0.5.0-rc.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TaurusDB MCP contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -28,17 +28,27 @@ Use this command in MCP client configs:
28
28
  }
29
29
  ```
30
30
 
31
+ Configure Huawei Cloud identity through the operating-system credential store
32
+ before adding the server. AK/SK values should not be copied into MCP client
33
+ configuration:
34
+
35
+ ```bash
36
+ npx -y taurusdb-mcp credentials configure
37
+ TAURUSDB_CLOUD_KEYCHAIN_SERVICE=taurusdb-mcp/huaweicloud \
38
+ npx -y taurusdb-mcp credentials check
39
+ ```
40
+
31
41
  Claude Code:
32
42
 
33
43
  ```bash
34
44
  claude mcp add huaweicloud-taurusdb \
35
45
  --transport stdio \
36
46
  -e TAURUSDB_CLOUD_REGION=<your-region> \
37
- -e TAURUSDB_CLOUD_ACCESS_KEY_ID=<your-ak> \
38
- -e TAURUSDB_CLOUD_SECRET_ACCESS_KEY=<your-sk> \
47
+ -e TAURUSDB_CLOUD_KEYCHAIN_SERVICE=taurusdb-mcp/huaweicloud \
48
+ -e TAURUSDB_ENABLE_DYNAMIC_TARGETS=true \
39
49
  -e TAURUSDB_SQL_DATABASE=<your-database> \
40
50
  -e TAURUSDB_SQL_USER=<your-readonly-user> \
41
- -e TAURUSDB_SQL_PASSWORD=<your-readonly-password> \
51
+ -e TAURUSDB_SQL_PASSWORD='hw-kms-file:~/.taurusdb-mcp/password.ciphertext' \
42
52
  -- npx -y taurusdb-mcp
43
53
  ```
44
54
 
@@ -47,11 +57,11 @@ Codex:
47
57
  ```bash
48
58
  codex mcp add huaweicloud-taurusdb \
49
59
  --env TAURUSDB_CLOUD_REGION=<your-region> \
50
- --env TAURUSDB_CLOUD_ACCESS_KEY_ID=<your-ak> \
51
- --env TAURUSDB_CLOUD_SECRET_ACCESS_KEY=<your-sk> \
60
+ --env TAURUSDB_CLOUD_KEYCHAIN_SERVICE=taurusdb-mcp/huaweicloud \
61
+ --env TAURUSDB_ENABLE_DYNAMIC_TARGETS=true \
52
62
  --env TAURUSDB_SQL_DATABASE=<your-database> \
53
63
  --env TAURUSDB_SQL_USER=<your-readonly-user> \
54
- --env TAURUSDB_SQL_PASSWORD=<your-readonly-password> \
64
+ --env TAURUSDB_SQL_PASSWORD='hw-kms-file:~/.taurusdb-mcp/password.ciphertext' \
55
65
  -- npx -y taurusdb-mcp
56
66
  ```
57
67
 
@@ -63,7 +73,43 @@ npx taurusdb-mcp init --client cursor
63
73
  npx taurusdb-mcp init --client vscode
64
74
  ```
65
75
 
76
+ Configure and verify the operating-system credential store:
77
+
78
+ ```bash
79
+ npx taurusdb-mcp credentials configure
80
+ npx taurusdb-mcp credentials check
81
+ ```
82
+
66
83
  ## Notes
67
84
 
68
85
  - Requires Node.js `>= 20`
69
86
  - Depends on `taurusdb-core`
87
+ - Database passwords support `env:`, `file:`, `hw-csms:`, `hw-kms:`, and `hw-kms-file:` references
88
+ - Huawei DEW CSMS is recommended when the database password should be stored and retrieved from Huawei Cloud
89
+ - macOS Keychain, Linux Secret Service, or Windows Credential Manager cloud identity is enabled with `TAURUSDB_CLOUD_KEYCHAIN_SERVICE`
90
+ - SQL TLS with certificate verification is required by default
91
+ - Mutation and dynamic-target tools are disabled by default
92
+ - Mutation tools require a dedicated `TAURUSDB_SQL_MUTATION_USER` /
93
+ `TAURUSDB_SQL_MUTATION_PASSWORD` pair and an external operator-signed approval
94
+ - MCP audit events are written to `~/.taurusdb-mcp/audit.jsonl` by default, with
95
+ configurable size rotation for collection into centralized immutable storage
96
+ - Run one stdio process per customer/client trust boundary; this package is not
97
+ a shared multi-tenant HTTP service
98
+
99
+ Enable mutations only when required:
100
+
101
+ ```bash
102
+ export TAURUSDB_ENABLE_MUTATIONS=true
103
+ export TAURUSDB_SQL_MUTATION_USER='<dedicated-writer>'
104
+ export TAURUSDB_SQL_MUTATION_PASSWORD='hw-csms:<writer-secret-name>'
105
+ export TAURUSDB_MUTATION_APPROVAL_SECRET_FILE='/run/secrets/taurusdb-approval'
106
+ ```
107
+
108
+ Sign a returned `approval_request` outside the MCP client:
109
+
110
+ ```bash
111
+ npx taurusdb-mcp approve \
112
+ --request '<approval_request>' \
113
+ --actor '<operator-identity>' \
114
+ --secret-file /run/secrets/taurusdb-approval
115
+ ```
@@ -0,0 +1 @@
1
+ export declare function runApprove(args: string[]): Promise<number>;
@@ -0,0 +1,66 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { signApprovalRequest } from "taurusdb-core";
5
+ function readOption(args, name) {
6
+ const index = args.indexOf(name);
7
+ if (index === -1) {
8
+ return undefined;
9
+ }
10
+ const value = args[index + 1];
11
+ if (!value || value.startsWith("--")) {
12
+ throw new Error(`${name} requires a value.`);
13
+ }
14
+ return value;
15
+ }
16
+ function expandTilde(input) {
17
+ if (input === "~") {
18
+ return os.homedir();
19
+ }
20
+ return input.startsWith("~/") ? path.join(os.homedir(), input.slice(2)) : input;
21
+ }
22
+ function usage() {
23
+ return `Usage: taurusdb-mcp approve --request <approval-request> --actor <identity> [options]
24
+
25
+ Options:
26
+ --secret-file <path> Approval secret file; defaults to
27
+ TAURUSDB_MUTATION_APPROVAL_SECRET_FILE
28
+ --request <value> approval_request returned by a mutation tool
29
+ --actor <identity> Human approver identity recorded in the signed token
30
+
31
+ The command prints a one-time approval_token. Run it outside the MCP client
32
+ after reviewing the SQL hash, datasource, database, risk, and expiry encoded
33
+ in approval_request.`;
34
+ }
35
+ async function readProtectedSecret(filePath) {
36
+ const resolved = expandTilde(filePath);
37
+ const info = await stat(resolved);
38
+ if (!info.isFile()) {
39
+ throw new Error("Mutation approval secret path must reference a regular file.");
40
+ }
41
+ if (process.platform !== "win32" && (info.mode & 0o077) !== 0) {
42
+ throw new Error("Mutation approval secret file must not be accessible by group or other users.");
43
+ }
44
+ const secret = (await readFile(resolved, "utf8")).trim();
45
+ if (Buffer.byteLength(secret, "utf8") < 32) {
46
+ throw new Error("Mutation approval secret must contain at least 32 bytes.");
47
+ }
48
+ return secret;
49
+ }
50
+ export async function runApprove(args) {
51
+ if (args.includes("--help") || args.includes("-h")) {
52
+ process.stdout.write(`${usage()}\n`);
53
+ return 0;
54
+ }
55
+ const request = readOption(args, "--request");
56
+ const actor = readOption(args, "--actor");
57
+ const secretFile = readOption(args, "--secret-file") ??
58
+ process.env.TAURUSDB_MUTATION_APPROVAL_SECRET_FILE?.trim();
59
+ if (!request || !actor || !secretFile) {
60
+ process.stderr.write(`${usage()}\n`);
61
+ return 2;
62
+ }
63
+ const secret = await readProtectedSecret(secretFile);
64
+ process.stdout.write(`${signApprovalRequest(request, actor, secret)}\n`);
65
+ return 0;
66
+ }
@@ -0,0 +1,3 @@
1
+ export declare function runCredentialsConfigure(args: string[]): number;
2
+ export declare function runCredentialsCheck(args: string[]): Promise<number>;
3
+ export declare function runCredentials(args: string[]): Promise<number>;
@@ -0,0 +1,190 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { canAuthenticateHuaweiCloudRequests, createConfigFromEnv, createHuaweiCsmsSecretResolver, createHuaweiKmsSecretResolver, createSqlProfileLoader, getHuaweiCloudAuthFromConfig, resolveHuaweiCloudProjectId, } from "taurusdb-core";
5
+ function readOption(args, name, fallback) {
6
+ const index = args.indexOf(name);
7
+ if (index === -1) {
8
+ return fallback;
9
+ }
10
+ const value = args[index + 1];
11
+ if (!value || value.startsWith("--")) {
12
+ throw new Error(`${name} requires a value.`);
13
+ }
14
+ return value;
15
+ }
16
+ function configureUsage() {
17
+ return `Usage: taurusdb-mcp credentials configure [options]
18
+
19
+ Options:
20
+ --service <name> Credential service prefix (default: taurusdb-mcp/huaweicloud)
21
+ --account <name> Credential account (default: default)
22
+ --with-security-token Also store a temporary security token`;
23
+ }
24
+ function checkUsage() {
25
+ return `Usage: taurusdb-mcp credentials check
26
+
27
+ Checks the configured Huawei Cloud identity and cloud-backed database password
28
+ references without printing or connecting with any secret values.`;
29
+ }
30
+ function runCommand(command, args, errorMessage) {
31
+ const result = spawnSync(command, args, { stdio: "inherit" });
32
+ if (result.error && "code" in result.error && result.error.code === "ENOENT") {
33
+ throw new Error(`${command} was not found.`);
34
+ }
35
+ if (result.status !== 0) {
36
+ throw new Error(errorMessage);
37
+ }
38
+ }
39
+ function storeMacOsSecret(service, account, label) {
40
+ process.stderr.write(`Enter ${label} in the macOS Keychain prompt.\n`);
41
+ runCommand("security", ["add-generic-password", "-U", "-s", service, "-a", account, "-w"], `Failed to store ${label} in macOS Keychain.`);
42
+ }
43
+ function storeLinuxSecret(service, account, key, label) {
44
+ process.stderr.write(`Enter ${label} when prompted by Linux Secret Service.\n`);
45
+ runCommand("secret-tool", [
46
+ "store",
47
+ `--label=TaurusDB MCP Huawei Cloud ${label}`,
48
+ "service",
49
+ service,
50
+ "account",
51
+ account,
52
+ "key",
53
+ key,
54
+ ], `Failed to store ${label} in Linux Secret Service.`);
55
+ }
56
+ function configureWindows(service, account, withSecurityToken) {
57
+ const scriptPath = fileURLToPath(new URL("../../scripts/windows-credential-configure.ps1", import.meta.url));
58
+ const args = [
59
+ "-NoLogo",
60
+ "-NoProfile",
61
+ "-ExecutionPolicy",
62
+ "Bypass",
63
+ "-File",
64
+ path.normalize(scriptPath),
65
+ "-Service",
66
+ service,
67
+ "-Account",
68
+ account,
69
+ ];
70
+ if (withSecurityToken) {
71
+ args.push("-WithSecurityToken");
72
+ }
73
+ runCommand("powershell.exe", args, "Failed to store credentials in Windows Credential Manager.");
74
+ }
75
+ export function runCredentialsConfigure(args) {
76
+ if (args.includes("--help") || args.includes("-h")) {
77
+ process.stdout.write(`${configureUsage()}\n`);
78
+ return 0;
79
+ }
80
+ const service = readOption(args, "--service", "taurusdb-mcp/huaweicloud");
81
+ const account = readOption(args, "--account", "default");
82
+ const withSecurityToken = args.includes("--with-security-token");
83
+ if (process.platform === "darwin") {
84
+ storeMacOsSecret(`${service}/access-key-id`, account, "Huawei Cloud access key ID");
85
+ storeMacOsSecret(`${service}/secret-access-key`, account, "Huawei Cloud secret access key");
86
+ if (withSecurityToken) {
87
+ storeMacOsSecret(`${service}/security-token`, account, "Huawei Cloud security token");
88
+ }
89
+ }
90
+ else if (process.platform === "linux") {
91
+ storeLinuxSecret(service, account, "access-key-id", "Huawei Cloud access key ID");
92
+ storeLinuxSecret(service, account, "secret-access-key", "Huawei Cloud secret access key");
93
+ if (withSecurityToken) {
94
+ storeLinuxSecret(service, account, "security-token", "Huawei Cloud security token");
95
+ }
96
+ }
97
+ else if (process.platform === "win32") {
98
+ configureWindows(service, account, withSecurityToken);
99
+ }
100
+ else {
101
+ throw new Error(`System credential storage is not supported on platform "${process.platform}".`);
102
+ }
103
+ process.stdout.write(`Stored Huawei Cloud credentials in service "${service}" for account "${account}".\n`);
104
+ return 0;
105
+ }
106
+ function printResult(ok, title, details) {
107
+ process.stdout.write(`${ok ? "[ok]" : "[fail]"} ${title}${details ? `: ${details}` : ""}\n`);
108
+ }
109
+ async function check(title, action) {
110
+ try {
111
+ printResult(true, title, await action());
112
+ return true;
113
+ }
114
+ catch (error) {
115
+ printResult(false, title, error instanceof Error ? error.message : String(error));
116
+ return false;
117
+ }
118
+ }
119
+ function getCloudResolver(uri, config) {
120
+ const normalized = uri.startsWith("uri:") ? uri.slice("uri:".length) : uri;
121
+ if (normalized.startsWith("hw-csms:")) {
122
+ return { kind: "CSMS", resolve: () => createHuaweiCsmsSecretResolver({ config })(normalized) };
123
+ }
124
+ if (normalized.startsWith("hw-kms:") || normalized.startsWith("hw-kms-file:")) {
125
+ return { kind: "KMS", resolve: () => createHuaweiKmsSecretResolver({ config })(normalized) };
126
+ }
127
+ return undefined;
128
+ }
129
+ export async function runCredentialsCheck(args) {
130
+ if (args.includes("--help") || args.includes("-h")) {
131
+ process.stdout.write(`${checkUsage()}\n`);
132
+ return 0;
133
+ }
134
+ const config = createConfigFromEnv(process.env);
135
+ const auth = getHuaweiCloudAuthFromConfig(config);
136
+ let failed = false;
137
+ failed ||= !(await check("Huawei Cloud identity source", async () => {
138
+ if (auth.authToken)
139
+ return "IAM token configured";
140
+ if (auth.accessKeyId && auth.secretAccessKey)
141
+ return "AK/SK configured in environment";
142
+ if (auth.credentialProvider) {
143
+ await auth.credentialProvider();
144
+ return "system credential store readable";
145
+ }
146
+ if (!canAuthenticateHuaweiCloudRequests(auth)) {
147
+ throw new Error("No IAM token, AK/SK, or system credential store is configured.");
148
+ }
149
+ return "configured";
150
+ }));
151
+ if (!failed) {
152
+ failed ||= !(await check("Huawei Cloud project", async () => {
153
+ const projectId = await resolveHuaweiCloudProjectId(auth);
154
+ if (!projectId) {
155
+ throw new Error("Project ID could not be resolved.");
156
+ }
157
+ return config.cloud.projectId ? "configured" : "resolved through IAM";
158
+ }));
159
+ }
160
+ const profiles = await createSqlProfileLoader({ config }).load();
161
+ const cloudRefs = [...profiles.values()]
162
+ .map((profile) => profile.user?.password)
163
+ .filter((ref) => ref?.type === "uri")
164
+ .map((ref) => getCloudResolver(ref.uri, config))
165
+ .filter((resolver) => resolver !== undefined);
166
+ if (cloudRefs.length === 0) {
167
+ printResult(true, "Cloud-backed database password references", "none configured; skipped");
168
+ }
169
+ else if (!failed) {
170
+ for (const resolver of cloudRefs) {
171
+ const readable = await check(`${resolver.kind} database password reference`, async () => {
172
+ await resolver.resolve();
173
+ return "readable";
174
+ });
175
+ failed ||= !readable;
176
+ }
177
+ }
178
+ return failed ? 1 : 0;
179
+ }
180
+ export async function runCredentials(args) {
181
+ const command = args[0];
182
+ if (command === "configure") {
183
+ return runCredentialsConfigure(args.slice(1));
184
+ }
185
+ if (command === "check") {
186
+ return runCredentialsCheck(args.slice(1));
187
+ }
188
+ process.stderr.write("Usage: taurusdb-mcp credentials <configure|check>\n");
189
+ return 1;
190
+ }
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { runInit } from "./commands/init.js";
3
+ import { runCredentials } from "./commands/credentials.js";
4
+ import { runApprove } from "./commands/approve.js";
3
5
  import { startMcpServer } from "./server.js";
4
6
  import { VERSION } from "./version.js";
5
7
  async function main() {
@@ -9,6 +11,14 @@ async function main() {
9
11
  process.exitCode = await runInit(args.slice(1));
10
12
  return;
11
13
  }
14
+ if (firstArg === "credentials") {
15
+ process.exitCode = await runCredentials(args.slice(1));
16
+ return;
17
+ }
18
+ if (firstArg === "approve") {
19
+ process.exitCode = await runApprove(args.slice(1));
20
+ return;
21
+ }
12
22
  if (firstArg === "--version" || firstArg === "-v") {
13
23
  process.stdout.write(`${VERSION}\n`);
14
24
  return;
@@ -0,0 +1,9 @@
1
+ export declare class SessionCoordinator {
2
+ private readers;
3
+ private writerActive;
4
+ private readonly readerQueue;
5
+ private readonly writerQueue;
6
+ runShared<T>(operation: () => Promise<T>): Promise<T>;
7
+ runExclusive<T>(operation: () => Promise<T>): Promise<T>;
8
+ private drain;
9
+ }
@@ -0,0 +1,46 @@
1
+ export class SessionCoordinator {
2
+ readers = 0;
3
+ writerActive = false;
4
+ readerQueue = [];
5
+ writerQueue = [];
6
+ async runShared(operation) {
7
+ if (this.writerActive || this.writerQueue.length > 0) {
8
+ await new Promise((resolve) => this.readerQueue.push(resolve));
9
+ }
10
+ this.readers += 1;
11
+ try {
12
+ return await operation();
13
+ }
14
+ finally {
15
+ this.readers -= 1;
16
+ this.drain();
17
+ }
18
+ }
19
+ runExclusive(operation) {
20
+ return new Promise((resolve, reject) => {
21
+ this.writerQueue.push({
22
+ operation,
23
+ resolve: resolve,
24
+ reject,
25
+ });
26
+ this.drain();
27
+ });
28
+ }
29
+ drain() {
30
+ if (this.writerActive || this.readers > 0) {
31
+ return;
32
+ }
33
+ const writer = this.writerQueue.shift();
34
+ if (writer) {
35
+ this.writerActive = true;
36
+ void writer.operation().then(writer.resolve, writer.reject).finally(() => {
37
+ this.writerActive = false;
38
+ this.drain();
39
+ });
40
+ return;
41
+ }
42
+ for (const resolve of this.readerQueue.splice(0)) {
43
+ resolve();
44
+ }
45
+ }
46
+ }
package/dist/server.d.ts CHANGED
@@ -1,11 +1,18 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { TaurusDBEngine, type Config, type RuntimeTargetProfileLoader } from "taurusdb-core";
2
+ import { TaurusDBEngine, type Config, type AuditWriter, type RuntimeTargetProfileLoader } from "taurusdb-core";
3
3
  import { type CredentialLoginService } from "./security/local-credential-login.js";
4
+ import { SessionCoordinator } from "./security/session-coordinator.js";
4
5
  export interface ServerDeps {
5
6
  config: Config;
6
7
  profileLoader: RuntimeTargetProfileLoader;
7
8
  engine: TaurusDBEngine;
8
9
  credentialLogin: CredentialLoginService;
10
+ auditWriter?: AuditWriter;
11
+ sessionCoordinator?: SessionCoordinator;
12
+ clientIdentityProvider?: () => {
13
+ name: string;
14
+ version: string;
15
+ } | undefined;
9
16
  pingResponse: string;
10
17
  }
11
18
  export declare function bootstrapDependencies(): Promise<ServerDeps>;
package/dist/server.js CHANGED
@@ -1,19 +1,27 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
- import { createSqlProfileLoader, getConfig, RuntimeOverrideProfileLoader, redactConfigForLog, TaurusDBEngine, } from "taurusdb-core";
3
+ import { createSqlProfileLoader, createJsonlAuditWriter, getConfig, RuntimeOverrideProfileLoader, redactConfigForLog, TaurusDBEngine, } from "taurusdb-core";
4
4
  import { registerTools } from "./tools/registry.js";
5
5
  import { logger } from "taurusdb-core";
6
6
  import { VERSION } from "./version.js";
7
7
  import { LocalCredentialLoginService, } from "./security/local-credential-login.js";
8
+ import { SessionCoordinator } from "./security/session-coordinator.js";
8
9
  export async function bootstrapDependencies() {
9
10
  const config = getConfig();
10
11
  const profileLoader = new RuntimeOverrideProfileLoader(createSqlProfileLoader({ config }));
11
12
  const engine = await TaurusDBEngine.create({ config, profileLoader });
13
+ const auditWriter = await createJsonlAuditWriter({
14
+ logPath: config.audit.logPath,
15
+ maxBytes: config.audit.maxBytes,
16
+ maxFiles: config.audit.maxFiles,
17
+ });
12
18
  return {
13
19
  config,
14
20
  profileLoader,
15
21
  engine,
16
22
  credentialLogin: new LocalCredentialLoginService(),
23
+ auditWriter,
24
+ sessionCoordinator: new SessionCoordinator(),
17
25
  pingResponse: "pong",
18
26
  };
19
27
  }
@@ -22,11 +30,13 @@ export function createServer(deps) {
22
30
  name: "huaweicloud-taurusdb",
23
31
  version: VERSION,
24
32
  });
33
+ deps.clientIdentityProvider = () => server.server.getClientVersion();
25
34
  let cleanupPromise;
26
35
  const cleanup = () => {
27
36
  cleanupPromise ??= Promise.all([
28
37
  deps.credentialLogin.close(),
29
38
  deps.engine.close(),
39
+ deps.auditWriter?.close() ?? Promise.resolve(),
30
40
  ]).then(() => undefined);
31
41
  return cleanupPromise;
32
42
  };
@@ -57,6 +57,8 @@ export declare function toPublicQueryResult(result: QueryResult): {
57
57
  row_truncated: boolean;
58
58
  column_truncated: boolean;
59
59
  field_truncated: boolean;
60
+ byte_truncated: boolean;
61
+ returned_bytes: number;
60
62
  redacted_columns: string[];
61
63
  dropped_columns: string[];
62
64
  truncated_columns: string[];
@@ -78,6 +80,8 @@ export declare function toPublicGuardrailDecision(decision: GuardrailDecision):
78
80
  max_rows: number;
79
81
  max_columns: number;
80
82
  max_field_chars: number;
83
+ max_result_bytes: number;
84
+ max_blob_bytes: number;
81
85
  };
82
86
  };
83
87
  export declare function toPublicExplainResult(result: ExplainResult, decision: GuardrailDecision): {
@@ -105,6 +109,8 @@ export declare function toPublicExplainResult(result: ExplainResult, decision: G
105
109
  max_rows: number;
106
110
  max_columns: number;
107
111
  max_field_chars: number;
112
+ max_result_bytes: number;
113
+ max_blob_bytes: number;
108
114
  };
109
115
  };
110
116
  };
@@ -146,6 +152,8 @@ export declare function toPublicEnhancedExplainResult(result: EnhancedExplainRes
146
152
  max_rows: number;
147
153
  max_columns: number;
148
154
  max_field_chars: number;
155
+ max_result_bytes: number;
156
+ max_blob_bytes: number;
149
157
  };
150
158
  };
151
159
  };
@@ -67,6 +67,8 @@ export function toPublicQueryResult(result) {
67
67
  row_truncated: result.rowTruncated,
68
68
  column_truncated: result.columnTruncated,
69
69
  field_truncated: result.fieldTruncated,
70
+ byte_truncated: result.byteTruncated,
71
+ returned_bytes: result.returnedBytes,
70
72
  redacted_columns: result.redactedColumns,
71
73
  dropped_columns: result.droppedColumns,
72
74
  truncated_columns: result.truncatedColumns,
@@ -92,6 +94,8 @@ export function toPublicGuardrailDecision(decision) {
92
94
  max_rows: decision.runtimeLimits.maxRows,
93
95
  max_columns: decision.runtimeLimits.maxColumns,
94
96
  max_field_chars: decision.runtimeLimits.maxFieldChars,
97
+ max_result_bytes: decision.runtimeLimits.maxResultBytes,
98
+ max_blob_bytes: decision.runtimeLimits.maxBlobBytes,
95
99
  },
96
100
  };
97
101
  }
@@ -1,4 +1,4 @@
1
- import { ConnectionPoolError, DatasourceResolutionError, FlashbackNoViewError, logger, SchemaIntrospectionError, UnsupportedFeatureError, } from "taurusdb-core";
1
+ import { ConnectionPoolError, DatasourceResolutionError, FlashbackNoViewError, logger, QueryConcurrencyError, SchemaIntrospectionError, UnsupportedFeatureError, } from "taurusdb-core";
2
2
  import { ErrorCode, formatError, } from "../utils/formatter.js";
3
3
  export class ToolInputError extends Error {
4
4
  constructor(message) {
@@ -100,6 +100,15 @@ export function formatToolError(error, context) {
100
100
  details: detailsOf(error),
101
101
  });
102
102
  }
103
+ if (error instanceof QueryConcurrencyError) {
104
+ return formatError({
105
+ code: ErrorCode.SERVER_BUSY,
106
+ message: error.message,
107
+ summary: `${context.action} could not start because query capacity is exhausted.`,
108
+ metadata: context.metadata,
109
+ retryable: true,
110
+ });
111
+ }
103
112
  if (cancelledLikely(error)) {
104
113
  return formatError({
105
114
  code: ErrorCode.QUERY_CANCELLED,