diff --git a/README.md b/README.md
index c628b36018..150f2c5b9a 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,7 @@
### 40+ Databases, One Tool
-MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Redshift, DM, TDengine, CockroachDB, Access, HighGo, and more. Agent/JDBC-oriented profiles extend DBX to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, and custom JDBC connections. All in a single ~15 MB app. No bundled Chromium.
+MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Redshift, DM, TDengine, XuguDB, CockroachDB, Access, HighGo, and more. Agent/JDBC-oriented profiles extend DBX to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, and custom JDBC connections. All in a single ~15 MB app. No bundled Chromium.
### Query Editor
@@ -290,7 +290,7 @@ DBX is 15 MB with no runtime dependencies (no Java, no Python). It includes AI a
What databases are supported?
-MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Redshift, DM, TDengine, CockroachDB, Access, HighGo, and more. JDBC-oriented profiles extend support to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, and custom JDBC connections.
+MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Redshift, DM, TDengine, XuguDB, CockroachDB, Access, HighGo, and more. JDBC-oriented profiles extend support to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, and custom JDBC connections.
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 55ceb23319..ded6d0d6c4 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -82,7 +82,7 @@
### 40+ 种数据库,一个工具搞定
-MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Redshift、DM、TDengine、CockroachDB、Access、HighGo 等数据库都能直接连接。Agent/JDBC 方向的配置还可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB 和自定义 JDBC。全部装进约 15 MB 的应用里,不内嵌 Chromium。
+MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Redshift、DM、TDengine、虚谷 XuguDB、CockroachDB、Access、HighGo 等数据库都能直接连接。Agent/JDBC 方向的配置还可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB 和自定义 JDBC。全部装进约 15 MB 的应用里,不内嵌 Chromium。
### 查询编辑器
@@ -290,7 +290,7 @@ DBX 仅 15 MB,无需运行时依赖(无需 Java、无需 Python)。AI 和
支持哪些数据库?
-MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Redshift、DM、TDengine、CockroachDB、Access、HighGo 等。JDBC 方向配置可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB 及自定义 JDBC 连接。
+MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Redshift、DM、TDengine、虚谷 XuguDB、CockroachDB、Access、HighGo 等。JDBC 方向配置可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB 及自定义 JDBC 连接。
diff --git a/apps/desktop/public/icons/database/xugu.png b/apps/desktop/public/icons/database/xugu.png
new file mode 100644
index 0000000000..e564ac2294
Binary files /dev/null and b/apps/desktop/public/icons/database/xugu.png differ
diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue
index 19f687c8c0..582030b767 100644
--- a/apps/desktop/src/components/connection/ConnectionDialog.vue
+++ b/apps/desktop/src/components/connection/ConnectionDialog.vue
@@ -257,6 +257,7 @@ const driverProfiles: Record<
sundb: { type: "sundb", port: 22000, user: "root", label: "SunDB", icon: "sundb" },
jdbc: { type: "jdbc", port: 0, user: "", label: "JDBC", icon: "jdbc" },
tdengine: { type: "tdengine", port: 6041, user: "root", label: "TDengine", icon: "tdengine" },
+ xugu: { type: "xugu", port: 5138, user: "", label: "虚谷 XuguDB", icon: "xugu" },
iris: { type: "iris", port: 1972, user: "_SYSTEM", label: "IRIS", icon: "iris" },
custom_mysql: {
type: "mysql",
@@ -486,6 +487,7 @@ const iconTypeMap: Record = {
redshift: "redshift",
cockroachdb: "cockroachdb",
tdengine: "tdengine",
+ xugu: "xugu",
dm: "dm",
h2: "h2",
snowflake: "snowflake",
@@ -554,6 +556,7 @@ const dbOptions = [
{ value: "bigquery", label: "BigQuery" },
{ value: "kylin", label: "Kylin" },
{ value: "sundb", label: "SunDB" },
+ { value: "xugu", label: "虚谷 XuguDB" },
{ value: "iris", label: "IRIS" },
{ value: "jdbc", label: "JDBC" },
{ value: "custom_mysql", label: "Custom (MySQL)" },
diff --git a/apps/desktop/src/components/icons/DatabaseIcon.vue b/apps/desktop/src/components/icons/DatabaseIcon.vue
index c1892dd5d9..76d88fd913 100644
--- a/apps/desktop/src/components/icons/DatabaseIcon.vue
+++ b/apps/desktop/src/components/icons/DatabaseIcon.vue
@@ -62,6 +62,7 @@ const assetIcons: Record = {
tdsql: "tdsql.webp",
polardb: "polardb.webp",
greatsql: "greatsql.webp",
+ xugu: "xugu.png",
iris: "iris.png",
};
diff --git a/apps/desktop/src/lib/connectionPresentation.ts b/apps/desktop/src/lib/connectionPresentation.ts
index 733d470a9b..be4eb0a166 100644
--- a/apps/desktop/src/lib/connectionPresentation.ts
+++ b/apps/desktop/src/lib/connectionPresentation.ts
@@ -70,6 +70,9 @@ export function connectionUrlPlaceholder(dbType: DatabaseType): string {
case "tdengine":
return "tdengine://user:password@host:6041/database";
+ case "xugu":
+ return "xugu://user:password@host:5138/database";
+
case "bigquery":
return "bigquery://https://www.googleapis.com/bigquery/v2:443/project-id";
diff --git a/apps/desktop/src/lib/connectionUrl.ts b/apps/desktop/src/lib/connectionUrl.ts
index 2ad2e44e7c..bdfc140ff0 100644
--- a/apps/desktop/src/lib/connectionUrl.ts
+++ b/apps/desktop/src/lib/connectionUrl.ts
@@ -45,6 +45,7 @@ const SCHEME_PROFILES: Record = {
opengauss: { type: "gaussdb", profile: "opengauss", label: "openGauss", defaultPort: 5432 },
tdengine: { type: "tdengine", profile: "tdengine", label: "TDengine", defaultPort: 6041 },
"taos-ws": { type: "tdengine", profile: "tdengine", label: "TDengine", defaultPort: 6041 },
+ xugu: { type: "xugu", profile: "xugu", label: "XuguDB", defaultPort: 5138 },
iris: { type: "iris", profile: "iris", label: "IRIS", defaultPort: 1972 },
};
diff --git a/apps/desktop/src/lib/databaseCapabilitySets.ts b/apps/desktop/src/lib/databaseCapabilitySets.ts
index e34488a651..cebefe8bd7 100644
--- a/apps/desktop/src/lib/databaseCapabilitySets.ts
+++ b/apps/desktop/src/lib/databaseCapabilitySets.ts
@@ -25,6 +25,7 @@ export const SCHEMA_AWARE_TYPES = new Set([
"trino",
"db2",
"tdengine",
+ "xugu",
"iris",
"duckdb",
]);
@@ -98,6 +99,7 @@ export const DATABASE_SEARCH_SUPPORTED_TYPES = new Set([
"kylin",
"sundb",
"tdengine",
+ "xugu",
"iris",
]);
@@ -206,6 +208,7 @@ export const TREE_SCHEMA_TYPES = new Set([
"trino",
"h2",
"tdengine",
+ "xugu",
"iris",
"duckdb",
]);
@@ -243,6 +246,7 @@ export const AGENT_DRIVER_TYPES = new Set([
"sundb",
"gaussdb",
"tdengine",
+ "xugu",
"iris",
]);
diff --git a/apps/desktop/src/types/database.ts b/apps/desktop/src/types/database.ts
index 111bd49256..5d1f5a2139 100644
--- a/apps/desktop/src/types/database.ts
+++ b/apps/desktop/src/types/database.ts
@@ -41,6 +41,7 @@ export type DatabaseType =
| "kylin"
| "sundb"
| "tdengine"
+ | "xugu"
| "iris"
| "jdbc";
diff --git a/crates/dbx-core/assets/database-drivers.manifest.json b/crates/dbx-core/assets/database-drivers.manifest.json
index 138b1a005c..ea8da538f6 100644
--- a/crates/dbx-core/assets/database-drivers.manifest.json
+++ b/crates/dbx-core/assets/database-drivers.manifest.json
@@ -449,6 +449,17 @@
"skipTcpProbe": true,
"defaultPort": 6041
},
+ {
+ "dbType": "xugu",
+ "label": "虚谷 XuguDB",
+ "runtimeMode": "agent",
+ "mcpMode": "bridge",
+ "agentKey": "xugu",
+ "singleConnectionPool": false,
+ "metadataConnectionScoped": false,
+ "skipTcpProbe": true,
+ "defaultPort": 5138
+ },
{
"dbType": "jdbc",
"label": "JDBC",
diff --git a/crates/dbx-core/src/agent_catalog.rs b/crates/dbx-core/src/agent_catalog.rs
index 56881aac8e..17b589dba5 100644
--- a/crates/dbx-core/src/agent_catalog.rs
+++ b/crates/dbx-core/src/agent_catalog.rs
@@ -205,6 +205,13 @@ const AGENT_CATALOG: &[AgentCatalogEntry] = &[
store_visible: true,
profiles: &[],
},
+ AgentCatalogEntry {
+ db_type: DatabaseType::Xugu,
+ key: "xugu",
+ label: "虚谷 XuguDB",
+ store_visible: true,
+ profiles: &[],
+ },
AgentCatalogEntry {
db_type: DatabaseType::MongoDb,
key: "mongodb",
diff --git a/crates/dbx-core/src/connection.rs b/crates/dbx-core/src/connection.rs
index 5f7437e130..d23c8e9874 100644
--- a/crates/dbx-core/src/connection.rs
+++ b/crates/dbx-core/src/connection.rs
@@ -300,6 +300,7 @@ impl AppState {
| DatabaseType::Kylin
| DatabaseType::Sundb
| DatabaseType::Tdengine
+ | DatabaseType::Xugu
| DatabaseType::Iris
| DatabaseType::Access => {
let connect_params =
diff --git a/crates/dbx-core/src/models/connection.rs b/crates/dbx-core/src/models/connection.rs
index 1afe119524..60c954a21a 100644
--- a/crates/dbx-core/src/models/connection.rs
+++ b/crates/dbx-core/src/models/connection.rs
@@ -190,6 +190,7 @@ pub enum DatabaseType {
Kylin,
Sundb,
Tdengine,
+ Xugu,
#[serde(rename = "iris")]
Iris,
Jdbc,
@@ -377,6 +378,7 @@ impl ConnectionConfig {
DatabaseType::Kylin => format!("kylin://{host}:{port}{db_part}"),
DatabaseType::Sundb => format!("sundb://{host}:{port}{db_part}"),
DatabaseType::Tdengine => format!("tdengine://{host}:{port}{db_part}"),
+ DatabaseType::Xugu => format!("xugu://{host}:{port}{db_part}"),
DatabaseType::Iris => format!("iris://{host}:{port}{db_part}"),
DatabaseType::Jdbc => "jdbc:".to_string(),
}
@@ -538,6 +540,9 @@ impl ConnectionConfig {
DatabaseType::Tdengine => {
format!("tdengine://{}:{}@{host}:{port}{db_part}", username, password)
}
+ DatabaseType::Xugu => {
+ format!("xugu://{}:{}@{host}:{port}{db_part}", username, password)
+ }
DatabaseType::Iris => {
format!("iris://{}:{}@{host}:{port}{db_part}", username, password)
}
diff --git a/docs/content/docs/databases.cn.mdx b/docs/content/docs/databases.cn.mdx
index ec289be9e2..eb5f60d321 100644
--- a/docs/content/docs/databases.cn.mdx
+++ b/docs/content/docs/databases.cn.mdx
@@ -18,7 +18,7 @@ DBX 主应用会尽量使用 Rust 原生驱动。部分数据库通过 MySQL 或
| MySQL 兼容类型 | MariaDB、TiDB、OceanBase、Doris、SelectDB、StarRocks、GoldenDB、自定义 MySQL | 复用 MySQL 风格连接能力 |
| PostgreSQL 兼容类型 | openGauss、KingBase、HighGo、Vastbase、CockroachDB、自定义 PostgreSQL | 复用 PostgreSQL 风格连接能力 |
| 文件型数据库 | SQLite、DuckDB、Microsoft Access | 选择本地数据库文件,不填写主机和端口 |
-| Agent/JDBC 扩展类型 | H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB、TDengine、JDBC | 功能覆盖取决于对应驱动路径 |
+| Agent/JDBC 扩展类型 | H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB、TDengine、虚谷 XuguDB、JDBC | 功能覆盖取决于对应驱动路径 |
## 默认端口
@@ -52,6 +52,7 @@ DBX 主应用会尽量使用 Rust 原生驱动。部分数据库通过 MySQL 或
| Kylin | 7070 |
| SunDB | 22000 |
| TDengine | 6041 |
+| 虚谷 XuguDB | 5138 |
SQLite、DuckDB、Access 和 JDBC 在不需要网络端口时,会在连接模型中保存为端口 `0`。
@@ -63,9 +64,9 @@ DBX 只会在具备足够元数据和 SQL 生成能力的数据库上启用高
| 功能 | 支持类型 |
|---|---|
-| Schema 感知树 | PostgreSQL、SQL Server、Oracle、Redshift、DM、GaussDB、KingBase、HighGo、Vastbase、JDBC、H2、Snowflake、Trino、DB2、TDengine |
+| Schema 感知树 | PostgreSQL、SQL Server、Oracle、Redshift、DM、GaussDB、KingBase、HighGo、Vastbase、JDBC、H2、Snowflake、Trino、DB2、TDengine、虚谷 XuguDB |
| ER 图 | MySQL、PostgreSQL、SQLite、SQL Server、Oracle、Redshift、DM、GaussDB、KingBase、HighGo、Vastbase、GoldenDB、Access、H2、DB2 |
-| 数据库搜索 | MySQL、PostgreSQL、SQLite、SQL Server、Oracle、Redshift、DuckDB、ClickHouse、DM、GaussDB、KingBase、HighGo、Vastbase、GoldenDB、Access、H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB、TDengine |
+| 数据库搜索 | MySQL、PostgreSQL、SQLite、SQL Server、Oracle、Redshift、DuckDB、ClickHouse、DM、GaussDB、KingBase、HighGo、Vastbase、GoldenDB、Access、H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB、TDengine、虚谷 XuguDB |
| 表数据导入 | MySQL、PostgreSQL、SQLite、DuckDB、ClickHouse、SQL Server、Oracle、Doris、StarRocks、Redshift、DM、GaussDB、KingBase、HighGo、Vastbase、GoldenDB、Access |
| 表结构编辑器 | MySQL、PostgreSQL、SQLite、SQL Server |
| 创建数据库 | MySQL、PostgreSQL、SQL Server、ClickHouse、Oracle、DM、GaussDB、Doris、StarRocks、Redshift |
@@ -81,7 +82,7 @@ DBX 只会在具备足够元数据和 SQL 生成能力的数据库上启用高
大多数网络数据库支持主机、端口、用户名、密码、默认数据库、URL 参数、SSL、连接颜色、SSH 隧道和代理设置。文件型数据库会改为选择本地文件。
-DBX 也可以解析常见连接 URL,例如 MySQL、PostgreSQL、Redis、MongoDB、ClickHouse、SQL Server、Oracle、Elasticsearch、DM、GaussDB、openGauss、TDengine 和 Access。
+DBX 也可以解析常见连接 URL,例如 MySQL、PostgreSQL、Redis、MongoDB、ClickHouse、SQL Server、Oracle、Elasticsearch、DM、GaussDB、openGauss、TDengine、虚谷 XuguDB 和 Access。
### ClickHouse TLS
diff --git a/docs/content/docs/databases.mdx b/docs/content/docs/databases.mdx
index b396b0299b..ff76fa7bd0 100644
--- a/docs/content/docs/databases.mdx
+++ b/docs/content/docs/databases.mdx
@@ -18,7 +18,7 @@ The connection dialog exposes ready-to-use profiles with default ports and drive
| MySQL-compatible profiles | MariaDB, TiDB, OceanBase, Doris, SelectDB, StarRocks, GoldenDB, custom MySQL | Reuse MySQL-style connection handling where the engine speaks a compatible protocol |
| PostgreSQL-compatible profiles | openGauss, KingBase, HighGo, Vastbase, CockroachDB, custom PostgreSQL | Reuse PostgreSQL-style connection handling where the engine speaks a compatible protocol |
| File-based engines | SQLite, DuckDB, Microsoft Access | Choose a local database file instead of host and port |
-| Agent/JDBC-oriented engines | H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, TDengine, JDBC | Feature coverage depends on the driver path used by that engine |
+| Agent/JDBC-oriented engines | H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, TDengine, XuguDB, JDBC | Feature coverage depends on the driver path used by that engine |
## Default Ports
@@ -52,6 +52,7 @@ The connection dialog exposes ready-to-use profiles with default ports and drive
| Kylin | 7070 |
| SunDB | 22000 |
| TDengine | 6041 |
+| XuguDB | 5138 |
SQLite, DuckDB, Access, and JDBC profiles use port `0` in the saved connection model when a network port is not part of the connection.
@@ -63,9 +64,9 @@ DBX intentionally enables advanced workflows only where the app has enough metad
| Feature | Supported Types |
|---|---|
-| Schema-aware tree | PostgreSQL, SQL Server, Oracle, Redshift, DM, GaussDB, KingBase, HighGo, Vastbase, JDBC, H2, Snowflake, Trino, DB2, TDengine |
+| Schema-aware tree | PostgreSQL, SQL Server, Oracle, Redshift, DM, GaussDB, KingBase, HighGo, Vastbase, JDBC, H2, Snowflake, Trino, DB2, TDengine, XuguDB |
| ER diagram | MySQL, PostgreSQL, SQLite, SQL Server, Oracle, Redshift, DM, GaussDB, KingBase, HighGo, Vastbase, GoldenDB, Access, H2, DB2 |
-| Database search | MySQL, PostgreSQL, SQLite, SQL Server, Oracle, Redshift, DuckDB, ClickHouse, DM, GaussDB, KingBase, HighGo, Vastbase, GoldenDB, Access, H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, TDengine |
+| Database search | MySQL, PostgreSQL, SQLite, SQL Server, Oracle, Redshift, DuckDB, ClickHouse, DM, GaussDB, KingBase, HighGo, Vastbase, GoldenDB, Access, H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, TDengine, XuguDB |
| Table import | MySQL, PostgreSQL, SQLite, DuckDB, ClickHouse, SQL Server, Oracle, Doris, StarRocks, Redshift, DM, GaussDB, KingBase, HighGo, Vastbase, GoldenDB, Access |
| Table structure editor | MySQL, PostgreSQL, SQLite, SQL Server |
| Create database | MySQL, PostgreSQL, SQL Server, ClickHouse, Oracle, DM, GaussDB, Doris, StarRocks, Redshift |
@@ -81,7 +82,7 @@ If a database can connect but does not appear in a feature row, that feature may
Most network databases support host, port, username, password, default database, optional URL parameters, SSL, connection color, SSH tunnel, and proxy settings. File-based engines replace host and port with a file picker.
-DBX can also parse common connection URLs for engines such as MySQL, PostgreSQL, Redis, MongoDB, ClickHouse, SQL Server, Oracle, Elasticsearch, DM, GaussDB, openGauss, TDengine, and Access.
+DBX can also parse common connection URLs for engines such as MySQL, PostgreSQL, Redis, MongoDB, ClickHouse, SQL Server, Oracle, Elasticsearch, DM, GaussDB, openGauss, TDengine, XuguDB, and Access.
### ClickHouse TLS
diff --git a/docs/content/docs/driver-management.cn.mdx b/docs/content/docs/driver-management.cn.mdx
index effab3d052..e0b076bcbd 100644
--- a/docs/content/docs/driver-management.cn.mdx
+++ b/docs/content/docs/driver-management.cn.mdx
@@ -10,7 +10,7 @@ DBX 使用混合驱动架构:常用数据库使用内置原生驱动,需要
| 驱动类型 | 工作方式 | 适用场景 |
|---|---|---|
| 原生(内置) | Rust 驱动编译进 DBX | MySQL、PostgreSQL、SQLite、SQL Server、Oracle、Redis、MongoDB、DuckDB、ClickHouse 等 |
-| JDBC Agent | DBX 管理的 Java 子进程 | 提供 JDBC 驱动的数据库:GaussDB、openGauss、DM、KingBase、HighGo、Vastbase、Trino、Hive、DB2、Informix、Neo4j、TDengine、YashanDB、GoldenDB、Kylin、SunDB 等 |
+| JDBC Agent | DBX 管理的 Java 子进程 | 提供 JDBC 驱动的数据库:GaussDB、openGauss、DM、KingBase、HighGo、Vastbase、Trino、Hive、DB2、Informix、Neo4j、TDengine、虚谷 XuguDB、YashanDB、GoldenDB、Kylin、SunDB 等 |
原生驱动安装后立即可用。Agent 驱动需要一次性下载 JDBC 驱动和 JRE 设置,首次创建连接时 DBX 会自动处理。
diff --git a/docs/content/docs/driver-management.mdx b/docs/content/docs/driver-management.mdx
index 4ed15fcc52..a1eda4708e 100644
--- a/docs/content/docs/driver-management.mdx
+++ b/docs/content/docs/driver-management.mdx
@@ -10,7 +10,7 @@ DBX uses a hybrid driver architecture: built-in native drivers for common databa
| Driver Type | How It Works | Best For |
|---|---|---|
| Native (built-in) | Rust drivers compiled into DBX | MySQL, PostgreSQL, SQLite, SQL Server, Oracle, Redis, MongoDB, DuckDB, ClickHouse, and more |
-| JDBC Agent | Java subprocess managed by DBX | Databases that provide JDBC drivers: GaussDB, openGauss, DM, KingBase, HighGo, Vastbase, Trino, Hive, DB2, Informix, Neo4j, TDengine, YashanDB, GoldenDB, Kylin, SunDB, and more |
+| JDBC Agent | Java subprocess managed by DBX | Databases that provide JDBC drivers: GaussDB, openGauss, DM, KingBase, HighGo, Vastbase, Trino, Hive, DB2, Informix, Neo4j, TDengine, XuguDB, YashanDB, GoldenDB, Kylin, SunDB, and more |
Native drivers work immediately after installation. Agent drivers require a one-time JDBC driver download and JRE setup, which DBX handles automatically when you first create a connection.
diff --git a/packages/app-tests/connectionUrl.test.ts b/packages/app-tests/connectionUrl.test.ts
index eba4db9937..8fd9f3892a 100644
--- a/packages/app-tests/connectionUrl.test.ts
+++ b/packages/app-tests/connectionUrl.test.ts
@@ -71,6 +71,20 @@ test("parses TDengine WebSocket JDBC URLs", () => {
assert.equal(parsed.urlParams, "timezone=UTC");
});
+test("parses XuguDB JDBC URLs", () => {
+ const parsed = parseConnectionUrl("jdbc:xugu://alice:secret@xugu.example.com:5138/demo?charset=utf8");
+
+ assert.equal(parsed.dbType, "xugu");
+ assert.equal(parsed.driverProfile, "xugu");
+ assert.equal(parsed.driverLabel, "XuguDB");
+ assert.equal(parsed.host, "xugu.example.com");
+ assert.equal(parsed.port, 5138);
+ assert.equal(parsed.username, "alice");
+ assert.equal(parsed.password, "secret");
+ assert.equal(parsed.database, "demo");
+ assert.equal(parsed.urlParams, "charset=utf8");
+});
+
test("parses UCanAccess JDBC URLs as Access database files", () => {
const parsed = parseConnectionUrl("jdbc:ucanaccess:///Users/me/data/Northwind.accdb;memory=false");
diff --git a/packages/app-tests/connectionUrlPlaceholder.test.ts b/packages/app-tests/connectionUrlPlaceholder.test.ts
index 78c44bb658..970120ebea 100644
--- a/packages/app-tests/connectionUrlPlaceholder.test.ts
+++ b/packages/app-tests/connectionUrlPlaceholder.test.ts
@@ -20,6 +20,7 @@ const expected: Record = {
elasticsearch: "http://user:password@host:port",
dameng: "dm://user:password@host:port",
tdengine: "tdengine://user:password@host:6041/database",
+ xugu: "xugu://user:password@host:5138/database",
bigquery: "bigquery://https://www.googleapis.com/bigquery/v2:443/project-id",
jdbc: "jdbc:mysql://host:3306/database",
};
diff --git a/packages/app-tests/databaseCapabilities.test.ts b/packages/app-tests/databaseCapabilities.test.ts
index e038d7873d..c466f2c366 100644
--- a/packages/app-tests/databaseCapabilities.test.ts
+++ b/packages/app-tests/databaseCapabilities.test.ts
@@ -35,6 +35,13 @@ test("treats TDengine databases as schema tree roots and agent driver databases"
assert.equal(supportsDriverManagement("tdengine"), true);
});
+test("treats XuguDB as a schema-aware agent driver database", () => {
+ assert.equal(TREE_SCHEMA_TYPES.has("xugu"), true);
+ assert.equal(SCHEMA_AWARE_TYPES.has("xugu"), true);
+ assert.equal(supportsDatabaseSearch("xugu"), true);
+ assert.equal(supportsDriverManagement("xugu"), true);
+});
+
test("treats Access as a local single-database agent driver", () => {
assert.equal(SCHEMA_AWARE_TYPES.has("access"), false);
assert.equal(supportsDriverManagement("access"), true);
diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts
index 3685336f1f..7da4ec1a79 100644
--- a/packages/mcp-server/src/index.ts
+++ b/packages/mcp-server/src/index.ts
@@ -34,7 +34,7 @@ function withDatabase(config: ConnectionConfig, database?: string): ConnectionCo
}
export const DBX_CONNECTION_TYPE_DESCRIPTION =
- "Database type: postgres, mysql, sqlite, redis, duckdb, clickhouse, sqlserver, mongodb, oracle, elasticsearch, doris, starrocks, redshift, dameng, kingbase, highgo, vastbase, goldendb, gaussdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, neo4j, cassandra, bigquery, kylin, sundb, tdengine, jdbc, access";
+ "Database type: postgres, mysql, sqlite, redis, duckdb, clickhouse, sqlserver, mongodb, oracle, elasticsearch, doris, starrocks, redshift, dameng, kingbase, highgo, vastbase, goldendb, gaussdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, neo4j, cassandra, bigquery, kylin, sundb, tdengine, xugu, jdbc, access";
export function createDbxMcpServer(backend: Backend, options: { isWebMode?: boolean } = {}): McpServer {
const isWebMode = options.isWebMode ?? !!process.env.DBX_WEB_URL;
@@ -44,199 +44,208 @@ export function createDbxMcpServer(backend: Backend, options: { isWebMode?: bool
});
server.tool("dbx_list_connections", "List all database connections configured in DBX", {}, async () => {
- const connections = await backend.loadConnections();
- if (connections.length === 0) return text("No connections configured in DBX.");
- const rows = connections.map((c) => [c.name, c.db_type, c.host, String(c.port), c.database || ""]);
- return text(mdTable(["Name", "Type", "Host", "Port", "Database"], rows));
+ const connections = await backend.loadConnections();
+ if (connections.length === 0) return text("No connections configured in DBX.");
+ const rows = connections.map((c) => [c.name, c.db_type, c.host, String(c.port), c.database || ""]);
+ return text(mdTable(["Name", "Type", "Host", "Port", "Database"], rows));
});
server.tool(
- "dbx_list_tables",
- "List tables and views for a database connection",
- {
- connection_name: z.string().describe("Name of the DBX connection"),
- database: z.string().optional().describe("Database name"),
- schema: z.string().optional().describe("Schema name (default: public for PostgreSQL)"),
- },
- async ({ connection_name, database, schema }) => {
- const config = await backend.findConnection(connection_name);
- if (!config) return text(`Connection "${connection_name}" not found`);
- const tables = await backend.listTables(withDatabase(config, database), schema);
- if (tables.length === 0) return text("No tables found.");
- const rows = tables.map((t) => [t.name, t.type]);
- return text(mdTable(["Table", "Type"], rows));
- },
- );
-
- server.tool(
- "dbx_describe_table",
- "Get column definitions for a table",
- {
- connection_name: z.string().describe("Name of the DBX connection"),
- table: z.string().describe("Table name"),
- database: z.string().optional().describe("Database name"),
- schema: z.string().optional().describe("Schema name (default: public for PostgreSQL)"),
- },
- async ({ connection_name, table, database, schema }) => {
- const config = await backend.findConnection(connection_name);
- if (!config) return text(`Connection "${connection_name}" not found`);
- const columns = await backend.describeTable(withDatabase(config, database), table, schema);
- if (columns.length === 0) return text("No columns found.");
- const rows = columns.map((c) => [
- c.is_primary_key ? `${c.name} (PK)` : c.name,
- c.data_type,
- c.is_nullable ? "YES" : "NO",
- c.column_default ?? "",
- c.comment ?? "",
- ]);
- return text(mdTable(["Column", "Type", "Nullable", "Default", "Comment"], rows));
- },
- );
-
- server.tool(
- "dbx_execute_query",
- "Execute a SQL query on a database connection (max 100 rows returned)",
- {
- connection_name: z.string().describe("Name of the DBX connection"),
- database: z.string().optional().describe("Database name"),
- sql: z.string().describe("SQL query to execute"),
- },
- async ({ connection_name, database, sql }) => {
- const config = await backend.findConnection(connection_name);
- if (!config) return text(`Connection "${connection_name}" not found`);
- if (config.db_type !== "mongodb") {
- const safety = evaluateSqlSafety(sql, sqlSafetyFromEnv());
- if (!safety.allowed) return text(`Query blocked: ${safety.reason}`);
- }
- // MongoDB shell commands don't fit the SQL safety evaluator; the backend
- // (node-core executeQuery) applies command-aware read/write gating.
- try {
- const result = await backend.executeQuery(withDatabase(config, database), sql);
- if (result.columns.length === 0) return text(`Query executed. ${result.row_count} row(s) affected.`);
- const rows = result.rows.map((r) => result.columns.map((c) => formatCell(r[c])));
- return text(`${mdTable(result.columns, rows)}\n\n${result.row_count} row(s)`);
- } catch (e: unknown) {
- const msg = e instanceof Error ? e.message : String(e);
- return text(`Query error: ${msg}`);
- }
- },
- );
-
- server.tool(
- "dbx_get_schema_context",
- "Get compact table and column context for writing SQL",
- {
- connection_name: z.string().describe("Name of the DBX connection"),
- database: z.string().optional().describe("Database name"),
- schema: z.string().optional().describe("Schema name (default: public for PostgreSQL)"),
- tables: z.array(z.string()).optional().describe("Specific table names to include"),
- max_tables: z.number().int().min(1).max(20).default(8).describe("Maximum number of tables to include"),
- },
- async ({ connection_name, database, schema, tables, max_tables }) => {
- const config = await backend.findConnection(connection_name);
- if (!config) return text(`Connection "${connection_name}" not found`);
- const context = await buildSchemaContext(backend, withDatabase(config, database), { schema, tables, maxTables: max_tables });
- if (context.tables.length === 0) return text("No matching tables found.");
- return text(formatSchemaContext(context));
- },
- );
-
- server.tool(
- "dbx_add_connection",
- "Add a new database connection to DBX",
- {
- name: z.string().describe("Connection name"),
- db_type: z
- .string()
- .describe(DBX_CONNECTION_TYPE_DESCRIPTION),
- host: z.string().describe("Database host"),
- port: z.number().optional().describe("Database port (TDengine defaults to 6041)"),
- username: z.string().default("").describe("Username"),
- password: z.string().default("").describe("Password"),
- database: z.string().optional().describe("Default database name"),
- ssl: z.boolean().default(false).describe("Enable SSL"),
- },
- async ({ name, db_type, host, port, username, password, database, ssl }) => {
- const existing = await backend.findConnection(name);
- if (existing) return text(`Connection "${name}" already exists.`);
- const FILE_BASED_TYPES = new Set(["sqlite", "duckdb", "access"]);
- const resolvedPort = port ?? (db_type === "tdengine" ? 6041 : FILE_BASED_TYPES.has(db_type) ? 0 : undefined);
- if (resolvedPort === undefined) return text("Port is required for this database type.");
- const config = await backend.addConnection({
- name,
- db_type,
- host,
- port: resolvedPort,
- username,
- password,
- database,
- ssl,
- ssh_enabled: false,
- } as Omit);
- await notifyReload();
- return text(`Connection "${config.name}" added (id: ${config.id}).`);
- },
- );
-
- server.tool(
- "dbx_remove_connection",
- "Remove a database connection from DBX",
- {
- connection_name: z.string().describe("Name of the connection to remove"),
- },
- async ({ connection_name }) => {
- const removed = await backend.removeConnection(connection_name);
- if (!removed) return text(`Connection "${connection_name}" not found.`);
- await notifyReload();
- return text(`Connection "${connection_name}" removed.`);
- },
- );
-
-// Desktop-only tools: open table and execute-and-show require the Tauri bridge
- if (!isWebMode) {
- server.tool(
- "dbx_open_table",
- "Open a table in DBX desktop app UI. Requires DBX to be running.",
+ "dbx_list_tables",
+ "List tables and views for a database connection",
{
connection_name: z.string().describe("Name of the DBX connection"),
- table: z.string().describe("Table name to open"),
database: z.string().optional().describe("Database name"),
- schema: z.string().optional().describe("Schema name"),
+ schema: z.string().optional().describe("Schema name (default: public for PostgreSQL)"),
+ },
+ async ({ connection_name, database, schema }) => {
+ const config = await backend.findConnection(connection_name);
+ if (!config) return text(`Connection "${connection_name}" not found`);
+ const tables = await backend.listTables(withDatabase(config, database), schema);
+ if (tables.length === 0) return text("No tables found.");
+ const rows = tables.map((t) => [t.name, t.type]);
+ return text(mdTable(["Table", "Type"], rows));
+ },
+ );
+
+ server.tool(
+ "dbx_describe_table",
+ "Get column definitions for a table",
+ {
+ connection_name: z.string().describe("Name of the DBX connection"),
+ table: z.string().describe("Table name"),
+ database: z.string().optional().describe("Database name"),
+ schema: z.string().optional().describe("Schema name (default: public for PostgreSQL)"),
},
async ({ connection_name, table, database, schema }) => {
- return bridgeRequest("/open-table", { connection_name, table, database, schema }, `Opened ${table} in DBX`);
+ const config = await backend.findConnection(connection_name);
+ if (!config) return text(`Connection "${connection_name}" not found`);
+ const columns = await backend.describeTable(withDatabase(config, database), table, schema);
+ if (columns.length === 0) return text("No columns found.");
+ const rows = columns.map((c) => [
+ c.is_primary_key ? `${c.name} (PK)` : c.name,
+ c.data_type,
+ c.is_nullable ? "YES" : "NO",
+ c.column_default ?? "",
+ c.comment ?? "",
+ ]);
+ return text(mdTable(["Column", "Type", "Nullable", "Default", "Comment"], rows));
},
+ );
+
+ server.tool(
+ "dbx_execute_query",
+ "Execute a SQL query on a database connection (max 100 rows returned)",
+ {
+ connection_name: z.string().describe("Name of the DBX connection"),
+ database: z.string().optional().describe("Database name"),
+ sql: z.string().describe("SQL query to execute"),
+ },
+ async ({ connection_name, database, sql }) => {
+ const config = await backend.findConnection(connection_name);
+ if (!config) return text(`Connection "${connection_name}" not found`);
+ if (config.db_type !== "mongodb") {
+ const safety = evaluateSqlSafety(sql, sqlSafetyFromEnv());
+ if (!safety.allowed) return text(`Query blocked: ${safety.reason}`);
+ }
+ // MongoDB shell commands don't fit the SQL safety evaluator; the backend
+ // (node-core executeQuery) applies command-aware read/write gating.
+ try {
+ const result = await backend.executeQuery(withDatabase(config, database), sql);
+ if (result.columns.length === 0) return text(`Query executed. ${result.row_count} row(s) affected.`);
+ const rows = result.rows.map((r) => result.columns.map((c) => formatCell(r[c])));
+ return text(`${mdTable(result.columns, rows)}\n\n${result.row_count} row(s)`);
+ } catch (e: unknown) {
+ const msg = e instanceof Error ? e.message : String(e);
+ return text(`Query error: ${msg}`);
+ }
+ },
+ );
+
+ server.tool(
+ "dbx_get_schema_context",
+ "Get compact table and column context for writing SQL",
+ {
+ connection_name: z.string().describe("Name of the DBX connection"),
+ database: z.string().optional().describe("Database name"),
+ schema: z.string().optional().describe("Schema name (default: public for PostgreSQL)"),
+ tables: z.array(z.string()).optional().describe("Specific table names to include"),
+ max_tables: z.number().int().min(1).max(20).default(8).describe("Maximum number of tables to include"),
+ },
+ async ({ connection_name, database, schema, tables, max_tables }) => {
+ const config = await backend.findConnection(connection_name);
+ if (!config) return text(`Connection "${connection_name}" not found`);
+ const context = await buildSchemaContext(backend, withDatabase(config, database), {
+ schema,
+ tables,
+ maxTables: max_tables,
+ });
+ if (context.tables.length === 0) return text("No matching tables found.");
+ return text(formatSchemaContext(context));
+ },
+ );
+
+ server.tool(
+ "dbx_add_connection",
+ "Add a new database connection to DBX",
+ {
+ name: z.string().describe("Connection name"),
+ db_type: z.string().describe(DBX_CONNECTION_TYPE_DESCRIPTION),
+ host: z.string().describe("Database host"),
+ port: z.number().optional().describe("Database port (TDengine defaults to 6041, XuguDB defaults to 5138)"),
+ username: z.string().default("").describe("Username"),
+ password: z.string().default("").describe("Password"),
+ database: z.string().optional().describe("Default database name"),
+ ssl: z.boolean().default(false).describe("Enable SSL"),
+ },
+ async ({ name, db_type, host, port, username, password, database, ssl }) => {
+ const existing = await backend.findConnection(name);
+ if (existing) return text(`Connection "${name}" already exists.`);
+ const FILE_BASED_TYPES = new Set(["sqlite", "duckdb", "access"]);
+ const DEFAULT_PORTS: Record = { tdengine: 6041, xugu: 5138 };
+ const resolvedPort = port ?? DEFAULT_PORTS[db_type] ?? (FILE_BASED_TYPES.has(db_type) ? 0 : undefined);
+ if (resolvedPort === undefined) return text("Port is required for this database type.");
+ const config = await backend.addConnection({
+ name,
+ db_type,
+ host,
+ port: resolvedPort,
+ username,
+ password,
+ database,
+ ssl,
+ ssh_enabled: false,
+ } as Omit);
+ await notifyReload();
+ return text(`Connection "${config.name}" added (id: ${config.id}).`);
+ },
+ );
+
+ server.tool(
+ "dbx_remove_connection",
+ "Remove a database connection from DBX",
+ {
+ connection_name: z.string().describe("Name of the connection to remove"),
+ },
+ async ({ connection_name }) => {
+ const removed = await backend.removeConnection(connection_name);
+ if (!removed) return text(`Connection "${connection_name}" not found.`);
+ await notifyReload();
+ return text(`Connection "${connection_name}" removed.`);
+ },
+ );
+
+ // Desktop-only tools: open table and execute-and-show require the Tauri bridge
+ if (!isWebMode) {
+ server.tool(
+ "dbx_open_table",
+ "Open a table in DBX desktop app UI. Requires DBX to be running.",
+ {
+ connection_name: z.string().describe("Name of the DBX connection"),
+ table: z.string().describe("Table name to open"),
+ database: z.string().optional().describe("Database name"),
+ schema: z.string().optional().describe("Schema name"),
+ },
+ async ({ connection_name, table, database, schema }) => {
+ return bridgeRequest("/open-table", { connection_name, table, database, schema }, `Opened ${table} in DBX`);
+ },
);
server.tool(
- "dbx_execute_and_show",
- "Execute a SQL query in DBX desktop app UI and show results there. Requires DBX to be running.",
- {
- connection_name: z.string().describe("Name of the DBX connection"),
- sql: z.string().describe("SQL query to execute"),
- database: z.string().optional().describe("Database name"),
- },
- async ({ connection_name, sql, database }) => {
- const config = await backend.findConnection(connection_name);
- const safetyOptions = sqlSafetyFromEnv();
- if (config?.db_type === "mongodb") {
- const aggregate = parseMongoAggregateCommand(sql);
- if (aggregate) {
- const safety = evaluateMongoAggregateSafety(aggregate, safetyOptions);
+ "dbx_execute_and_show",
+ "Execute a SQL query in DBX desktop app UI and show results there. Requires DBX to be running.",
+ {
+ connection_name: z.string().describe("Name of the DBX connection"),
+ sql: z.string().describe("SQL query to execute"),
+ database: z.string().optional().describe("Database name"),
+ },
+ async ({ connection_name, sql, database }) => {
+ const config = await backend.findConnection(connection_name);
+ const safetyOptions = sqlSafetyFromEnv();
+ if (config?.db_type === "mongodb") {
+ const aggregate = parseMongoAggregateCommand(sql);
+ if (aggregate) {
+ const safety = evaluateMongoAggregateSafety(aggregate, safetyOptions);
+ if (!safety.allowed) return text(`Query blocked: ${safety.reason}`);
+ }
+ } else {
+ const safety = evaluateSqlSafety(sql, safetyOptions);
if (!safety.allowed) return text(`Query blocked: ${safety.reason}`);
}
- } else {
- const safety = evaluateSqlSafety(sql, safetyOptions);
- if (!safety.allowed) return text(`Query blocked: ${safety.reason}`);
- }
- // MongoDB shell commands bypass the SQL safety evaluator; pass MCP
- // safety flags to the desktop executor for command-aware gating.
- return bridgeRequest(
- "/execute-query",
- { connection_name, sql, database, allow_writes: safetyOptions.allowWrites, allow_dangerous: safetyOptions.allowDangerous },
- "Query sent to DBX",
- );
- },
+ // MongoDB shell commands bypass the SQL safety evaluator; pass MCP
+ // safety flags to the desktop executor for command-aware gating.
+ return bridgeRequest(
+ "/execute-query",
+ {
+ connection_name,
+ sql,
+ database,
+ allow_writes: safetyOptions.allowWrites,
+ allow_dangerous: safetyOptions.allowDangerous,
+ },
+ "Query sent to DBX",
+ );
+ },
);
}
diff --git a/packages/node-core/src/diagnostics.ts b/packages/node-core/src/diagnostics.ts
index 53664aded7..3955cf3f3f 100644
--- a/packages/node-core/src/diagnostics.ts
+++ b/packages/node-core/src/diagnostics.ts
@@ -38,6 +38,7 @@ export const BRIDGE_REQUIRED_TYPES = [
"bigquery",
"kylin",
"sundb",
+ "xugu",
"jdbc",
"access",
] as const;