@bytebase/dbhub 0.8.2 → 0.9.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 CHANGED
@@ -24,8 +24,6 @@ DBHub is a universal database gateway implementing the Model Context Protocol (M
24
24
  | | | | | |
25
25
  | Cursor +--->+ DBHub +--->+ SQL Server |
26
26
  | | | | | |
27
- | Other Clients +--->+ +--->+ SQLite |
28
- | | | | | |
29
27
  | | | +--->+ MySQL |
30
28
  | | | | | |
31
29
  | | | +--->+ MariaDB |
@@ -44,27 +42,27 @@ https://demo.dbhub.ai/message connects a [sample employee database](https://gith
44
42
 
45
43
  ### Database Resources
46
44
 
47
- | Resource Name | URI Format | PostgreSQL | MySQL | MariaDB | SQL Server | SQLite |
48
- | --------------------------- | ------------------------------------------------------ | :--------: | :---: | :-----: | :--------: | :----: |
49
- | schemas | `db://schemas` | ✅ | ✅ | ✅ | ✅ | ✅ |
50
- | tables_in_schema | `db://schemas/{schemaName}/tables` | ✅ | ✅ | ✅ | ✅ | ✅ |
51
- | table_structure_in_schema | `db://schemas/{schemaName}/tables/{tableName}` | ✅ | ✅ | ✅ | ✅ | ✅ |
52
- | indexes_in_table | `db://schemas/{schemaName}/tables/{tableName}/indexes` | ✅ | ✅ | ✅ | ✅ | ✅ |
53
- | procedures_in_schema | `db://schemas/{schemaName}/procedures` | ✅ | ✅ | ✅ | ✅ | ❌ |
54
- | procedure_details_in_schema | `db://schemas/{schemaName}/procedures/{procedureName}` | ✅ | ✅ | ✅ | ✅ | ❌ |
45
+ | Resource Name | URI Format | PostgreSQL | MySQL | MariaDB | SQL Server |
46
+ | --------------------------- | ------------------------------------------------------ | :--------: | :---: | :-----: | :--------: |
47
+ | schemas | `db://schemas` | ✅ | ✅ | ✅ | ✅ |
48
+ | tables_in_schema | `db://schemas/{schemaName}/tables` | ✅ | ✅ | ✅ | ✅ |
49
+ | table_structure_in_schema | `db://schemas/{schemaName}/tables/{tableName}` | ✅ | ✅ | ✅ | ✅ |
50
+ | indexes_in_table | `db://schemas/{schemaName}/tables/{tableName}/indexes` | ✅ | ✅ | ✅ | ✅ |
51
+ | procedures_in_schema | `db://schemas/{schemaName}/procedures` | ✅ | ✅ | ✅ | ✅ |
52
+ | procedure_details_in_schema | `db://schemas/{schemaName}/procedures/{procedureName}` | ✅ | ✅ | ✅ | ✅ |
55
53
 
56
54
  ### Database Tools
57
55
 
58
- | Tool | Command Name | Description | PostgreSQL | MySQL | MariaDB | SQL Server | SQLite |
59
- | ----------- | ------------- | ------------------------------------------------------------------- | :--------: | :---: | :-----: | :--------: | ------ |
60
- | Execute SQL | `execute_sql` | Execute single or multiple SQL statements (separated by semicolons) | ✅ | ✅ | ✅ | ✅ | ✅ |
56
+ | Tool | Command Name | Description | PostgreSQL | MySQL | MariaDB | SQL Server |
57
+ | ----------- | ------------- | ------------------------------------------------------------------- | :--------: | :---: | :-----: | :--------: |
58
+ | Execute SQL | `execute_sql` | Execute single or multiple SQL statements (separated by semicolons) | ✅ | ✅ | ✅ | ✅ |
61
59
 
62
60
  ### Prompt Capabilities
63
61
 
64
- | Prompt | Command Name | PostgreSQL | MySQL | MariaDB | SQL Server | SQLite |
65
- | ------------------- | -------------- | :--------: | :---: | :-----: | :--------: | ------ |
66
- | Generate SQL | `generate_sql` | ✅ | ✅ | ✅ | ✅ | ✅ |
67
- | Explain DB Elements | `explain_db` | ✅ | ✅ | ✅ | ✅ | ✅ |
62
+ | Prompt | Command Name | PostgreSQL | MySQL | MariaDB | SQL Server |
63
+ | ------------------- | -------------- | :--------: | :---: | :-----: | :--------: |
64
+ | Generate SQL | `generate_sql` | ✅ | ✅ | ✅ | ✅ |
65
+ | Explain DB Elements | `explain_db` | ✅ | ✅ | ✅ | ✅ |
68
66
 
69
67
  ## Installation
70
68
 
@@ -81,16 +79,6 @@ docker run --rm --init \
81
79
  --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
82
80
  ```
83
81
 
84
- ```bash
85
- # Demo mode with sample employee database
86
- docker run --rm --init \
87
- --name dbhub \
88
- --publish 8080:8080 \
89
- bytebase/dbhub \
90
- --transport http \
91
- --port 8080 \
92
- --demo
93
- ```
94
82
 
95
83
 
96
84
  ### NPM
@@ -100,12 +88,6 @@ docker run --rm --init \
100
88
  npx @bytebase/dbhub --transport http --port 8080 --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
101
89
  ```
102
90
 
103
- ```bash
104
- # Demo mode with sample employee database
105
- npx @bytebase/dbhub --transport http --port 8080 --demo
106
- ```
107
-
108
- > Note: The demo mode includes a bundled SQLite sample "employee" database with tables for employees, departments, salaries, and more.
109
91
 
110
92
  ### Claude Desktop
111
93
 
@@ -142,10 +124,6 @@ npx @bytebase/dbhub --transport http --port 8080 --demo
142
124
  "postgres://user:password@localhost:5432/dbname?sslmode=disable"
143
125
  ]
144
126
  },
145
- "dbhub-demo": {
146
- "command": "npx",
147
- "args": ["-y", "@bytebase/dbhub", "--transport", "stdio", "--demo"]
148
- }
149
127
  }
150
128
  }
151
129
  ```
@@ -171,7 +149,6 @@ You can specify the SSL mode using the `sslmode` parameter in your DSN string:
171
149
  | MySQL | ✅ | ✅ | Certificate verification |
172
150
  | MariaDB | ✅ | ✅ | Certificate verification |
173
151
  | SQL Server | ✅ | ✅ | Certificate verification |
174
- | SQLite | ❌ | ❌ | N/A (file-based) |
175
152
 
176
153
  **SSL Mode Options:**
177
154
 
@@ -208,12 +185,6 @@ This provides an additional layer of security when connecting to production data
208
185
 
209
186
  ### Configure your database connection
210
187
 
211
- You can use DBHub in demo mode with a sample employee database for testing:
212
-
213
- ```bash
214
- npx @bytebase/dbhub --demo
215
- ```
216
-
217
188
  > [!WARNING]
218
189
  > If your user/password contains special characters, you need to escape them first. (e.g. `pass#word` should be escaped as `pass%23word`)
219
190
 
@@ -250,7 +221,6 @@ DBHub supports the following database connection string formats:
250
221
  | MariaDB | `mariadb://[user]:[password]@[host]:[port]/[database]` | `mariadb://user:password@localhost:3306/dbname?sslmode=disable` |
251
222
  | PostgreSQL | `postgres://[user]:[password]@[host]:[port]/[database]` | `postgres://user:password@localhost:5432/dbname?sslmode=disable` |
252
223
  | SQL Server | `sqlserver://[user]:[password]@[host]:[port]/[database]` | `sqlserver://user:password@localhost:1433/dbname?sslmode=disable` |
253
- | SQLite | `sqlite:///[path/to/file]` or `sqlite:///:memory:` | `sqlite:///path/to/database.db`, `sqlite:C:/Users/YourName/data/database.db (windows)` or `sqlite:///:memory:` |
254
224
 
255
225
 
256
226
  #### SQL Server
@@ -276,15 +246,13 @@ Extra query parameters:
276
246
 
277
247
  ### Command line options
278
248
 
279
- | Option | Environment Variable | Description | Default |
280
- | --------- | -------------------- | ---------------------------------------------------------------- | ---------------------------- |
281
- | dsn | `DSN` | Database connection string | Required if not in demo mode |
282
- | transport | `TRANSPORT` | Transport mode: `stdio` or `http` | `stdio` |
283
- | port | `PORT` | HTTP server port (only applicable when using `--transport=http`) | `8080` |
284
- | readonly | `READONLY` | Restrict SQL execution to read-only operations | `false` |
285
- | demo | N/A | Run in demo mode with sample employee database | `false` |
249
+ | Option | Environment Variable | Description | Default |
250
+ | --------- | -------------------- | ---------------------------------------------------------------- | -------- |
251
+ | dsn | `DSN` | Database connection string | Required |
252
+ | transport | `TRANSPORT` | Transport mode: `stdio` or `http` | `stdio` |
253
+ | port | `PORT` | HTTP server port (only applicable when using `--transport=http`) | `8080` |
254
+ | readonly | `READONLY` | Restrict SQL execution to read-only operations | `false` |
286
255
 
287
- The demo mode uses an in-memory SQLite database loaded with the [sample employee database](https://github.com/bytebase/dbhub/tree/main/resources/employee-sqlite) that includes tables for employees, departments, titles, salaries, department employees, and department managers. The sample database includes SQL scripts for table creation, data loading, and testing.
288
256
 
289
257
  ## Development
290
258
 
@@ -342,8 +310,6 @@ pnpm test src/connectors/__tests__/mysql.integration.test.ts
342
310
  pnpm test src/connectors/__tests__/mariadb.integration.test.ts
343
311
  # Run only SQL Server integration tests
344
312
  pnpm test src/connectors/__tests__/sqlserver.integration.test.ts
345
- # Run only SQLite integration tests
346
- pnpm test src/connectors/__tests__/sqlite.integration.test.ts
347
313
  # Run JSON RPC integration tests
348
314
  pnpm test src/__tests__/json-rpc-integration.test.ts
349
315
  ```
package/dist/index.js CHANGED
@@ -159,9 +159,6 @@ function obfuscateDSNPassword(dsn) {
159
159
  return dsn;
160
160
  }
161
161
  const protocol = protocolMatch[1];
162
- if (protocol === "sqlite") {
163
- return dsn;
164
- }
165
162
  const protocolPart = dsn.split("://")[1];
166
163
  if (!protocolPart) {
167
164
  return dsn;
@@ -879,246 +876,6 @@ var SQLServerConnector = class {
879
876
  var sqlServerConnector = new SQLServerConnector();
880
877
  ConnectorRegistry.register(sqlServerConnector);
881
878
 
882
- // src/connectors/sqlite/index.ts
883
- import Database from "better-sqlite3";
884
- var SQLiteDSNParser = class {
885
- async parse(dsn) {
886
- if (!this.isValidDSN(dsn)) {
887
- const obfuscatedDSN = obfuscateDSNPassword(dsn);
888
- const expectedFormat = this.getSampleDSN();
889
- throw new Error(
890
- `Invalid SQLite DSN format.
891
- Provided: ${obfuscatedDSN}
892
- Expected: ${expectedFormat}`
893
- );
894
- }
895
- try {
896
- const url = new SafeURL(dsn);
897
- let dbPath;
898
- if (url.hostname === "" && url.pathname === "/:memory:") {
899
- dbPath = ":memory:";
900
- } else {
901
- if (url.pathname.startsWith("//")) {
902
- dbPath = url.pathname.substring(2);
903
- } else {
904
- dbPath = url.pathname;
905
- }
906
- }
907
- return { dbPath };
908
- } catch (error) {
909
- throw new Error(
910
- `Failed to parse SQLite DSN: ${error instanceof Error ? error.message : String(error)}`
911
- );
912
- }
913
- }
914
- getSampleDSN() {
915
- return "sqlite:///path/to/database.db";
916
- }
917
- isValidDSN(dsn) {
918
- try {
919
- return dsn.startsWith("sqlite://");
920
- } catch (error) {
921
- return false;
922
- }
923
- }
924
- };
925
- var SQLiteConnector = class {
926
- constructor() {
927
- this.id = "sqlite";
928
- this.name = "SQLite";
929
- this.dsnParser = new SQLiteDSNParser();
930
- this.db = null;
931
- this.dbPath = ":memory:";
932
- }
933
- // Default to in-memory database
934
- async connect(dsn, initScript) {
935
- const config = await this.dsnParser.parse(dsn);
936
- this.dbPath = config.dbPath;
937
- try {
938
- this.db = new Database(this.dbPath);
939
- console.error("Successfully connected to SQLite database");
940
- if (initScript) {
941
- this.db.exec(initScript);
942
- console.error("Successfully initialized database with script");
943
- }
944
- } catch (error) {
945
- console.error("Failed to connect to SQLite database:", error);
946
- throw error;
947
- }
948
- }
949
- async disconnect() {
950
- if (this.db) {
951
- try {
952
- this.db.close();
953
- this.db = null;
954
- } catch (error) {
955
- throw error;
956
- }
957
- }
958
- return Promise.resolve();
959
- }
960
- async getSchemas() {
961
- if (!this.db) {
962
- throw new Error("Not connected to SQLite database");
963
- }
964
- return ["main"];
965
- }
966
- async getTables(schema) {
967
- if (!this.db) {
968
- throw new Error("Not connected to SQLite database");
969
- }
970
- try {
971
- const rows = this.db.prepare(
972
- `
973
- SELECT name FROM sqlite_master
974
- WHERE type='table' AND name NOT LIKE 'sqlite_%'
975
- ORDER BY name
976
- `
977
- ).all();
978
- return rows.map((row) => row.name);
979
- } catch (error) {
980
- throw error;
981
- }
982
- }
983
- async tableExists(tableName, schema) {
984
- if (!this.db) {
985
- throw new Error("Not connected to SQLite database");
986
- }
987
- try {
988
- const row = this.db.prepare(
989
- `
990
- SELECT name FROM sqlite_master
991
- WHERE type='table' AND name = ?
992
- `
993
- ).get(tableName);
994
- return !!row;
995
- } catch (error) {
996
- throw error;
997
- }
998
- }
999
- async getTableIndexes(tableName, schema) {
1000
- if (!this.db) {
1001
- throw new Error("Not connected to SQLite database");
1002
- }
1003
- try {
1004
- const indexInfoRows = this.db.prepare(
1005
- `
1006
- SELECT
1007
- name as index_name,
1008
- 0 as is_unique
1009
- FROM sqlite_master
1010
- WHERE type = 'index'
1011
- AND tbl_name = ?
1012
- `
1013
- ).all(tableName);
1014
- const indexListRows = this.db.prepare(`PRAGMA index_list(${tableName})`).all();
1015
- const indexUniqueMap = /* @__PURE__ */ new Map();
1016
- for (const indexListRow of indexListRows) {
1017
- indexUniqueMap.set(indexListRow.name, indexListRow.unique === 1);
1018
- }
1019
- const tableInfo = this.db.prepare(`PRAGMA table_info(${tableName})`).all();
1020
- const pkColumns = tableInfo.filter((col) => col.pk > 0).map((col) => col.name);
1021
- const results = [];
1022
- for (const indexInfo of indexInfoRows) {
1023
- const indexDetailRows = this.db.prepare(`PRAGMA index_info(${indexInfo.index_name})`).all();
1024
- const columnNames = indexDetailRows.map((row) => row.name);
1025
- results.push({
1026
- index_name: indexInfo.index_name,
1027
- column_names: columnNames,
1028
- is_unique: indexUniqueMap.get(indexInfo.index_name) || false,
1029
- is_primary: false
1030
- });
1031
- }
1032
- if (pkColumns.length > 0) {
1033
- results.push({
1034
- index_name: "PRIMARY",
1035
- column_names: pkColumns,
1036
- is_unique: true,
1037
- is_primary: true
1038
- });
1039
- }
1040
- return results;
1041
- } catch (error) {
1042
- throw error;
1043
- }
1044
- }
1045
- async getTableSchema(tableName, schema) {
1046
- if (!this.db) {
1047
- throw new Error("Not connected to SQLite database");
1048
- }
1049
- try {
1050
- const rows = this.db.prepare(`PRAGMA table_info(${tableName})`).all();
1051
- const columns = rows.map((row) => ({
1052
- column_name: row.name,
1053
- data_type: row.type,
1054
- // In SQLite, primary key columns are automatically NOT NULL even if notnull=0
1055
- is_nullable: row.notnull === 1 || row.pk > 0 ? "NO" : "YES",
1056
- column_default: row.dflt_value
1057
- }));
1058
- return columns;
1059
- } catch (error) {
1060
- throw error;
1061
- }
1062
- }
1063
- async getStoredProcedures(schema) {
1064
- if (!this.db) {
1065
- throw new Error("Not connected to SQLite database");
1066
- }
1067
- return [];
1068
- }
1069
- async getStoredProcedureDetail(procedureName, schema) {
1070
- if (!this.db) {
1071
- throw new Error("Not connected to SQLite database");
1072
- }
1073
- throw new Error(
1074
- "SQLite does not support stored procedures. Functions are defined programmatically through the SQLite API, not stored in the database."
1075
- );
1076
- }
1077
- async executeSQL(sql2) {
1078
- if (!this.db) {
1079
- throw new Error("Not connected to SQLite database");
1080
- }
1081
- try {
1082
- const statements = sql2.split(";").map((statement) => statement.trim()).filter((statement) => statement.length > 0);
1083
- if (statements.length === 1) {
1084
- const trimmedStatement = statements[0].toLowerCase().trim();
1085
- const isReadStatement = trimmedStatement.startsWith("select") || trimmedStatement.startsWith("with") || trimmedStatement.startsWith("explain") || trimmedStatement.startsWith("analyze") || trimmedStatement.startsWith("pragma") && (trimmedStatement.includes("table_info") || trimmedStatement.includes("index_info") || trimmedStatement.includes("index_list") || trimmedStatement.includes("foreign_key_list"));
1086
- if (isReadStatement) {
1087
- const rows = this.db.prepare(statements[0]).all();
1088
- return { rows };
1089
- } else {
1090
- this.db.prepare(statements[0]).run();
1091
- return { rows: [] };
1092
- }
1093
- } else {
1094
- const readStatements = [];
1095
- const writeStatements = [];
1096
- for (const statement of statements) {
1097
- const trimmedStatement = statement.toLowerCase().trim();
1098
- if (trimmedStatement.startsWith("select") || trimmedStatement.startsWith("with") || trimmedStatement.startsWith("explain") || trimmedStatement.startsWith("analyze") || trimmedStatement.startsWith("pragma") && (trimmedStatement.includes("table_info") || trimmedStatement.includes("index_info") || trimmedStatement.includes("index_list") || trimmedStatement.includes("foreign_key_list"))) {
1099
- readStatements.push(statement);
1100
- } else {
1101
- writeStatements.push(statement);
1102
- }
1103
- }
1104
- if (writeStatements.length > 0) {
1105
- this.db.exec(writeStatements.join("; "));
1106
- }
1107
- let allRows = [];
1108
- for (const statement of readStatements) {
1109
- const result = this.db.prepare(statement).all();
1110
- allRows.push(...result);
1111
- }
1112
- return { rows: allRows };
1113
- }
1114
- } catch (error) {
1115
- throw error;
1116
- }
1117
- }
1118
- };
1119
- var sqliteConnector = new SQLiteConnector();
1120
- ConnectorRegistry.register(sqliteConnector);
1121
-
1122
879
  // src/connectors/mysql/index.ts
1123
880
  import mysql from "mysql2/promise";
1124
881
  var MySQLDSNParser = class {
@@ -1880,9 +1637,9 @@ import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js
1880
1637
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
1881
1638
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
1882
1639
  import express from "express";
1883
- import path3 from "path";
1640
+ import path2 from "path";
1884
1641
  import { readFileSync } from "fs";
1885
- import { fileURLToPath as fileURLToPath3 } from "url";
1642
+ import { fileURLToPath as fileURLToPath2 } from "url";
1886
1643
 
1887
1644
  // src/connectors/manager.ts
1888
1645
  var managerInstance = null;
@@ -2016,10 +1773,6 @@ function loadEnvFiles() {
2016
1773
  }
2017
1774
  return null;
2018
1775
  }
2019
- function isDemoMode() {
2020
- const args = parseCommandLineArgs();
2021
- return args.demo === "true";
2022
- }
2023
1776
  function isReadOnlyMode() {
2024
1777
  const args = parseCommandLineArgs();
2025
1778
  if (args.readonly !== void 0) {
@@ -2032,13 +1785,6 @@ function isReadOnlyMode() {
2032
1785
  }
2033
1786
  function resolveDSN() {
2034
1787
  const args = parseCommandLineArgs();
2035
- if (isDemoMode()) {
2036
- return {
2037
- dsn: "sqlite:///:memory:",
2038
- source: "demo mode",
2039
- isDemo: true
2040
- };
2041
- }
2042
1788
  if (args.dsn) {
2043
1789
  return { dsn: args.dsn, source: "command line argument" };
2044
1790
  }
@@ -2087,45 +1833,6 @@ function redactDSN(dsn) {
2087
1833
  }
2088
1834
  }
2089
1835
 
2090
- // src/config/demo-loader.ts
2091
- import fs2 from "fs";
2092
- import path2 from "path";
2093
- import { fileURLToPath as fileURLToPath2 } from "url";
2094
- var __filename2 = fileURLToPath2(import.meta.url);
2095
- var __dirname2 = path2.dirname(__filename2);
2096
- var DEMO_DATA_DIR;
2097
- var projectRootPath = path2.join(__dirname2, "..", "..", "..");
2098
- var projectResourcesPath = path2.join(projectRootPath, "resources", "employee-sqlite");
2099
- var distPath = path2.join(__dirname2, "resources", "employee-sqlite");
2100
- if (fs2.existsSync(projectResourcesPath)) {
2101
- DEMO_DATA_DIR = projectResourcesPath;
2102
- } else if (fs2.existsSync(distPath)) {
2103
- DEMO_DATA_DIR = distPath;
2104
- } else {
2105
- DEMO_DATA_DIR = path2.join(process.cwd(), "resources", "employee-sqlite");
2106
- if (!fs2.existsSync(DEMO_DATA_DIR)) {
2107
- throw new Error(`Could not find employee-sqlite resources in any of the expected locations:
2108
- - ${projectResourcesPath}
2109
- - ${distPath}
2110
- - ${DEMO_DATA_DIR}`);
2111
- }
2112
- }
2113
- function loadSqlFile(fileName) {
2114
- const filePath = path2.join(DEMO_DATA_DIR, fileName);
2115
- return fs2.readFileSync(filePath, "utf8");
2116
- }
2117
- function getSqliteInMemorySetupSql() {
2118
- let sql2 = loadSqlFile("employee.sql");
2119
- const readRegex = /\.read\s+([a-zA-Z0-9_]+\.sql)/g;
2120
- let match;
2121
- while ((match = readRegex.exec(sql2)) !== null) {
2122
- const includePath = match[1];
2123
- const includeContent = loadSqlFile(includePath);
2124
- sql2 = sql2.replace(match[0], includeContent);
2125
- }
2126
- return sql2;
2127
- }
2128
-
2129
1836
  // src/resources/index.ts
2130
1837
  import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
2131
1838
 
@@ -2478,7 +2185,6 @@ var allowedKeywords = {
2478
2185
  postgres: ["select", "with", "explain", "analyze", "show"],
2479
2186
  mysql: ["select", "with", "explain", "analyze", "show", "describe", "desc"],
2480
2187
  mariadb: ["select", "with", "explain", "analyze", "show", "describe", "desc"],
2481
- sqlite: ["select", "with", "explain", "analyze", "pragma"],
2482
2188
  sqlserver: ["select", "with", "explain", "showplan"]
2483
2189
  };
2484
2190
 
@@ -2546,9 +2252,6 @@ async function sqlGeneratorPromptHandler({
2546
2252
  case "postgres":
2547
2253
  sqlDialect = "postgres";
2548
2254
  break;
2549
- case "sqlite":
2550
- sqlDialect = "sqlite";
2551
- break;
2552
2255
  case "mysql":
2553
2256
  sqlDialect = "mysql";
2554
2257
  break;
@@ -2609,11 +2312,6 @@ ${accessibleSchemas.map(
2609
2312
  "SELECT u.name, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.name HAVING COUNT(o.id) > 5",
2610
2313
  "SELECT product_name, price FROM products WHERE price > (SELECT AVG(price) FROM products)"
2611
2314
  ],
2612
- sqlite: [
2613
- "SELECT * FROM users WHERE created_at > datetime('now', '-1 day')",
2614
- "SELECT u.name, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.name HAVING COUNT(o.id) > 5",
2615
- "SELECT product_name, price FROM products WHERE price > (SELECT AVG(price) FROM products)"
2616
- ],
2617
2315
  mysql: [
2618
2316
  "SELECT * FROM users WHERE created_at > NOW() - INTERVAL 1 DAY",
2619
2317
  "SELECT u.name, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.name HAVING COUNT(o.id) > 5",
@@ -2945,9 +2643,9 @@ function registerPrompts(server) {
2945
2643
  }
2946
2644
 
2947
2645
  // src/server.ts
2948
- var __filename3 = fileURLToPath3(import.meta.url);
2949
- var __dirname3 = path3.dirname(__filename3);
2950
- var packageJsonPath = path3.join(__dirname3, "..", "package.json");
2646
+ var __filename2 = fileURLToPath2(import.meta.url);
2647
+ var __dirname2 = path2.dirname(__filename2);
2648
+ var packageJsonPath = path2.join(__dirname2, "..", "package.json");
2951
2649
  var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
2952
2650
  var SERVER_NAME = "DBHub MCP Server";
2953
2651
  var SERVER_VERSION = packageJson.version;
@@ -2974,8 +2672,7 @@ async function main() {
2974
2672
  ERROR: Database connection string (DSN) is required.
2975
2673
  Please provide the DSN in one of these ways (in order of priority):
2976
2674
 
2977
- 1. Use demo mode: --demo (uses in-memory SQLite with sample employee database)
2978
- 2. Command line argument: --dsn="your-connection-string"
2675
+ 1. Command line argument: --dsn="your-connection-string"
2979
2676
  3. Environment variable: export DSN="your-connection-string"
2980
2677
  4. .env file: DSN=your-connection-string
2981
2678
 
@@ -2999,22 +2696,13 @@ See documentation for more details on configuring database connections.
2999
2696
  const connectorManager = new ConnectorManager();
3000
2697
  console.error(`Connecting with DSN: ${redactDSN(dsnData.dsn)}`);
3001
2698
  console.error(`DSN source: ${dsnData.source}`);
3002
- if (dsnData.isDemo) {
3003
- const initScript = getSqliteInMemorySetupSql();
3004
- await connectorManager.connectWithDSN(dsnData.dsn, initScript);
3005
- } else {
3006
- await connectorManager.connectWithDSN(dsnData.dsn);
3007
- }
2699
+ await connectorManager.connectWithDSN(dsnData.dsn);
3008
2700
  const transportData = resolveTransport();
3009
2701
  console.error(`Using transport: ${transportData.type}`);
3010
2702
  console.error(`Transport source: ${transportData.source}`);
3011
2703
  const readonly = isReadOnlyMode();
3012
2704
  const activeModes = [];
3013
2705
  const modeDescriptions = [];
3014
- if (dsnData.isDemo) {
3015
- activeModes.push("DEMO");
3016
- modeDescriptions.push("using sample employee database");
3017
- }
3018
2706
  if (readonly) {
3019
2707
  activeModes.push("READ-ONLY");
3020
2708
  modeDescriptions.push("only read only queries allowed");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebase/dbhub",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "Universal Database MCP Server",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -18,7 +18,6 @@
18
18
  "dependencies": {
19
19
  "@azure/identity": "^4.8.0",
20
20
  "@modelcontextprotocol/sdk": "^1.12.1",
21
- "better-sqlite3": "^11.9.0",
22
21
  "dotenv": "^16.4.7",
23
22
  "express": "^4.18.2",
24
23
  "mariadb": "^3.4.0",
@@ -32,7 +31,6 @@
32
31
  "@testcontainers/mssqlserver": "^11.0.3",
33
32
  "@testcontainers/mysql": "^11.0.3",
34
33
  "@testcontainers/postgresql": "^11.0.3",
35
- "@types/better-sqlite3": "^7.6.12",
36
34
  "@types/express": "^4.17.21",
37
35
  "@types/mssql": "^9.1.7",
38
36
  "@types/node": "^22.13.10",
@@ -61,7 +59,7 @@
61
59
  "src/**/*"
62
60
  ],
63
61
  "lint-staged": {
64
- "*.{js,ts}": "vitest related --run"
62
+ "*.{js,ts}": "pnpm run test:pre-commit"
65
63
  },
66
64
  "scripts": {
67
65
  "build": "tsup",
@@ -71,6 +69,7 @@
71
69
  "test": "vitest run",
72
70
  "test:watch": "vitest",
73
71
  "test:integration": "vitest run --testNamePattern='Integration Tests'",
72
+ "test:pre-commit": "vitest related --run --exclude '**/sqlserver.integration.test.ts'",
74
73
  "pre-commit": "lint-staged"
75
74
  }
76
75
  }