Database MCP Java
Database MCP Java 是一个通用数据库 MCP 服务,基于 Java 21、Spring Boot 和 Spring AI MCP Server 构建。当前支持 PostgreSQL、MySQL、达梦数据库和 Apache Doris 的基础数据库工具,并提供按数据库方言实现的慢查询统计、健康检查和索引建议。
支持范围
PostgreSQL
- 基础工具:
execute_sql、list_schemas、list_objects、get_object_details - 执行计划:
explain_query,支持文本执行计划;可结合 HypoPG 评估假设索引 - 慢查询统计:
get_top_queries,依赖pg_stat_statements - 健康检查:
analyze_db_health,支持index、connection、vacuum、sequence、replication、buffer、constraint、all - 索引建议:
analyze_workload_indexes、analyze_query_indexes,使用 PostgreSQLEXPLAIN (FORMAT JSON)和 HypoPG 评估候选索引
MySQL
- 受控 SQL 执行:
execute_sql - 结构查看:
list_schemas、list_objects、get_object_details - 执行计划:
explain_query,使用EXPLAIN FORMAT=JSON - 慢查询统计:
get_top_queries,依赖performance_schema.events_statements_summary_by_digest,支持mean_time和total_time - 健康检查:
analyze_db_health,支持index、connection、fragmentation、auto_increment、replication、buffer、constraint、all - 索引建议:
analyze_workload_indexes、analyze_query_indexes,使用 MySQLEXPLAIN FORMAT=JSON和规则引擎评分生成建议 - 不支持项:
explain_query的analyze=true和hypothetical_indexes暂不支持
达梦数据库
- 基础工具:
execute_sql、list_schemas、list_objects、get_object_details - 执行计划:
explain_query,使用达梦EXPLAIN - 慢查询统计:
get_top_queries,优先读取V$SQL_HISTORY,支持mean_time、total_time、executions - 健康检查:
analyze_db_health,支持index、connection、wait、storage、sequence、buffer、constraint、all - 索引建议:
analyze_workload_indexes、analyze_query_indexes,只做只读分析和建议输出,不自动创建索引 - 不支持项:
extension对象、analyze=true、hypothetical_indexes
Apache Doris
- 基础工具:
execute_sql、list_schemas、list_objects、get_object_details,复用mysql-connector-j(不引入新的 JDBC 驱动) - 执行计划:
explain_query,使用 Doris 原生EXPLAIN(不附加FORMAT=JSON) - 慢查询统计:
get_top_queries,从__internal_schema.audit_log聚合 SQL 摘要,支持mean_time、total_time、executions,依赖审计插件 - 健康检查:
analyze_db_health,使用独立的doris_*原语命名空间(doris_audit_log/doris_compaction/doris_tablet_health/all),PG/MySQL/达梦遗留的 10 个健康检查名会抛UnsupportedOperationException - 索引建议:
analyze_workload_indexes、analyze_query_indexes,从__internal_schema.audit_log和EXPLAIN输出只读建议 - 不支持项:
sequence/extension对象、analyze=true、hypothetical_indexes
SQL 授权
execute_sql、explain_query 和 analyze_query_indexes 的调用方只需传原业务参数和 user_id。权限默认关闭;开启后,服务端会把未经修改的 user_id 与原始 SQL 交给唯一的 SqlAuthorizer,只有返回 true 才进入执行、解释或分析。空 SQL、空 user_id、明确拒绝、超时或授权器异常都会 fail-closed。
接入项目可以提供自定义 Spring Bean:
@Bean
SqlAuthorizer sqlAuthorizer() {
return (userId, sql) -> permissionService.isAllowed(userId, sql);
}
自定义实现只作允许或拒绝决定,不修改 SQL,也不负责验证 user_id 的真实性。database-mcp.permission.enabled=true 时必须恰好存在一个 SqlAuthorizer Bean,否则应用拒绝启动。
非 Java 权限系统可配置 database-mcp.permission.http.url 使用内置 HTTP 授权器。它以 POST JSON 原样发送 userId 与 SQL,接受 2xx 且正文只含布尔 allowed 的响应;静态认证请求头和默认 3 秒总超时由服务端配置提供,不重试、不缓存,也不会把请求头或远端响应正文写入日志。HTTP、指标和自定义授权器不能同时启用。
现有“Druid AST + 指标范围 Provider”能力继续作为内置 SqlAuthorizer 使用:启用 database-mcp.permission.metric.enabled 后,从 SQL 的 quota_id / quota_scene 条件派生请求范围并与 Provider 返回的授权范围比较;未启用指标实现时,通用核心不解释任何指标语义。指标 SQL 无法检查或范围不足统一返回 permission_denied,Provider 超时与其他故障分别返回 permission_authorizer_timeout、permission_authorizer_unavailable;细分原因只进入服务端诊断日志。指标实现的受保护表、指标列、场景列、Provider 查询与缓存配置项见 application.yml 内的注释示例。
MCP 传输
服务默认启用 HTTP/SSE,默认监听 127.0.0.1:8000,SSE 地址为:
http://127.0.0.1:8000/sse
常用环境变量:
SERVER_ADDRESS=127.0.0.1
SERVER_PORT=8000
MCP_STDIO_ENABLED=false
如需让受信任内网中的 MCP Client 访问,可绑定到所有网卡:
SERVER_ADDRESS=0.0.0.0
SERVER_PORT=8000
本项目不内置 MCP 入口身份认证。公开网络访问时,应放在具备身份认证和访问控制能力的反向代理或网关之后。SQL 授权依赖 Agent 或网关先完成用户认证,并把真实用户可信绑定到每次请求的 user_id;本项目只把该不透明标识原样交给授权器。
控制台启动与部署(前端 + 后端)
控制台由 Vue 3 前端、Spring Boot 后端和独立 MySQL 控制库组成。前端不直连目标数据库;所有登录、连接管理、SQL 执行和诊断请求都通过后端 /api/v1/** 完成。只部署 MCP 服务、不需要 Web 控制台时,可以跳过本节,继续使用下文的数据库连接配置。
一键部署(推荐)
一键部署只要求服务器已安装 Docker Engine 和 Docker Compose v2,并准备好内网域名的 PEM 证书与私钥。Compose 会自动完成以下操作:
- 启动 MySQL 8.4 控制库并执行
deploy/init-control.sql; - 创建全部控制表、初始状态和默认管理员;
- 等待控制库健康后启动 Spring Boot 后端并执行 Flyway 迁移;
- 构建 Vue 前端,通过 Nginx 的 HTTPS 端口统一提供页面、REST API 和 MCP/SSE。
在项目根目录创建不会提交到 Git 的 .env:
CONTROL_DB_USERNAME=control_user
CONTROL_DB_PASSWORD=<control-db-password>
CONTROL_DB_ROOT_PASSWORD=<control-db-root-password>
CONTROL_CREDENTIAL_KEY=<base64-encoded-32-byte-key>
TLS_CERT_FILE=<absolute-path-to-tls-certificate.pem>
TLS_KEY_FILE=<absolute-path-to-tls-private-key.pem>
CONSOLE_HTTPS_PORT=8443
MCP_ALLOWED_NETWORKS=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
CONTROL_CREDENTIAL_KEY 用于 AES-256 加密目标数据库密码,可用 openssl rand -base64 32 生成。该密钥必须持久化保存;丢失或更换后,控制库中已保存的目标密码将无法解密。
上线前根据实际内网修改 deploy/nginx.conf 中 /sse、/mcp/ 和 /message 的 allow 列表,然后执行唯一的启动命令:
docker compose -f docker-compose.console.yml up -d --build
查看启动状态:
docker compose -f docker-compose.console.yml ps
所有服务显示为运行状态后,浏览器访问 https://<内网域名>:8443,无需再执行 SQL 或创建账号,直接登录:
用户名:admin
密码:[email protected]
首次登录后请在“系统设置”中修改默认密码。生产配置使用 Secure Session Cookie,必须通过 HTTPS 访问。再次执行启动命令会复用现有 control-data 数据卷,不会覆盖已修改的管理员密码或已有数据。
如果启动失败,通过以下命令查看日志:
docker compose -f docker-compose.console.yml logs -f control-db backend console
外部控制库初始化
控制库用于保存管理员、加密后的目标连接、当前目标和执行历史。使用外部 MySQL 时,只需以具备建库权限的账号执行一个脚本:
mysql -u <数据库账号> -p < deploy/init-control.sql
该脚本一次完成 database_mcp_control schema、全部控制表、初始状态和管理员数据,并且可重复执行。全新控制库执行后可直接使用以下账号登录,无需再运行建表脚本或配置初始管理员环境变量:
用户名:admin
密码:[email protected]
CONTROL_DB_USERNAME 对应的 MySQL 账号需要具备 database_mcp_control.* 的读写和后续迁移权限;账号创建与授权由 DBA 按部署环境管理,不写入应用 schema 脚本。Docker Compose 会自动创建并授权该账号。
后端仍使用 Flyway 管理后续升级:由完整脚本初始化的库会自动在 V4 建立结构基线并执行 V5 数据迁移;已有 V1~V4 控制库也会自动补入默认管理员(仅在管理员表为空时)。以后启动不会覆盖已修改的密码。控制库不可用、账号无访问权限或迁移失败时,后端会拒绝启动。
一键部署会在全新 MySQL 数据卷中自动执行同一个脚本,因此不需要手工初始化。目标业务库不要求创建本项目的表;只需提供可查询业务表、元数据及所需诊断视图的账号。
本地开发启动
本地源码开发要求 Java 21、Maven 3.9+、Node.js ^20.19.0 或 >=22.12.0、npm 和 MySQL 8.x。先按上一节准备本机 MySQL 控制库,然后在项目根目录启动后端。PowerShell 示例:
$env:DATABASE_MCP_CONTROL_ENABLED="true"
$env:DATABASE_MCP_CONTROL_URL="jdbc:mysql://127.0.0.1:3306/database_mcp_control"
$env:DATABASE_MCP_CONTROL_USERNAME="control_user"
$env:DATABASE_MCP_CONTROL_PASSWORD="<control-db-password>"
$env:DATABASE_MCP_CONTROL_CREDENTIAL_KEY="<base64-encoded-32-byte-key>"
mvn spring-boot:run
另开一个终端启动前端:
Set-Location frontend
npm ci
npm run dev
浏览器打开终端显示的地址(默认 http://localhost:5173)。Vite 会把相对路径 /api/** 代理到 http://127.0.0.1:8000,因此本地开发不需要配置 CORS,也不要让前端直接请求目标数据库。
前后端联动流程
- 浏览器访问前端;开发环境由 Vite、生产环境由 Nginx 把同源
/api/**转发到 Spring Boot8000。 - 登录成功后,后端创建 HttpOnly Session Cookie。前端在写请求前访问
/api/v1/auth/csrf,再携带X-XSRF-TOKEN,后端据此完成会话认证与 CSRF 校验。 - 前端保存目标连接时,后端用
CONTROL_CREDENTIAL_KEY对目标密码做 AES-GCM 加密,仅把密文写入 MySQL 控制库,密码不会回显到浏览器。 - 激活连接时,后端更新全局当前目标和
revision;前端把修订号保存到本地,并在目标相关请求中发送X-Target-Revision。若其他页面或会话已切换目标,后端返回409 target_revision_conflict,本次操作不会误发到新数据库,也不会自动重试。 - 后端在当前目标对应的独立连接池中执行受限只读 SQL/诊断,把 JSON 结果返回前端,并将执行结果写入
execution_history。前端始终只连接后端,不持有控制库或目标库的直连能力。
调试 REST 适配器
除标准 MCP 传输外,仓库提供镜像 9 个 MCP 工具的 REST 适配器 DebugHttpAdapter,路径前缀 /api/debug(如 POST /api/debug/execute_sql),请求体为对应工具参数的 JSON,响应固定为 {"output": "..."}。它不含任何业务逻辑,仅直接转发到 DatabaseToolFacade,便于在没有 MCP Client 时用 curl / Postman 排查问题。
默认关闭,需显式启用:
DATABASE_MCP_DEBUG_HTTP_ENABLED=true
该适配器仅用于本地调试,不替代 MCP 传输,也不应暴露到生产网络;启用后同样遵循 SERVER_ADDRESS 绑定范围,公网暴露需放反代/网关后。
数据库连接
可以使用完整 JDBC URL:
DATABASE_TYPE=postgresql
DATABASE_URI=jdbc:postgresql://localhost:5432/postgres?user=postgres&password=postgres
也可以使用拆分配置:
DATABASE_TYPE=postgresql
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=postgres
DATABASE_USERNAME=postgres
DATABASE_PASSWORD=postgres
如果同时配置 DATABASE_URI 和拆分连接参数,服务优先使用 DATABASE_URI。用户名或密码包含特殊字符时,请按 JDBC URL 参数规则编码。
访问模式可通过环境变量配置:
DATABASE_MCP_ACCESS_MODE=restricted
restricted 模式用于受控 SQL 执行,unrestricted 模式适合本地开发和可信环境。
PostgreSQL 示例
完整 JDBC URL:
DATABASE_TYPE=postgresql
DATABASE_URI=jdbc:postgresql://localhost:5432/postgres?user=postgres&password=postgres
拆分配置:
DATABASE_TYPE=postgresql
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=postgres
DATABASE_USERNAME=postgres
DATABASE_PASSWORD=postgres
MySQL 示例
完整 JDBC URL:
DATABASE_TYPE=mysql
DATABASE_URI=jdbc:mysql://localhost:3306/app?user=root&password=secret
拆分配置:
DATABASE_TYPE=mysql
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATABASE_NAME=app
DATABASE_USERNAME=root
DATABASE_PASSWORD=secret
Apache Doris 示例
使用规范的数据库类型值 doris。Doris 复用 MySQL 客户端协议,默认端口 9030,JDBC 前缀 jdbc:mysql://,复用项目已有的 mysql-connector-j。可通过 spring.profiles.active=doris 激活 application-doris.yml,也可直接通过环境变量覆盖。
完整 JDBC URL(推荐,含 5 项 Doris MySQL 兼容参数):
DATABASE_TYPE=doris
DATABASE_URI='jdbc:mysql://localhost:9030/example_db?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&tinyInt1isBit=false&allowPublicKeyRetrieval=true'
拆分配置:
DATABASE_TYPE=doris
DATABASE_HOST=localhost
DATABASE_PORT=9030
DATABASE_NAME=example_db
DATABASE_USERNAME=root
DATABASE_PASSWORD=<password>
5 项 Doris MySQL 兼容参数(缺一不可):
诊断工具依赖审计插件(enable_audit_plugin=true)和 __internal_schema.audit_log 表存在;未启用时对应项返回退化说明,其它检查项继续执行。get_object_details 在 Doris < 2.0 缺少 JSON_ARRAYAGG 支持时会走退化路径,建议生产环境使用 Doris ≥ 2.0。
达梦数据库示例
使用规范的数据库类型值 dameng。拆分配置的默认端口是 5236,完整 JDBC URL 使用 jdbc:dm:// 前缀。
完整 JDBC URL:
DATABASE_TYPE=dameng
DATABASE_URI=jdbc:dm://localhost:5236/app
DATABASE_USERNAME=app_user
DATABASE_PASSWORD=<password>
拆分配置:
DATABASE_TYPE=dameng
DATABASE_HOST=localhost
DATABASE_PORT=5236
DATABASE_NAME=app
DATABASE_USERNAME=app_user
DATABASE_PASSWORD=<password>
达梦支持使用当前 Java 21 项目选定的达梦 JDBC 驱动依赖 com.dameng:DmJdbcDriver11。诊断工具均按只读方式实现;如果当前用户无法访问某些达梦系统视图,对应诊断项会返回退化说明,其它可执行项继续返回结果。
真实达梦实例冒烟测试默认跳过。需要验证所有 MCP 工具时,可显式启用:
DAMENG_SMOKE_ENABLED=true
DAMENG_SMOKE_URI=jdbc:dm://localhost:5236/app
DAMENG_SMOKE_USERNAME=app_user
DAMENG_SMOKE_PASSWORD=<password>
mvn -q -Dtest=DamengMcpSmokeTest test
也可以使用拆分连接参数:DAMENG_SMOKE_HOST、DAMENG_SMOKE_PORT、DAMENG_SMOKE_DATABASE、DAMENG_SMOKE_USERNAME、DAMENG_SMOKE_PASSWORD。如果实例中没有普通业务表,可额外设置 DAMENG_SMOKE_SCHEMA 和 DAMENG_SMOKE_TABLE 指定一个当前用户可见的表。该冒烟测试只执行只读 SQL,不会创建索引或写入数据。
如果 JDBC URL 中未包含账号密码,也可以同时设置 DAMENG_SMOKE_USERNAME 和 DAMENG_SMOKE_PASSWORD。
Docker
构建镜像:
docker build -t database-mcp-java .
使用 PostgreSQL JDBC URL 运行:
docker run --rm -i \
-p 127.0.0.1:8000:8000 \
-e SERVER_ADDRESS=0.0.0.0 \
-e SERVER_PORT=8000 \
-e DATABASE_TYPE=postgresql \
-e "DATABASE_URI=jdbc:postgresql://host.docker.internal:5432/postgres?user=postgres&password=postgres" \
-e DATABASE_MCP_ACCESS_MODE=restricted \
database-mcp-java
使用 MySQL 拆分配置运行:
docker run --rm -i \
-p 127.0.0.1:8000:8000 \
-e SERVER_ADDRESS=0.0.0.0 \
-e SERVER_PORT=8000 \
-e DATABASE_TYPE=mysql \
-e DATABASE_HOST=host.docker.internal \
-e DATABASE_PORT=3306 \
-e DATABASE_NAME=app \
-e DATABASE_USERNAME=root \
-e DATABASE_PASSWORD=secret \
-e DATABASE_MCP_ACCESS_MODE=restricted \
database-mcp-java
仓库提供 docker-compose.yml,用于本地启动一个 PostgreSQL 示例数据库和 MCP 服务:
docker compose up --build
默认会把 MCP HTTP/SSE 端口映射到宿主机 127.0.0.1:8000。如需调整绑定地址或端口:
DATABASE_MCP_BIND_ADDRESS=0.0.0.0
DATABASE_MCP_HTTP_PORT=8000
docker compose up --build
绑定到 0.0.0.0 会让宿主机所有网卡暴露 MCP HTTP/SSE 端口,仅应在受信任网络中使用。
构建与测试
mvn test
mvn -DskipTests package
mvn test 会运行单元测试和 MCP 注解可见性测试。PostgreSQL 集成测试使用 Testcontainers;如果本机 Docker daemon 不可用,相关测试会自动跳过并在日志中说明原因。
兼容性说明
不同数据库的系统视图、执行计划格式和诊断指标并不完全等价。项目通过 DiagnosticDialect 为 PostgreSQL、MySQL、达梦数据库和 Apache Doris 分别实现诊断逻辑;各数据库支持的工具范围、健康检查类型、索引建议方式和不支持项的差异已在上方“支持范围”章节逐库列出。
第三方来源
早期实现参考了 crystaldba/postgres-mcp 的工具意图和 PostgreSQL 诊断能力。本项目已经改造为通用数据库 MCP 服务,但仍保留原项目许可声明,详见 THIRD_PARTY_NOTICES.md。
许可证
本项目使用 MIT License。