# database-mcp **Repository Path**: karentwan/database-mcp ## Basic Information - **Project Name**: database-mcp - **Description**: 数据库mcp - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-10 - **Last Updated**: 2026-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # db-mcp MySQL / OceanBase 增删改查 MCP 服务器(stdio 传输)。面向智能体提供多数据库的 **数据级**操作能力:查询、写入、查看表结构;**禁止一切 DDL**(建表、改字段、删表、清空表等)。 支持两种模式(按库配置,可混用): | mode | 适用 | 驱动 | 额外依赖 | |---|---|---|---| | `mysql`(默认) | MySQL / OceanBase MySQL 租户 | PyMySQL | 无 | | `oracle` | **OceanBase Oracle 租户** | OceanBase Connector/J + JayDeBeApi/JPype | **JRE 8+(仅配置了 oracle 库才需要)** | Java 按需依赖:未配置任何 `oracle` 库时,不会加载 jpype/jaydebeapi、不会启动 JVM, 纯 MySQL 用法对环境无 Java 要求。 ## 工具集 | 工具 | 功能 | 关键规则 | |---|---|---| | `list_databases()` | 列出可用数据库 key、库名与 mode | 不泄露连接凭据 | | `list_tables(key)` | 表名 / 类型 / 表注释 | | | `describe_table(key, table)` | 完整列信息 + 索引 + 建表语句 | 表名走标识符校验;OB Oracle 小写自动大写归一 | | `query(key, sql, max_rows?)` | 只读查询 | 仅放行 `SELECT`;默认 100 行、硬上限可配;超时可配 | | `execute(key, sql, allow_full_table?)` | 写入 | 单语句自动提交;无 WHERE 的 UPDATE/DELETE 拒绝,需显式 `allow_full_table=true` | **写白名单按方言区分**: - mysql:`INSERT / UPDATE / DELETE / REPLACE`(upsert 用 REPLACE) - oracle:`INSERT / UPDATE / DELETE / MERGE`(upsert 用 MERGE INTO;无 REPLACE) 安全实现:去注释/去字符串字面量后按**语句首关键字白名单**判断,默认拒绝一切未列出语句 (`CREATE/DROP/ALTER/TRUNCATE/GRANT/CALL/WITH...` 全部被拦);拒绝分号多语句。 注释语法也按方言处理(`#` 行注释仅 MySQL 方言识别)。生产环境建议再配合仅授予 DML 权限的数据库账号做双重防护。 分页写法:MySQL 模式 `LIMIT`;OB Oracle 模式无 LIMIT,用 `FETCH FIRST n ROWS ONLY` 或 `ROWNUM`。 ## 配置 ### 数据库连接(必需) 单个 JSON 环境变量 `DB_MCP_DATABASES`,key 即智能体传入的库标识: ```json { "order": {"host": "10.0.0.1", "port": 3306, "user": "rw", "password": "p@ss", "database": "order_db"}, "ob": {"mode": "oracle", "host": "10.0.0.2", "port": 2883, "user": "ORDER_USER@TENANT01#CLUSTER01:1683858802", "password": "p@ss", "database": "order_user"} } ``` - `mode` 缺省为 `mysql`;OceanBase Oracle 租户配 `"mode": "oracle"` - Oracle 租户的 `user` 用 OB 完整格式 `用户名@租户名#集群名`(如控制台给的串带 `:数字` 后缀,原样保留), `database` 填 schema(通常等于用户名) - Oracle 租户端口通常是 OBProxy 的 2883 - 可选字段:`charset`(默认 `utf8mb4`,仅 mysql 模式生效)、`connect_timeout`(默认 10 秒) - 密码无需 URL 编码 ### OB Oracle 专用(可选) | 环境变量 | 说明 | |---|---| | `DB_MCP_JVM_PATH` | 显式指定 JVM 路径(Windows 为 `jvm.dll`,Linux 为 `libjvm.so`);不设则用 JAVA_HOME 自动发现 | | `DB_MCP_OB_JAR` | 显式指定 OceanBase Connector/J jar;不设则用包内 `db_mcp/jars/` 自带的驱动 | ### 限制类(可选) | 环境变量 | 默认 | 说明 | |---|---|---| | `DB_MCP_DEFAULT_MAX_ROWS` | `100` | query 默认最大返回行数 | | `DB_MCP_HARD_MAX_ROWS` | `1000` | max_rows 参数的硬上限 | | `DB_MCP_QUERY_TIMEOUT` | `30` | 查询超时(秒;MySQL 走 socket+服务端超时,Oracle 走 JDBC socketTimeout) | | `DB_MCP_LOG_LEVEL` | `INFO` | 日志级别(输出到 stderr) | ## 运行 ```bash uv sync # 安装依赖 uv run db-mcp # 以 stdio 启动(需要 DB_MCP_DATABASES) ``` ## 智能体接入示例 ```json { "mcpServers": { "db-mcp": { "command": "uv", "args": ["run", "--directory", "E:\\Document\\sill_creator\\数据库MCP", "db-mcp"], "env": { "DB_MCP_DATABASES": "{\"order\":{\"host\":\"10.0.0.1\",\"port\":3306,\"user\":\"rw\",\"password\":\"p@ss\",\"database\":\"order_db\"},\"ob\":{\"mode\":\"oracle\",\"host\":\"10.0.0.2\",\"port\":2883,\"user\":\"ORDER_USER@TENANT01#CLUSTER01:1683858802\",\"password\":\"p@ss\",\"database\":\"order_user\"}}", "DB_MCP_JVM_PATH": "D:\\software\\graalvm-ce-java17\\bin\\server\\jvm.dll" } } } } ``` `DB_MCP_JVM_PATH` 仅在配置了 oracle 库时需要(或确保 JAVA_HOME 已设置)。 ## 测试 ```bash # 单元测试(无需数据库、无需 Java) uv run pytest tests/test_sqlguard.py -v # MySQL 集成测试 TEST_DB_MCP_DATABASES='{"test":{"host":"127.0.0.1","port":3306,"user":"root","password":"xxx","database":"test"}}' \ uv run pytest tests/test_integration.py -v # OB Oracle 集成测试(只读 + 零行写,不动业务数据;需要 JVM) TEST_OB_DATABASES='{"ob":{"mode":"oracle","host":"10.0.0.2","port":2883,"user":"U@T#C","password":"xxx","database":"schema"}}' \ DB_MCP_JVM_PATH='C:\\path\\to\\jvm.dll' \ uv run pytest tests/test_ob_oracle.py -v ``` 注:pytest 下 JPype 触发 Java 异常时可能打印 `Windows fatal exception: access violation` ——这是 pytest faulthandler 与 JPype SEH 的已知良性噪音,进程不受影响;stdio 服务器 不启用 faulthandler,生产环境无此输出。 ## 项目结构 ``` src/db_mcp/ ├── config.py # 环境变量解析(JSON 连接配置 + mode + 限制) ├── sqlguard.py # SQL 白名单拦截器(安全核心,mysql/oracle 方言) ├── connections.py # 懒加载单连接 + 重连 + 每 key 锁;JVM 懒加载单例(OB Oracle) ├── serialize.py # 结果序列化(Decimal/datetime->str, blob->hex, Java Clob->str) ├── tools.py # 工具纯逻辑实现(可独立测试,元数据按方言分支) ├── server.py # MCPServer 装配 + stdio 入口 └── jars/ # 内置 OceanBase Connector/J 驱动(oracle 模式使用) ``` ## 已知限制 - OB Oracle 模式下 `last_insert_id` 恒为 null(Oracle 用序列,无此语义) - `describe_table` 的建表语句依赖 `DBMS_METADATA` 权限,无权限时该字段降级为 null - OceanBase Oracle 模式仅企业版提供;python-oracledb (thin) 与 PyMySQL 均无法连接 Oracle 租户(协议不兼容),必须走 JDBC