Skip to main content
Glama
Yukuiii

any-db-mcp

by Yukuiii
README.md
# any-db-mcp

[English](./README.en.md) | 简体中文

> 让大模型通过 MCP (Model Context Protocol) 安全地操作数据库。支持 **MySQL / MariaDB / PostgreSQL / SQLite / Microsoft SQL Server / Oracle**。

[![npm version](https://img.shields.io/npm/v/@sakura0v0/any-db-mcp.svg)](https://www.npmjs.com/package/@sakura0v0/any-db-mcp)

## 特性

- **统一适配**:MySQL / MariaDB / PostgreSQL / SQLite / MSSQL / Oracle 共用同一套工具接口
- **双传输模式**:`stdio` 本地子进程 + `Streamable HTTP` 远程,后者带 stateful session 与可选 Bearer Token 鉴权
- **MCP Resources 暴露 schema**:`db://tables`、`db://table/{name}` 与 `db://table/{schema}/{name}` 让客户端主动消化库结构,大幅减少每次对话重复 describe 的 token 开销
- **三档权限模式**:`readonly` / `readwrite` / `full`,启动时由环境变量决定,**运行时不可篡改**(5 层防 LLM 提权设计)
- **事务支持**:单工具批量提交,任一失败自动回滚
- **连接弹性**:TCP keepalive + 连接丢失自动重建并重试 + 健康检查工具
- **一次调研到位**:`describe_table` 一次返回列定义、索引、行数估算、数据采样,减少 LLM 来回试探
- **响应耗时透明**:所有 SQL 类工具返回 `elapsedMs`,便于 LLM 感知性能并调整策略
- **统一 JSON 响应**:所有工具返回结构化 JSON,便于 LLM 解析
- **零部署**:通过 `npx` 一行命令即可在任意 MCP 客户端中使用

## 工具一览

| Tool | 说明 | 受权限模式约束 |
|------|------|----------------|
| `connect` | 动态连接数据库,返回当前数据库的表信息列表与权限模式 | 否 |
| `disconnect` | 主动断开连接并释放连接池(幂等) | 否 |
| `connection_status` | 查看当前连接状态、ping 健康度、表信息列表与权限模式 | 否 |
| `query` | 执行只读查询(`SELECT` / `SHOW` / `DESCRIBE`),响应最多返回前 1000 行 | 否 |
| `execute` | 执行单条写操作(DML,或 `full` 模式下 DDL) | ✓ |
| `transaction` | 在事务中顺序执行多条 SQL,任一失败回滚 | ✓ |
| `list_tables` | 列出当前连接数据库的所有表名与表注释 | 否 |
| `describe_table` | 一次返回指定表的列定义、索引、估算行数与数据采样 | 否 |
| `search_schema` | 按关键词搜索表名、列名和字段类型 | 否 |
| `explain` | 获取 SQL 执行计划(不实际执行原 SQL),辅助优化 | 否 |

## 权限模式(PERMISSION_MODE)

| Mode | `query` | `execute` / `transaction` | DDL | 适用场景 |
|------|---------|----------------------------|-----|----------|
| `readonly` | ✓ | ✗ | ✗ | 生产环境查询、数据探索 |
| `readwrite` ⭐默认 | ✓ | ✓ DML(INSERT/UPDATE/DELETE) | ✗ | 常规业务操作 |
| `full` | ✓ | ✓ DML + DDL | ✓ | 迁移、初始化、Schema 演进 |

> **安全保证**:`PERMISSION_MODE` 只能在 server 启动时通过环境变量设定。`AppConfig` 在加载后被 `Object.freeze` 深冻结,且任何工具的 `inputSchema` 都不暴露权限相关参数,杜绝 LLM 通过"重连提权"等手段绕过限制。

## 快速开始

### 通过 npx 使用(推荐)

在 MCP 客户端配置中添加:

```json
{
  "mcpServers": {
    "any-db-mcp": {
      "command": "npx",
      "args": ["-y", "@sakura0v0/any-db-mcp"],
      "env": {
        "PERMISSION_MODE": "readwrite",
        "DB_TYPE": "mysql",
        "DB_HOST": "localhost",
        "DB_PORT": "3306",
        "DB_USER": "root",
        "DB_PASSWORD": "your_password",
        "DB_NAME": "your_database"
      }
    }
  }
}
```

### 本地源码运行

```bash
npm install
npm run build
node dist/index.js
```

对应 MCP 客户端配置:

```json
{
  "mcpServers": {
    "any-db-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/any-db-mcp/dist/index.js"],
      "env": {
        "PERMISSION_MODE": "readwrite"
      }
    }
  }
}
```

## 环境变量

| 变量 | 说明 | 默认值 |
|------|------|--------|
| `PERMISSION_MODE` | 权限模式:`readonly` / `readwrite` / `full` | `readwrite` |
| `DB_TYPE` | 数据库类型:`mysql` / `mariadb` / `postgresql` / `sqlite` / `mssql` / `oracle` | `mysql` |
| `DB_HOST` | 数据库主机 | `localhost` |
| `DB_PORT` | 数据库端口 | `3306`(MySQL/MariaDB)/ `5432`(PG)/ `1433`(MSSQL)/ `1521`(Oracle) |
| `DB_USER` | 数据库用户名 | `root` |
| `DB_PASSWORD` | 数据库密码 | (空) |
| `DB_NAME` | 默认数据库 | (空) |
| `DB_SCHEMA` | 仅 PostgreSQL/MSSQL/Oracle:schema 名称;空值表示所有非系统 schema | (空) |
| `DB_FILEPATH` | SQLite 数据库文件路径 | (空) |
| `DB_ENCRYPT` | 仅 MSSQL:是否启用 TLS 加密 | `true` |
| `DB_TRUST_SERVER_CERTIFICATE` | 仅 MSSQL:是否信任自签证书 | `false` |
| `QUERY_TIMEOUT_MS` | `query` 工具响应超时时间(ms) | `30000` |
| `MCP_TRANSPORT` | 传输方式:`stdio`(默认) / `http` | `stdio` |
| `MCP_HTTP_HOST` | 仅 http:监听主机,公网暴露请显式设 `0.0.0.0` 并配 token | `127.0.0.1` |
| `MCP_HTTP_PORT` | 仅 http:监听端口 | `3000` |
| `MCP_HTTP_PATH` | 仅 http:MCP endpoint 路径 | `/mcp` |
| `MCP_AUTH_TOKEN` | 仅 http:可选 Bearer Token,设置后所有请求需带 `Authorization: Bearer <token>` | (空,不鉴权) |

> 不配置 `DB_*` 时,Server 启动后不自动连接,需 LLM 主动调用 `connect` 工具。

## 数据库连接示例

LLM 调用 `connect` 工具时的入参示例:

### MySQL

```json
{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "user": "root",
  "password": "xxx",
  "database": "mydb"
}
```

### MariaDB

```json
{
  "type": "mariadb",
  "host": "localhost",
  "port": 3306,
  "user": "root",
  "password": "xxx",
  "database": "mydb"
}
```

### PostgreSQL

```json
{
  "type": "postgresql",
  "host": "localhost",
  "port": 5432,
  "user": "postgres",
  "password": "xxx",
  "database": "mydb",
  "schema": "billing"
}
```

### SQLite

```json
{
  "type": "sqlite",
  "filepath": "/path/to/database.db"
}
```

### Microsoft SQL Server

```json
{
  "type": "mssql",
  "host": "localhost",
  "port": 1433,
  "user": "sa",
  "password": "xxx",
  "database": "mydb",
  "schema": "sales",
  "encrypt": true,
  "trustServerCertificate": false
}
```

### Oracle

```json
{
  "type": "oracle",
  "host": "localhost",
  "port": 1521,
  "user": "app",
  "password": "xxx",
  "database": "FREEPDB1",
  "schema": "BILLING"
}
```

Oracle 使用 `oracledb` Thin mode;`database` 参数可填写 service name,也可填写完整 TNS connect string。

> 协议兼容数据库可直接复用现有适配器:
>
> - **TiDB / OceanBase** 等 MySQL 协议兼容数据库 → 选 `type: mysql`
> - **CockroachDB / YugabyteDB** 等 PG 协议兼容数据库 → 选 `type: postgresql`

## 传输方式 (Transport)

支持两种 transport,通过 `MCP_TRANSPORT` 切换。

### `stdio` (默认)

最常见的本地集成方式,client 以子进程方式启动 server,通过标准输入输出通信。无需端口/网络,Claude Code、Cursor 等 IDE 默认走这条路径。

### `Streamable HTTP`

按 [MCP spec 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26) 实现:`POST /mcp` 接收 JSON-RPC,响应可为 JSON 或 SSE 流;`GET /mcp` 用于建立长连接接收 server-initiated 消息;`DELETE /mcp` 关闭 session。每个 session 由服务端生成 `Mcp-Session-Id` 头并返回,客户端后续请求需带回。

```bash
# 本地开发:监听 127.0.0.1,无鉴权
MCP_TRANSPORT=http npx @sakura0v0/any-db-mcp

# 远程访问:绑 0.0.0.0 + Bearer Token + 反向代理 TLS
MCP_TRANSPORT=http \
MCP_HTTP_HOST=0.0.0.0 \
MCP_HTTP_PORT=3000 \
MCP_AUTH_TOKEN="$(openssl rand -hex 32)" \
npx @sakura0v0/any-db-mcp
```

**安全约定**:
- 默认 `MCP_HTTP_HOST=127.0.0.1`,只接受本机回环。生产远程访问务必同时设置 `MCP_AUTH_TOKEN` 并通过反向代理(nginx / caddy)套 TLS。
- 设置 `MCP_AUTH_TOKEN` 后所有请求需带 `Authorization: Bearer <token>`,使用常数时间比较抵御计时攻击。
- HTTP 请求 body 上限 1 MB,防止简单 DoS。
- 多 session 共享 `db` 单例数据库连接池:适合"个人远程访问",多用户场景应每 client 部署独立 server。

## 响应格式

所有工具返回统一的 JSON 结构。

**成功响应**:

```json
{
  "success": true,
  "rowCount": 2,
  "limit": 1000,
  "truncated": false,
  "timeoutMs": 30000,
  "rows": [
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob" }
  ],
  "elapsedMs": 3
}
```

**失败响应**(MCP 协议层会同时设置 `isError: true`):

```json
{
  "success": false,
  "error": "当前权限模式为 readonly,禁止任何写操作。"
}
```

### 表信息列表响应

`list_tables`、`connect` 和已连接状态下的 `connection_status` 都会返回 `tableCount` 与
`tables`。`tables` 是结构化表信息数组,不是字符串数组;PostgreSQL/MSSQL/Oracle 会带 `schema`:

```json
{
  "success": true,
  "tableCount": 2,
  "tables": [
    { "schema": "public", "name": "users", "comment": "系统用户" },
    { "schema": "billing", "name": "orders", "comment": null }
  ],
  "elapsedMs": 4
}
```

`schema` 在 MySQL/SQLite 中为 `null`;`comment` 来自数据库原生表注释,无注释或 SQLite 这类无原生表注释的数据库返回 `null`。

## search_schema 快速定位

`search_schema` 可按关键词搜索当前库的表名、列名和字段类型,适合大库中先定位相关表字段再调用 `describe_table`。响应最多返回前 50 个命中项,并带 `failedTables` 说明个别表结构读取失败的情况。

```json
{
  "keyword": "email"
}
```

## describe_table 增强响应

调用 `describe_table` 时可传入 `schema` 和 `sampleLimit`(默认 3,0 表示不采样,最大 20)。响应一次性返回结构、索引、行数估算与采样数据:

```json
{
  "success": true,
  "schema": "public",
  "table": "users",
  "columns": [
    { "name": "id", "type": "bigint", "nullable": false, "key": "PRI", "extra": "auto_increment", "defaultValue": null, "comment": "用户 ID" },
    { "name": "email", "type": "varchar(120)", "nullable": false, "key": "UNI", "extra": "", "defaultValue": null, "comment": "邮箱地址" }
  ],
  "indexes": [
    { "name": "PRIMARY", "columns": ["id"], "unique": true },
    { "name": "uk_email", "columns": ["email"], "unique": true }
  ],
  "rowCount": 12453,
  "rowCountIsEstimate": true,
  "sampleCount": 3,
  "sample": [
    { "id": 1, "email": "alice@example.com" },
    { "id": 2, "email": "bob@example.com" },
    { "id": 3, "email": "carol@example.com" }
  ],
  "elapsedMs": 12
}
```

**行数估算策略**:

| 数据库 | 数据源 | `rowCountIsEstimate` | 备注 |
|--------|--------|----------------------|------|
| MySQL/MariaDB | `information_schema.TABLES.TABLE_ROWS` | `true` | InnoDB 估算,避免 COUNT(*) 全表扫描 |
| PostgreSQL | `pg_class.reltuples` | `true` | 依赖 ANALYZE,从未分析时为 `null` |
| MSSQL | `sys.partitions` | `true` | 元数据估算,避免 COUNT(*) 全表扫描 |
| Oracle | `ALL_TABLES.NUM_ROWS` | `true` | 依赖统计信息,未收集时为 `null` |
| SQLite | `SELECT COUNT(*)` | `false` | 本地文件,精确值 |

## MCP Resources

除工具外,server 还暴露三个 MCP Resource,让客户端可以主动订阅库结构(配合
`notifications/resources/list_changed`,连接切换时自动刷新):

| URI | 类型 | 说明 |
|-----|------|------|
| `db://tables` | 静态 | 当前库的所有表名 + 表注释 + 估算行数,JSON 格式,适合 LLM 一次摸清规模量级 |
| `db://table/{name}` | 动态模板 | 单表的列定义与索引,每张表自动一个 URI(由 server 根据当前库动态生成) |
| `db://table/{schema}/{name}` | 动态模板 | PostgreSQL/MSSQL/Oracle 跨 schema 精确定位单表结构 |

`connect` / `disconnect` 成功后会发送 `notifications/resources/list_changed`,
支持订阅的客户端会自动刷新可用资源列表。未连接时读 `db://tables` 返回 `connected: false`
的友好提示,读不存在的表返回 `error` 字段。

`db://tables` 返回示例:

```json
{
  "connected": true,
  "databaseType": "postgresql",
  "tableCount": 2,
  "tables": [
    {
      "table": "users",
      "schema": "public",
      "comment": "系统用户",
      "rowCount": 12453,
      "rowCountIsEstimate": true
    },
    {
      "table": "orders",
      "schema": "billing",
      "comment": null,
      "rowCount": 98210,
      "rowCountIsEstimate": true
    }
  ]
}
```

> 与 `list_tables` / `describe_table` 工具的区别:Resources 是"声明式订阅",由客户端缓存并复用,
> 适合放进每次对话的上下文;Tools 是"命令式调用",适合需要最新数据(如刚做完写入)或需要采样数据时。

## 事务示例

LLM 调用 `transaction` 工具:

```json
{
  "sqls": [
    "UPDATE accounts SET balance = balance - 100 WHERE user_id = 1",
    "UPDATE accounts SET balance = balance + 100 WHERE user_id = 2"
  ]
}
```

任一语句失败,事务自动回滚,所有改动撤销。

## 架构

```
src/
├── index.ts              入口:加载配置 → 注册工具 → 可选自动连接 → 按 transport 启动
├── transport.ts          stdio + Streamable HTTP 启动器(stateful session + Bearer)
├── config.ts             AppConfig 与 PermissionMode(启动后冻结,运行时不可改)
├── db.ts                 DatabaseManager 单例,持有当前 Adapter
├── adapters/
│   ├── types.ts          DatabaseAdapter 统一接口
│   ├── mysql.ts          mysql2/promise 连接池实现(MySQL/MariaDB)
│   ├── postgresql.ts     pg 连接池实现
│   ├── sqlite.ts         better-sqlite3 实现
│   ├── mssql.ts          mssql 连接池实现(SHOWPLAN_XML via transaction)
│   └── oracle.ts         oracledb Thin mode 连接池实现
└── tools/
    ├── index.ts          所有 Tools 注册入口
    ├── connect.ts        connect 工具
    ├── disconnect.ts     disconnect 工具
    ├── connection-status.ts connection_status 工具
    ├── query.ts          query 工具
    ├── execute.ts        execute 工具
    ├── transaction.ts    transaction 工具
    ├── list-tables.ts    list_tables 工具
    ├── describe-table.ts describe_table 工具
    ├── search-schema.ts  search_schema 工具
    ├── explain.ts        explain 工具
    ├── resources.ts      MCP Resources(db://tables + db://table/{name} + db://table/{schema}/{name})
    ├── permission.ts     权限检查 helper
    ├── response.ts       统一响应工厂 ok() / fail()
    └── sql-patterns.ts   SQL 类型正则 + 多语句拦截
```

## License

MIT

Maintenance

ActivityInactive
ResponsivenessNo issues