@bytebase/dbhub 0.14.0 → 0.16.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 +15 -9
- package/dist/{chunk-WGDSRFBW.js → chunk-IBBG4PSO.js} +92 -39
- package/dist/index.js +160 -82
- package/dist/public/assets/index-BJ-1UrcV.css +1 -0
- package/dist/public/assets/index-DBYlgGks.js +147 -0
- package/dist/public/index.html +2 -2
- package/dist/{registry-FVGT25UH.js → registry-D77Y4CIA.js} +1 -1
- package/package.json +1 -1
- package/dist/public/assets/index-gVrYRID4.css +0 -1
- package/dist/public/assets/index-hd88eD9m.js +0 -51
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
resolveSourceConfigs,
|
|
17
17
|
resolveTransport,
|
|
18
18
|
stripCommentsAndStrings
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-IBBG4PSO.js";
|
|
20
20
|
|
|
21
21
|
// src/connectors/postgres/index.ts
|
|
22
22
|
import pg from "pg";
|
|
@@ -477,22 +477,26 @@ var PostgresConnector = class _PostgresConnector {
|
|
|
477
477
|
const statements = sql2.split(";").map((statement) => statement.trim()).filter((statement) => statement.length > 0);
|
|
478
478
|
if (statements.length === 1) {
|
|
479
479
|
const processedStatement = SQLRowLimiter.applyMaxRows(statements[0], options.maxRows);
|
|
480
|
+
let result;
|
|
480
481
|
if (parameters && parameters.length > 0) {
|
|
481
482
|
try {
|
|
482
|
-
|
|
483
|
+
result = await client.query(processedStatement, parameters);
|
|
483
484
|
} catch (error) {
|
|
484
485
|
console.error(`[PostgreSQL executeSQL] ERROR: ${error.message}`);
|
|
485
486
|
console.error(`[PostgreSQL executeSQL] SQL: ${processedStatement}`);
|
|
486
487
|
console.error(`[PostgreSQL executeSQL] Parameters: ${JSON.stringify(parameters)}`);
|
|
487
488
|
throw error;
|
|
488
489
|
}
|
|
490
|
+
} else {
|
|
491
|
+
result = await client.query(processedStatement);
|
|
489
492
|
}
|
|
490
|
-
return
|
|
493
|
+
return { rows: result.rows, rowCount: result.rowCount ?? result.rows.length };
|
|
491
494
|
} else {
|
|
492
495
|
if (parameters && parameters.length > 0) {
|
|
493
496
|
throw new Error("Parameters are not supported for multi-statement queries in PostgreSQL");
|
|
494
497
|
}
|
|
495
498
|
let allRows = [];
|
|
499
|
+
let totalRowCount = 0;
|
|
496
500
|
await client.query("BEGIN");
|
|
497
501
|
try {
|
|
498
502
|
for (let statement of statements) {
|
|
@@ -501,13 +505,16 @@ var PostgresConnector = class _PostgresConnector {
|
|
|
501
505
|
if (result.rows && result.rows.length > 0) {
|
|
502
506
|
allRows.push(...result.rows);
|
|
503
507
|
}
|
|
508
|
+
if (result.rowCount) {
|
|
509
|
+
totalRowCount += result.rowCount;
|
|
510
|
+
}
|
|
504
511
|
}
|
|
505
512
|
await client.query("COMMIT");
|
|
506
513
|
} catch (error) {
|
|
507
514
|
await client.query("ROLLBACK");
|
|
508
515
|
throw error;
|
|
509
516
|
}
|
|
510
|
-
return { rows: allRows };
|
|
517
|
+
return { rows: allRows, rowCount: totalRowCount };
|
|
511
518
|
}
|
|
512
519
|
} finally {
|
|
513
520
|
client.release();
|
|
@@ -929,9 +936,6 @@ var SQLServerConnector = class _SQLServerConnector {
|
|
|
929
936
|
}
|
|
930
937
|
return {
|
|
931
938
|
rows: result.recordset || [],
|
|
932
|
-
fields: result.recordset && result.recordset.length > 0 ? Object.keys(result.recordset[0]).map((key) => ({
|
|
933
|
-
name: key
|
|
934
|
-
})) : [],
|
|
935
939
|
rowCount: result.rowsAffected[0] || 0
|
|
936
940
|
};
|
|
937
941
|
} catch (error) {
|
|
@@ -1215,7 +1219,7 @@ var SQLiteConnector = class _SQLiteConnector {
|
|
|
1215
1219
|
if (parameters && parameters.length > 0) {
|
|
1216
1220
|
try {
|
|
1217
1221
|
const rows = this.db.prepare(processedStatement).all(...parameters);
|
|
1218
|
-
return { rows };
|
|
1222
|
+
return { rows, rowCount: rows.length };
|
|
1219
1223
|
} catch (error) {
|
|
1220
1224
|
console.error(`[SQLite executeSQL] ERROR: ${error.message}`);
|
|
1221
1225
|
console.error(`[SQLite executeSQL] SQL: ${processedStatement}`);
|
|
@@ -1224,12 +1228,13 @@ var SQLiteConnector = class _SQLiteConnector {
|
|
|
1224
1228
|
}
|
|
1225
1229
|
} else {
|
|
1226
1230
|
const rows = this.db.prepare(processedStatement).all();
|
|
1227
|
-
return { rows };
|
|
1231
|
+
return { rows, rowCount: rows.length };
|
|
1228
1232
|
}
|
|
1229
1233
|
} else {
|
|
1234
|
+
let result;
|
|
1230
1235
|
if (parameters && parameters.length > 0) {
|
|
1231
1236
|
try {
|
|
1232
|
-
this.db.prepare(processedStatement).run(...parameters);
|
|
1237
|
+
result = this.db.prepare(processedStatement).run(...parameters);
|
|
1233
1238
|
} catch (error) {
|
|
1234
1239
|
console.error(`[SQLite executeSQL] ERROR: ${error.message}`);
|
|
1235
1240
|
console.error(`[SQLite executeSQL] SQL: ${processedStatement}`);
|
|
@@ -1237,9 +1242,9 @@ var SQLiteConnector = class _SQLiteConnector {
|
|
|
1237
1242
|
throw error;
|
|
1238
1243
|
}
|
|
1239
1244
|
} else {
|
|
1240
|
-
this.db.prepare(processedStatement).run();
|
|
1245
|
+
result = this.db.prepare(processedStatement).run();
|
|
1241
1246
|
}
|
|
1242
|
-
return { rows: [] };
|
|
1247
|
+
return { rows: [], rowCount: result.changes };
|
|
1243
1248
|
}
|
|
1244
1249
|
} else {
|
|
1245
1250
|
if (parameters && parameters.length > 0) {
|
|
@@ -1255,8 +1260,10 @@ var SQLiteConnector = class _SQLiteConnector {
|
|
|
1255
1260
|
writeStatements.push(statement);
|
|
1256
1261
|
}
|
|
1257
1262
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1263
|
+
let totalChanges = 0;
|
|
1264
|
+
for (const statement of writeStatements) {
|
|
1265
|
+
const result = this.db.prepare(statement).run();
|
|
1266
|
+
totalChanges += result.changes;
|
|
1260
1267
|
}
|
|
1261
1268
|
let allRows = [];
|
|
1262
1269
|
for (let statement of readStatements) {
|
|
@@ -1264,7 +1271,7 @@ var SQLiteConnector = class _SQLiteConnector {
|
|
|
1264
1271
|
const result = this.db.prepare(statement).all();
|
|
1265
1272
|
allRows.push(...result);
|
|
1266
1273
|
}
|
|
1267
|
-
return { rows: allRows };
|
|
1274
|
+
return { rows: allRows, rowCount: totalChanges + allRows.length };
|
|
1268
1275
|
}
|
|
1269
1276
|
} catch (error) {
|
|
1270
1277
|
throw error;
|
|
@@ -1303,6 +1310,26 @@ function extractRowsFromMultiStatement(results) {
|
|
|
1303
1310
|
}
|
|
1304
1311
|
return allRows;
|
|
1305
1312
|
}
|
|
1313
|
+
function extractAffectedRows(results) {
|
|
1314
|
+
if (isMetadataObject(results)) {
|
|
1315
|
+
return results.affectedRows || 0;
|
|
1316
|
+
}
|
|
1317
|
+
if (!Array.isArray(results)) {
|
|
1318
|
+
return 0;
|
|
1319
|
+
}
|
|
1320
|
+
if (isMultiStatementResult(results)) {
|
|
1321
|
+
let totalAffected = 0;
|
|
1322
|
+
for (const result of results) {
|
|
1323
|
+
if (isMetadataObject(result)) {
|
|
1324
|
+
totalAffected += result.affectedRows || 0;
|
|
1325
|
+
} else if (Array.isArray(result)) {
|
|
1326
|
+
totalAffected += result.length;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return totalAffected;
|
|
1330
|
+
}
|
|
1331
|
+
return results.length;
|
|
1332
|
+
}
|
|
1306
1333
|
function parseQueryResults(results) {
|
|
1307
1334
|
if (!Array.isArray(results)) {
|
|
1308
1335
|
return [];
|
|
@@ -1716,7 +1743,8 @@ var MySQLConnector = class _MySQLConnector {
|
|
|
1716
1743
|
}
|
|
1717
1744
|
const [firstResult] = results;
|
|
1718
1745
|
const rows = parseQueryResults(firstResult);
|
|
1719
|
-
|
|
1746
|
+
const rowCount = extractAffectedRows(firstResult);
|
|
1747
|
+
return { rows, rowCount };
|
|
1720
1748
|
} catch (error) {
|
|
1721
1749
|
console.error("Error executing query:", error);
|
|
1722
1750
|
throw error;
|
|
@@ -2127,7 +2155,8 @@ var MariaDBConnector = class _MariaDBConnector {
|
|
|
2127
2155
|
results = await conn.query(processedSQL);
|
|
2128
2156
|
}
|
|
2129
2157
|
const rows = parseQueryResults(results);
|
|
2130
|
-
|
|
2158
|
+
const rowCount = extractAffectedRows(results);
|
|
2159
|
+
return { rows, rowCount };
|
|
2131
2160
|
} catch (error) {
|
|
2132
2161
|
console.error("Error executing query:", error);
|
|
2133
2162
|
throw error;
|
|
@@ -2274,6 +2303,27 @@ function getClientIdentifier(extra) {
|
|
|
2274
2303
|
return "stdio";
|
|
2275
2304
|
}
|
|
2276
2305
|
|
|
2306
|
+
// src/utils/tool-handler-helpers.ts
|
|
2307
|
+
function getEffectiveSourceId(sourceId) {
|
|
2308
|
+
return sourceId || "default";
|
|
2309
|
+
}
|
|
2310
|
+
function createReadonlyViolationMessage(toolName, sourceId, connectorType) {
|
|
2311
|
+
return `Tool '${toolName}' cannot execute in readonly mode for source '${sourceId}'. Only read-only SQL operations are allowed: ${allowedKeywords[connectorType]?.join(", ") || "none"}`;
|
|
2312
|
+
}
|
|
2313
|
+
function trackToolRequest(metadata, startTime, extra, success, error) {
|
|
2314
|
+
requestStore.add({
|
|
2315
|
+
id: crypto.randomUUID(),
|
|
2316
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2317
|
+
sourceId: metadata.sourceId,
|
|
2318
|
+
toolName: metadata.toolName,
|
|
2319
|
+
sql: metadata.sql,
|
|
2320
|
+
durationMs: Date.now() - startTime,
|
|
2321
|
+
client: getClientIdentifier(extra),
|
|
2322
|
+
success,
|
|
2323
|
+
error
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2277
2327
|
// src/tools/execute-sql.ts
|
|
2278
2328
|
var executeSqlSchema = {
|
|
2279
2329
|
sql: z.string().describe("SQL to execute (multiple statements separated by ;)")
|
|
@@ -2289,29 +2339,30 @@ function createExecuteSqlToolHandler(sourceId) {
|
|
|
2289
2339
|
return async (args, extra) => {
|
|
2290
2340
|
const { sql: sql2 } = args;
|
|
2291
2341
|
const startTime = Date.now();
|
|
2292
|
-
const effectiveSourceId = sourceId
|
|
2342
|
+
const effectiveSourceId = getEffectiveSourceId(sourceId);
|
|
2293
2343
|
let success = true;
|
|
2294
2344
|
let errorMessage;
|
|
2295
2345
|
let result;
|
|
2296
2346
|
try {
|
|
2347
|
+
await ConnectorManager.ensureConnected(sourceId);
|
|
2297
2348
|
const connector = ConnectorManager.getCurrentConnector(sourceId);
|
|
2298
2349
|
const actualSourceId = connector.getId();
|
|
2299
2350
|
const registry = getToolRegistry();
|
|
2300
2351
|
const toolConfig = registry.getBuiltinToolConfig(BUILTIN_TOOL_EXECUTE_SQL, actualSourceId);
|
|
2301
2352
|
const isReadonly = toolConfig?.readonly === true;
|
|
2302
2353
|
if (isReadonly && !areAllStatementsReadOnly(sql2, connector.id)) {
|
|
2303
|
-
errorMessage = `Read-only mode is enabled
|
|
2354
|
+
errorMessage = `Read-only mode is enabled. Only the following SQL operations are allowed: ${allowedKeywords[connector.id]?.join(", ") || "none"}`;
|
|
2304
2355
|
success = false;
|
|
2305
2356
|
return createToolErrorResponse(errorMessage, "READONLY_VIOLATION");
|
|
2306
2357
|
}
|
|
2307
2358
|
const executeOptions = {
|
|
2308
|
-
readonly:
|
|
2309
|
-
|
|
2359
|
+
readonly: toolConfig?.readonly,
|
|
2360
|
+
maxRows: toolConfig?.max_rows
|
|
2310
2361
|
};
|
|
2311
2362
|
result = await connector.executeSQL(sql2, executeOptions);
|
|
2312
2363
|
const responseData = {
|
|
2313
2364
|
rows: result.rows,
|
|
2314
|
-
count: result.
|
|
2365
|
+
count: result.rowCount,
|
|
2315
2366
|
source_id: effectiveSourceId
|
|
2316
2367
|
};
|
|
2317
2368
|
return createToolSuccessResponse(responseData);
|
|
@@ -2320,17 +2371,17 @@ function createExecuteSqlToolHandler(sourceId) {
|
|
|
2320
2371
|
errorMessage = error.message;
|
|
2321
2372
|
return createToolErrorResponse(errorMessage, "EXECUTION_ERROR");
|
|
2322
2373
|
} finally {
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2374
|
+
trackToolRequest(
|
|
2375
|
+
{
|
|
2376
|
+
sourceId: effectiveSourceId,
|
|
2377
|
+
toolName: effectiveSourceId === "default" ? "execute_sql" : `execute_sql_${effectiveSourceId}`,
|
|
2378
|
+
sql: sql2
|
|
2379
|
+
},
|
|
2380
|
+
startTime,
|
|
2381
|
+
extra,
|
|
2331
2382
|
success,
|
|
2332
|
-
|
|
2333
|
-
|
|
2383
|
+
errorMessage
|
|
2384
|
+
);
|
|
2334
2385
|
}
|
|
2335
2386
|
};
|
|
2336
2387
|
}
|
|
@@ -2617,7 +2668,7 @@ async function searchIndexes(connector, pattern, schemaFilter, tableFilter, deta
|
|
|
2617
2668
|
return results;
|
|
2618
2669
|
}
|
|
2619
2670
|
function createSearchDatabaseObjectsToolHandler(sourceId) {
|
|
2620
|
-
return async (args,
|
|
2671
|
+
return async (args, extra) => {
|
|
2621
2672
|
const {
|
|
2622
2673
|
object_type,
|
|
2623
2674
|
pattern = "%",
|
|
@@ -2626,29 +2677,31 @@ function createSearchDatabaseObjectsToolHandler(sourceId) {
|
|
|
2626
2677
|
detail_level = "names",
|
|
2627
2678
|
limit = 100
|
|
2628
2679
|
} = args;
|
|
2680
|
+
const startTime = Date.now();
|
|
2681
|
+
const effectiveSourceId = getEffectiveSourceId(sourceId);
|
|
2682
|
+
let success = true;
|
|
2683
|
+
let errorMessage;
|
|
2629
2684
|
try {
|
|
2685
|
+
await ConnectorManager.ensureConnected(sourceId);
|
|
2630
2686
|
const connector = ConnectorManager.getCurrentConnector(sourceId);
|
|
2631
2687
|
if (table) {
|
|
2632
2688
|
if (!schema) {
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
);
|
|
2689
|
+
success = false;
|
|
2690
|
+
errorMessage = "The 'table' parameter requires 'schema' to be specified";
|
|
2691
|
+
return createToolErrorResponse(errorMessage, "SCHEMA_REQUIRED");
|
|
2637
2692
|
}
|
|
2638
2693
|
if (!["column", "index"].includes(object_type)) {
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
);
|
|
2694
|
+
success = false;
|
|
2695
|
+
errorMessage = `The 'table' parameter only applies to object_type 'column' or 'index', not '${object_type}'`;
|
|
2696
|
+
return createToolErrorResponse(errorMessage, "INVALID_TABLE_FILTER");
|
|
2643
2697
|
}
|
|
2644
2698
|
}
|
|
2645
2699
|
if (schema) {
|
|
2646
2700
|
const schemas = await connector.getSchemas();
|
|
2647
2701
|
if (!schemas.includes(schema)) {
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
);
|
|
2702
|
+
success = false;
|
|
2703
|
+
errorMessage = `Schema '${schema}' does not exist. Available schemas: ${schemas.join(", ")}`;
|
|
2704
|
+
return createToolErrorResponse(errorMessage, "SCHEMA_NOT_FOUND");
|
|
2652
2705
|
}
|
|
2653
2706
|
}
|
|
2654
2707
|
let results = [];
|
|
@@ -2669,10 +2722,9 @@ function createSearchDatabaseObjectsToolHandler(sourceId) {
|
|
|
2669
2722
|
results = await searchIndexes(connector, pattern, schema, table, detail_level, limit);
|
|
2670
2723
|
break;
|
|
2671
2724
|
default:
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
);
|
|
2725
|
+
success = false;
|
|
2726
|
+
errorMessage = `Unsupported object_type: ${object_type}`;
|
|
2727
|
+
return createToolErrorResponse(errorMessage, "INVALID_OBJECT_TYPE");
|
|
2676
2728
|
}
|
|
2677
2729
|
return createToolSuccessResponse({
|
|
2678
2730
|
object_type,
|
|
@@ -2685,10 +2737,24 @@ function createSearchDatabaseObjectsToolHandler(sourceId) {
|
|
|
2685
2737
|
truncated: results.length === limit
|
|
2686
2738
|
});
|
|
2687
2739
|
} catch (error) {
|
|
2740
|
+
success = false;
|
|
2741
|
+
errorMessage = error.message;
|
|
2688
2742
|
return createToolErrorResponse(
|
|
2689
|
-
`Error searching database objects: ${
|
|
2743
|
+
`Error searching database objects: ${errorMessage}`,
|
|
2690
2744
|
"SEARCH_ERROR"
|
|
2691
2745
|
);
|
|
2746
|
+
} finally {
|
|
2747
|
+
trackToolRequest(
|
|
2748
|
+
{
|
|
2749
|
+
sourceId: effectiveSourceId,
|
|
2750
|
+
toolName: effectiveSourceId === "default" ? "search_objects" : `search_objects_${effectiveSourceId}`,
|
|
2751
|
+
sql: `search_objects(object_type=${object_type}, pattern=${pattern}, schema=${schema || "all"}, table=${table || "all"}, detail_level=${detail_level})`
|
|
2752
|
+
},
|
|
2753
|
+
startTime,
|
|
2754
|
+
extra,
|
|
2755
|
+
success,
|
|
2756
|
+
errorMessage
|
|
2757
|
+
);
|
|
2692
2758
|
}
|
|
2693
2759
|
};
|
|
2694
2760
|
}
|
|
@@ -2731,9 +2797,14 @@ function zodToParameters(schema) {
|
|
|
2731
2797
|
function getExecuteSqlMetadata(sourceId) {
|
|
2732
2798
|
const sourceIds = ConnectorManager.getAvailableSourceIds();
|
|
2733
2799
|
const sourceConfig = ConnectorManager.getSourceConfig(sourceId);
|
|
2734
|
-
const executeOptions = ConnectorManager.getCurrentExecuteOptions(sourceId);
|
|
2735
2800
|
const dbType = sourceConfig.type;
|
|
2736
2801
|
const isSingleSource = sourceIds.length === 1;
|
|
2802
|
+
const registry = getToolRegistry();
|
|
2803
|
+
const toolConfig = registry.getBuiltinToolConfig(BUILTIN_TOOL_EXECUTE_SQL, sourceId);
|
|
2804
|
+
const executeOptions = {
|
|
2805
|
+
readonly: toolConfig?.readonly,
|
|
2806
|
+
maxRows: toolConfig?.max_rows
|
|
2807
|
+
};
|
|
2737
2808
|
const toolName = isSingleSource ? "execute_sql" : `execute_sql_${normalizeSourceId(sourceId)}`;
|
|
2738
2809
|
const title = isSingleSource ? `Execute SQL (${dbType})` : `Execute SQL on ${sourceId} (${dbType})`;
|
|
2739
2810
|
const readonlyNote = executeOptions.readonly ? " [READ-ONLY MODE]" : "";
|
|
@@ -2783,13 +2854,17 @@ function customParamsToToolParams(params) {
|
|
|
2783
2854
|
description: param.description
|
|
2784
2855
|
}));
|
|
2785
2856
|
}
|
|
2786
|
-
function buildExecuteSqlTool(sourceId) {
|
|
2857
|
+
function buildExecuteSqlTool(sourceId, toolConfig) {
|
|
2787
2858
|
const executeSqlMetadata = getExecuteSqlMetadata(sourceId);
|
|
2788
2859
|
const executeSqlParameters = zodToParameters(executeSqlMetadata.schema);
|
|
2860
|
+
const readonly = toolConfig && "readonly" in toolConfig ? toolConfig.readonly : void 0;
|
|
2861
|
+
const max_rows = toolConfig && "max_rows" in toolConfig ? toolConfig.max_rows : void 0;
|
|
2789
2862
|
return {
|
|
2790
2863
|
name: executeSqlMetadata.name,
|
|
2791
2864
|
description: executeSqlMetadata.description,
|
|
2792
|
-
parameters: executeSqlParameters
|
|
2865
|
+
parameters: executeSqlParameters,
|
|
2866
|
+
readonly,
|
|
2867
|
+
max_rows
|
|
2793
2868
|
};
|
|
2794
2869
|
}
|
|
2795
2870
|
function buildSearchObjectsTool(sourceId) {
|
|
@@ -2834,14 +2909,19 @@ function buildSearchObjectsTool(sourceId) {
|
|
|
2834
2909
|
required: false,
|
|
2835
2910
|
description: "Max results (default: 100, max: 1000)"
|
|
2836
2911
|
}
|
|
2837
|
-
]
|
|
2912
|
+
],
|
|
2913
|
+
readonly: true
|
|
2914
|
+
// search_objects is always readonly
|
|
2838
2915
|
};
|
|
2839
2916
|
}
|
|
2840
2917
|
function buildCustomTool(toolConfig) {
|
|
2841
2918
|
return {
|
|
2842
2919
|
name: toolConfig.name,
|
|
2843
2920
|
description: toolConfig.description,
|
|
2844
|
-
parameters: customParamsToToolParams(toolConfig.parameters)
|
|
2921
|
+
parameters: customParamsToToolParams(toolConfig.parameters),
|
|
2922
|
+
statement: toolConfig.statement,
|
|
2923
|
+
readonly: toolConfig.readonly,
|
|
2924
|
+
max_rows: toolConfig.max_rows
|
|
2845
2925
|
};
|
|
2846
2926
|
}
|
|
2847
2927
|
function getToolsForSource(sourceId) {
|
|
@@ -2849,7 +2929,7 @@ function getToolsForSource(sourceId) {
|
|
|
2849
2929
|
const enabledToolConfigs = registry.getEnabledToolConfigs(sourceId);
|
|
2850
2930
|
return enabledToolConfigs.map((toolConfig) => {
|
|
2851
2931
|
if (toolConfig.name === "execute_sql") {
|
|
2852
|
-
return buildExecuteSqlTool(sourceId);
|
|
2932
|
+
return buildExecuteSqlTool(sourceId, toolConfig);
|
|
2853
2933
|
} else if (toolConfig.name === "search_objects") {
|
|
2854
2934
|
return buildSearchObjectsTool(sourceId);
|
|
2855
2935
|
} else {
|
|
@@ -2915,13 +2995,15 @@ function createCustomToolHandler(toolConfig) {
|
|
|
2915
2995
|
let paramValues = [];
|
|
2916
2996
|
try {
|
|
2917
2997
|
const validatedArgs = zodSchema.parse(args);
|
|
2998
|
+
await ConnectorManager.ensureConnected(toolConfig.source);
|
|
2918
2999
|
const connector = ConnectorManager.getCurrentConnector(toolConfig.source);
|
|
2919
|
-
const executeOptions =
|
|
2920
|
-
toolConfig.
|
|
2921
|
-
|
|
3000
|
+
const executeOptions = {
|
|
3001
|
+
readonly: toolConfig.readonly,
|
|
3002
|
+
maxRows: toolConfig.max_rows
|
|
3003
|
+
};
|
|
2922
3004
|
const isReadonly = executeOptions.readonly === true;
|
|
2923
3005
|
if (isReadonly && !isReadOnlySQL(toolConfig.statement, connector.id)) {
|
|
2924
|
-
errorMessage =
|
|
3006
|
+
errorMessage = createReadonlyViolationMessage(toolConfig.name, toolConfig.source, connector.id);
|
|
2925
3007
|
success = false;
|
|
2926
3008
|
return createToolErrorResponse(errorMessage, "READONLY_VIOLATION");
|
|
2927
3009
|
}
|
|
@@ -2936,7 +3018,7 @@ function createCustomToolHandler(toolConfig) {
|
|
|
2936
3018
|
);
|
|
2937
3019
|
const responseData = {
|
|
2938
3020
|
rows: result.rows,
|
|
2939
|
-
count: result.
|
|
3021
|
+
count: result.rowCount,
|
|
2940
3022
|
source_id: toolConfig.source
|
|
2941
3023
|
};
|
|
2942
3024
|
return createToolSuccessResponse(responseData);
|
|
@@ -2954,17 +3036,17 @@ Parameters: ${JSON.stringify(paramValues)}`;
|
|
|
2954
3036
|
}
|
|
2955
3037
|
return createToolErrorResponse(errorMessage, "EXECUTION_ERROR");
|
|
2956
3038
|
} finally {
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3039
|
+
trackToolRequest(
|
|
3040
|
+
{
|
|
3041
|
+
sourceId: toolConfig.source,
|
|
3042
|
+
toolName: toolConfig.name,
|
|
3043
|
+
sql: toolConfig.statement
|
|
3044
|
+
},
|
|
3045
|
+
startTime,
|
|
3046
|
+
extra,
|
|
2965
3047
|
success,
|
|
2966
|
-
|
|
2967
|
-
|
|
3048
|
+
errorMessage
|
|
3049
|
+
);
|
|
2968
3050
|
}
|
|
2969
3051
|
};
|
|
2970
3052
|
}
|
|
@@ -3039,7 +3121,6 @@ function registerCustomTool(server, sourceId, toolConfig) {
|
|
|
3039
3121
|
},
|
|
3040
3122
|
createCustomToolHandler(toolConfig)
|
|
3041
3123
|
);
|
|
3042
|
-
console.error(` - ${toolConfig.name} \u2192 ${toolConfig.source} (${dbType})`);
|
|
3043
3124
|
}
|
|
3044
3125
|
|
|
3045
3126
|
// src/api/sources.ts
|
|
@@ -3057,6 +3138,9 @@ function transformSourceConfig(source) {
|
|
|
3057
3138
|
id: source.id,
|
|
3058
3139
|
type: source.type
|
|
3059
3140
|
};
|
|
3141
|
+
if (source.description) {
|
|
3142
|
+
dataSource.description = source.description;
|
|
3143
|
+
}
|
|
3060
3144
|
if (source.host) {
|
|
3061
3145
|
dataSource.host = source.host;
|
|
3062
3146
|
}
|
|
@@ -3069,12 +3153,6 @@ function transformSourceConfig(source) {
|
|
|
3069
3153
|
if (source.user) {
|
|
3070
3154
|
dataSource.user = source.user;
|
|
3071
3155
|
}
|
|
3072
|
-
if (source.readonly !== void 0) {
|
|
3073
|
-
dataSource.readonly = source.readonly;
|
|
3074
|
-
}
|
|
3075
|
-
if (source.max_rows !== void 0) {
|
|
3076
|
-
dataSource.max_rows = source.max_rows;
|
|
3077
|
-
}
|
|
3078
3156
|
if (source.ssh_host) {
|
|
3079
3157
|
const sshTunnel = {
|
|
3080
3158
|
enabled: true,
|
|
@@ -3314,7 +3392,7 @@ See documentation for more details on configuring database connections.
|
|
|
3314
3392
|
const sources = sourceConfigsData.sources;
|
|
3315
3393
|
console.error(`Configuration source: ${sourceConfigsData.source}`);
|
|
3316
3394
|
await connectorManager.connectWithSources(sources);
|
|
3317
|
-
const { initializeToolRegistry } = await import("./registry-
|
|
3395
|
+
const { initializeToolRegistry } = await import("./registry-D77Y4CIA.js");
|
|
3318
3396
|
initializeToolRegistry({
|
|
3319
3397
|
sources: sourceConfigsData.sources,
|
|
3320
3398
|
tools: sourceConfigsData.tools
|
|
@@ -3343,7 +3421,7 @@ See documentation for more details on configuring database connections.
|
|
|
3343
3421
|
console.error(generateBanner(SERVER_VERSION, activeModes));
|
|
3344
3422
|
const sourceDisplayInfos = buildSourceDisplayInfo(
|
|
3345
3423
|
sources,
|
|
3346
|
-
(sourceId) => getToolsForSource(sourceId).map((t) => t.name),
|
|
3424
|
+
(sourceId) => getToolsForSource(sourceId).map((t) => t.readonly ? `\u{1F512} ${t.name}` : t.name),
|
|
3347
3425
|
isDemo
|
|
3348
3426
|
);
|
|
3349
3427
|
console.error(generateStartupTable(sourceDisplayInfos));
|
|
@@ -3404,11 +3482,11 @@ See documentation for more details on configuring database connections.
|
|
|
3404
3482
|
app.listen(port, "0.0.0.0", () => {
|
|
3405
3483
|
if (process.env.NODE_ENV === "development") {
|
|
3406
3484
|
console.error("Development mode detected!");
|
|
3407
|
-
console.error("
|
|
3485
|
+
console.error(" Workbench dev server (with HMR): http://localhost:5173");
|
|
3408
3486
|
console.error(" Backend API: http://localhost:8080");
|
|
3409
3487
|
console.error("");
|
|
3410
3488
|
} else {
|
|
3411
|
-
console.error(`
|
|
3489
|
+
console.error(`Workbench at http://localhost:${port}/`);
|
|
3412
3490
|
}
|
|
3413
3491
|
console.error(`MCP server endpoint at http://localhost:${port}/mcp`);
|
|
3414
3492
|
});
|