@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/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  resolveSourceConfigs,
17
17
  resolveTransport,
18
18
  stripCommentsAndStrings
19
- } from "./chunk-WGDSRFBW.js";
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
- return await client.query(processedStatement, parameters);
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 await client.query(processedStatement);
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
- if (writeStatements.length > 0) {
1259
- this.db.exec(writeStatements.join("; "));
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
- return { rows };
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
- return { rows };
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 || "default";
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 for source '${actualSourceId}'. Only the following SQL operations are allowed: ${allowedKeywords[connector.id]?.join(", ") || "none"}`;
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: isReadonly,
2309
- max_rows: toolConfig?.max_rows
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.rows.length,
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
- requestStore.add({
2324
- id: crypto.randomUUID(),
2325
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2326
- sourceId: effectiveSourceId,
2327
- toolName: effectiveSourceId === "default" ? "execute_sql" : `execute_sql_${effectiveSourceId}`,
2328
- sql: sql2,
2329
- durationMs: Date.now() - startTime,
2330
- client: getClientIdentifier(extra),
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
- error: errorMessage
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, _extra) => {
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
- return createToolErrorResponse(
2634
- "The 'table' parameter requires 'schema' to be specified",
2635
- "SCHEMA_REQUIRED"
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
- return createToolErrorResponse(
2640
- `The 'table' parameter only applies to object_type 'column' or 'index', not '${object_type}'`,
2641
- "INVALID_TABLE_FILTER"
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
- return createToolErrorResponse(
2649
- `Schema '${schema}' does not exist. Available schemas: ${schemas.join(", ")}`,
2650
- "SCHEMA_NOT_FOUND"
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
- return createToolErrorResponse(
2673
- `Unsupported object_type: ${object_type}`,
2674
- "INVALID_OBJECT_TYPE"
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: ${error.message}`,
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 = ConnectorManager.getCurrentExecuteOptions(
2920
- toolConfig.source
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 = `Tool '${toolConfig.name}' cannot execute in readonly mode for source '${toolConfig.source}'. Only read-only SQL operations are allowed: ${allowedKeywords[connector.id]?.join(", ") || "none"}`;
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.rows.length,
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
- requestStore.add({
2958
- id: crypto.randomUUID(),
2959
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2960
- sourceId: toolConfig.source,
2961
- toolName: toolConfig.name,
2962
- sql: toolConfig.statement,
2963
- durationMs: Date.now() - startTime,
2964
- client: getClientIdentifier(extra),
3039
+ trackToolRequest(
3040
+ {
3041
+ sourceId: toolConfig.source,
3042
+ toolName: toolConfig.name,
3043
+ sql: toolConfig.statement
3044
+ },
3045
+ startTime,
3046
+ extra,
2965
3047
  success,
2966
- error: errorMessage
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-FVGT25UH.js");
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(" Admin console dev server (with HMR): http://localhost:5173");
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(`Admin console at http://localhost:${port}/`);
3489
+ console.error(`Workbench at http://localhost:${port}/`);
3412
3490
  }
3413
3491
  console.error(`MCP server endpoint at http://localhost:${port}/mcp`);
3414
3492
  });