# Java-Database-MCP **Repository Path**: huo-wanliang/Java-Database-MCP ## Basic Information - **Project Name**: Java-Database-MCP - **Description**: 这个项目参考了crystaldba/postgres-mcp项目的代码和设计理念,实现了Java版本的数据库连接MCP服务 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-05-21 - **Last Updated**: 2026-08-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: Java, MCP, Database ## README # 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`,使用 PostgreSQL `EXPLAIN (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`,使用 MySQL `EXPLAIN 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: ```java @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 地址为: ```text http://127.0.0.1:8000/sse ``` 常用环境变量: ```bash SERVER_ADDRESS=127.0.0.1 SERVER_PORT=8000 MCP_STDIO_ENABLED=false ``` 如需让受信任内网中的 MCP Client 访问,可绑定到所有网卡: ```bash 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 会自动完成以下操作: 1. 启动 MySQL 8.4 控制库并执行 `deploy/init-control.sql`; 2. 创建全部控制表、初始状态和默认管理员; 3. 等待控制库健康后启动 Spring Boot 后端并执行 Flyway 迁移; 4. 构建 Vue 前端,通过 Nginx 的 HTTPS 端口统一提供页面、REST API 和 MCP/SSE。 在项目根目录创建不会提交到 Git 的 `.env`: ```dotenv CONTROL_DB_USERNAME=control_user CONTROL_DB_PASSWORD= CONTROL_DB_ROOT_PASSWORD= CONTROL_CREDENTIAL_KEY= TLS_CERT_FILE= TLS_KEY_FILE= 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` 列表,然后执行唯一的启动命令: ```bash docker compose -f docker-compose.console.yml up -d --build ``` 查看启动状态: ```bash docker compose -f docker-compose.console.yml ps ``` 所有服务显示为运行状态后,浏览器访问 `https://<内网域名>:8443`,无需再执行 SQL 或创建账号,直接登录: ```text 用户名:admin 密码:Admin@123.com ``` 首次登录后请在“系统设置”中修改默认密码。生产配置使用 Secure Session Cookie,必须通过 HTTPS 访问。再次执行启动命令会复用现有 `control-data` 数据卷,不会覆盖已修改的管理员密码或已有数据。 如果启动失败,通过以下命令查看日志: ```bash docker compose -f docker-compose.console.yml logs -f control-db backend console ``` ### 外部控制库初始化 控制库用于保存管理员、加密后的目标连接、当前目标和执行历史。使用外部 MySQL 时,只需以具备建库权限的账号执行一个脚本: ```bash mysql -u <数据库账号> -p < deploy/init-control.sql ``` 该脚本一次完成 `database_mcp_control` schema、全部控制表、初始状态和管理员数据,并且可重复执行。全新控制库执行后可直接使用以下账号登录,无需再运行建表脚本或配置初始管理员环境变量: ```text 用户名:admin 密码:Admin@123.com ``` `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 示例: ```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="" $env:DATABASE_MCP_CONTROL_CREDENTIAL_KEY="" mvn spring-boot:run ``` 另开一个终端启动前端: ```powershell Set-Location frontend npm ci npm run dev ``` 浏览器打开终端显示的地址(默认 `http://localhost:5173`)。Vite 会把相对路径 `/api/**` 代理到 `http://127.0.0.1:8000`,因此本地开发不需要配置 CORS,也不要让前端直接请求目标数据库。 ### 前后端联动流程 1. 浏览器访问前端;开发环境由 Vite、生产环境由 Nginx 把同源 `/api/**` 转发到 Spring Boot `8000`。 2. 登录成功后,后端创建 HttpOnly Session Cookie。前端在写请求前访问 `/api/v1/auth/csrf`,再携带 `X-XSRF-TOKEN`,后端据此完成会话认证与 CSRF 校验。 3. 前端保存目标连接时,后端用 `CONTROL_CREDENTIAL_KEY` 对目标密码做 AES-GCM 加密,仅把密文写入 MySQL 控制库,密码不会回显到浏览器。 4. 激活连接时,后端更新全局当前目标和 `revision`;前端把修订号保存到本地,并在目标相关请求中发送 `X-Target-Revision`。若其他页面或会话已切换目标,后端返回 `409 target_revision_conflict`,本次操作不会误发到新数据库,也不会自动重试。 5. 后端在当前目标对应的独立连接池中执行受限只读 SQL/诊断,把 JSON 结果返回前端,并将执行结果写入 `execution_history`。前端始终只连接后端,不持有控制库或目标库的直连能力。 ## 调试 REST 适配器 除标准 MCP 传输外,仓库提供镜像 9 个 MCP 工具的 REST 适配器 `DebugHttpAdapter`,路径前缀 `/api/debug`(如 `POST /api/debug/execute_sql`),请求体为对应工具参数的 JSON,响应固定为 `{"output": "..."}`。它不含任何业务逻辑,仅直接转发到 `DatabaseToolFacade`,便于在没有 MCP Client 时用 `curl` / Postman 排查问题。 默认关闭,需显式启用: ```bash DATABASE_MCP_DEBUG_HTTP_ENABLED=true ``` 该适配器**仅用于本地调试**,不替代 MCP 传输,也不应暴露到生产网络;启用后同样遵循 `SERVER_ADDRESS` 绑定范围,公网暴露需放反代/网关后。 ## 数据库连接 可以使用完整 JDBC URL: ```bash DATABASE_TYPE=postgresql DATABASE_URI=jdbc:postgresql://localhost:5432/postgres?user=postgres&password=postgres ``` 也可以使用拆分配置: ```bash DATABASE_TYPE=postgresql DATABASE_HOST=localhost DATABASE_PORT=5432 DATABASE_NAME=postgres DATABASE_USERNAME=postgres DATABASE_PASSWORD=postgres ``` 如果同时配置 `DATABASE_URI` 和拆分连接参数,服务优先使用 `DATABASE_URI`。用户名或密码包含特殊字符时,请按 JDBC URL 参数规则编码。 访问模式可通过环境变量配置: ```bash DATABASE_MCP_ACCESS_MODE=restricted ``` `restricted` 模式用于受控 SQL 执行,`unrestricted` 模式适合本地开发和可信环境。 ### PostgreSQL 示例 完整 JDBC URL: ```bash DATABASE_TYPE=postgresql DATABASE_URI=jdbc:postgresql://localhost:5432/postgres?user=postgres&password=postgres ``` 拆分配置: ```bash DATABASE_TYPE=postgresql DATABASE_HOST=localhost DATABASE_PORT=5432 DATABASE_NAME=postgres DATABASE_USERNAME=postgres DATABASE_PASSWORD=postgres ``` ### MySQL 示例 完整 JDBC URL: ```bash DATABASE_TYPE=mysql DATABASE_URI=jdbc:mysql://localhost:3306/app?user=root&password=secret ``` 拆分配置: ```bash 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 兼容参数): ```bash DATABASE_TYPE=doris DATABASE_URI='jdbc:mysql://localhost:9030/example_db?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&tinyInt1isBit=false&allowPublicKeyRetrieval=true' ``` 拆分配置: ```bash DATABASE_TYPE=doris DATABASE_HOST=localhost DATABASE_PORT=9030 DATABASE_NAME=example_db DATABASE_USERNAME=root DATABASE_PASSWORD= ``` 5 项 Doris MySQL 兼容参数(缺一不可): | 参数 | 取值 | 作用 | |---|---|---| | `tinyInt1isBit` | `false` | 避免 TINYINT(1) 被当 BIT 处理 | | `zeroDateTimeBehavior` | `convertToNull` | `0000-00-00` 映射为 NULL 而非抛错 | | `characterEncoding` | `UTF-8` | 元数据查询使用 UTF-8 解码 | | `useUnicode` | `true` | 配合 `characterEncoding` 启用 Unicode 传输 | | `allowPublicKeyRetrieval` | `true` | 本地受信场景可启用;**生产请改 `useSSL=true` 并设为 `false`**,避免中间人风险 | 诊断工具依赖审计插件(`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: ```bash DATABASE_TYPE=dameng DATABASE_URI=jdbc:dm://localhost:5236/app DATABASE_USERNAME=app_user DATABASE_PASSWORD= ``` 拆分配置: ```bash DATABASE_TYPE=dameng DATABASE_HOST=localhost DATABASE_PORT=5236 DATABASE_NAME=app DATABASE_USERNAME=app_user DATABASE_PASSWORD= ``` 达梦支持使用当前 Java 21 项目选定的达梦 JDBC 驱动依赖 `com.dameng:DmJdbcDriver11`。诊断工具均按只读方式实现;如果当前用户无法访问某些达梦系统视图,对应诊断项会返回退化说明,其它可执行项继续返回结果。 真实达梦实例冒烟测试默认跳过。需要验证所有 MCP 工具时,可显式启用: ```bash DAMENG_SMOKE_ENABLED=true DAMENG_SMOKE_URI=jdbc:dm://localhost:5236/app DAMENG_SMOKE_USERNAME=app_user DAMENG_SMOKE_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 构建镜像: ```bash docker build -t database-mcp-java . ``` 使用 PostgreSQL JDBC URL 运行: ```bash 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 拆分配置运行: ```bash 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 服务: ```bash docker compose up --build ``` 默认会把 MCP HTTP/SSE 端口映射到宿主机 `127.0.0.1:8000`。如需调整绑定地址或端口: ```bash DATABASE_MCP_BIND_ADDRESS=0.0.0.0 DATABASE_MCP_HTTP_PORT=8000 docker compose up --build ``` 绑定到 `0.0.0.0` 会让宿主机所有网卡暴露 MCP HTTP/SSE 端口,仅应在受信任网络中使用。 ## 构建与测试 ```bash 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](THIRD_PARTY_NOTICES.md)。 ## 许可证 本项目使用 [MIT License](LICENSE)。