\data\dbx.db`
* **macOS:** `~/Library/Application Support/com.dbx.app/dbx.db`
* **Linux:** `~/.local/share/com.dbx.app/dbx.db`
SSH 主机指纹保存在同目录的 `known_hosts` 中,DBX 不会读写 `~/.ssh`。数据目录下还可能出现 `dbx.db-wal`、`dbx.db-shm` 检查点文件。
旧版本 DBX 曾使用 `connections.json` 和 `secrets.json` 保存连接,现在启动时会自动迁移进 `dbx.db`,原文件改名为 `*.bak` 保留。
跨设备迁移推荐使用加密的[配置导出/导入](/cn/docs/config-export),而不是直接拷贝文件。手动备份时请先退出 DBX,再复制整个数据目录,或至少复制 `dbx.db` 并连同 `-wal`、`-shm` 文件。
### 能把数据放在程序同目录,或自定义数据目录吗?
可以,有两种官方支持的方式:
* **Windows 便携版:** Release 页面的 `DBX_<版本>_<架构>-portable.zip` 自带 `portable.dbx` 标记文件。解压到任意目录运行,所有数据自动保存在 `DBX.exe` 旁边的 `data` 目录。首次启动时,如果便携目录还没有数据、而 AppData 中存在旧数据,会自动导入一次。
* **`DBX_DATA_DIR` 环境变量:** 所有平台、安装版和便携版均可用,优先级最高,可指向任意目录。新目录首次启动是空库,请用配置导出/导入迁移,或在 DBX 退出后拷贝 `dbx.db`。
`portable.dbx` 标记仅对 Windows 生效,且当 exe 旁存在 `uninstall.exe`(安装版)时会被忽略;解压版目录中手动创建该标记同样可以启用便携模式。应用内没有切换数据目录的设置项。
升级已有安装前,请先阅读
[数据安全升级与迁移说明](/cn/docs/data-security-migration)
。
## Linux 窗口闪烁或内容消失
在 GNOME 且系统已开启窗口合成时,Linux 主窗口会绘制带圆角、阴影的浮动边框;在其他桌面(KDE、XFCE、Cinnamon 等)默认使用不透明背景,避免部分显卡驱动与 WebKitGTK 的透明窗口合成兼容问题。两种模式都不会关闭 GPU 加速或改变 Wayland/X11 后端。
可以通过环境变量覆盖默认行为。在其他桌面强制启用浮动边框:
```bash
DBX_LINUX_FLOATING_FRAME=1 dbx
```
若在 GNOME 上出现闪烁、内容消失或必须缩放窗口才能重绘,请完全退出 DBX(包括托盘),并使用 `DBX_LINUX_FLOATING_FRAME=0 dbx` 重新启动以强制使用不透明窗口。没有窗口合成时始终不启用浮动边框。AppImage 用户请将 `dbx` 替换为实际的 AppImage 文件路径。
如果默认的不透明窗口仍有问题,请在反馈中提供 DBX 版本、安装方式、KDE/Plasma 版本、Wayland/X11 会话类型、显卡及驱动信息,以及系统 WebKitGTK 版本。
## PostgreSQL / openGauss 中文乱码
如果数据库声明为 `LATIN1`,但历史文本实际保存的是 GB18030 字节,可以在 **编辑连接 → 连接 → URL 参数** 中填写:
```text
clientEncoding=GB18030&serverEncoding=ISO-8859-1
```
保存后重新连接。DBX 原生驱动使用这组参数转换查询结果、中文 SQL 和绑定参数;支持表格读取与编辑、文本数组、JSON、元数据和按行导出。不会修改数据库编码或已有数据。`clientEncoding` 也支持 `GBK` 和 `UTF-8`,`serverEncoding` 可写为 `LATIN1`;两个参数必须同时提供。
这组参数只适用于数据库声明编码与实际文本字节不一致的连接。服务端必须报告 `server_encoding=LATIN1`,且 `standard_conforming_strings=on`。读取遇到无法转换的值时保留原文,并在查询消息中提示;其他完整的文本仍正常解码。按字节截断的脱敏值(例如半个汉字后接星号)不会再导致整条查询失败,也不会被替换字符或 NULL 覆盖。写入时不能用指定编码表示的内容仍明确报错。未填写参数的连接使用正常的 PostgreSQL 编码转换。
COPY 文本导入支持 DBX 的默认文本格式;跨连接数据传输会使用按行 INSERT 路径。原始 COPY 输出和其他 COPY 格式请使用按行导入/导出。
---
# 字段血缘
> 从外键、视图定义、查询历史和同名字段中分析字段的上游、下游与潜在影响范围。
Source: https://dbxio.com/cn/docs/field-lineage
Language: zh-CN
Relative links resolve against https://dbxio.com/cn/docs/field-lineage.
字段血缘用于回答“这个字段从哪里来、被谁使用、修改后可能影响什么”。DBX 会组合数据库元数据和本地查询历史,并按证据强度标记关系,而不是把所有同名字段都当成确定依赖。
## 打开方式
从字段节点、表结构或相关上下文菜单打开字段血缘。当前字段会作为中心目标,结果列表展示相关表、字段、视图或历史 SQL。
## 关系来源与可信度
| 来源 | 默认可信度 | 说明 |
| ---- | ------ | -------------------- |
| 外键 | 确定 | 数据库声明了当前字段与目标字段的约束关系 |
| 视图定义 | 高置信或可能 | 视图源码同时引用目标表和字段时置信度更高 |
| 查询历史 | 高置信或可能 | 历史 SQL 同时命中表和字段时更可信 |
| 同名字段 | 可能 | 仅根据字段名相同推断,需要业务确认 |
界面会区分**确定**、**高置信**和**可能相关**。筛选低置信结果可以先聚焦外键和明确源码引用。
## 搜索与筛选
* 搜索表、字段、视图或 SQL 片段
* 按置信度过滤
* 查看当前显示数量和总关系数
* 复制表名或字段名
* 打开目标表数据或结构
* 从结果回到对应对象树位置
血缘读取会按数据库能力加载外键、视图源码和相关元数据。大型 Schema 首次分析可能需要时间。
## 查询历史的作用
DBX 会把已执行查询作为辅助证据,例如:
* `JOIN` 中同时出现两个字段
* `WHERE`、`SELECT` 或表达式中引用目标字段
* 历史修复 SQL 或报表 SQL 使用同名字段
查询历史只代表曾经在 DBX 中执行或保存过的 SQL,不代表应用代码、ETL、BI 或其他客户端的完整使用情况。
查询历史可能包含敏感表名、条件和字面量。演示血缘结果、导出日志或共享截图前先检查隐私信息。
## 视图与源码分析
视图来源通过数据库返回的定义进行文本和结构分析。以下情况可能降低置信度:
* 动态 SQL 或存储过程拼接
* 同名表/字段但没有明确 Schema
* `SELECT *`、复杂子查询或厂商扩展语法
* 数据库没有返回完整视图源码
点击视图结果后,可以结合 [对象浏览器](/cn/docs/object-browser) 中的源码进行人工确认。
## 使用方式
### 修改字段前
1. 先看确定的外键关系
2. 检查高置信视图和历史 SQL
3. 对可能相关的同名字段进行业务确认
4. 在代码仓库、ETL 和 BI 中继续搜索
5. 使用 [Schema 对比](/cn/docs/schema-diff) 审查目标环境变化
### 接手陌生数据库
从核心主键、业务编号、用户 ID 或时间字段开始,逐步打开关联表和视图。字段注释和对象源码通常比单纯同名推断更可靠。
## 支持与边界
* 血缘需要外键、视图源码或可解析查询历史;功能范围因数据库而异
* 数据库没有声明外键时,DBX 只能提供视图、历史 SQL 和同名字段线索
* 结果不是强一致数据治理图,不包含所有应用代码、消息流、ETL 和外部 BI
* 删除历史记录或清理本地数据会减少查询历史来源
* 当前支持范围以 [数据库支持](/cn/docs/databases) 的功能矩阵为准
关键结构变更仍应结合数据库约束、对象源码、应用代码搜索和实际业务负责人确认。字段血缘用于缩小调查范围,不替代变更影响分析。
### [结构浏览](/cn/docs/schema-browser)
查看字段、外键、注释和对象层级。
### [对象源码](/cn/docs/object-browser)
查看视图、过程、函数和触发器定义。
### [Schema 对比](/cn/docs/schema-diff)
检查不同环境之间的结构差异和部署脚本。
---
# 快速开始
> 安装 DBX、创建第一个连接,并了解桌面版、Docker 版和源码运行方式。
Source: https://dbxio.com/cn/docs/getting-started
Language: zh-CN
Relative links resolve against https://dbxio.com/cn/docs/getting-started.
本页帮助你完成三件事:
1. 安装 DBX 或启动 Docker 版本
2. 创建并测试第一个数据库连接
3. 在需要参与开发或本地调试时从源码运行 DBX
## 选择安装方式
### macOS
使用 Homebrew 安装:
```bash
brew install --cask dbx
```
之后可用以下命令更新:
```bash
brew upgrade --cask dbx
```
也可以从 [GitHub Releases](https://github.com/t8y2/dbx/releases) 下载 `.dmg` 安装包。
### Windows
使用 Scoop 安装:
```bash
scoop bucket add dbx https://github.com/t8y2/scoop-bucket
scoop install dbx
```
之后可用以下命令更新:
```bash
scoop update dbx
```
也可以从 [GitHub Releases](https://github.com/t8y2/dbx/releases) 下载 `.msi` 安装包。
### Linux
使用 Flatpak 从 [FlatPark](https://flatpark.org/apps/com.dbxio.dbx/) 安装(适用于任意发行版):
```bash
flatpak remote-add --if-not-exists flatpark https://dl.flatpark.org/flatpark.flatpakrepo
flatpak install flatpark com.dbxio.dbx
```
之后可用以下命令更新:
```bash
flatpak update com.dbxio.dbx
```
银河麒麟 V10、统信 UOS 等系统推荐通过[星火应用商店](https://spk-resolv.spark-app.store/?spk=spk://store/development/dbx)安装,并选择 **APM 版本**。AmberPM 提供兼容运行环境,可减少发行版依赖差异导致的安装或启动问题,后续也可直接在星火应用商店客户端中获取更新。
APM 版本在兼容环境中运行 DBX。如果为 Agent/JDBC 驱动选择宿主机 Java,需要在路径前添加 `/host`,例如将 `/usr/bin/java` 填写为 `/host/usr/bin/java`。
也可以从 [GitHub Releases](https://github.com/t8y2/dbx/releases) 下载对应安装包:
| 格式 | 适用场景 |
| ----------- | --------------------------- |
| `.deb` | Debian、Ubuntu 及兼容发行版 |
| `.rpm` | Fedora、 CentOS、 SUSE 及兼容发行版 |
| `.AppImage` | 通用 Linux 桌面环境 |
如果使用 `.AppImage`,首次运行前可能需要添加执行权限:
```bash
chmod +x DBX*.AppImage
```
### Docker
Docker 版本适合部署在服务器上,并通过浏览器访问:
```bash
docker run -d \
--pull=always \
--name dbx \
-p 4224:4224 \
-v dbx-data:/app/data \
t8y2/dbx:latest
```
`latest` 标签会拉取当前发布版本。这里使用跨平台的 `dbx-data` 命名卷;中国大陆用户可改用 `docker.cnb.cool/dbxio.com/dbx:latest`,以获得更快的拉取速度。
### 环境变量
Docker 镜像支持以下启动参数。使用 `-e 变量名=值` 指定,例如生产环境可添加 `-e DBX_PASSWORD=your-password`:
| 参数 | 默认值 | 用途 |
| ----------------------------- | ----------- | ---------------------------------------------------- |
| `DBX_PASSWORD` | 未设置 | Web 登录密码,生产环境建议设置 |
| `DBX_DISABLE_PASSWORD` | `false` | 设为 `true` 或 `1` 可关闭登录保护 |
| `DBX_DISABLE_PASSWORD_VIEWER` | `false` | 设为 `true` 或 `1` 后,已保存连接凭据不返回浏览器,关闭密码查看、含密码复制及含凭据同步导出 |
| `DBX_DATA_DIR` | `/app/data` | 持久化数据目录 |
| `DBX_PORT` | `4224` | 容器内监听端口 |
| `DBX_PUBLIC_BASE_PATH` | `/` | 子路径部署,例如 `/dbx` |
关闭密码查看后,已配置连接仍使用服务端保存的凭据。密码框显示固定占位符;不修改时保留原值,输入新值可替换原值。修改连接目标时不能复用隐藏的旧凭据,需要输入替换凭据。修改环境变量后请重启服务端并刷新浏览器。
启动后访问 `http://localhost:4224`。
`deploy/docker-compose.yml` 用于构建当前源码。若要部署已发布镜像,请使用 `deploy/docker-compose.release.yml`:
```bash
docker compose -f deploy/docker-compose.release.yml up -d
```
```yaml
services:
dbx:
image: t8y2/dbx:latest
# 中国大陆用户可改用 CNB 镜像,以加快拉取速度:
# image: docker.cnb.cool/dbxio.com/dbx:latest
pull_policy: always
ports:
- "4224:4224"
volumes:
- dbx-data:/app/data
restart: unless-stopped
volumes:
dbx-data:
```
## 桌面版还是 Docker
| 模式 | 适合场景 | 存储位置 | 需要注意 |
| ------------ | -------------------- | ---------------- | ----------------------------------------- |
| 桌面版 | 本机日常工作、本地数据库文件、完整工作台 | 本机应用数据目录 | 支持本地 SQL 文件树/SQL 库、桌面 Deep Link 和操作系统文件集成 |
| Docker / Web | 服务器自托管、远程浏览器访问 | Docker 卷或服务器数据目录 | 文件路径属于服务器;部分本地文件和桌面集成功能不可用 |
桌面版和 Web 版共享大部分数据库工作流和 Rust 核心能力,但并非所有本地集成完全一致。需要 SQLite、DuckDB、Access、外部 SQL 文件或本机目录时,先确认文件实际位于哪台机器;Docker 中通常还需要把目录挂载进容器。
通过 MCP 打开表或展示查询结果等桌面 UI 工具,需要 DBX 桌面版正在运行。只使用查询类 MCP 工具时,可以直接读取本机 DBX 数据目录,或连接 DBX Web/Docker 后端。
## 创建第一个连接
### 打开新建连接
在侧边栏或工具栏中点击 **新建连接**。
### 选择数据库类型
选择 MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle,或 [数据库支持](/cn/docs/databases) 中列出的兼容类型、Agent/JDBC 类型。
### 填写连接信息
网络数据库需要填写主机、端口、用户名、密码和必要的默认数据库。SQLite、DuckDB、Access 这类文件型数据库需要选择本地数据库文件,不填写主机和端口。
### 有 URL 时直接粘贴
DBX 可以解析常见连接 URL,例如 MySQL、PostgreSQL、Redis、MongoDB、ClickHouse、SQL Server、Oracle、Elasticsearch、Easysearch、Meilisearch、CouchDB、DM、GaussDB、openGauss、TDengine 和 Access。保存前请检查解析出的字段。
### 配置网络选项
如果数据库在内网、跳板机后面、只能通过 Web 网关访问,或网络要求 SOCKS5/HTTP 代理,可以配置 [隧道/代理](/cn/docs/ssh-tunnel)。
### 测试并保存
点击 **测试** 验证账号、网络和权限。测试通过后保存连接,并从侧边栏打开。
连接密码、SSH 密码、SSH 密钥密码和连接字符串会与普通连接 JSON 分开存储在 DBX 本地数据中。需要迁移加密连接配置时,使用
[配置导出/导入](/cn/docs/config-export)
。
## 降低生产误操作
* 给生产连接起明确名称,例如 `prod-orders`,并使用颜色、分组和备注说明用途。
* 查询专用连接同时启用数据库只读账号和 DBX **只读连接**。
* 启用**生产环境保护**,按连接或指定数据库标记生产范围;写入时 DBX 会逐次要求明确确认。
* 一个服务器上数据库或 Schema 很多时,只显示当前需要的对象,减少误选目标。
* 对编辑、导入、传输、SQL 文件执行或 Schema 同步生成的 SQL,先审查再执行。
* 提供给 MCP 的连接使用 allowlist,并优先选择“只读”或“数据读写”,不要默认开放“完全访问”。
完整行为和推荐配置见 [生产环境与写入安全](/cn/docs/production-safety)。
## 下一步可以做什么
### [写 SQL](/cn/docs/query-editor)
使用补全、格式化、选中执行、取消执行和查询历史。
### [看数据](/cn/docs/data-grid)
查看结果、在安全时编辑行、预览 SQL 并导出数据。
### [看结构](/cn/docs/schema-browser)
浏览数据库、Schema、表、字段、Redis 键和 MongoDB 集合。
## 常见连接问题
| 现象 | 检查项 |
| --------- | ------------------------------------ |
| 连接超时 | 主机、端口、防火墙、安全组、VPN、Docker 主机网络或内网访问权限 |
| 认证失败 | 用户名、密码、认证方式、SSL 要求、账号是否允许远程登录 |
| 能连接但看不到表 | 默认数据库、Schema、权限、元数据读取权限、可见数据库过滤 |
| 文件数据库打不开 | 文件路径、文件权限、Docker volume 挂载、文件扩展名是否支持 |
| 内网数据库无法访问 | 配置隧道/代理、VPN,或让 Docker 部署机器能访问目标数据库 |
## 从源码运行
当你想参与开发或本地调试 DBX 时,可以从源码运行。
第一次参与开发请阅读[从源码编译与参与贡献](/cn/docs/contributing)。教程包含各系统环境安装、Fork、Issue 认领、测试和提交 PR 的完整步骤。
### 环境要求
* [Node.js](https://nodejs.org/) >= 22.13.0
* [pnpm](https://pnpm.io/) 10.34.7
* Make(macOS 和 Linux 需要;Windows 可选)
* [Rust](https://www.rust-lang.org/tools/install) >= 1.88
### 系统依赖
### macOS
`bash brew install unixodbc `
### Linux
`bash sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev unixodbc-dev `
### Windows
安装 [Strawberry Perl](https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases)(编译内置 OpenSSL 所需):
```powershell
winget install StrawberryPerl.StrawberryPerl
```
DBX 默认启用 `sqlite-sqlcipher` 特性,需要从源码编译 SQLCipher 和 OpenSSL,而 Windows 上编译 OpenSSL 必须使用 Perl 执行 `Configure` 脚本。安装后请重新打开终端,使 `perl` 进入 `PATH`。
### 启动开发环境
```bash
git clone https://github.com/t8y2/dbx.git
cd dbx
make
```
`make` 会在需要时安装根目录依赖,并启动本地 Tauri 桌面端开发环境。
Web 版本:
```bash
make dev-web
make dev-backend
```
### 构建桌面安装包
```bash
make package
```
桌面安装包会输出到 `target/release/bundle/`。
---
# 快捷键
> 查看当前默认按键,并在设置中为编辑器、表格、侧边栏和全局操作自定义快捷键。
Source: https://dbxio.com/cn/docs/keyboard-shortcuts
Language: zh-CN
Relative links resolve against https://dbxio.com/cn/docs/keyboard-shortcuts.
DBX 的快捷键来自同一份可配置 action registry。**设置 → 快捷键**显示当前版本和当前平台的实际绑定,是默认键变化或用户自定义后的权威来源。
`Mod` 表示 macOS 的 `Cmd`,Windows/Linux 的 `Ctrl`。
## 常用默认快捷键
### SQL 编辑器
| 默认键 | 操作 |
| --------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `Mod+Enter` | 执行当前语句或选中 SQL |
| `Mod+\` | 在新的结果标签页执行 |
| `Shift+Mod+F` | 格式化 SQL |
| `Mod+/` | 切换行注释 |
| `Mod+S` | 保存 SQL |
| `Tab` | 接受补全 |
| `Shift+Tab` | 减少缩进 |
| `Mod+D` | 复制当前行 |
| `Shift+Mod+K` | 删除当前行 |
| `Alt+↑` / `Alt+↓` | 上下移动当前行 |
| `Ctrl+↑` / `Ctrl+↓`(Windows/Linux),`Ctrl+Alt+↑` / `Ctrl+Alt+↓`(macOS) | 编辑器上下滚动一行,不移动光标或选区 |
| `Shift+Alt+↑` / `Shift+Alt+↓` | 向上/下复制当前行 |
| `Mod+Shift+U` | 切换选中内容大小写(首次默认转为大写) |
| `Shift+Alt+U` / `Shift+Alt+L` | 选中内容转大写/小写 |
| `Shift+Alt+C` | 切换选中内容的命名风格(camelCase → PascalCase → snake\_case → SCREAMING\_SNAKE\_CASE → kebab-case) |
| `Mod+.` | 折叠或展开代码块 |
| `Mod+Shift+A` | 把选中内容发送给 AI |
当前 registry 没有“执行全部 SQL”的默认 action。需要运行多条语句时,选中范围执行或使用编辑器提供的多语句执行入口,不要依赖旧文档中的 `Ctrl/Cmd+Shift+Enter`。
### 表格和数据
| 默认键 | 操作 |
| -------- | ------- |
| `F5` | 刷新当前数据 |
| `Mod+D` | 复制当前行 |
| `Delete` | 标记删除当前行 |
| `Tab` | 切换转置视图 |
普通复制/粘贴仍遵循平台标准按键,但“复制当前行”“删除当前行”和“切换转置”是 DBX 可配置 action。
「聚焦 WHERE 条件输入框」默认不绑定快捷键。可在 **设置 → 快捷键 → 数据表格** 中自行设置,按下已配置的快捷键后将光标移至当前表数据标签页的 WHERE 输入框,保留现有条件且不执行查询。WHERE 输入框不可用时不生效。
网格还有两个固定手势(不可自定义):光标停在当前显示的最后一行时按 `↓` 会在结果末尾追加一行(与「新增行」按钮不同,按钮跟随「插入位置」设置);编辑器内的 `Esc` 只取消本次输入,焦点回到网格后按 `Esc` 会撤掉未填写过的新增行,否则把当前单元格回退为原值。详见[数据表格](/cn/docs/data-grid)。
### 全局和导航
| 默认键 | 操作 |
| ----------------------------- | -------------- |
| `Mod+T` | 新建查询 |
| `Mod+P` | 快速打开 |
| `Mod+W` | 关闭当前标签页 |
| `Ctrl+Alt+←` / `Ctrl+Alt+→` | 后退/前进标签页访问历史 |
| `Shift+Mod+[` / `Shift+Mod+]` | 左侧/右侧标签页 |
| `Mod+1` … `Mod+9` | 切换到指定标签页 |
| `Mod+B` | 显示或隐藏侧边栏 |
| `Mod+=` / `Mod+-` / `Mod+0` | 放大、缩小、重置 UI 缩放 |
侧边栏还提供可配置的复制、粘贴、编辑连接和按住修饰键在新标签页打开数据等 action。
## 快速打开
按 `Mod+P` 搜索当前工作区中的连接、数据库、Schema、表、视图和保存的 SQL。结果来自已加载和可搜索的对象;大型连接尚未加载元数据时,先展开或刷新对应节点。
## 自定义和冲突
1. 打开 **设置 → 快捷键**
2. 选择 action 并进入录制
3. 按下新组合键;也可以清空不需要的绑定
4. 处理冲突后保存
DBX 会检测同一作用域中的冲突。编辑器、表格、搜索、侧边栏和全局 action 具有不同作用域,但浏览器、操作系统、输入法或辅助功能仍可能先占用按键。
快捷键页签的搜索框还支持**键盘录入**:点击搜索框右侧的键盘图标,直接按下组合键即可筛出绑定该组合的 action;跨作用域共用同一组合的 action 会一并列出,排查冲突时不必先知道组合键的写法。录入期间按下的组合键不会触发真实命令;`Esc` 退出录入,`Backspace` 清空已录入的组合。也可以在搜索框里直接输入文本形式,`Ctrl+T` 与 `Ctrl + T` 都能命中。
**被系统抢占的组合无法录入**:`Alt+F4`、`Win` 键、`Ctrl+Alt+Del`、macOS 的 `⌘Tab` 这类按键先被操作系统或窗口管理器处理,DBX 收不到,录制时不会有任何结果(也不是录入失败)。这类组合即使手工配置了绑定也不会触发,排查时请改用文本搜索。
Web 形态还要多一层:浏览器自己保留的按键(`Ctrl+W` / `Ctrl+Shift+W` / `Ctrl+T` / `Ctrl+N` 等,macOS 的 `⌘W`)由浏览器直接处理,页面拿不到事件。桌面形态没有这条限制——`Ctrl+Shift+W` 是「关闭窗口」的默认键,`Ctrl+W` 是「关闭标签页」的默认键,都可以正常录入。
Windows/Linux 上 `Ctrl+Alt` 可能被键盘布局当作 AltGr;DBX 对相关组合采取更保守的匹配。macOS 的 Option+字母可能产生变形字符,DBX 会在安全情况下使用物理键位回退。
## 相关页面
### [SQL 编辑器](/cn/docs/query-editor)
了解执行范围、多结果标签页和编辑器行为。
### [SQL 快捷操作](/cn/docs/sql-quick-actions)
选中表名或将光标放在表名上后,执行内置或自定义 SQL。
### [SQL 格式化](/cn/docs/sql-formatter)
配置格式化规则和格式化设置编辑器快捷键。
---
# MCP 集成
> 通过 Model Context Protocol 让 AI 编程助手在 DBX 权限策略内读取元数据、查询数据和使用有状态会话。
Source: https://dbxio.com/cn/docs/mcp
Language: zh-CN
Relative links resolve against https://dbxio.com/cn/docs/mcp.
把 AI 助手连接到 DBX,即可查看数据库结构、查询数据,并在 DBX 中打开结果。
## 什么是 MCP?
MCP(Model Context Protocol)是让 AI 客户端调用外部工具的开放协议。DBX MCP 可以让 AI 助手使用 DBX 中已经配置好的数据库连接。
```text
AI 助手 → DBX MCP → 你的数据库 → 返回结果
↘ DBX 桌面端(打开或展示结果)
```
## 原生安装(推荐)
无需 Node.js。macOS 或 Linux 执行:
```bash
curl -fsSL https://dbxio.com/install-mcp | sh
```
Windows 在 PowerShell 中执行:
```powershell
irm https://dbxio.com/install-mcp.ps1 | iex
```
脚本校验下载内容,将 `dbx-mcp` 安装到 `~/.dbx/bin`,并打印 Claude Code、Cursor、Codex、ZCode 和通用 MCP 配置。请使用输出中**展开后的可执行文件绝对路径**,不要填写 `~` 或裸命令 `dbx-mcp`:GUI 客户端不一定继承 shell 的 PATH。已有的 `DBX_DATA_DIR` 等环境配置继续有效。DBX 桌面设置优先使用发现的原生二进制,找不到时保留原有 npm 启动方式。
重跑同一安装命令即可升级;版本相同时提示 `already up to date`。版本优先读取 `dbx-mcp --version`,旧版二进制不支持时回退读取 `~/.dbx/bin/.dbx-mcp-version`。断网时安装失败但不会替换现有二进制。下载源依次为 npmjs、npmmirror、GitHub Releases;内容校验不匹配时立即拒绝安装。
macOS 和 Linux 也可以使用 Homebrew:
```bash
brew install t8y2/tap/dbx-mcp
brew upgrade t8y2/tap/dbx-mcp
```
Homebrew 安装后,客户端配置使用 `echo "$(brew --prefix)/bin/dbx-mcp"` 输出的绝对路径。此通道只安装 MCP 服务器,不安装独立的 `dbx` CLI。
npm/npx 通道保持兼容。DBX 桌面端现在默认安装独立原生服务,并为已有 npm 用户显示推荐的原生迁移入口。迁移会保留 npm 包作为兜底,也不会自动改写外部客户端文件:请将启动命令替换为页面生成的原生绝对路径,删除 Node/npx 参数并保留 `env`。仍可选择执行 `npm rm -g @dbx-app/mcp-server` 清理旧包。桌面端可以更新和卸载当前的独立原生或 Homebrew 安装;卸载独立原生版本后,保留的 npm 安装会重新成为兜底。
macOS 上,Shell 安装器还会在替换二进制前验证官方 Developer ID 签名及稳定的 `com.dbx.app.mcp` designated requirement。未签名、临时签名、签名身份不符或绑定单次构建哈希的安装包会被拒绝,已安装的程序和版本标记保持不变。此校验针对 Shell 安装器,Homebrew 和 npm 保持各自的安装流程。
## npm 快速开始
### 安装 MCP Server
```bash
npm install -g @dbx-app/mcp-server
```
npm 会自动安装当前平台需要的依赖。不要使用 `--no-optional`。
### 配置 AI 助手
在项目目录创建 `.mcp.json`:
```json
{
"mcpServers": {
"dbx": {
"command": "npx",
"args": ["-y", "@dbx-app/mcp-server"]
}
}
}
```
如果使用全局安装,可将 `command` 改为 `dbx-mcp-server`。连接 allowlist 和执行权限统一在 **DBX 设置 → MCP** 中管理,常规客户端配置不需要权限环境变量。Windows 便携版请将 `DBX_DATA_DIR` 设置为 `DBX.exe` 同级的 `data` 目录。
### 开始使用
在 AI 助手中直接使用自然语言:
* "列出我的数据库连接"
* "查看 local-pg 上有哪些表"
* "查看 users 表的结构"
* "查询最近 7 天的订单数量"
* "打开 orders 表"(需要 DBX 运行中)
## 支持的 AI 助手
| AI 助手 | 配置方式 |
| ----------------- | ----------------------------------------------- |
| Claude Code | `.mcp.json` |
| Cursor | `.cursor/mcp.json` |
| Windsurf | MCP 配置 |
| VS Code + Copilot | MCP 扩展/配置 |
| DeepSeek Harness | `$DSH_HOME/profiles//cordis.patch.yml` |
### DeepSeek Harness
DeepSeek Harness 通过 Cordis 插件条目加载 MCP Server,不读取 `mcpServers` JSON。安装 `@dbx-app/mcp-server` 后,为 `web` profile 将以下条目合并到 `$DSH_HOME/profiles/web/cordis.patch.yml`:未设置 `DSH_HOME` 时默认为 `~/.dsh`。
```yaml
- insert:
- id: mcp-dbx
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: dbx
transport: stdio
command: dbx-mcp-server
```
保留最外层的 `- insert:`,不要覆盖文件中已有的 patch 条目。使用其他 DSH profile 时,将路径中的 `web` 替换为对应 profile 名称。DSH 进程的 `PATH` 必须能找到 `dbx-mcp-server`;必要时请改用可执行文件的绝对路径。
运行 `dsh web --dump-config` 检查组合后的配置,再重启 DSH 或等待热加载应用该 patch。模型侧工具名为 `mcp__dbx__`。请保持 `serverName: dbx` 稳定,避免工具名和权限规则发生变化。连接访问范围和执行模式仍统一在 **DBX 设置 → MCP** 中管理。
## 工具列表
DBX MCP 当前提供以下工具(具体可用工具取决于构建功能及权限设置):
| 工具 | 说明 |
| ------------------------------ | -------------------------------------------------------------------- |
| `dbx_list_connections` | 列出当前 MCP 会话可见的连接,包括已保存的备注 |
| `dbx_list_databases` | 列出连接中可通过 MCP 访问的数据库,并遵守该连接的数据库范围 |
| `dbx_add_connection` | 添加连接到 DBX 存储 |
| `dbx_duplicate_connection` | 复制一个连接及其完整配置 |
| `dbx_remove_connection` | 从 DBX 存储删除连接 |
| `dbx_list_tables` | 列出表、视图或集合 |
| `dbx_describe_table` | 返回列定义和表元数据 |
| `dbx_list_routines` | 列出 Schema 中的存储过程和函数,支持可选的 `routine_type` 过滤(PROCEDURE 或 FUNCTION) |
| `dbx_get_routine_source` | 按名称返回存储过程或函数的源码,重载场景可用可选的 `signature` 区分 |
| `dbx_get_schema_context` | 返回适合 AI 使用的紧凑 Schema 上下文 |
| `dbx_execute_query` | 执行 SQL 或支持的 MongoDB shell 命令,默认返回 100 行,可用 `max_rows` 参数提高到最多 1000 行 |
| `dbx_execute_batch` | 一次执行包含多条语句的 SQL 脚本,按语句返回结果(多语句脚本搭配 `use_transaction` 时返回单个合并结果) |
| `dbx_open_session` | 为 SQL 连接打开固定后端连接的有状态查询会话 |
| `dbx_begin_transaction` | 在已启用事务的原生 MySQL 会话上开始事务 |
| `dbx_commit_transaction` | 在 MySQL 确认 `COMMIT` 后提交当前会话事务 |
| `dbx_rollback_transaction` | 回滚当前会话事务 |
| `dbx_close_session` | 关闭会话并释放固定连接资源 |
| `dbx_execute_redis_command` | 执行 Redis 命令 |
| `dbx_salesforce_current_user` | 显示连接背后的 Salesforce 用户与组织,包括简档是否具有 “Modify All Data” |
| `dbx_salesforce_prepare_write` | 准备一条 Salesforce 记录写入,返回摘要和一次性确认令牌 |
| `dbx_salesforce_apply_write` | 使用确认令牌应用已准备的 Salesforce 写入 |
| `dbx_peek_messages` | 读取 Kafka 消息,不提交消费位点 |
| `dbx_send_message` | 向支持的消息队列 Topic 或队列发送消息 |
| `dbx_open_table` | 在运行中的 DBX 桌面端打开表 |
| `dbx_execute_and_show` | 执行查询并在 DBX 中展示结果 |
`dbx_list_connections` 和 `dbx://connections` 会返回已保存的连接备注,不受侧边栏显示开关影响。可访问该连接的 MCP 客户端也能看到备注,请勿在备注中保存密码或其他敏感信息。
`dbx_execute_query` 返回行数:
* `max_rows`:取值 1–1000,默认 100。越界值会被夹取到范围内,而不是报错。仅对 SQL 连接生效——MongoDB shell 命令始终最多返回 100 行,路由到批量执行器的多语句脚本每条语句最多返回 100 行。
启用连接作用域后,修改连接和桌面 UI 工具会被隐藏。
## 插件工具
实现了 `mcp/tools` 桥接协议的 DBX 插件 sidecar,其工具可由 `dbx` MCP 服务器合并进 `tools/list`,无需在客户端逐个配置插件的 `--mcp` 进程。该机制按作者声明加入:只有 manifest 中声明了 `mcp` 贡献且 `external_tools: true` 的插件(SSH、Files、Kafka、LDAP 等均可)才会暴露工具:
* 工具名为 `dbx_<插件前缀>__<工具名>`,前缀取插件 id 的最后一段:`io.dbx.ssh` → `dbx_ssh__sftp_list_dir`,`io.dbx.kafka` → `dbx_kafka__kafka_topics_list`;
* 连接由宿主绑定:工具 schema 中的 `connectionId` / `connectionName` 会被移除,改由可选的 `dbx_connection` 参数选择该插件**已保存且被 MCP 设置放行**的连接;只有一个可用连接时省略该参数即可自动绑定;凭据由宿主从保存的连接生成 lifecycle 注入,永不经过模型或客户端;
* 作用域会话(`DBX_MCP_SCOPE_*`)与全局 MCP 设置(工具 allowlist、连接 allowlist)同样约束插件工具;
* 工具白名单按精确名称匹配:启用插件工具后,请把要暴露的 `dbx_<前缀>__<工具名>` 逐个加入白名单(或清空白名单以全部放行);
* Web / Docker 后端不提供插件工具。
### 懒发现(`DBX_MCP_PLUGIN_TOOLS`)
插件较多时,平铺的 `tools/list` 会在参数 schema 上消耗大量上下文。设置 `DBX_MCP_PLUGIN_TOOLS=lazy` 只暴露三个元工具——`dbx_plugin_list`(可过滤的插件目录)、`dbx_plugin_tools`(按**插件 id** 查看某插件的工具与 schema)、`dbx_plugin_call`(按插件 id + 工具名调用)——schema 在需要时才进入上下文。`both` 同时平铺与元工具。默认仍为 `flat`。
## Resources
支持 MCP Resources 的客户端可以读取连接目录,并通过模板获取数据库元数据:
| Resource URI | 说明 |
| ------------------------------------------------------------------------ | ---------------------- |
| `dbx://connections` | 当前 MCP 范围内可见的连接 |
| `dbx://connections/{connection_id}/databases` | 指定连接中可见的数据库 |
| `dbx://connections/{connection_id}/tables{?database,schema}` | 可选数据库或 Schema 中的表和视图 |
| `dbx://connections/{connection_id}/table-schema{?database,schema,table}` | 指定表的字段定义;`table` 为必填参数 |
Resource 的发现和读取会复用对应 Tool 的白名单,以及连接、分组、数据库和运行时范围限制。查询参数值必须进行 URI 编码。SQL 执行和所有可写操作仍只通过 Tool 提供。
## 读取 Kafka 消息
包含 `mq-admin` 的构建在本地和 Web 模式下均提供 `dbx_peek_messages`。通过 `connection_id` 或 `connection_name` 选择已保存的 Kafka 连接,并指定 `topic`。工具遵守 MCP 连接范围及工具白名单,允许读取只读连接和生产连接,不提交消费位点。
```json
{
"connection_name": "Kafka",
"topic": "events",
"count": 20,
"start_position": "offset",
"partition": 0,
"offset": 120
}
```
* `count`:1–100,默认 20。
* `start_position`:`latest`(默认)、`earliest` 或 `offset`。仅 `offset` 模式必须且允许传入非负 `offset`。
* `partition`:可选的非负分区号。不传时跨分区读取;offset 模式下从各分区的该位点开始读取。
* JSON 结果包含 `messages`,保留 base64 消息体、可无损解码时的 UTF-8 预览、消息 ID 和元数据。`incomplete` 表示读取达到超时或扫描上限;`outputTruncated` 表示为满足 256 KiB 消息输出预算而省略了整条消息。如果首条消息过大,可能返回空列表并标记 `outputTruncated: true`,不会静默截断消息体。
该工具读取有限条消息快照,不提供持续订阅或全 Topic 文本搜索。其他消息队列类型会被拒绝。
## 批量 SQL 执行
`dbx_execute_batch` 在单次调用内执行包含多条语句的 SQL 脚本。默认(自动提交)模式下按语句返回结果,因此调用方可以清楚看到哪条失败、每条影响多少行、各自返回什么;使用 `use_transaction` 且脚本包含多条语句时,只返回一个合并的事务结果。
* 脚本通过方言感知的解析器拆分成独立语句,字符串、注释、存储过程中出现分号也不会破坏批次。
* 默认遇到第一条失败语句即停止;传入 `continue_on_error` 可让批内在单条语句出错后继续执行(连接级错误仍会终止)。
* 传入 `use_transaction` 可把多条语句放入同一个 `BEGIN … COMMIT`,使整批要么全部成功要么回滚;这要求脚本包含多条语句(单语句脚本会忽略该选项,按普通自动提交执行)。此模式下调用只返回一个合并结果(而非逐语句结果),且 `use_transaction` 不能与 `session_id` 同时使用——事务批处理运行在池连接上,会丢弃会话状态;也不能与 `continue_on_error` 同时使用——事务批处理在第一条失败时即回滚并停止。当当前后端无法提供可回滚事务时,DBX 会拒绝该选项。MySQL 系连接对含 DDL 的脚本会拒绝 `use_transaction`,因为 MySQL 的 DDL 会隐式提交、无法回滚。
* SQL 策略(只读、危险 SQL、生产保护、切换数据库)作为整体在匹配前重新检查,与 `dbx_execute_query` 一致;只要批内含一条写入或 DDL,在只读策略下整次调用都会被拒绝。
* 每个批次在其完整执行期间都会使用独占连接,因此临时表和 `SET` 状态可在批内语句之间保留。若要跨多次 MCP 调用保留这些状态,先用 `dbx_open_session` 打开会话,再传入其 `session_id`。
* Redis 和 MongoDB 连接不支持 `dbx_execute_batch`。
## 有状态查询会话
普通 `dbx_execute_query` 调用彼此独立。需要保持数据库 Session 状态时,先调用 `dbx_open_session`,再把返回的 `sessionId` 传给后续 `dbx_execute_query` 或 `dbx_execute_batch`:
* `USE` 或数据库上下文切换
* 临时表
* Session 变量和设置
* 需要固定连接的显式事务或多步诊断
会话只支持 SQL 连接,并固定到一个连接和数据库。未知、已关闭或过期的 `sessionId` 会失败,不会静默退化为普通查询。完成后应调用 `dbx_close_session`;会话默认空闲 30 分钟后回收,同时最多允许 32 个并发会话。在 MCP 宿主进程设置 `DBX_SESSION_IDLE_TTL_SECS=43200` 可将空闲时间延长为 12 小时,事务专属连接也使用此配置。值必须为正整数秒;未设置、非法值、零、负数或无法表示的时长均保留默认 1800 秒。修改后需重启宿主。使用嵌入式 DBX Web MCP 时,在 Web 服务端设置;使用独立启动器时,在启动器环境中设置。
有状态会话不会放宽 SQL 策略。
`USE`
只有在会话中才有意义,但写入、DDL、生产保护、连接只读和数据库权限仍按每次请求重新检查。
### 原生 MySQL 显式事务
调用 `dbx_open_session` 时传入 `enable_transactions: true`,DBX 会立即保留一条物理原生 MySQL 连接。随后依次调用 `dbx_begin_transaction`、带该 `session_id` 的一个或多个 `dbx_execute_query`/`dbx_execute_batch`,最后调用 `dbx_commit_transaction` 或 `dbx_rollback_transaction`。事务前后的查询仍使用同一条受管连接。`use_transaction` 仍不能与 `session_id` 同时使用;它是前文所述的独立原子批处理功能。
该 opt-in 模式仅支持本地原生 MySQL 连接。DBX Web/`DBX_WEB_URL`、外部驱动 profile、兼容引擎及其他数据库类型会返回 `TRANSACTION_UNSUPPORTED`,不会静默退化为自动提交。事务会话每次操作只接受一条经过解析的 `SELECT`(含锁定读)、`INSERT`、`UPDATE`、`DELETE` 或 `REPLACE`;原始事务控制、DDL/临时 DDL、`CALL`、`LOAD`、表锁、`SET`、`USE`、XA、文件/输出子句、可执行注释、优化器 hint 及多语句均会被拒绝。完整批次持有同一个操作槽位,并为每条语句返回执行后的事务状态。
响应包含 `transaction_state`(`idle`、`active` 或 `unknown`),并在适用时包含 `transaction_outcome`(`committed`、`rolled_back` 或 `unknown`)。普通 MySQL 语句错误可能仍让事务保持 active;DBX 会在同一连接上重新探测服务器状态后再返回。超时、取消、传输故障或丢失 `COMMIT` 确认会把结果永久标为 `unknown`,禁止该会话继续执行 SQL,并在不重放语句或 `COMMIT` 的前提下销毁连接。显式正值的连接查询超时同样用于事务操作;当连接配置为“无限制”(`0`)时,事务 owner 仍使用默认 300 秒操作上限,确保 busy 操作保持有界。关闭、过期和服务退出会对状态已知的 active 事务执行有界回滚,然后销毁连接。会话的回收途径是 `dbx_close_session`、空闲超时或 MCP 服务退出。HTTP 传输层不持有任何会话,因此没有传输会话可供 `DELETE` 结束、也不会因空闲而丢失;承载状态的只有 `session_id` 句柄本身。
回滚保证依赖 InnoDB 等事务型存储。触发器、存储函数、非事务表及外部副作用可能产生 MySQL 无法回滚的效果。DBX 会在排队完成后重新检查当前连接/数据库范围、工具 allowlist、只读与生产保护以及已确认 SQL。即使写权限被撤销,仍允许原会话执行回滚和关闭以完成清理。
## Salesforce SOQL 与 DML
Salesforce 连接使用 SOQL 而非 SQL,DBX 据此调整了 MCP 的行为:
* `dbx_list_tables` 列出组织中的对象,`dbx_describe_table` 列出对象字段,`dbx_execute_query` 执行 SOQL(例如 `SELECT Id, Name FROM Account LIMIT 10`)。
* `dbx_list_databases` 会说明一个 Salesforce 组织就是一个作用域,而不会虚构数据库。
* `dbx_execute_batch` 与 `dbx_open_session` 会被拒绝:SOQL 只读,不存在需要批处理的多语句脚本;每次调用都是无状态 REST 请求,没有可固定的会话,也没有可开启的事务。
* 写入记录永远不会走查询通道。`dbx_execute_query` 会以 `SALESFORCE_DML_REQUIRES_CONFIRMATION` 拒绝写入尝试,因此下面的确认流程无法被绕过。
### 写入确认
写入分为两次调用,且只有当人看到第一步的摘要后第二步才可能执行:
1. 调用 `dbx_salesforce_prepare_write`,传入 `connection_id`(或 `connection_name`)、`op`(`insert`、`update` 或 `delete`)、`object`(API 名称,如 `Account` 或 `Invoice__c`);`update`/`delete` 需要记录 `id`,`insert`/`update` 需要 `fields`。此时不会向 Salesforce 发送任何请求。
2. 把返回的摘要展示给用户:操作、对象、记录 Id、每个字段值、连接,以及该变更所归属的身份。
3. 调用 `dbx_salesforce_apply_write`,传入第 1 步返回的 `confirm_token`。
令牌只能使用一次,签发 5 分钟后过期,并与那一条语句绑定——写入内容变了就必须重新准备。重放、过期或从未签发的令牌会以 `CONFIRM_TOKEN_INVALID` 失败。DBX 在应用阶段会重新检查连接范围、工具白名单、只读与生产保护以及 DML 开关,因此两次调用之间撤销权限会立即生效。
Salesforce 写入不是事务性的。
`dbx_salesforce_apply_write`
返回后,组织中的记录已经改变,DBX 无法回滚。每次调用只影响一条记录:
`upsert`
、批量与 composite 写入会在准备阶段以
`SALESFORCE_DML_INVALID`
拒绝。准备写入需要
**设置 → MCP**
中该连接的
**允许 DML**
开关,它默认关闭,未开启时返回
`SALESFORCE_DML_DISABLED`
;执行模式为只读时该开关一律无效。
### 写入归属的身份
`dbx_salesforce_current_user` 返回当前连接用户、简档、组织显示名,以及该简档是否具有 **Modify All Data**——这个标志决定字段级安全和记录共享规则是否生效。准备写入前先调用它,也可以用它区分权限失败与记录 Id 错误。`dbx_salesforce_prepare_write` 的摘要中包含同样的身份信息;若查询失败,摘要会写明身份未知并仍然完成准备,把是否应用的决定权留给用户。
## 数据库访问
### DBX Desktop 原生 Streamable HTTP
Desktop 可以选择直接托管 Streamable HTTP MCP 服务。该服务**默认关闭**;在 **设置 → MCP → HTTP 服务**启用后,默认仅监听 `127.0.0.1:5225/mcp`。监听服务由 Desktop 进程管理,会生成本地 Bearer Token,页面提供可复制的客户端配置;服务异常退出时会由 Desktop 自动重新拉起。
本机 MCP 客户端的接入步骤:
1. 打开 **设置 → MCP → HTTP 服务**,开启 **Streamable HTTP 服务**。除非确实需要让其他设备访问,否则保持默认本机回环地址。
2. 点击 **保存并应用**。该按钮会保存配置,并根据开关状态启动、重启或停止服务;修改地址、端口或路径时会自动重启服务。
3. 将页面展示的服务地址和 Bearer Token 复制到 MCP 客户端。
不同客户端的字段名称可能不同,但核心配置如下:
```json
{
"type": "http",
"url": "http://127.0.0.1:5225/mcp",
"headers": {
"Authorization": "Bearer "
}
}
```
本机客户端建议保留默认回环监听。绑定到局域网地址时,必须开启 **允许远程访问**,并填写精确的允许 `Host`;浏览器客户端还必须填写精确的 `Origin`。客户端通过非默认端口访问时,允许的 Host 应写成 `host:port`。轮换 Token 会立即使旧凭证失效。
同一个端点同时响应两代 MCP 协议,任何版本的 Agent 都无需特殊配置即可连接:
| Agent | 握手方式 | 传输状态 |
| ----- | ---------------------------------- | ----------------------------------- |
| 旧版客户端 | `initialize`(协议 `2025-11-25` 及更早) | 无状态:响应不返回 `Mcp-Session-Id`,每个请求独立处理 |
| 新版客户端 | `server/discover`(协议 `2026-07-28`) | 无状态:每个请求在 `_meta` 中自带协议版本与能力 |
两代客户端都以无状态方式服务,因此端点只接受 `POST`:`GET` 与 `DELETE` 返回 `405 Method Not Allowed`。DBX 不依赖任何 HTTP 层会话,所以客户端无论空闲多久再连接都能正常工作,不会撞上已被服务端回收的会话。
DBX 的有状态会话在两种情况下都可用,因为它是**显式句柄**:`dbx_open_session` 返回的 `session_id` 由 Agent 在后续调用中作为普通工具参数回传。该句柄独立于传输层、有自己的空闲 TTL,负责让固定连接、`USE`/`SET` 状态、临时表或已开启的事务跨请求保持。
### 本地连接
这是默认模式。MCP 使用 DBX 中保存的连接配置。原生可执行的连接不要求 DBX 桌面端保持运行;需要 Desktop bridge 或已安装 Agent/驱动的连接仍依赖对应运行时。
常见的本地数据库文件路径:
| 平台 | 默认路径 |
| ------- | -------------------------------------------------- |
| macOS | `~/Library/Application Support/com.dbx.app/dbx.db` |
| Linux | `~/.local/share/com.dbx.app/dbx.db` |
| Windows | `%APPDATA%\com.dbx.app\dbx.db` |
`DBX_DATA_DIR` 必须指向包含 `dbx.db` 的目录,而不是数据库文件本身。Windows 便携版通常是 `DBX.exe` 同级的 `data` 目录。
原生 SQL、独立 Redis 和 MongoDB 等路径可以由 MCP 直接执行。SSH、集群、厂商专用、外部驱动以及 Agent/JDBC 连接是否可用,取决于连接配置和本机已安装的 DBX 组件;不要从“DBX 支持该数据库”推断 MCP 原生包已经内置全部运行时。
DuckDB 使用独立的 DBX DuckDB 驱动。通过本地 MCP 查询 DuckDB 前,需要先在 **DBX Driver Manager** 中安装该驱动。MCP 二进制只包含 sidecar 客户端,不会内置 DuckDB 引擎。
### Agent/JDBC 数据库
Oracle、金仓KingbaseES 和虚谷需要匹配的 DBX 原生 Agent,但不需要 JRE。达梦、DB2、Hive、Trino、Snowflake、SAP HANA 等 JDBC Agent 数据库需要匹配的 Agent、JDBC 驱动和 JRE。请先在 DBX 中安装所需组件,再使用 MCP。
### DBX Web / Docker 模式
设置 `DBX_WEB_URL` 后,MCP 会使用部署的 DBX Web 后端,而不是读取本机连接。如果 Web 登录启用了密码保护,还要设置 `DBX_WEB_PASSWORD`,值为 Web 登录页使用的密码。
DBX Web 请求遵循标准系统代理环境变量:https 地址读取 `HTTPS_PROXY`/`https_proxy`,http 地址读取 `HTTP_PROXY`/`http_proxy`,`ALL_PROXY`/`all_proxy` 作为兜底,`NO_PROXY`/`no_proxy`(逗号分隔的主机列表,例如 `localhost,127.0.0.1,.internal.example`)作为绕过列表。代理值为空或未设置时直连(不走代理)。支持 HTTP、HTTPS 与 SOCKS5 代理(`http://127.0.0.1:7890` 或 `socks5://127.0.0.1:1080`);需要认证的代理使用标准 `user:password@host:port` URL 形式,例如 `http://admin:admin123@127.0.0.1:7890`。如需为每次 DBX Web 请求附加自定义请求头(例如网关前的令牌认证),将 `DBX_WEB_HEADERS` 设置为 JSON 对象,键为请求头名称、值为字符串,例如 `{"Authorization":"Bearer "}`。目标为自签名 HTTPS 时,证书验证默认开启:设置 `DBX_WEB_INSECURE_SKIP_VERIFY=1` 可跳过验证,或设置 `DBX_WEB_CA_CERT` 指向 PEM/DER CA 文件以信任私有 CA。同样的变量在 DBX CLI 的 Web 模式下同样生效。
DBX Web 和 Docker 同样需要独立 DuckDB 驱动。首次启动后可通过 Driver Manager 安装;Docker 会把驱动保存到 `/app/data/agents`,挂载 `/app/data` 数据卷后升级容器不会丢失。
### DBX Web 原生 Streamable HTTP
DBX Web 可以直接托管 MCP,复用现有 Web 监听器和 `/mcp` 路径,因此 Docker 和反向代理部署不需要额外暴露第二个端口。单实例、已启用 Web 登录密码的部署可在 **设置 → MCP → HTTP 服务**填写允许的 Host 并启用服务;DBX 自动生成 Bearer Token,使用现有加密 Secret 存储,可在页面复制、轮换或禁用,修改立即对新请求生效。未启用时页面不会把 `/mcp` 显示为可连接地址。无 Web 登录密码时,页面管理的 MCP 不会生效;演示部署禁用 MCP。
部署环境变量仍然优先:配置 `DBX_WEB_MCP_TOKEN` 或 `DBX_WEB_MCP_TOKEN_FILE` 后,页面只读显示状态,不会覆盖部署 Secret。此前启用的页面 Token 仍会保留;移除部署 Token 并重启 Web 后,它会重新生效。将 `DBX_WEB_MCP_ALLOWED_HOSTS` 配置为客户端在 `Host` 请求头中发送的公网访问地址;如有端口映射,必须包含映射后的端口。多实例部署应使用一致的部署 Secret 与白名单,而不是页面管理模式。生产环境请使用 `DBX_WEB_MCP_TOKEN_FILE` 或部署平台的 Secret 管理能力,不要把真实 Token 提交到 Compose 文件中。
例如容器映射为 `4225:4224` 时,MCP 地址为 `http://localhost:4225/mcp`:
```yaml
environment:
DBX_WEB_MCP_TOKEN: replace-with-a-long-random-secret
DBX_WEB_MCP_ALLOWED_HOSTS: localhost:4225
ports:
- "4225:4224"
```
客户端必须携带 `Authorization: Bearer `。浏览器客户端还需要在 `DBX_WEB_MCP_ALLOWED_ORIGINS` 中填写精确 Origin,例如 `https://mcp.example.com`;原生客户端通常不会发送 `Origin` 请求头。若反向代理添加了公网路径前缀,请设置 `DBX_PUBLIC_BASE_PATH=/dbx`,此时原生端点为 `/dbx/mcp`。原生 HTTP 与现有的 `DBX_WEB_URL` stdio 适配方式可以同时使用:两者共享 DBX 连接和 MCP 策略,后者仍适合只支持 stdio 的客户端。
### 桌面 UI 工具
`dbx_open_table` 和 `dbx_execute_and_show` 要求 DBX 桌面端正在运行,并且在 Web 模式或连接作用域隐藏 UI 工具时不可用。其他工具是否需要 Desktop 取决于该连接是原生执行还是 bridge/Agent 路径。
## 安全和环境变量
DBX 在 **设置 → MCP** 中保存一份权威策略,并在每次请求时重新读取:
| 权限模式 | 允许的操作 |
| ---- | --------------------------------------------------------- |
| 只读 | 查询和元数据读取 |
| 数据读写 | 普通插入、带有效过滤条件的更新/删除、范围明确的 MongoDB 修改和普通 Redis 写入 |
| 完全访问 | 额外允许大范围更新/删除、DDL、`TRUNCATE`、MongoDB 破坏性操作和 Redis `FLUSH*` |
`WHERE TRUE`、`WHERE 1 = 1`、`_id: {$exists: true}` 或不透明 MongoDB 过滤器仍按高风险处理。连接自身只读、生产库保护、数据库账号权限和 MCP 连接 allowlist 在任何模式下都是权限上限。
对于已暴露给 MCP 的连接,**设置 → MCP** 可以设置连接默认执行权限:继承全局、只读、安全写入或高风险写入。选择指定数据库后,还可为单个数据库设置执行权限。执行权限按范围由小到大回退:**单库设置 → 连接默认 → 全局默认**;例如全局和连接默认均为“数据读写”时,可为单个数据库设置“完全访问”。连接自身只读、生产库保护、数据库范围和数据库账号权限仍是独立的硬性限制,不能被单库设置绕过。
同一页面还可只暴露选定的 MCP 工具。这项限制在服务端的每一次调用中都会强制执行,不只是客户端的展示偏好;即使客户端缓存了旧工具列表,也会在服务端 allowlist 更新后被拒绝。
### 按顺序配置授权范围
在 **设置 → MCP** 中建议按以下顺序定义最终权限范围:
1. 选择 MCP 可见的是**所有连接**(包括以后新增的连接),还是仅**指定连接**。
2. 为每个已暴露连接选择**全部数据库**、**仅指定数据库**或**不允许访问**。指定数据库名按精确名称匹配;可先调用 `dbx_list_databases` 获取当前允许使用的名称,并为选中的数据库按需设置执行权限。
3. 为每个连接设置默认执行权限。未配置单库覆盖、或选择全部数据库时,该默认值就是连接内数据库的执行权限。
4. 仅选择客户端实际需要的 MCP 工具,再设置全局默认执行权限模式。
执行权限由最具体的设置决定,但已允许的工具仍不能绕过隐藏连接、数据库范围、连接只读、生产库保护或数据库账号本身的权限。请求未被选中数据库时,服务会返回 `DATABASE_OUT_OF_SCOPE`;配置单库执行权限时,跨库 SQL 和 MongoDB 聚合写入会被拒绝,避免绕过数据库级限制。
升级时,未带执行策略版本的已保存连接规则继续使用旧的权限上限语义,不会放大全局权限。只有当前设置页面保存的规则会标记为范围覆盖语义;编辑旧规则时,系统会先固化其实际生效的权限上限,再启用新的覆盖行为。
新版 Server 不允许 `DBX_MCP_ALLOW_WRITES` 或 `DBX_MCP_ALLOW_DANGEROUS_SQL` 放宽 DBX 中央策略。为兼容升级,在中央策略首次保存前,旧配置中的 `DBX_MCP_ALLOW_WRITES=0`(或 `false`)仍会保持 MCP 只读;策略保存后仅以中央策略为准,并忽略旧权限变量。旧连接 scope 变量只能进一步收窄 DBX allowlist。
| 变量 | 用途 |
| ------------------------------------------ | ------------------------------------------------------------------------------ |
| `DBX_DATA_DIR` | 覆盖本地 DBX 数据目录 |
| `DBX_SESSION_IDLE_TTL_SECS` | 有状态会话空闲超时,单位为正整数秒,默认 `1800`。非法值、零、负数或无法表示的时长回退默认值;同样适用于事务专属连接。修改后需重启 MCP 宿主进程。 |
| `DBX_WEB_URL` | 使用 DBX Web/Docker 后端 |
| `DBX_WEB_PASSWORD` | 登录 DBX Web |
| `HTTP_PROXY` / `HTTPS_PROXY` / `ALL_PROXY` | DBX Web 请求的标准系统代理变量;空值表示不走代理。认证格式 `http://user:pass@host:port` |
| `NO_PROXY` | 上述代理的标准绕过列表(逗号分隔主机) |
| `DBX_WEB_HEADERS` | DBX Web 请求附加的请求头 JSON 对象,例如 `{"Authorization":"Bearer token"}` |
| `DBX_WEB_INSECURE_SKIP_VERIFY` | `1`/`true` 时跳过 TLS 证书验证(用于自签名 DBX Web 后端;默认验证) |
| `DBX_WEB_CA_CERT` | DBX Web TLS 验证时信任的 PEM/DER CA 文件 |
| `DBX_WEB_MCP_TOKEN` | 使用该 Bearer Token 启用原生 Web Streamable HTTP MCP |
| `DBX_WEB_MCP_TOKEN_FILE` | 从文件读取原生 Web MCP Token;不能与 `DBX_WEB_MCP_TOKEN` 同时设置 |
| `DBX_WEB_MCP_ALLOWED_HOSTS` | 原生 Web MCP 必填:允许的公网 Host authority,逗号分隔 |
| `DBX_WEB_MCP_ALLOWED_ORIGINS` | 原生 Web MCP 的浏览器 Origin allowlist,逗号分隔 |
| `DBX_MCP_ALLOW_WRITES` | 仅用于升级兼容:`0`/`false` 使尚未配置的策略保持只读 |
| `DBX_MCP_SCOPE_CONNECTION_ID` | 兼容旧配置:限制为一个连接 ID |
| `DBX_MCP_SCOPE_CONNECTION_IDS` | 兼容旧配置:限制为多个连接 ID |
| `DBX_MCP_SCOPE_CONNECTION_NAME` | 限制为一个连接名称 |
| `DBX_MCP_SCOPE_DATABASE` | 限制为一个数据库 |
| `DBX_MCP_DEBUG_SQL` | 临时诊断时输出 SQL |
## 常见问题
### 升级后的凭据访问
独立 macOS MCP 在后台运行时不弹出钥匙串对话框。已有加密密钥被锁定或拒绝访问时,启动会保留 `KEYRING_ACCESS_FAILED`(可能包含在 `SECRET_KEY_UNAVAILABLE` 中),而不是反复要求输入密码。先解锁登录钥匙串;对于旧版绑定构建哈希的授权,在终端对 **MCP 客户端实际使用的同一个官方程序**执行一次:
```bash
"$HOME/.dbx/bin/dbx-mcp" --authorize-keychain
```
Homebrew 或 npm 安装需要替换为对应的二进制路径。该命令先验证运行程序的官方签名和稳定 designated requirement,再读取已有 DBX 钥匙串条目;不会打开数据库、启动 MCP 传输、创建或替换密钥、导出密钥,也不会自行改写 ACL。macOS 首次迁移时可能要求确认一次,对已验证的 DBX 程序选择 **始终允许**(不要选 **允许**)。随后命令会用一个全新的非交互进程再读取一次密钥;若授权未被保留,会以 `KEYRING_ACCESS_FAILED` 报错,因此看到成功提示即表示后台启动可用。最后重启 MCP 客户端。已获授权的程序应直接成功。稳定签名使普通正式升级继续沿用授权,但不能绕过签名团队变更或用户撤销权限。
不要将 `--authorize-keychain` 添加到 MCP 客户端的启动参数,它是执行后立即退出的一次性恢复命令。缺失的密钥仍需通过 Desktop 数据安全设置处理,该命令不能恢复丢失的密钥。Windows 和 Linux 不使用此 macOS 命令;应恢复同一系统用户的凭据库访问(或配置的无界面密钥文件),再重启 MCP。凭据库拒绝访问或密钥损坏时,不应自动生成替代加密密钥。
### npm 没有安装当前平台包
不要使用
`--no-optional`
,重新安装
`@dbx-app/mcp-server`
,并用
`node -p 'process.platform + "-" + process.arch'`
检查平台。Alpine Linux 默认使用 musl,目前不在 Linux 发布包支持范围内。
### 找不到 dbx.db
将
`DBX_DATA_DIR`
设置为包含
`dbx.db`
的目录。Windows 便携版通常是
`DBX.exe`
旁边的
`data`
目录。
### 提示 DBX 未运行
只有
`dbx_open_table`
和
`dbx_execute_and_show`
需要桌面端运行;本地查询工具可以在 DBX 关闭时执行。
### Desktop HTTP 客户端提示 ERR_CONNECTION_REFUSED
进入
**设置 → MCP → HTTP 服务**
,确认服务已开启并点击
**保存并应用**
。客户端应使用页面展示的地址、路径和当前 Bearer Token。默认的
`127.0.0.1`
只接受同一台电脑上的连接。
### Desktop 提示 HTTP 地址已被占用
已有其他进程监听了所选地址和端口。请在
**设置 → MCP → HTTP 服务**
中改用未被占用的端口,再保存配置以重启服务。不要让两个 DBX Desktop 实例使用相同 HTTP 端点。
### 请求返回 DATABASE_OUT_OF_SCOPE
该连接虽然已暴露给 MCP,但请求的数据库不在它的 MCP 数据库范围内。请在
**设置 → MCP**
中添加精确的数据库名称,或在合适时将该连接设为全部数据库。指定范围时,应先调用
`dbx_list_databases`
,再使用返回的名称。
### 之前可见的工具现在被拒绝
该工具已不在
**设置 → MCP**
的选中范围内,或当前权限策略不允许它。修改工具 allowlist 后请刷新 MCP 客户端的工具列表;服务端同样会拒绝缓存的旧工具调用。
### Docker 或反向代理下 MCP 请求失败
请使用公网访问地址,包括映射后的端口和
`DBX_PUBLIC_BASE_PATH`
前缀。
`DBX_WEB_MCP_ALLOWED_HOSTS`
必须与实际
`Host`
authority 精确一致;浏览器客户端还必须在
`DBX_WEB_MCP_ALLOWED_ORIGINS`
中配置精确 Origin。
### Agent/JDBC 数据库无法启动
在 DBX Driver Manager 中安装或更新匹配的 Agent、JDBC 驱动和 JRE。厂商专有驱动不会随 MCP 原生包发布。
### DuckDB 连接无法启动
在 DBX Driver Manager 中安装或更新 DuckDB 驱动。本地 MCP、DBX Web 和 Docker 都通过独立驱动运行 DuckDB,不会内置 DuckDB 引擎。
### 出现 better-sqlite3 或 Node ABI 错误
MCP 不需要
`better-sqlite3`
。请先升级
`@dbx-app/mcp-server`
;如果错误来自
`@dbx-app/cli`
,请按照 CLI 的安装要求处理,因为它们是两个独立的包。
## 系统要求
* Node.js 18.18.0 或更高版本
* 已安装 DBX,并至少配置一个数据库连接
* Agent/JDBC 数据库需要匹配的 Agent、驱动和 JRE
* 使用两个桌面 UI 工具时,需要保持 DBX 桌面端运行
---
# MongoDB 工作台
> 浏览、筛选、编辑和复制 MongoDB 文档,并管理集合、索引和 GridFS。
Source: https://dbxio.com/cn/docs/mongodb
Language: zh-CN
Relative links resolve against https://dbxio.com/cn/docs/mongodb.
MongoDB 工作台围绕数据库、Collection、文档、索引和 GridFS 组织,不把文档强制转换成关系型表。它提供表格视图和完整 JSON 视图,并保留 `ObjectId`、日期、长整数等 Extended JSON 类型。
## 连接与驱动
推荐使用标准 `mongodb://` 或 `mongodb+srv://` 连接字符串,并在 URL 中包含副本集、认证库、TLS 和其他参数。Atlas、Replica Set 和直连部署都使用同一个连接入口。
DBX 优先使用原生 MongoDB 路径。当服务端或认证协议需要旧驱动时,可以选择或自动回退到 `mongodb-legacy` Agent。旧驱动的管理和修改能力可能少于原生驱动。
## 数据库与 Collection
对象树可以:
* 列出数据库、Collection、索引和 GridFS Bucket
* 显示 Collection 文档数、大小和其他可获取统计
* 创建、重命名或删除 Collection(原生驱动且连接可写时)
* 删除数据库、单个索引或除 `_id_` 外的可删除索引
* 从 Collection 打开文档浏览器或查询编辑器
删除和重命名会显示目标和请求预览,并受只读与生产保护约束。
## 文档浏览与分页
文档浏览器支持:
* 分页读取和估算总数
* 表格视图与完整文档视图
* 顶层和嵌套字段列,例如 `address.city`
* 可搜索字段选择器、隐藏列和持久化列布局
* 快速过滤器以及多个字段条件
* 数据库侧排序和 Collection 查询
MongoDB 的总数可能使用估算值。数据持续写入时,翻页过程中的总数和最后一页可能变化。
## 过滤与命令
可以在文档浏览器中构建字段过滤,也可以在 MongoDB 查询标签中输入 shell 风格命令。日期类型的过滤值除 RFC 3339 外也接受 `2025-04-01 19:46:03` 或 `2025-04-01`,不带时区的文本按本地时区解析。编辑器会根据数据库、Collection、字段、查询运算符、更新运算符、聚合阶段和游标方法提供补全。
常见命令包括:
```javascript
db.users.find({ status: "active" }).sort({ createdAt: -1 })
```
```javascript
db.orders.aggregate([
{ $match: { status: "paid" } },
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } }
])
```
`use ` 会切换当前 MongoDB 查询上下文。在 `use ` 之后以及 `db.getSiblingDB("…")` 内部会补全数据库名。
## 表格编辑
表格视图把常见字段展开成列。支持:
* 编辑顶层或嵌套字段
* 新增和删除字段
* 新建、克隆和删除文档
* 复制选中文档为 JSON、Markdown 或 MongoDB Shell 语句
* 排除 `_id` 后复制为新文档模板
* 在保存前查看待执行更新或删除目标
字段结构差异很大的 Collection 更适合使用完整文档视图,避免隐藏字段在表格列中被忽略。
### 查询结果编辑
当查询标签中只有一条不带投影的 `find` 或 `findOne`、且结果包含 `_id` 时,结果表格可以直接编辑:可以修改字段、选中并删除行,保存前查看将要执行的 `updateOne` 和 `deleteOne` 语句,删除后表格会自动重新加载。结果表格不支持新增行,请使用 `insertOne` 或文档浏览器。聚合、带投影的查询以及多条命令的脚本保持只读,因为它们的行无法对应到单个文档。
## JSON 文档编辑
文档详情可以在字段树和完整 JSON 源码之间切换:
* 新建文档时粘贴完整 JSON
* 保存前校验 JSON 语法和根对象结构
* 格式化、折叠和复制嵌套对象/数组
* 保留 `$oid`、`$date`、`$numberLong` 等 Extended JSON
* 修改 `_id` 时按新标识创建文档,并删除旧文档
* 完整 JSON 保存按整文档替换语义处理
整文档替换会写回完整对象。编辑前确认当前 JSON 包含需要保留的所有字段,尤其是并发修改频繁的 Collection。
## 索引
在对象树或 Collection 结构中可以查看索引名称、字段、唯一性和其他元数据。原生驱动支持时,可以删除单个索引、批量删除可删除索引,或从结构入口管理索引。
MongoDB 会保留 `_id_` 索引;分片键等服务端规则也可能阻止删除其他索引。最终结果以服务端响应为准。
## GridFS
GridFS 工作台用于管理 Bucket 和文件:
* 浏览、创建和删除 Bucket
* 上传、下载、预览和删除文件
* 查看文件名、大小、上传时间、Chunk 和 Metadata
* 按字段过滤和排序文件
* 导出文件列表或 Metadata
删除 Bucket 会删除其中的文件和 Chunk。生产环境执行前先确认 Bucket 名称和备份。
## 导入与导出
Collection 文档提供独立的 CSV/JSON/NDJSON 与 BSON 导入导出,和关系型 Table Import 不是同一条工作流。CSV 每一行生成一个文档,嵌套值保持嵌套,BSON 备份保留原生 BSON 类型。
### 导入数据
1. 在集合上右键选择「导入数据」。
2. 先明确选择格式,再选择 `.csv`、`.json`、`.ndjson`/`.jsonl`、`.bson` 或 `.bson.gz` 文件。桌面端读取本地路径,Web 端上传到临时文件;更换文件不会覆盖已选择的格式。
3. 对照预览检查数据。文本格式支持编码和类型设置,CSV 可逐列覆盖推断类型;BSON 导入不应用 CSV 文本转换。
4. 确认以追加方式写入。重复 `_id` 会停止导入,已提交的批次不会回滚。
CSV 按 MongoDB Compass:首行表头,嵌套字段用点号路径(`address.city`),数组索引(`tags[0]`、`matrix[0][1]`),ObjectId 写成 24 位十六进制,日期为 ISO-8601,空单元格为 null。导入采样前 1000 行推断列类型;`_id` 的十六进制会还原为 ObjectId,`recognizeObjectIdHex` 可将此规则扩展到其他列。JSON/NDJSON 使用 Extended JSON(`$oid`、`$date`)。全部按字符串会把每个单元格当文本。
CSV 类型保真:`Double` 导出再导入会变为 `Decimal128`(十进制文本无损)。非 `_id` 的 ObjectId 字段会往返为 String,除非打开 `recognizeObjectIdHex`。小的 `Int64` 可能收窄为 `Int32`;ISO 日期格式的字符串会变为 `DateTime`。Extended JSON 类型(`$binary`、`$regularExpression`、`$timestamp`、`$minKey`、`$maxKey`、`$code`)通过 JSON 文本单元格往返。空数组 `[]` 和空对象 `{}` 往返正确。
集合导入限制:只支持追加(无清空或 upsert),CSV 导出从前 10000 个文档发现字段(之后的字段会被静默丢弃;变化 schema 请改用 NDJSON 或 BSON),无 JSON 数组导出格式,不支持 Excel/GridFS 导入,失败批次不会自动重试。集合级 BSON 导入只恢复文档,不恢复配套元数据和索引。
### 导出数据
* 在集合上右键选择「导出数据」,再选 CSV、NDJSON、BSON 或 Gzip BSON,会像表导出一样直接打开保存文件对话框。
* CSV 嵌套对象写为点号列(`address.city`),数组写为索引列(`tags[0]`、`tags[1]`)。NDJSON 每行一个规范 Extended JSON 文档。
* 字段数超过 256 的 Collection 请改用 NDJSON 或 BSON。
### 数据库备份与恢复
在数据库节点右键选择「备份数据库」或「恢复数据库」。数据库备份包含选中集合、集合选项、索引和视图。原生驱动和 `mongodb-legacy` Agent 均支持;Agent 路径需要较新的 Agent 版本(支持 find 游标),以保证 BSON 类型在传输中不丢失。
* 桌面端支持官方目录布局与 MongoDB archive 格式,均可使用 gzip。Web 端导出 archive 文件,恢复时支持 archive 或上传目录。
* 目录备份包含 `<数据库>/<集合>.bson` 和 `.metadata.json`,或对应的 `.gz` 文件。MongoDB archive 是独立的流式格式,不是 ZIP 或 tar。
* 格式与 gzip 选项需明确选择。目录恢复的「读取备份」只读取清单和元数据;确认源库、目标库和集合后,才上传选中的数据文件。
* 恢复按单遍流式读取和写入进行。可选的 `objcheck` 默认关闭,开启后在同一遍读取中逐文档校验;BSON 边界、gzip 完整性和 archive 校验和检查始终保留。
* 默认追加写入。「恢复前删除选中的目标同名集合」只删除并重建这些集合。已有 `_id` 可能导致 `E11000`;失败或取消不会回滚此前的写入。
* Web 上传复用服务端 `DBX_MAX_UPLOAD_MB` 配置。桌面端直接读取本地文件,无需 HTTP 上传。
上述格式可与官方 `mongodump`/`mongorestore` 对支持的集合双向互通。本流程不提供 oplog 回放、时间点一致性保证、UUID 保留,也不处理内部数据库、时间序列集合和加密集合;这些场景请使用官方工具。
如果只需要当前可见选择,仍可从表格复制当前文档、选中文档或字段值为普通 JSON 或 Extended JSON。
## 安全与兼容边界
* 只读连接会阻止文档、字段、索引、Collection、数据库和 GridFS 修改
* 生产环境保护会在可识别写入前要求确认
* MCP“数据读写”只允许范围明确的 MongoDB 修改;不透明或近似全量过滤按高风险处理
* 旧版 Agent 可能不支持 Collection/索引管理等原生能力
* Atlas 权限、认证库、TLS 和 IP allowlist 都由 MongoDB 服务端决定
* 分页总数可能为估算值,不能作为强一致统计
### [生产写入保护](/cn/docs/production-safety)
了解 MongoDB 过滤范围、只读连接和 MCP 策略。
### [连接与驱动](/cn/docs/driver-management)
管理原生与 legacy Agent,并排查驱动启动问题。
### [专项工作台](/cn/docs/specialized-workspaces)
查看 Redis、搜索、向量、HBase、消息队列和配置中心。
---
# 对象浏览器
> 使用列表或网格集中查看数据库对象、统计信息、源码和批量操作。
Source: https://dbxio.com/cn/docs/object-browser
Language: zh-CN
Relative links resolve against https://dbxio.com/cn/docs/object-browser.
对象浏览器把当前数据库或 Schema 中的对象集中到一个可搜索的列表/网格中。它适合对象数量很多、需要按类型和元数据筛选,或需要批量处理多个对象的场景。
## 适合的场景
* 在一个页面查看大量表、视图、过程、函数、序列和其他对象
* 按名称、类型、Schema、注释或统计信息筛选
* 比较表大小、行数、创建/更新时间等驱动可提供的信息
* 多选对象后执行打开、复制、导出、删除或其他批量操作
* 在不展开深层对象树的情况下快速查看 DDL 或源码
## 打开方式
从连接、数据库或 Schema 的上下文菜单打开**对象浏览器**。DBX 会根据当前节点确定 Catalog、数据库和 Schema 范围。
对象浏览器可以作为主标签页或侧边面板打开。侧边面板适合一边查看对象列表,一边保留当前查询或数据标签。
## 视图与筛选
| 功能 | 说明 |
| ------ | --------------------------- |
| 列表视图 | 适合查看名称、类型、Schema、注释、行数和大小等列 |
| 网格视图 | 适合快速扫描对象卡片和主要摘要 |
| 对象类型筛选 | 默认优先显示表,也可以切换视图、例程和其他类型 |
| 搜索 | 按对象名称、Schema、类型和部分元数据过滤 |
| 列调整 | 调整列宽、显示列和滚动位置;视口状态可以保留 |
统计列只在驱动能够可靠读取时显示。大型数据库读取行数或大小可能有额外开销,必要时关闭不需要的统计信息。
## 对象操作
单击或双击对象可以按类型打开:
* 表和视图数据
* 表结构、字段、索引、外键、触发器和 DDL
* 视图、过程、函数、触发器等对象源码
* 数据库专属管理界面
上下文菜单还可以提供:
* 复制名称、限定名称或 DDL
* 生成查询 SQL
* 导入、导出、传输和结构相关入口
* 打开 ER 图、字段血缘或 Schema 对比
* 重命名、清空、删除或管理对象
具体操作由数据库 capability、连接只读状态和当前权限决定。
## 多选与批量操作
对象浏览器支持复选框多选。批量操作可能包括:
* 打开或复制多个对象名称
* 批量导出或生成 SQL
* 删除、清空或截断所选表
* 删除所选索引
* 对 PostgreSQL 等数据库使用带 `CASCADE` 的批量对象操作
批量删除、清空和截断可能影响大量对象。生产环境先确认所选范围、生成 SQL、备份和依赖关系。
## DDL 与源码
* **查看 DDL**优先读取数据库或驱动提供的定义
* **对象源码**用于视图、过程、函数、触发器和其他可编辑对象
* 源码视图支持搜索;数据库和对象允许时,可以打开到编辑器修改
* 保存源码或执行 DDL 前会进入只读、生产保护和危险操作检查
DBX 显示的是当前驱动能获取到的定义。格式、是否包含权限/注释/存储属性,以及能否直接编辑,都会因数据库而异。
## 与对象树的区别
| 对象树 | 对象浏览器 |
| ------------- | --------------- |
| 适合层级导航和固定常用对象 | 适合集中筛选和比较大量同级对象 |
| 展开后查看字段和子节点 | 通过列、卡片和侧面板查看摘要 |
| 强调上下文菜单和拖拽 | 强调搜索、多选和批量操作 |
两者共享对象身份和元数据。可以从对象浏览器打开对象,再回到对象树定位对应节点。
## 功能边界
* 不同数据库公开的对象类型和统计列不同
* 行数和大小可能是估算值或缓存值
* 系统对象是否显示取决于可见 Schema 和系统 Schema 设置
* 只读连接仍可查看对象、DDL 和源码,但修改入口会被禁用或拒绝
* 大量对象首次加载时,驱动可能分批读取元数据
### [对象树](/cn/docs/schema-browser)
使用层级导航、固定、拖拽和数据库专属上下文菜单。
### [表结构](/cn/docs/table-structure)
可视化编辑字段和索引并预览 DDL。
### [字段血缘](/cn/docs/field-lineage)
从外键、视图和历史 SQL 中追踪字段关系。
---
# 开发和提交 DBX 插件
> 从 CLI、Manifest、Workbench 和 Sidecar 开始开发 DBX 插件,完成本地调试、打包、自动上架和官方签名发布。
Source: https://dbxio.com/cn/docs/plugin-development
Language: zh-CN
Relative links resolve against https://dbxio.com/cn/docs/plugin-development.
DBX 插件是独立安装的 `.dbxp` 包,可以提供连接类型、工作台、文件系统和原生 Sidecar。插件源码、DBX 插件框架和官方商店目录由不同仓库负责。
**推荐路径:**
使用
`dbx-plugin create`
创建项目,在自己的仓库开发并发布未签名候选包;
`dbx-store`
会为已注册的插件自动创建或更新候选 PR,维护者审核并签名后才会进入官方目录。
**插件上架 Pull Request 提交到 [`t8y2/dbx-store`](https://github.com/t8y2/dbx-store),不是 `t8y2/dbx`。** 插件自己的功能代码通常保留在开发者自己的源码仓库;只有修改 DBX Host、SDK、CLI、协议、Schema、文档或官方示例时,才向 [`t8y2/dbx`](https://github.com/t8y2/dbx) 提交 PR。
## 插件快捷入口
在 **插件中心 → 设置 → 全局配置** 中管理快捷入口。默认开启并显示在右侧顶部;可选择左侧或右侧的顶部/底部优先、连接树底部,或更新按钮左侧的浮动栏。浮动栏默认显示 3 个图标,可设置 0–10 个,空间不足的入口放入下拉菜单,以图标和名称逐行显示。
连接树底部区域的「插件」标题栏右上角默认提供「插件设置」入口,其他显示位置则将该入口固定在末尾,点击直达插件中心的设置页,不参与拖动排序。浮动栏溢出时,该入口位于下拉菜单末尾。在「全局配置」中关闭「显示“插件设置”快捷入口」可隐藏它;仍可从插件中心的「设置」页重新开启。没有可显示的插件快捷入口时,整个快捷区域(包括设置入口)隐藏,不占用布局空间。
每个功能有独立图标,可以拖动排序;显示开关按插件生效,关闭后隐藏该插件的所有入口。所有位置共用保存的顺序。隐藏或卸载不会删除已有排序记录,重新出现的相同入口恢复原位置,未记录的入口排列在已保存入口之后。排序标识由插件 ID、入口类型和功能 ID 组成,修改这些 ID 会被视为新入口。
拖动预览跟随光标,靠近窗口边缘时自动调整方向和位置;右侧停靠优先显示在光标左侧,长名称会根据可用宽度省略显示。
选择「插件中心右侧(下拉)」可通过插件中心按钮旁的箭头展开全部快捷入口,每行显示图标和名称,支持拖动排序;该位置不受浮动栏显示数量限制。
连接树底部采用左侧图标、右侧名称的单列列表,行样式和字号与连接树一致。默认按入口数量显示所需行数,最多五行,超出后竖向滚动。拖动分隔线可保存自定义高度,双击恢复自动高度。拖动图标时按 Esc、切换窗口或在区域外释放会取消排序;保存失败会提示并回滚。
快捷入口保留 `appToolbar` 声明的可见条件及命令执行条件。无连接类型的插件还可从快捷栏打开已有工作台;有对应命令时优先执行命令,没有命令体系的旧式插件也可显示文件浏览入口。连接型插件只显示明确声明的全局命令,不自动生成缺少连接上下文的工作台入口。不兼容插件不展示。
显示位置只决定图标位置,内容继续按原有 `panel/tab` 语义打开。隐藏快捷栏、切换位置或隐藏插件均不会关闭已打开的会话。面板快捷入口仅切换当前选中且匹配的命令面板,恢复时保留该实例。无需修改插件 Manifest 或后端协议;旧 `left/right` 设置迁移为对应侧顶部优先。
## 应该提交到哪个仓库
| 你要修改的内容 | 提交位置 | 是否向 DBX 官方提 PR |
| -------------------------------------------------------- | ----------------------------------------------------- | ----------------------- |
| 你的插件前端、Rust/Go 后端、测试和发布脚本 | 插件自己的源码仓库 | 不向 `dbx` 提交;在自己的仓库开发和发布 |
| 新插件上架、版本更新、商店图标和介绍 | [`t8y2/dbx-store`](https://github.com/t8y2/dbx-store) | 是,目标分支为 `main` |
| DBX 插件 Host、Manifest/Marketplace Schema、SDK、CLI、Packager | [`t8y2/dbx`](https://github.com/t8y2/dbx) | 是,目标分支为 `main` |
| DBX 官方示例或插件开发文档 | [`t8y2/dbx`](https://github.com/t8y2/dbx) | 是 |
| 某个第三方插件自身的 Bug | 该插件的源码仓库 | 不要提交到 `dbx-store` |
| 自定义或企业私有仓库 | 你的私有仓库 | 不需要向官方商店提交 |
| 数据库厂商 JDBC Driver JAR | 不提交到 Git 仓库 | 用户在本机或服务器中导入 |
DBX 官方维护但需要独立发布节奏的插件,通常也应使用独立源码仓库。只有与 Host 强耦合的最小示例、SDK 验证项目或维护者明确同意的组件才放进 `t8y2/dbx`。
## 插件由哪些部分组成
```text
my-plugin/
├── manifest.json
├── dbx-plugin.toml
├── assets/
├── ui/
├── backend/ # frontend 模板没有此目录
├── .github/workflows/
│ └── plugin-release.yml
└── dist/ # 构建输出,不提交到 Git
```
* `manifest.json` 声明插件身份、版本、权限、入口和 Contributions。
* `ui/` 在沙箱工作台中运行,通过 Host API 与 DBX 交互。
* `backend/` 是可选的原生 Sidecar,可以使用 Rust、Go 或其他能够实现 DBX JSON-RPC 协议的语言。
* `.dbxp` 是安装包,不是源码仓库。
* 前端插件可以发布一个 `universal` 包;包含原生 Sidecar 的插件需要按操作系统和 CPU 架构分别构建。
## Manifest 完整说明
`manifest.json` 是运行时契约,文件必须位于插件包根目录。Manifest v1 不接受未声明字段,建议在编辑器中引用仓库内的 [`plugins/manifest.schema.json`](https://github.com/t8y2/dbx/blob/main/plugins/manifest.schema.json)。最小的纯前端 Manifest 如下:
```json
{
"$schema": "https://raw.githubusercontent.com/t8y2/dbx/main/plugins/manifest.schema.json",
"manifest_version": 1,
"id": "com.example.files",
"name": "Example Files",
"version": "0.1.0",
"publisher": "example",
"description": "Browse files from an example service.",
"icon": "assets/plugin.svg",
"source": "https://github.com/example/dbx-plugin-files",
"homepage": "https://github.com/example/dbx-plugin-files",
"engines": { "host_api": "1" },
"permissions": [],
"entrypoints": { "ui": { "root": "ui", "entry": "ui/index.html" } },
"contributions": [{ "type": "workbench", "id": "com.example.files.main", "label": "Files", "icon": "assets/plugin.svg" }]
}
```
Manifest 中的路径相对于包根目录,不能以 `/` 开头、不能包含 `..`、反斜杠或重复斜杠。`ui.entry` 必须位于 `ui.root` 内:当 root 为 `ui` 时,入口写 `ui/index.html`,不是 `index.html`。`signingKeyId` 属于商店 artifact metadata,不是 Manifest 字段。
| 字段 | 必需 | 说明 |
| ------------------ | -- | ----------------------------------------------------------------------- |
| `$schema` | 否 | 编辑器使用的 JSON Schema 地址,不参与身份校验。 |
| `manifest_version` | 是 | 当前必须为数字 `1`。 |
| `id` | 是 | 全局稳定 ID,只能使用小写字母、数字、`.`, `_`, `-`,例如 `io.github.example.files`;发布后不要更改。 |
| `name` | 是 | 默认显示名称。 |
| `icon` | 否 | 插件默认图标的包内相对路径;推荐 SVG 或 PNG。 |
| `version` | 是 | `major.minor.patch` 语义化版本,可带 prerelease/build 后缀。相同 ID 和版本的正式包不能覆盖。 |
| `publisher` | 是 | 发布者标识;首次上架后应保持不变。 |
| `description` | 否 | 插件说明。 |
| `source` | 否 | 源码仓库 HTTPS 地址,安装后可在插件信息中查看。 |
| `homepage` | 否 | 项目主页、文档或支持地址。 |
| `engines` | 是 | 运行时兼容范围,至少包含 `host_api`。 |
| `permissions` | 否 | 最小权限集合,见下文。 |
| `entrypoints` | 否 | UI 和原生 Sidecar 入口;贡献点存在时按需声明。 |
| `contributions` | 否 | 连接、工作台、文件系统、连接右键菜单、结果视图、命令/菜单和 MCP 工具面声明。 |
| `localizations` | 否 | 按 locale 覆盖名称、说明、贡献点、字段和动作文案。 |
### `engines`、权限和入口
```json
{
"engines": { "dbx": ">=0.6.0", "host_api": "1" },
"permissions": [
"host.workbench",
"host.events",
"host.filesystem",
"host.binary",
"host.plans:read",
"host.schema:read",
"host.storage",
"host.clipboard:read",
"host.data:read",
"host.connections:read",
"host.network:https://s3.example.com:443"
],
"entrypoints": {
"ui": { "root": "ui", "entry": "ui/index.html" },
"backend": {
"protocol_versions": [1],
"transport": "stdio-jsonl",
"executable": "bin/linux-x64/backend"
}
}
}
```
* `engines.dbx` 是可选的 DBX 版本范围;`engines.host_api` 是必需的 Host API 版本声明。
* `host.workbench` 允许打开另一个工作台,`host.events` 接收宿主事件,`host.binary` 使用二进制通道,`host.filesystem` 使用文件系统入口。
* `host.plans:read` 允许针对 DBX 自己的连接读取估算执行计划(见 [估算执行计划](#估算执行计划))。它是只读权限:不授予普通 SQL 执行、写操作、DDL 或真实执行计划,且这是唯一存在的计划类权限。
* `host.schema:read` 允许通过 `host.getTableMetadata` 读取已打开连接的窄化 table schema metadata;它不会授予任意 SQL、写入或隐式重连(见 [Table Schema Metadata](#table-schema-metadata))。
* `host.storage` 为工作台 UI 提供本插件独享的持久化键值存储(见 [持久化 UI 状态](#持久化-ui-状态));数据只落在插件自己的插件数据目录里。
* `host.ai` 允许插件接入 DBX 全局 AI 面板:可以打开 Ask 快照对话、选择性打开使用实时插件工具的 Agent 对话,以及注册当前工作台的推荐问题。旧版 DBX 会在安装时因未知权限而失败,需要兼容旧宿主的插件应把 `host.ai` 作为可选能力,并通过 `capabilities.ai` / `capabilities.aiRecommendations` 判断运行时支持。
* `host.clipboard:read` 允许工作台 UI 读取系统剪贴板(见 [系统剪贴板](#系统剪贴板))。写剪贴板不需要权限;读取会把用户数据(密码、令牌)交给插件代码,因此需要门控。
* `host.data:read` 允许 `window.dbxPlugin.queryData` 在用户授权给插件的连接上执行一条只读 SQL(见 [只读数据查询](#只读数据查询))。每个连接都需要用户同意;它不会授予写入、DDL 或重连。
* `host.connections:read` 允许通过 `window.dbxPlugin.getConnections()` 或 `window.dbxPlugin.connections.list()` 获取当前所有已配置连接的只读脱敏信息(见 [连接信息读取](#连接信息读取))。
* `host.network:https://host[:port]` 声明浏览器可访问的 HTTPS origin,DBX 将它加入 CSP 的 `connect-src`;最多 8 个,不允许路径、通配符或 Token。仍受目标服务 CORS 规则约束。该权限不是原生 Sidecar 的网络防火墙。
* `backend.transport` 默认是 `stdio-jsonl`;需要二进制帧时使用 `stdio-framed`,并同时声明 `host.binary`。
* `backend.executable`、`ui.root` 和 `ui.entry` 必须指向包内文件;带原生后端的包必须为每个目标平台提供对应可执行文件。
### Connection Provider
连接 Provider 负责声明连接表单,DBX 负责渲染表单和保存生命周期;插件只处理自己的连接协议。`binding` 决定字段语义:`config` 写入外部配置,`secret` 写入 Secret Store,`name`、`host`、`port`、`username`、`password`、`database` 映射到标准连接字段。
```json
{
"type": "connection-provider",
"id": "com.example.files.connection",
"label": "Example Service",
"icon": "assets/connection.svg",
"database_type": "example-files",
"description": "Connect to an Example Service.",
"fields": [
{ "key": "display_name", "label": "Name", "type": "text", "binding": "name", "required": true },
{ "key": "endpoint", "label": "Endpoint", "type": "text", "binding": "host", "required": true },
{ "key": "port", "label": "Port", "type": "number", "binding": "port", "default": 443 },
{
"key": "region",
"label": "Region",
"type": "radio",
"options": [
{ "label": "US", "value": "us" },
{ "label": "EU", "value": "eu" }
],
"binding": "config"
},
{ "key": "token", "label": "Access token", "type": "password", "binding": "secret", "required": true }
],
"workbench": "com.example.files.main",
"capabilities": ["test", "connect", "disconnect"],
"actions": [{ "id": "refresh", "label": "Refresh metadata", "variant": "outline", "when": "edit", "requires_valid_form": true, "timeout_ms": 30000 }]
}
```
字段类型为 `text`、`password`、`number`、`boolean`、`select`、`radio` 或 `textarea`;`select`/`radio` 必须提供非空 `options`,每项包含 `label` 和字符串 `value`。`binding: "port"` 必须使用 `number`。不要把密码、Token 或私钥放进 `config`、Workbench context、事件或日志。
每个字段必须声明 `key`、`label`、`type`,可选 `description`、`placeholder`、`required`、`default`、`options` 和 `binding`;默认值必须符合字段类型。省略 binding 的 `password` 字段默认按 `secret` 处理。`database_type` 是插件自定义类型标识,不会给 DBX 内置数据库枚举添加成员。
字段还支持条件显隐/条件必填。`visible_when` 与 `required_when` 接受单条子句 `{ "field": "mode", "one_of": ["custom"] }`(引用字段取到列表中的值时命中,按字符串比较,因此 `[false]` 与 `["false"]` 都能匹配布尔 `false`),并用 `all_of` / `any_of` / `not` 组合:
```json
{
"key": "sudo_command",
"label": "Sudo command",
"type": "text",
"visible_when": {
"all_of": [
{ "field": "sudo_source", "one_of": ["custom"] },
{ "field": "read_only", "one_of": [false] }
]
}
}
```
条件会级联:子句引用的字段自身处于隐藏状态时该子句不参与判定,因此隐藏容器的默认值不会把孙级字段点亮;未填写或空值永不命中;组合树最多 8 层、64 个节点。DBX 在对话框与保存/测试/连接校验中使用同一套求值,不会出现「表单放行、宿主拒绝」的分歧。
`text`、`password`、`textarea` 字段可以用 `picker` 声明**本机文件选择**(例如 SSH 私钥、keystore):
```json
{
"key": "private_key_path",
"label": "Private key path",
"type": "text",
"binding": "config",
"picker": { "kind": "file", "accept": [".pem", ".key"], "content_field": "private_key" }
}
```
桌面端打开系统文件选择器,把选中的**绝对路径**写回该字段(插件后端同机运行,可自行读取文件);网页端拿不到客户端路径,同一操作变成**上传**:DBX 读取文件内容写入声明的 `content_field` 兄弟字段,并清空路径字段。两者互相清除——选了路径就丢弃已上传内容,上传内容就清空路径,避免同时存在两份互相矛盾的来源。`kind` 还支持 `directory`(仅桌面端),`accept` 最多 16 条扩展名或 MIME 过滤,上传上限 1 MiB。
插件在连接过程中需要用户输入时(堡垒机登录期 keyboard-interactive 验证码、主机密钥确认、账号选择等),可以调用 Host API 1.1 新增的 `host/requestUserInput`,通过 DBX 同一个阻塞对话框拿到用户输入,`连接测试` 与真实连接走同一条通道:
```json
{
"jsonrpc": "2.0",
"id": "prompt-1",
"method": "host/requestUserInput",
"params": { "prompt": "Verification code (6 digits)", "title": "JumpServer login", "echo": false, "timeoutSecs": 300 }
}
```
返回值为 `{ "action": "submit", "value": "123456" }`、`{ "action": "cancel" }` 或 `{ "action": "timeout" }`;只有 `submit` 带值,其余必须按「没有答案」处理并失败关闭。插件发起的请求使用字符串 id,DBX 自己的请求与响应继续使用数字 id;提示期间 DBX 会暂停等待该回答的请求超时计时,用户输入验证码不会被误判成连接超时。错误码 `-32001` 表示没有可用的用户界面(headless/MCP),`-32602` 参数非法,`-32601` 宿主不支持该方法,三种情况都要优雅降级。调用前请确认 `plugin/initialize` 通告的 `hostApiVersion` 为 `1.1.0`(或 `host.features` 含 `host.requestUserInput`);Rust SDK 对应 `dbx_plugin_sdk::host_client()` 与 `HostClient::supports("host/requestUserInput")`、`HostClient::request_user_input(&UserInputPrompt::secret("Verification code"))`。
连接生命周期使用固定的 `connection/test`、`connection/connect`、`connection/disconnect`,自定义表单动作使用 `connection/action`,参数包含 `provider`、`connection`、`runtime`;动作额外包含 `action: { id }`。后端使用 `connection.id` 保存会话,并使用 `runtime.host`/`runtime.port` 连接经过 DBX 隧道或代理转换后的端点。仅在后端生命周期请求中接收补齐 Secret 的连接;前端通过 `connectionId` 使用已经建立的会话。
多端点协议(Kafka `advertised.listeners`、集群发现等)在贡献点上声明 `proxy_route`。配置了传输层后,DBX 会在 payload 中下发 SOCKS5 路由而非静态转发:`runtime.host`/`runtime.port` 保留逻辑端点,插件通过 `runtime.proxy`(`{ "type": "socks5", "host": "...", "port": 1080, "username": "...", "password": "..." }`)拨号每个广播端点——SSH 末层暴露其动态 SOCKS5 端点,SOCKS5 代理层直接使用;代理凭据与连接 Secret 走同一加密通道,插件不得记录日志。未声明该旗标时传输层保持静态转发行为,要求标准 `host`/`port` 字段给出单一远端端点;对会隧道到空端点的插件连接,DBX 直接给出可行动的报错而非静默超时。
动作的 `when` 可为 `always`、`create`、`edit`;`variant` 可为 `default`、`outline`、`secondary`、`destructive`、`ghost`;`timeout_ms` 为 1–120000。`requires_valid_form` 决定是否要求完整表单,`close_on_success` 决定成功后是否关闭。返回 `{ "success": true, "message": "...", "fieldValues": { "port": 443 } }` 可以更新已声明的字段;返回 `success: false` 表示失败。
### 其他 Contributions
| 类型 | 必需字段 | 用途 |
| --------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `workbench` | `type`, `id`, `label` | 注册可从侧边栏或插件入口打开的工作台。 |
| `filesystem-provider` | `type`, `id`, `label`, `schemes` | 注册虚拟文件系统;`root_uri` 例如 `s3://bucket`,能力可选 `read`、`write`、`delete`、`rename`、`mkdir`。 |
| `context-menu` | `type`、`id`、`label`、`menu: "connection"` 或 `"table"`、可选 `action` | 向 Sidebar Tree 的连接或 table 右键菜单增加后端动作,或打开已声明的 Workbench。 |
| `result-view` | `type`, `id`, `label` | 注册查询或任务结果视图。 |
`menu: "table"` contribution 当前只在用户对 Sidebar Tree 中的具体 table 节点打开右键菜单时生效。未声明 `action` 的旧式 contribution 会通过必需的 backend entrypoint 调用 `contextMenu/`,并传递 table identity:
```json
{
"table": {
"connectionId": "connection-id",
"database": "example",
"schema": "public",
"table": "users"
}
}
```
`database` 和 `schema` 是可选字段;不可用时会省略,不会强制传递空字符串。该 context 只包含对象 identity,不包含 credential、connection string 或原始连接配置。Object Browser 后续可以复用相同 identity contract,但本次版本没有把它作为 table 菜单入口。
context-menu 也可以声明由 Host 处理的 Workbench action:
```json
{
"type": "context-menu",
"id": "vendor.example.generate",
"label": "生成测试数据",
"menu": "table",
"action": { "type": "open-workbench", "workbench": "vendor.example.main" }
}
```
`action.workbench` 必须引用同一插件 manifest 中声明的 `workbench`。Host 会直接打开该 Workbench,不调用 sidecar,并将当前 invocation context 作为 Workbench context 传入。`menu: "table"` 传入上面的 `TableContext` 对象本身(不是 backend 的 `{ "table": ... }` envelope);`menu: "connection"` 传入现有的非敏感 connection summary(`id`、`dbType`、`name`、`database`)。Host 还可能提供用于 tab 关联的标准 `connectionId`。两者都不会暴露 host、port、username、password、connection string 或原始连接配置。再次打开同一个 Workbench 时会用最新 invocation context 刷新其 context。
只有未声明 `action` 的旧式 context-menu 才要求 backend entrypoint;其返回的 `{ "message": "..." }` 仍会显示为 toast。
同一插件内通过 `id` 互相引用:Connection Provider 的 `workbench` 必须指向一个已声明的工作台,`filesystem_provider` 必须指向一个已声明的文件系统 Provider。图标优先使用 Contribution 的 `icon`,缺失时回退到插件级 `icon`。
自定义文件浏览器应使用 `workbench`:列表、虚拟滚动、预览、右键菜单和分栏由插件前端实现。只有希望使用 DBX 通用文件管理器时才选择 `filesystem_provider`;同时声明两者时默认打开工作台。未声明 `action` 的旧式 `context-menu` 调用后端 `contextMenu/`;声明式 `open-workbench` action 则由 Host 直接打开同插件 Workbench。`result-view` 在工作台 context 中接收结果快照。SDK 会在初始化后通过 `dbxPlugin.contributionId` 暴露 Host 选中的 contribution id,因此单个 UI 入口可以为多个工作台和结果视图服务;具体负载见[完整贡献点协议](https://github.com/t8y2/dbx/blob/main/plugins/README.md)。
### 文件系统协议
使用 DBX 通用文件管理器时,后端实现以下方法;自定义工作台也可以自行通过 RPC 使用这些方法,但不能把声明 Contribution 当成已经实现业务逻辑。
| 方法 | 参数与返回 |
| ---------------------------- | --------------------------------------------------------------------------------------- |
| `filesystem/list` | `providerId`、可选 `connectionId`、`uri`、可选 `cursor`、`limit`;返回 `{ entries, nextCursor? }`。 |
| `filesystem/read` | 同上身份字段、`uri`、`maxBytes`;返回 `{ dataBase64, contentType?, truncated, etag? }`。 |
| `filesystem/write` | `uri`、`dataBase64`、`create`、`overwrite`、可选 `etag`;需声明 `write`。 |
| `filesystem/createDirectory` | `uri`;需声明 `mkdir`。 |
| `filesystem/delete` | `uri`、`recursive`;需声明 `delete`。 |
| `filesystem/rename` | `sourceUri`、`targetUri`、`overwrite`;需声明 `rename`。 |
所有方法都携带 `providerId` 和可选 `connectionId`。目录项包含单个文件名 `name`、完整 `uri`、`kind`(`file`、`directory`、`symlink`、`other`)以及可选 `size`、`modifiedAt`、`contentType`。`name` 不能包含 `/`、`\\` 或是 `.`/`..`;完整路径放在 `uri`。最后一页省略 `nextCursor`,不要返回已经使用的 cursor。图片预览应返回实际 MIME 和 base64 字节,不能把二进制当作 UTF-8 文本。
写操作返回 `{ success, message?, entry? }`;内联读写限制为 4 MiB。大文件传输应采用分块与进度/取消协议,而不是一个巨大的 JSON/base64 值。
### 国际化
`localizations` 的 key 使用 `zh-CN`、`en` 等 locale。可覆盖插件名称、说明以及每个 Contribution 的 `label`、`description`、字段和动作文案;它不会翻译插件 UI 自己的文本。
```json
{
"localizations": {
"zh-CN": {
"name": "示例文件",
"contributions": {
"com.example.files.connection": {
"label": "示例服务",
"fields": { "token": { "label": "访问令牌" } }
}
}
}
}
}
```
## Workbench 上下文契约
Workbench 上下文跨越 DBX 与插件边界时是 JSON 数据快照。宿主会递归移除 Vue 响应式包装并发送独立副本,因此插件不能依赖 Vue ref、Proxy、DOM 节点、函数、组件实例或凭据。
上下文可以包含 `null`、布尔值、有限数字、字符串、数组和普通对象。对象中的 `undefined` 字段会省略,数组中的 `undefined` 会转换为 `null`。Date、Map、Set、Symbol、BigInt、非有限数字、循环引用和自定义 class 实例会被拒绝并返回错误。上下文 UTF-8 编码后的大小上限为 2 MiB。
连接 Provider 使用 `binding: "config"` 的字段会保存到 `external_config`;使用 `binding: "secret"` 的字段会保存到 Secret Store。插件连接的 `external_config` 会在新建、编辑、保存和重新连接流程中保留。
宿主还会为每个 workbench 上下文写入三个保留字段:`workbenchId`(宿主生成的稳定实例 id)、`restored` 和 `surface`。`surface` 表示当前 UI 跑在哪种容器里——`"tab"`(主多标签工作台)、`"dock"`(底部面板)或 `"window"`(桌面浮动小组件窗口,见[浮动窗口](#浮动窗口))。同一个插件的同一个 contribution 可以同时开在多个 surface 上,各自拥有独立的上下文和生命周期;遇到未知取值应退化成 `"tab"` 的行为。
## 前端 Host API
UI 在隔离的 iframe 中运行,DBX 通过 `window.dbxPlugin` 提供桥接对象。不要导入 DBX 的 Vue/Tauri 模块,也不要假设浏览器页面能直接访问 Node.js、文件系统或网络。
多个 Workbench 或 result-view contribution 共用同一个 UI 入口时,可通过 Host 选中的 identity 路由页面:
```js
await window.dbxPlugin.ready;
const contributionId = window.dbxPlugin.contributionId;
```
`contributionId` 与 `context` 相互独立;例如从 Plugin Center 打开的 Workbench,其 context 可以是空对象 `{}`。SDK 会在 resolve `ready` 前记录 identity,因此 `await dbxPlugin.ready` 后可确定性地读取。为兼容旧插件,`dbx-plugin-init` 仍会携带完整 init payload 并作为通知派发;但该事件只派发一次,不应成为读取权威状态的唯一来源。
以下自定义 `objects/list` 和 `objects/changed` 需要由插件后端实现,资源示例假设包内存在 `ui/assets/empty-state.svg`:
```js
await window.dbxPlugin.ready;
const contributionId = window.dbxPlugin.contributionId;
const context = window.dbxPlugin.context;
const result = await window.dbxPlugin.invoke("objects/list", { prefix: "docs/" }, { timeoutMs: 30000 });
const off = window.dbxPlugin.onContext((nextContext) => render(nextContext));
await window.dbxPlugin.notify("objects/changed", { count: result.items.length });
const assetUrl = await window.dbxPlugin.readAssetUrl("assets/empty-state.svg");
```
| API | 作用 |
| ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ready` | 等待 Host 完成初始化;应用启动逻辑放在 `await dbxPlugin.ready` 之后。 |
| `contributionId` | Host 打开的 contribution 的只读 identity;`await ready` 后可读取,且与 `context` 独立。 |
| `context` / `onContext(fn)` | 读取或监听当前工作台上下文。 |
| `locale` | 读取当前语言;插件 UI 需自行完成翻译。 |
| `theme` | 读取 `appearance` 和 DBX 设计 tokens,适配明暗主题。 |
| `request(method, params)` | 调用 Host API;常用内部方法包括 `host.getContext`、`ui.readAsset`。 |
| `invoke(method, params, { timeoutMs })` | 向自己的 Sidecar 发送有响应的 RPC。 |
| `notify(method, params)` | 向 Sidecar 发送无需返回业务结果的通知。 |
| `sendBinary(channel, data)` / `onBinary(fn)` | 发送或接收二进制数据;需要 `stdio-framed` 和 `host.binary`。 |
| `readAsset(path)` / `readAssetUrl(path)` | 读取包内资源;路径不能越出插件资源根目录。 |
| `openWorkbench(id, context)` | 打开本插件的另一个工作台;需要 `host.workbench`。 |
| `setTitle(title)` | 修改当前工作台页签标题(传入 `null` 恢复默认);需要 `host.workbench`。 |
| `getTitle()` | 读取当前工作台页签标题;需要 `host.workbench`。 |
| `closeWorkbench()` | 关闭承载当前 UI 的表面——工作台标签、dock 面板条目,或本插件的浮动窗口。与 `Ctrl/Cmd+W` 快捷键走同一条路径,因此插件可以提供自己的关闭或最小化按钮。 |
| `executeCommand(commandId, context?)` | 执行本插件自己声明的命令,与菜单执行完全同径——重新检查 `enablement`、按单例复用,并遵循声明的 `presentation`(panel 停靠底部面板,tab 打开工作台标签页)。`context` 合并到命令上下文之上,并解析 `instance_key` 的 `{{path}}` 占位符(如 `instance_key: "logs:{{connectionId}}"` 即每个连接一个面板实例)。预期结果通过 `{ error }` 返回;需要 `host.workbench`。 |
| `openFilesystem(id, context)` | 打开本插件的文件系统入口;需要 `host.filesystem`。 |
| `getPlanCapabilities(connectionId)` | 读取宿主与该连接能提供什么计划能力;需要 `host.plans:read`。 |
| `explainPlan({ connectionId, database?, schema?, sql, mode, timeoutMs? })` | 返回 `sql` 的估算执行计划;需要 `host.plans:read`。 |
| `getTableMetadata({ connectionId, database?, schema?, table })` | 读取已打开连接的窄化 table schema metadata;需要 `host.schema:read`。 |
| `queryData({ connectionId, database?, schema?, sql, maxRows?, timeoutMs? })` | 在用户授权给插件的连接上执行一条只读 SQL;需要 `host.data:read`。 |
| `capabilities` | 来自 init 消息的 `{ downloadFile, planApi, schemaMetadataApi, dataApi, storage, ai, aiRecommendations, clipboardWrite, clipboardRead, floating, workbenchTitle }`。字段缺失或为 `false` 表示当前宿主不支持该组 Host API,应据此关闭功能而不是用真实请求试探。 |
| `ai.openConversation({ title, prompt, context, send?, mode? })` | 在内置 AI 面板新建插件对话;`send` 默认 `false`,`mode` 默认 `ask`。`mode: "agent"` 会在 context 包含已打开插件连接时使用实时插件工具;需要 `host.ai`,并以 `capabilities.ai` 广播。 |
| `ai.setRecommendations({ context, items })` | 覆盖当前工作台的默认推荐问题并立即刷新全局 AI 面板;每次最多 5 条,支持 `{{path.to.value}}` 占位符;需要 `host.ai` 和 `capabilities.aiRecommendations`。 |
| `ai.clearRecommendations()` | 清空当前工作台的推荐问题;需要 `host.ai` 和 `capabilities.aiRecommendations`。 |
| `onInit(fn)` / `onEvent(fn)` | 监听初始化、环境变化或后端事件;转发后端事件需要 `host.events`。 |
| `storage` | 本插件独享的持久化键值状态;需要 `host.storage`;见下文。 |
| `fileTransfer` | 本地文件流式传输、下载与(桌面端)系统拖放;见下文。 |
| `clipboard` | 沙箱内的系统剪贴板访问;见下文。 |
| `floating` | 打开并控制桌面浮动小组件窗口(仅桌面宿主);见[浮动窗口](#浮动窗口)。 |
调用失败会以 Promise rejection 返回,处理时应展示可理解的错误并允许重试。通过 `request` 调用的宿主方法、参数和返回值以当前 Host API 版本为准,不要调用未在协议中声明的 DBX 内部函数。
`readAsset` 的路径相对于 `ui.root`,所以这里的 `assets/empty-state.svg` 对应包内 `ui/assets/empty-state.svg`。资源不用时调用 `URL.revokeObjectURL(assetUrl)`;组件销毁时调用 `onContext`/`onEvent` 等返回的取消订阅函数,避免重复监听。
### 估算执行计划
插件可以在不自带驱动、连接池和凭据的前提下读取一条查询的**估算**执行计划。插件只传自己的原始 SQL 和连接引用;DBX 用自己已有的方言规则生成 `EXPLAIN` 语句、应用与自身计划视图完全相同的只读安全校验,并在宿主连接上执行。插件只拿到原始计划,由自己完成解析、归一化和可视化。
```json
{
"permissions": ["host.plans:read"]
}
```
```js
if (window.dbxPlugin.capabilities.planApi) {
const capabilities = await window.dbxPlugin.getPlanCapabilities(connectionId);
if (capabilities.supports.estimatedPlan) {
const plan = await window.dbxPlugin.explainPlan({ connectionId, database, sql, mode: "estimated", timeoutMs: 15000 });
render(plan.rawPlan, plan.format);
}
}
```
`getPlanCapabilities(connectionId)` 返回 `{ dbType, dbVersion?, supports: { estimatedPlan }, limits: { maxTimeoutMs, maxPlanBytes } }`:
* `supports.estimatedPlan` 为 `false` 表示该连接的方言在 DBX 中没有估算计划路径;应直接禁用功能,而不是调用 `explainPlan`。
* `limits.maxTimeoutMs` 已经考虑该连接自身的查询超时,请求里的 `timeoutMs` 会被夹到该上限;`limits.maxPlanBytes` 限制计划负载大小。
* `dbVersion` 只在 DBX 已经知道该连接产品版本时才存在;宿主不会为了插件去探测服务器。
* 该调用只读取已保存的连接配置,不会建立连接;但连接必须已经打开:已保存但当前已断开的连接会被拒绝,而不是替插件重新建连。
`explainPlan(request)` 返回 `{ dbType, dbVersion?, format, rawPlan, truncated, warnings }`:
* `format` 为 `json`、`xml`(SQL Server `ShowPlanXML`)或 `text`。`format` 为 `json` 时 `rawPlan` 是已解析的 JSON 文档,其余情况是计划文本。
* `warnings` 可能包含:`plan_not_json`(服务端返回的内容不是 JSON,负载会如实标记为 `text`,而不是假装可解析)、`plan_truncated`(宿主为遵守 `maxPlanBytes` 截断了计划)、`plan_rows_truncated`(驱动达到计划行数上限)。只要发生过任一截断,`truncated` 都是 `true`。
计划 API 的边界:
* **只做估算计划。** `mode` 必须是 `"estimated"`,其它取值一律拒绝。真实执行计划(`EXPLAIN ANALYZE`、`SET STATISTICS XML`)会真正执行语句,不属于本 API。
* **插件不能自己提供要执行的 SQL。** 只接受原始 `sql`,`EXPLAIN` 语句完全由宿主生成,因此插件无法传入 `EXPLAIN` 文本、驱动命令或执行模式。
* **只允许只读目标。** DBX 自身计划视图使用的同一道校验会拒绝多语句、DDL、DML 和危险关键字。Oracle 是唯一例外:DBX 也会为它规划 DML,因为 `EXPLAIN PLAN FOR` 并不会执行该语句。
* **不涉及凭据,也不返回结果集。** 返回体只有计划和元信息,密码、凭据、连接串、驱动内部结构都不会越过这条边界。
* **连接必须已经打开。** DBX 不会替插件建立连接,也不会为插件创建连接。`getPlanCapabilities` 与 `explainPlan` 对「已保存但已断开」的连接都会以 `Connection is not open` 拒绝;只有 DBX 当前已经打开的连接才能规划。
判断能力时请读 `dbxPlugin.capabilities.planApi`(旧宿主不会带这个字段),再用 `getPlanCapabilities` 确认这条连接是否支持,最后才调用 `explainPlan`。自行拼 `EXPLAIN` 文本既没必要,也不会被接受。
计划 API 属于 Host API 1.2。无法离开它工作的插件应在 manifest 里声明下限:`"engines": { "host_api": "^1.2" }`。manifest 里的版本范围是兼容下限,`capabilities.planApi` 是运行期探测,两者都保留。
### Table Schema Metadata(表结构元数据)
插件可以读取当前 DBX 已打开连接中某个 table 的窄化 schema metadata,而不需要拥有驱动、连接池、凭据或自己拼 SQL。请求复用现有的 `PluginTableContext`,只允许 table identity:
```json
{
"permissions": ["host.schema:read"]
}
```
```js
if (window.dbxPlugin.capabilities.schemaMetadataApi) {
const metadata = await window.dbxPlugin.getTableMetadata({
connectionId,
database,
schema,
table: "users",
});
for (const column of metadata.columns) {
renderColumn(column.name, column.dataType, column.nullable);
}
}
```
`getTableMetadata({ connectionId, database?, schema?, table })` 返回:
```json
{
"columns": [
{
"name": "id",
"dataType": "integer",
"nullable": false,
"precision": 32,
"default": "nextval('users_id_seq'::regclass)"
}
],
"fieldCapabilities": {
"length": "supported",
"precision": "supported",
"scale": "supported",
"default": "supported"
}
}
```
* `columns` 只包含 `name`、`dataType`、`nullable`、可选的 `length`、`precision`、`scale` 和 `default`。不会返回 comment、key/index、credential、连接串、驱动内部对象或任意 SQL 结果。
* 可选值在没有值时保持 `null` 或直接省略,绝不会被伪造为 `0` 或空字符串。`fieldCapabilities` 用 `supported`、`unsupported`、`unknown` 区分提供方支持、明确不支持和宿主没有可靠 provenance 的情况;`unknown` 不应被插件当成支持。
* `database` 和 `schema` 可选;不可用时省略,不要把空字符串当作 public identity。`connectionId` 和 `table` 必须是非空且不超过 256 个字符的 identity 值。
* 这是只读 API。DBX 只复用已打开的 Host connection/session,禁止插件隐式重连、创建连接池或执行任意 SQL。已保存但当前断开的连接会以 `Connection is not open` 拒绝;请求的 database 没有对应已打开 session 时也会拒绝,而不是切换到别的连接。
该 API 属于 Host API 1.3。无法离开它工作的插件应声明:`"engines": { "host_api": "^1.3" }`;同时仍应读取 `capabilities.schemaMetadataApi`,因为旧宿主不会提供该字段。没有 `host.schema:read` 时,宿主会在请求到达 backend 前拒绝调用。
### 只读数据查询
插件可以在用户授权给它的 DBX 连接上执行一条只读 SQL,而不需要驱动、连接池、凭据或连接串。声明权限,并按能力位决定是否调用:
```json
{
"engines": { "host_api": "^1.4" },
"permissions": ["host.data:read"]
}
```
```js
if (window.dbxPlugin.capabilities.dataApi) {
const result = await window.dbxPlugin.queryData({
connectionId,
database,
sql: "SELECT status, count(*) AS total FROM orders GROUP BY status",
maxRows: 200,
});
renderChart(result.columns, result.rows);
}
```
`queryData({ connectionId, database?, schema?, sql, maxRows?, timeoutMs? })` 返回:
```json
{
"dbType": "postgres",
"columns": [
{ "name": "status", "dataType": "text" },
{ "name": "total", "dataType": "int8" }
],
"rows": [
["paid", 1204],
["refunded", 37]
],
"truncated": false,
"elapsedMs": 12
}
```
* **按连接征求同意。** 插件第一次查询某个连接时,宿主会弹窗写明插件名和连接名。用户允许后授权会持久保存,并显示在「插件中心 → 已安装」该插件下,用户可随时撤销;拒绝会在本次工作台会话内被记住。插件无法自行授权。
* **只读且单条语句。** 宿主只接受一条被 DBX SQL 风险分类器判定为只读的语句——与 MCP 只读模式和 AI Agent 使用同一道闸门。写入、DDL、`SELECT … FOR UPDATE`、多条语句以及 `USE` 这类切换会话数据库的语句都会被拒绝;请改用 `database` 参数。
* **只用已打开的连接。** 与执行计划和表结构元数据 API 一样,DBX 不会替插件发起连接:已保存但未打开的连接会以 `Connection is not open` 拒绝。Redis、MongoDB、搜索引擎等非 SQL 连接不提供该能力。
* **有上限。** `maxRows` 默认 500、最多 5000;序列化后的行数据上限 8 MiB;`timeoutMs` 会被限制在连接自身超时和 60 秒上限之内。只要有行被截断,`truncated` 就为 `true`。
* **不含凭据。** 响应只包含列和行。授权被撤销后,调用会返回以 `PLUGIN_DATA_ACCESS_NOT_GRANTED` 开头的错误,下一次查询会重新征求用户同意。
该 API 属于 Host API 1.4。请同时保留 `engines.host_api` 下限和 `capabilities.dataApi` 运行时检查;无法弹出确认框的 Web 宿主会拒绝请求,而不会静默授权。
### 连接信息读取
需要展示连接下拉框或根据连接执行特定任务(例如通过 `host.data:read` 查询数据)的插件,可以通过 `host.connections:read` 权限枚举当前配置的所有连接列表:
```json
{
"permissions": ["host.connections:read"]
}
```
```js
await window.dbxPlugin.ready;
if (window.dbxPlugin.capabilities.connectionsApi) {
const connections = await window.dbxPlugin.getConnections();
// 也可通过 window.dbxPlugin.connections.list();
for (const conn of connections) {
console.log(conn.id, conn.name, conn.dialect, conn.connected);
}
}
```
返回的每个连接对象包含:
* `id`: 连接唯一标识,可直接传给 `queryData`、`getPlanCapabilities` 等;
* `name`: 连接名称;
* `dialect` / `dbType`: 数据库方言/类型(如 `mysql`, `postgres`, `sqlite` 等);
* `connected` / `isConnected`: 当前是否已建立物理连接;
* `readOnly`: 是否为只读连接;
* `database` / `schema`: 默认数据库或模式(如有)。
> **安全边界**:返回列表完全脱敏,不包含密码、用户名、主机、端口或连接串等敏感凭据。
### 系统剪贴板
插件沙箱是 opaque origin 且没有剪贴板权限,`navigator.clipboard` 在里面不可用。宿主代为桥接系统剪贴板:
* `window.dbxPlugin.copy(text)` / `window.dbxPlugin.clipboard.writeText(text)` 写系统剪贴板。两者走同一条无权限门控的桥接方法:写操作的输入就是用户数据本身,是低风险的一半。
* `window.dbxPlugin.clipboard.readText()` 读系统剪贴板。它需要 `host.clipboard:read` 权限——读取会把用户数据(密码、令牌)交给插件代码,且没有后续用户交互兜底——属于 Host API 1.3:离开它无法工作的插件应声明 `"engines": { "host_api": "^1.3" }`。
读剪贴板请看 init 能力而不是试探:`capabilities.clipboardRead`(写对应 `capabilities.clipboardWrite`)在旧宿主上缺失即为 falsy。读被拒绝(缺权限、Web 宿主没有原生剪贴板访问)时 Promise 会 reject——请优雅降级,例如回落到键盘粘贴路径,而不是让交互直接失败。
```js
await window.dbxPlugin.ready;
const canRead = !!window.dbxPlugin.capabilities.clipboardRead;
const canWrite = !!window.dbxPlugin.capabilities.clipboardWrite;
async function pasteFromClipboard() {
if (!canRead) return null;
try {
return await window.dbxPlugin.clipboard.readText();
} catch {
// 缺权限或读取失败:保留键盘粘贴路径。
return null;
}
}
```
### 文件传输与系统拖放
桌面端宿主通过 `window.dbxPlugin.fileTransfer` 把本地文件流式接入插件沙箱。句柄只在用户明确同意后打开:原生打开/保存对话框(`pick` / `beginSave`),或从系统拖放到本插件工作台区域内的文件(`onDrop`)。传输按分块进行,多 GB 文件也不会整体载入内存。
```js
const fileTransfer = window.dbxPlugin.fileTransfer;
if (!fileTransfer) {
// Web 宿主:回退到 和 sidecar 落盘。
}
// 上传:用户在原生对话框选择文件,插件把分块推给自己的 sidecar。
const { files } = await fileTransfer.pick({ multiple: true });
for (const file of files) {
let offset = 0;
for (;;) {
const chunk = await fileTransfer.read(file.handleId, offset, 256 * 1024);
await uploadChunk(file.name, offset, chunk.dataBase64); // 你自己的 RPC
if (chunk.eof) break;
offset += chunk.length;
}
await fileTransfer.cancel(file.handleId);
}
// 下载:打开保存目标,分块写入,最后 finish 落盘。
const target = await fileTransfer.beginSave({ name: "export.csv", size });
await fileTransfer.write(target.handleId, 0, bytes);
await fileTransfer.finish(target.handleId);
// 系统拖放(仅桌面端):被拖入的文件以已打开的句柄送达。
const offDrop = fileTransfer.onDrop((files) => uploadAll(files));
const offDrag = fileTransfer.onDragState((active) => showDropOverlay(active));
```
| API | 用途 |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `pick({ multiple })` | 原生打开对话框;返回已打开的读句柄 `{ handleId, name, size, contentType }`。 |
| `read(handleId, offset, length?)` | 从读句柄流式读取一个分块 `{ dataBase64, length, eof }`。 |
| `beginSave({ name, contentType?, size? })` | 原生保存对话框 + 写句柄;返回 `{ handleId, chunkBytes }`,用户取消时为 `null`。 |
| `write(handleId, offset, data)` | 写入一个分块(二进制 transfer 或 base64);返回 `{ written, nextOffset }`。 |
| `finish(handleId)` / `cancel(handleId)` | 冲洗并关闭写句柄 / 丢弃任意句柄。 |
| `onDrop(fn)` | 拖入本工作台的文件以读句柄送达;拖入文件夹会被展开为其中包含的文件(`.git` 等点开头文件与目录会被跳过),每个文件额外携带 `relativePath`(以 `/` 分隔、以拖入文件夹自身名字开头的路径,如 `folder/nested/a.csv`),可用于还原拖入的目录结构,也能区分不同拖入根目录下的同名文件。监听器签名为 `(files, { dropId, truncated })`:`dropId` 标识本次拖入的整组条目(取消与进度记账的分组键),`truncated` 为 `true` 表示展开因 2000 文件或 8 层深度上限被截断。 |
| `onDragState(fn)` | 是否有系统拖拽悬在本工作台上方;用它驱动拖放遮罩。 |
桌面端与网页端的行为差异:请以 init 消息里 additive 的 `capabilities.fileTransfer` 标志位(`pick`、`beginSave`、`read`、`drop`、`folderExpansion`)做能力探测,不要靠试调用。桌面端 `pick` / `beginSave` 走原生对话框、`onDrop` 接收系统拖放(句柄由宿主惰性打开,读时分块流式,因此超大文件夹与大文件都不会占满句柄;选取文件数超过共享句柄池时自动降级为惰性条目,不会静默丢弃)。网页端 `pick` 回退到浏览器文件选择器、`beginSave` 回退为内存缓冲加浏览器下载、`onDrop` / `onDragState` 不会触发(`drop`/`folderExpansion` 为 `false`)、句柄也没有 `relativePath`。`onDrop` 只在拖放落点位于本插件工作台区域内时触发;落点在宿主其他区域时保持宿主自身的行为。
### 持久化 UI 状态
沙箱是 opaque origin,`localStorage` 在里面会直接抛错。需要跨重载或跨应用重启保留状态的工作台(最近访问的目录、面板尺寸、草稿等)改用 `window.dbxPlugin.storage`。它需要 `host.storage` 权限,并以 init 消息里的 `capabilities.storage` 广播;使用前请同时探测这两者。
```js
if (window.dbxPlugin.capabilities.storage) {
const storage = window.dbxPlugin.storage;
await storage.set("layout", { sidebar: "collapsed", sort: "name" });
const layout = await storage.get("layout"); // { sidebar: "collapsed", sort: "name" },未设置时为 null
await storage.delete("layout");
}
```
| API | 用途 |
| ----------------- | -------------------------------------- |
| `get(key)` | 返回存储的 JSON 值;键未设置时返回 `null`。 |
| `set(key, value)` | 持久化任意 JSON 值(`undefined` 归一化为 `null`)。 |
| `delete(key)` | 删除一个键;删除不存在的键同样成功。 |
键为不超过 256 字符的字符串;单个值序列化后上限 256 KiB,整库上限 1 MiB——这是 UI 状态存储,不是数据落盘通道。数据保存在插件自己的 `plugin-data/` 目录里,按插件隔离,版本升级和卸载后都保留。大批量数据、缓存以及 Sidecar 产生的任何文件请放进 Sidecar 的数据目录(见 [原生 Sidecar 和 RPC](#原生-sidecar-和-rpc))。Web 宿主上同一 API 由浏览器本地存储支撑,两端代码完全一致。
### 在 DBX AI 中分析插件数据
在 manifest 中声明 `"permissions": ["host.ai"]`。插件可以直接打开全局 AI 面板,也可以为每个 Workbench 注册快捷推荐问题。两种能力都沿用 DBX 的模型选择、历史、追问、停止和导出功能。
#### 声明 Workbench 的默认推荐问题
在 `workbench` contribution 下增加可选的 `ai.recommendations`。`label` 显示在 DBX 全局 AI 面板,`prompt` 是点击后发送给 AI 的文本;`order` 越小越靠前。
```json
{
"type": "workbench",
"id": "com.example.files.main",
"label": "Files",
"ai": {
"recommendations": [
{
"id": "health",
"label": "检查 {{resource.name}} 健康状态",
"prompt": "分析 {{resource.kind}}/{{resource.name}} 的健康状态和风险",
"order": 10
}
]
}
}
```
占位符从当前 Workbench context 读取,支持对象属性和数组下标,例如 `{{resource.name}}`、`{{items.0.status}}`。无法解析的占位符会使该条推荐被隐藏;`__proto__`、`prototype` 和 `constructor` 等路径会被拒绝。推荐问题最多显示 5 条。
#### 根据资源变化更新推荐问题
插件切换页面或资源时,可以提交运行时推荐问题。运行时 `items` 会覆盖 manifest 默认值;传入空数组表示清空当前推荐。运行时 context 通常只需要提交资源字段,Host 会保留当前 Workbench 的 `connectionId`、数据库和实例标识,确保点击推荐问题后仍绑定到正确的插件连接。
```js
function updateRecommendations(resource) {
if (!dbxPlugin.capabilities.aiRecommendations) return;
return dbxPlugin.ai.setRecommendations({
context: { resource },
items: [
{
id: "health",
label: `检查 ${resource.name} 健康状态`,
prompt: "分析 {{resource.kind}}/{{resource.name}} 的健康状态和风险",
order: 10,
},
{
id: "events",
label: "查看最近事件",
prompt: "列出这个资源最近的重要事件并给出处理建议",
order: 20,
},
],
});
}
await dbxPlugin.ai.clearRecommendations();
```
推荐问题显示在 DBX 全局 AI 对话窗口中,而不是插件页面内新增一个 AI 入口。用户点击后,DBX 会使用当前推荐文本创建新的 Agent 对话并立即发送;Agent 会通过当前已打开的插件连接调用插件工具获取实时数据。推荐列表本身只属于当前 Workbench 上下文,不会写入对话历史;用户点击后发送的实际问题会正常保存。
#### 直接打开 Ask 或 Agent 对话
`ai.openConversation` 仍适合插件按钮或其他明确动作。默认 `mode` 为 `ask`,宿主会复制插件提供的 JSON 快照;快照会随对话保存,后续资源刷新不会改变已经创建的对话。需要实时工具时显式使用 `mode: "agent"`,并在 context 中提供当前已打开插件连接的 `connectionId`:
```js
await dbxPlugin.ai.openConversation({
title: "Watchlist analysis",
prompt: "Compare the current quotes and explain risks and missing data.",
context: {
connectionId,
resource: { kind: "watchlist", name: "primary" },
dataTimestamp,
},
mode: "agent",
send: true,
});
```
`title` 最多 200 字符,`prompt` 最多 32000 字符,`context` 必须是纯 JSON 对象,上限 2 MiB。Agent 只能使用宿主为该插件连接公开的工具;插件不会收到模型回复或模型配置,也不能借此获得数据库执行能力。旧插件不声明推荐问题时仍可正常使用原有 AI API;旧宿主缺少新增 capability 字段时,插件应关闭对应入口并继续提供其他功能。
### 浮动窗口
浮动窗口把插件的某个 workbench 放进一个独立的无边框、置顶桌面窗口,而不是塞在 DBX 外壳里——这正是小型常驻小组件需要的表面(播放器胶囊、会话状态徽章、快捷选择器)。它会盖在其他应用之上,可以被拖到桌面任意位置。在屏幕中间松手就停在落点;落到或越过工作区边缘(不管怼得多用力)都会齐着那条边吸附并停靠。停靠不会在落下的那一刻就把小组件藏起来:它先保持整颗可读的胶囊,光标离开约 2.5 秒后才滑到屏外只留一条细边,光标碰到细边就滑回来。重新打开一个上次吸在边上的小组件也是这套时序(先胶囊、后收起);刚唤出的小组件即使默认落点就贴着边,也只停在胶囊态。使用前先判断 `capabilities.floating`:Web 宿主没有窗口,桌面宿主也可能不支持窗口管理。
```js
if (window.dbxPlugin.capabilities.floating) {
// 在标签或 dock 工作台里:打开小组件。
// 一个(插件, workbench contribution)只会有一个窗口,重复调用只是把已有窗口带到前台。
const { windowId } = await window.dbxPlugin.floating.open({
contributionId: "capsule",
title: "Now playing",
width: 260,
height: 60,
context: { queueId: currentQueueId },
});
}
// 在小组件内部(context.surface === "window"):控制自己所在的窗口。
grip.addEventListener("pointerdown", (event) => {
grip.setPointerCapture(event.pointerId);
dragging = false;
});
grip.addEventListener("pointermove", async (event) => {
if (dragging || Math.hypot(event.clientX - downX, event.clientY - downY) < 4) return;
dragging = true;
// 从这一刻起窗口归宿主移动:它自己读原生光标,不需要插件逐帧上报。
await window.dbxPlugin.floating.beginDrag();
});
grip.addEventListener("pointerup", async () => {
if (!dragging) return;
dragging = false;
await window.dbxPlugin.floating.endDrag(); // 吸附并记住位置
});
```
| API | 作用 |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `floating.open(options)` | 为本插件的某个 `workbench` contribution 打开(或前置)浮动窗口。`options`:`contributionId`(必填)、`title`、逻辑像素的 `width`/`height`、物理屏幕像素的 `x`/`y`、`alwaysOnTop`(默认 `true`)、`skipTaskbar`(默认 `true`)、`resizable`(默认 `false`)、`context`。返回 `{ windowId, reused }`;需要 `host.workbench`。 |
| `floating.close(contributionId?)` | 关闭本插件的浮动窗口——指定某个 contribution,或省略 id 关闭本插件的全部浮动窗口。在小组件内部不带参数调用即关闭自己。 |
| `floating.beginDrag()` | 把窗口交给宿主的拖动循环。在 `pointermove` 里、自己的拖动阈值越过之后调用(此时按键还按住)。之后由宿主自己读原生光标,插件没有逐帧调用要做。 |
| `floating.endDrag({ snap? })` | 结束拖动。`snap`(默认 `true`)时宿主把窗口齐着它到达或越过的工作区边缘吸附并停靠在那(先保持整颗胶囊,光标离开一会儿才收起到屏外、只留一条悬停细边),落点在屏幕中间则完整夹回屏内;位置与停靠边都会记住,供下次打开使用。返回物理像素的最终矩形。实践中可不调:宿主在光标静止后也会自己收尾,收不到 pointerup 的小组件不会把窗口一直粘在光标上。 |
| `floating.setSize(width, height)` | 以逻辑像素调整所在窗口大小;宿主会夹到自己的上下限内。 |
小组件决定拖动**何时**开始(哪个元素是拖拽把手、指针要先走多远);窗口由宿主移动,吸附与位置记忆也归宿主。刻意没有逐帧的桥调用:宿主轮询原生光标,webview 忙不过来时小组件也照样贴着指针走,光标静止即收尾,pointerup 丢了也不会一直拖下去。几何类调用(`beginDrag`/`endDrag`/`setSize`)只在浮动窗口内部有效,在其他表面调用会被拒绝,因此标签页永远无法移动它不在其中的窗口。
几条规则让这个表面的行为可预期:
* **一个 contribution 只有一个窗口。** 窗口 id 由插件 id 和 contribution id 推导,所以 `floating.open` 是幂等的:第二次调用会把已开的窗口带到前台,而不是叠出更多小组件。
* **窗口是不透明的。** 宿主自己不画任何外壳,用户看到的就是小组件本身:给页面一个背景加圆角,配合宿主按内容收好的窗口尺寸,读起来就是浮在桌面上的一张卡片。刻意不提供逐像素透明(带镂空角的塑形小组件)——透明区域还收不收鼠标事件各平台不一致,而一个要给用户拖的小组件必须处处点得动。
* **外壳导航会被转发。** 浮动窗口没有标签栏、dock 和面板,所以从它发起的 `openWorkbench` 和 `openFilesystem` 会在 DBX 主窗口里打开,主窗口会自行前置。`executeCommand` 在这个表面完全不提供:每个命令动作都要打开一个外壳表面,调用会成功返回但什么都看不见。
* **位置跨重启保留**,按插件和 contribution 分别记录;当记录的位置已经不在任何已连接的显示器上时会被丢弃(拔掉显示器后退化为工作区默认位置,而不是开到屏幕外)。
* **小组件就是一个完整工作台。** 它拿到和标签页相同的桥、权限、上下文契约和 sidecar RPC;`context.surface` 为 `"window"`,`context.workbenchId` 为窗口 id。它启动的是你 UI 的另一份实例,所以共享状态必须走 sidecar(或 `storage`),不能指望模块内存。
### 主题、布局和静态资源
DBX 将主题 tokens 注入文档根元素,并更新 `data-dbx-theme`。自定义组件库(包括 Svelte、shadcn-svelte)应使用这些变量,不要依赖父页面 CSS 自动穿透 iframe:
```css
body {
margin: 0;
background: var(--color-background, #fff);
color: var(--color-foreground, #18181b);
}
button {
background: var(--color-primary, #2563eb);
color: var(--color-primary-foreground, #fff);
cursor: pointer;
}
```
使用 `window.addEventListener("dbx-plugin-env", handler)` 响应语言或主题变化。先读取 `dbxPlugin.locale`/`theme` 初始化,再在事件中刷新自己的状态。DBX 提供轻量 `dbx-btn`、`dbx-input` 等样式,但开发宿主不模拟完整组件 kit,自定义 token 样式在两者中更一致。
#### 主题负载携带什么
env 消息的 `theme` 结构为 `{ appearance, tokens, editor? }`。`appearance` 是 `"light" | "dark"`;`tokens` 是按前缀扫取的根节点设计变量(`--color-*`、`--radius-*`、`--font-*`);`editor` 是无 CSS 令牌载体的 SQL 编辑器设置结构化快照。投递矩阵:
| DBX 设置 | 投递形式 |
| ------------------ | ----------------------------------------------- |
| 浅色/深色/跟随系统 | `theme.appearance` |
| 调色板 + 自定义配色 | `--color-*` tokens |
| 圆角风格 | `--radius-*` tokens |
| UI 字体 | `--font-sans` token |
| 编辑器(等宽)字体 | `--font-mono` token + `theme.editor.fontFamily` |
| 编辑器字号 | `theme.editor.fontSize` |
| SQL 编辑器语法主题 | `theme.editor.theme` |
| UI 缩放(宿主窗口级) | 不投递——插件自管缩放 |
| 数据网格字体/类型配色、编辑器背景图 | 不投递——DB 域(`--dbx-*` 不在扫取范围) |
字体"字号"类关注点归插件所有:宿主不规定你的字号;如适合你的 UI,可把 `theme.editor.fontSize` 当默认值消费。所有负载变化都经 env 通道实时推送——字体族变更走主题修订号,字号/语法主题走显式监听——无需刷新。
UI 必须构建为包内静态资源,不要把 Vite 开发服务器或 CDN 的脚本地址写入发行包。宿主把入口及资源转换成沙箱可加载内容;CSP 报错时检查构建产物是否存在、路径是否落在 `ui.root` 内,并使用匹配版本的 CLI 复现。用插件自己的对话框组件处理删除/重命名,不要依赖沙箱中的原生 `alert`/`confirm`/`prompt`。
#### 懒加载与代码分割
宿主会把入口脚本内联进沙箱文档,`ui/` 下的其余资源在运行时通过 `dbx-plugin` 协议保持可寻址:`dbx-plugin://localhost/<插件id>/`(WebView2 上映射为 `http://dbx-plugin.localhost/<插件id>/…`)。宿主会把平台对应的形式注入为沙箱文档的 ``,并放行资源类 CSP,因此打包后的插件可以正常动态 `import()` 代码分割的 chunk——前提是构建产物使用**相对**资源地址:Vite 设 `base: "./"`、webpack 设 `publicPath: "./"`,让 chunk 和 CSS 资源地址基于注入的 base 解析而不是宿主 origin。绝对路径 `/assets/…` 携带不了插件 id,会 404。该协议只读文件、限定在每个插件的 `ui.root` 内,且插件更新后不会沿用旧缓存。
#### 内联后的样式表
宿主会读取所有指向 `ui.root` 内部的 ``,替换成带同样属性的 `