TypeScript 实现的达梦 DM8 Model Context Protocol (MCP) 服务器,提供表结构浏览和只读 SQL 查询能力。支持多连接、多 Schema、配置文件管理以及主备容灾。
2.0 是一个 breaking change 版本,针对多连接、跨 schema 场景下 LLM 容易查错库的问题做了重构(详见 变更日志)。
移除的配置项(旧配置里写了会被静默忽略,建议清理):
defaultConnection(环境级)/connection.default(连接级):多连接场景下「默认连接」会让 LLM 在 dev/prod 之间静默查错库,已移除。- CLI
--default-connection/ 环境变量DM_DEFAULT_CONNECTION:同上。
迁移:多连接模式下未传 connection 时不再回落到默认连接,而是报错并返回连接目录(含每个连接的环境说明、可访问 schema 与正确调用示例),请让 LLM 显式传 connection。单连接模式行为不变(自动选中唯一连接)。
在项目根目录创建两个文件即可,所有配置都在项目内闭环:
.claude/dm8-mcp.json(数据库连接配置):
{
"activeEnv": "dev",
"environments": {
"dev": {
"connections": [
{
"name": "GASBASE",
"host": "127.0.0.1",
"port": 5236,
"username": "SYSDBA",
"password": "your_password",
"schema": "GASBASE"
}
]
},
"prod": {
"connections": [
{
"name": "BASE",
"host": "10.0.1.100",
"masterHost": "10.0.1.200",
"port": 5236,
"username": "BASE",
"password": "your_password",
"schema": "BASE"
}
]
}
}
}.mcp.json(注册 MCP server,Claude Code 自动读取):
{
"mcpServers": {
"dm8": {
"command": "npx",
"args": ["-y", "mcp-dm8-server", "--config", ".claude/dm8-mcp.json"],
"env": {
"NODE_OPTIONS": "--openssl-legacy-provider"
}
}
}
}切换环境只需修改 activeEnv 为 "prod",或通过 --env prod 覆盖。
本地开发:如果使用未发布到 npm 的本地版本,将
command改为node,args改为["--openssl-legacy-provider", "/path/to/mcp-dm8-server/dist/cli.js", "--config", ".claude/dm8-mcp.json"]。
配置文件位置:
- Windows:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
通过 --config 传入配置文件的绝对路径:
{
"mcpServers": {
"dm8": {
"command": "npx",
"args": ["-y", "mcp-dm8-server", "--config", "/path/to/project/.claude/dm8-mcp.json"],
"env": {
"DM_ENV": "production",
"NODE_OPTIONS": "--openssl-legacy-provider"
}
}
}
}Cline、mcp-router 等客户端的配置格式与 Claude Desktop 一致,均为 JSON 格式的 mcpServers 配置。
| 工具名 | 描述 | 必填参数 | 可选参数 |
|---|---|---|---|
list_schemas |
列出已配置的连接、Schema 及数据库中可见的模式 | 无 | 无 |
list_tables |
列出指定 Schema 下的所有表 | 无 | connection, schema |
describe_table |
返回表的列名、类型、长度、是否可空、列注释 | table |
connection, schema |
list_indexes |
返回表的索引名、唯一性、索引列(ALL_INDEXES + ALL_IND_COLUMNS) | table |
connection, schema |
execute_query |
执行 SQL(默认只读,实际权限由连接的 sqlAccess 级别决定) |
query |
connection, schema, maxRows |
安全限制:
execute_query默认仅允许 SELECT、SHOW、DESCRIBE、EXPLAIN 语句;写操作(DML/DDL)需为连接显式配置sqlAccess级别(见 SQL 访问级别)。详见 安全特性 与 docs/SECURITY.md。
所有工具均返回 content(文本)和 structuredContent(JSON)两种格式。
execute_query元数据提示:structuredContent同时返回schema(resolver 解析的「会话 schema」)与queriedSchemas(从 SQL 的FROM/JOIN子句解析出的实际触达 schema)。当 SQL 用SCHEMA.TABLE全限定跨 schema 查询时,两者可能不同(如schema=GASBASE但queriedSchemas=["CUSTOMER"]),便于 LLM 区分「连接默认 schema」与「SQL 真实查询目标」。
# 查看所有连接和 Schema
list_schemas()
# 单连接配置下无需传 connection(自动选中唯一连接)
list_tables()
describe_table(table: "USERS")
execute_query(query: "SELECT COUNT(*) FROM ORDERS")
# 显式指定连接
list_tables(connection: "hall")
describe_table(connection: "gasbase", table: "ACT_GE_PROPERTY")
execute_query(connection: "inspection", query: "SELECT COUNT(*) FROM USER_TABLES")
# 只传 schema,自动匹配唯一连接
list_tables(schema: "HALL")
=== 可用连接(调用工具时用 connection 参数指定)===
gasbase(schema: GASBASE)
hall — 大厅服务(schema: HALL, HALL_REPORT)
⚠ 同名 schema 跨多连接(必须显式传 connection,否则报错):
GASBASE → gasbase, gasbase-report
=== 数据库中可见的模式 ===
[gasbase] GASBASE, INSPECTION, SYSDBA
[hall] HALL, SYSDBA
多连接模式下,未显式传 connection 时:仅配置单个连接会自动选中;配置多个连接则报错并返回上面的连接目录,由调用方显式选择(不再自动回落到某个「默认连接」)。每个连接可在配置里写 description(如「开发环境」「生产环境,慎用」)以便在目录与错误提示中区分。
表结构以 MCP resource 暴露,client 可 resources/list 枚举、resources/read 按需读取,让 LLM 用 @dm8:///.../表名 直接引用表结构,避免每次 list→describe 三轮往返:
- URI 模板:
dm8:///{connection}/{schema}/{table} - 返回:列定义与列注释(同
describe_table) - 枚举:列出所有已配置连接/schema 下的表
dm8:///gasbase/GASBASE/USERS
dm8:///hall/HALL/ORDER
预定义的、带参数的指令模板,把 DB 探查最佳实践固化下来,减少 LLM 乱试:
| Prompt | 参数 | 用途 |
|---|---|---|
explore-schema |
connection?, schema? |
系统化探查 schema:列表 → 描述 → 索引 |
analyze-table |
table, connection?, schema? |
单表结构 + 索引 + 数据分布的只读分析 |
execute_query 每次调用通过 MCP logging 上报(client 订阅后可见):
info:正常查询(query / 连接 / 耗时 / 行数 / 是否截断)warning:耗时超过DM_SLOW_QUERY_MS(默认 1000ms)的慢查询,以及所有写操作(DML/DDL,附语句动词与影响行数,便于审计)error:执行失败
未订阅 logging 的 client 静默忽略,不影响查询返回。
execute_query 默认只读。需要执行写操作(DML/DDL)时,通过 sqlAccess 显式提升所选连接的访问级别:
| 级别 | 允许的语句 | 说明 |
|---|---|---|
readonly(默认) |
SELECT / SHOW / DESCRIBE / EXPLAIN | 与历史行为一致,不配置即只读 |
dml |
上述 + INSERT / UPDATE / DELETE / MERGE | 修改数据 |
ddl |
上述 + CREATE / ALTER / DROP / TRUNCATE | 修改表结构(含 DML) |
full |
不做语句类型限制 | CALL / GRANT / SET 等全部放开,慎用 |
所有级别共同的硬规则:分号多语句始终拦截(一次一条语句);WITH(CTE)前缀在 readonly/dml/ddl 下拦截(字符串校验无法定位 CTE 后的主语句动词,full 下放开);Schema 白名单对写操作同样生效。
写语句在驱动 autocommit 模式下执行即提交(无事务悬挂),返回 rowsAffected(影响行数)。启动时若检测到任何连接开启写权限,会在 stderr 输出警告并列出各连接级别。
生效优先级(高→低):连接级 sqlAccess > 配置文件环境级 sqlAccess > --sql-access / DM_SQL_ACCESS > readonly
{
"activeEnv": "work",
"environments": {
"work": {
"sqlAccess": "readonly",
"connections": [
{ "name": "prod", "sqlAccess": "readonly", "...": "..." },
{ "name": "dev", "sqlAccess": "ddl", "...": "..." }
]
}
}
}- 环境级:
environments.<env>.sqlAccess,作为该环境所有连接的默认 - 连接级:
connections[].sqlAccess,覆盖环境级(如上:prod 只读、dev 可 DDL) - 全局默认:CLI
--sql-access dml或环境变量DM_SQL_ACCESS=dml,作用于未显式配置的连接(单连接裸配、--connectionsJSON 场景)
配置文件示例(完整):
{
"name": "dev",
"host": "11.14.2.1",
"port": 5236,
"username": "GASBASE",
"password": "password1",
"schema": "GASBASE",
"description": "开发环境",
"sqlAccess": "dml"
}.claude/dm8-mcp.json 支持多环境管理:
{
"activeEnv": "dev",
"environments": {
"dev": {
"connections": [
{
"name": "gasbase",
"host": "11.14.2.1",
"port": 5236,
"username": "GASBASE",
"password": "password1",
"schema": "GASBASE",
"description": "开发环境"
}
]
},
"staging": {
"connections": [
{
"name": "test_db",
"host": "192.168.1.100",
"port": 5236,
"username": "TESTER",
"password": "test_password",
"schema": "TEST_SCHEMA"
}
]
},
"prod": {
"connections": [
{
"name": "BASE",
"host": "10.31.193.111",
"masterHost": "10.31.193.121",
"port": 5236,
"username": "BASE",
"password": "password",
"schema": "BASE",
"description": "生产环境,慎用"
},
{
"name": "HALL",
"host": "10.31.193.111",
"masterHost": "10.31.193.121",
"port": 5236,
"username": "HALL",
"password": "password",
"schema": "HALL"
}
]
}
}
}一个账号可访问多个 Schema 时,有两种配置方式:
方式一:schemas 数组(推荐,支持描述信息)
{
"name": "hall",
"host": "11.14.2.1",
"port": 5236,
"username": "HALL",
"password": "your_password",
"schema": "HALL",
"schemas": [
{"name": "HALL", "description": "大厅服务"},
{"name": "HALL_REPORT", "description": "大厅报表"}
]
}方式二:schema 逗号拼接(简洁,适用于快速配置)
{
"name": "hall",
"host": "11.14.2.1",
"port": 5236,
"username": "HALL",
"password": "your_password",
"schema": "HALL, HALL_REPORT, OTHER_SCHEMA"
}系统会自动取第一个作为默认 Schema,其余全部加入访问白名单。
当工具调用未显式指定 connection 参数时,按以下优先级路由:
- 指定了
connection→ 使用该连接 - 指定了
schema→ 匹配唯一拥有该 Schema 的连接(多个匹配则报错并列出候选) - 均未指定 →
- 仅配置单个连接:自动选中
- 配置了多个连接:报错并返回连接目录,要求显式传
connection
设计说明:旧版的
defaultConnection/connection.default配置项已移除。多连接场景下「默认连接」会让 LLM 在 dev/prod 之间静默查错库(同名 schema 跨连接时尤甚),因此改为强制显式选择。错误响应会列出每个连接的description(环境说明)与可访问 schema,并给出正确调用示例,引导 LLM 一次选对。
每个连接可配置 masterHost / masterPort,主库连接失败时自动切换到备用库:
{
"name": "primary",
"host": "10.0.1.100",
"port": "5236",
"masterHost": "10.0.1.200",
"masterPort": "5236",
"username": "SYSDBA",
"password": "your_password",
"schema": "SYSDBA"
}除了配置文件,也可以通过 CLI 参数或环境变量传入连接信息(适合简单场景或 CI 环境):
# 单连接
npx mcp-dm8-server --host 127.0.0.1 --port 5236 --username SYSDBA --password 密码 --schema SYSDBA
# 多连接
npx mcp-dm8-server --connections '[{"name":"gasbase","host":"11.14.2.1","port":"5236","username":"GASBASE","password":"pwd","schema":"GASBASE","description":"开发环境"}]'或通过环境变量:
{
"mcpServers": {
"dm8": {
"command": "npx",
"args": ["-y", "mcp-dm8-server"],
"env": {
"DM_HOST": "127.0.0.1",
"DM_PORT": "5236",
"DM_USERNAME": "SYSDBA",
"DM_PASSWORD": "your_password",
"DM_SCHEMA": "SYSDBA",
"NODE_OPTIONS": "--openssl-legacy-provider"
}
}
}
}| 参数 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
--config |
DM_CONFIG_FILE |
.claude/dm8-mcp.json |
配置文件路径 |
--env |
DM_ENV |
配置文件中的 activeEnv |
配置文件中的环境名 |
--host |
DM_HOST |
- | 数据库主机地址 |
--port |
DM_PORT |
5236 |
数据库端口 |
--username |
DM_USERNAME |
- | 数据库用户名 |
--password |
DM_PASSWORD |
- | 数据库密码 |
--schema |
DM_SCHEMA |
- | 默认 Schema |
--schemas |
DM_SCHEMAS |
- | Schema 列表(JSON 或逗号分隔) |
--connections |
DM_CONNECTIONS |
- | 多连接配置(JSON 数组) |
--sql-access |
DM_SQL_ACCESS |
readonly |
全局默认 SQL 访问级别(readonly/dml/ddl/full),连接级配置可覆盖 |
| - | DM_MAX_ROWS |
1000 |
execute_query 默认最大返回行数 |
| - | DM_QUERY_TIMEOUT_MS |
0(不限) |
连接级查询超时(dmdb socketTimeout),防慢查询 |
| - | DM_SLOW_QUERY_MS |
1000 |
慢查询阈值,超出则 logging 上报 warning |
| - | DM_POOL_MAX / DM_POOL_MIN / DM_POOL_TIMEOUT |
5 / 1 / 60 |
连接池大小与闲置超时 |
--version |
- | - | 打印版本信息 |
配置优先级(高→低):CLI 参数 → 环境变量 → 配置文件。
详见 docs/SECURITY.md,包含对照 Datadog 披露的官方 Postgres MCP 只读绕过漏洞(多语句
COMMIT;+ 会话污染SET)的自查,以及部署侧纵深防御要求。
- SQL 注入防护: 标识符格式校验 (
/^[A-Za-z_][A-Za-z0-9_]*$/),参数化查询 - 默认只读 + 分级写权限: 默认仅允许 SELECT / SHOW / DESCRIBE / EXPLAIN;写操作需显式配置
sqlAccess(readonly/dml/ddl/full,支持按连接控制);分号多语句在所有级别下均拦截 - Schema 白名单:
validateSchemaAccess()校验访问范围 - 凭据保护: 连接字符串中密码 URL 编码;配置文件被
.gitignore忽略;list_schemas返回的连接目录已剔除password,绝不外泄给 client/LLM - 连接池管理:
SELECT 1 FROM DUAL心跳检测,失效自动重建 - 查询超时:
DM_QUERY_TIMEOUT_MS连接级 socketTimeout,防慢查询拖垮连接池 - DB 账号最小权限: 部署侧应给 MCP 账号仅
GRANT SELECT(纵深防御,最后一道闸)
# 安装依赖
npm install
# 开发模式(tsx watch)
npm run dev
# 构建(tsup → dist/,ESM + 类型声明)
npm run build
# 测试(vitest)
npm test
# 运行单个测试
npx vitest run tests/validation.test.ts
# 代码检查
npm run lint
# 格式化
npm run formatNode.js 18+ 注意: DM8 驱动依赖旧版 OpenSSL,需添加
--openssl-legacy-provider:NODE_OPTIONS=--openssl-legacy-provider npm run dev
ISC License