为支持 MCP(Model Context Protocol)的 Agent(如 Claude Code、Codex)提供数据库只读访问能力的工具。基于 .NET 8 + 官方 ModelContextProtocol SDK,支持 SQL Server、MySQL、Oracle,内置 SQL 安全守卫、多环境配置、配置热重载、每环境并发限流、审计日志,以及本机 Admin UI 配置维护页面。
- 三数据库支持:SQL Server、MySQL、Oracle(兼容 11g R2+)
- 多环境配置:同一项目可维护
dev/test/prod等多环境,设置默认环境 - SQL 安全守卫:白名单(只读语句)+ 三层黑名单双重校验,拦截多语句注入
- 配置热重载:改
config.json即时生效,无需重启 - 并发与连接池可控:每个
(project, env)独立并发闸门,避免高并发打满连接池 - 审计日志:本地 SQLite 全局记录查询与阻止,支持自动/手动清理;可选记录查询结果(弹窗懒加载查看)
- AI 友好返回:columns 与 rows 分离,rows 用二维数组压缩 token
- 本机 Admin UI:浏览器维护
config.json,含测试连接、备份管理、审计查看与全局设置
Windows 用户:可直接从 GitHub Release 下载 zip,解压后运行 .\install.ps1 一键部署(无需 .NET SDK,详见发布版本安装)。
源码部署 / 非 Windows:
git clone <repo>
cd mcp-db-tools
dotnet build编辑 src/McpDbTools.Server/config.json,在 databases 下添加项目与环境:
程序默认读取
%ProgramData%\McpDbTools\config.json(Windows 跨用户共享数据目录,与程序目录分离便于升级;LocalSystem 服务与当前用户进程共享同一份数据),可用环境变量ConfigStore__ConfigPath覆盖。首次部署后,config.json 位于%ProgramData%\McpDbTools\,不在 exe 同目录——请通过 Admin UI 维护,或直接编辑该文件。文件不存在时空配置启动,可后续通过 Admin UI 补齐。开发时若用源码目录下的 config.json,需显式设置该环境变量。
本工具通过 MCP Streamable HTTP 与 Agent 通信。服务须先启动(开发时 dotnet run --project src/McpDbTools.Server;生产环境用 NSSM 服务或登录计划任务),再让 MCP 客户端连接 http://127.0.0.1:<port>/mcp。下面给出 Claude Code 与 Codex 的配置示例,其它 MCP 客户端按各自文档以 HTTP URL 接入即可。
建议先用 Admin UI 测试连接、确认配置无误,再接入客户端:
dotnet run --project src/McpDbTools.Server,浏览器打开http://127.0.0.1:5123/admin。
Claude Code 在 mcp.json(项目级 .mcp.json 或用户级配置)中用 JSON 配置 mcpServers。HTTP 模式下只需指定 URL,服务须先单独启动(开发时 dotnet run --project src/McpDbTools.Server,可用 ConfigStore__ConfigPath 指向源码目录的 config.json;生产环境用 NSSM 服务或计划任务):
{
"mcpServers": {
"db-tools": {
"type": "http",
"url": "http://127.0.0.1:5123/mcp"
}
}
}也可用 Claude Code CLI 一条命令添加(等效于上面配置;CLI 默认 scope 是 local,如要写用户级配置请加 -s user,要写项目级共享 .mcp.json 请加 -s project):
claude mcp add --transport http db-tools http://127.0.0.1:5123/mcpCodex 在 ~/.codex/config.toml(或项目级 .codex/config.toml)中用 TOML 配置,每个 server 一个 [mcp_servers.<name>] 表。Codex 通过是否存在 url 字段区分 stdio 与 streamable HTTP(无显式 type 字段),HTTP 模式只需写 url:
[mcp_servers.db-tools]
url = "http://127.0.0.1:5123/mcp"Codex 默认工具执行超时
tool_timeout_sec = 60秒。如果数据库查询可能较慢,可在[mcp_servers.db-tools]下追加tool_timeout_sec = 120调大。
重启客户端后,在对话中让 Agent:
- 先调用
db_list(不传参数)查看可用项目; - 再用
db_list(project="xxx")查看该项目环境; - 最后调用
db_query执行只读查询。
默认即单一 Web 进程,同端口同时提供 Admin UI(/admin)与 MCP Streamable HTTP(/mcp):
| 参数 | 说明 |
|---|---|
| 无参数 | 默认。启动 Web 服务,同端口出 /admin + /mcp |
--admin-port |
覆盖默认端口 5123(取值 1-65535) |
旧的 --admin-only / --admin 参数已移除。Admin UI 默认端口 5123(--admin-port 可改),只监听 127.0.0.1。首次访问 /admin 自动设置仅限该路径的 HttpOnly、SameSite=Strict 本机会话 cookie,secret 只存于进程内存。
服务须常驻(NSSM 服务或登录计划任务,见 发布与部署);不常驻则 MCP 客户端无法连接。
安全提示(本机信任模型): HTTP 合一后
/admin与/mcp同进程同端口,均仅监听127.0.0.1,且/mcp与/admin/api/*均不鉴权——/admin的会话 cookie 仅限浏览器/admin路径,不保护 API 调用。任何能访问127.0.0.1:<port>的本机进程或 Agent 都可调用/admin/api/*修改配置,或经/mcp查询数据库。远程访问、TLS、端点鉴权留作后续独立设计(本次不做);多用户主机或不受信任环境暂不适用。
# 开发时
dotnet run --project src/McpDbTools.Server
ConfigStore__ConfigPath=D:/GitHub/mcp-db-tools/src/McpDbTools.Server/config.json \
dotnet run --project src/McpDbTools.Server -- --admin-port 5123浏览器打开启动日志中的地址(如 http://127.0.0.1:5123/admin)即可维护配置。功能分五个页面:
- 项目配置(
#/projects):增删项目和环境,key 创建后不可修改;维护连接字符串、数据库类型、maxRows、commandTimeout、环境级并发/连接池参数与阻止关键字;内置测试连接(不落盘)。 - 全局关键字(
#/keywords):维护全局默认与按类型追加的阻止关键字。 - 审计日志(
#/audit-log):按项目/环境/类型/状态/时间/SQL 关键词筛选,分页查看,长文本点击弹窗复制。纯只读。 - 备份管理(
#/backups):列出、下载、恢复(恢复前自动快照可撤销)、删除配置备份。 - 全局设置(
#/settings):审计日志与备份文件的自动清理开关和保留天数;手动清理两者(按 10/20/30/50 天)。
写入安全:保存前自动备份当前 config.json,经临时文件校验后原子替换,避免 MCP 进程读到半写入文件。生产环境显示风险提示。保存会重写为标准 JSON,原注释与手工排版不保留。
列出数据库项目与环境,按需加载避免环境多时返回数据量过大。建议查询前先调用。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
project |
string | 否 | 项目名。不传返回项目索引(轻量);传则返回该项目环境详情 |
environment |
string | 否 | 环境名,配合 project 缩小到单环境。单独传无意义 |
空白字符串等同未传。行为矩阵:
| project | environment | 返回 |
|---|---|---|
| 不传 | — | {success:true, projects:[{name, defaultEnvironment}]}(项目索引,不含环境) |
| 传(存在) | 不传 | 该项目全环境详情 |
| 传(存在) | 传(存在) | 该单环境详情 |
| 传(存在) | 传(不存在) | {success:false, errorCode:"ENVIRONMENT_NOT_FOUND", environments:[该项目全环境]} |
| 传(不存在) | 任意 | {success:false, errorCode:"PROJECT_NOT_FOUND", availableProjects:[项目名数组]} |
环境详情含 name、type、isProduction、maxRows 及并发/连接池/超时配置,便于 Agent 按库类型组织 SQL、在生产环境谨慎操作。传错时响应直接回显可用项目或环境列表,可据此重试。
不传 project(首次发现项目):
{
"success": true,
"projects": [
{ "name": "my-project", "defaultEnvironment": "test" }
]
}在指定项目和环境上执行只读 SQL 查询。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
project |
string | 是 | 项目名,对应 config.json 中 databases 的键 |
sql |
string | 是 | SQL 语句,仅允许只读操作 |
environment |
string | 否 | 环境名;未传时使用项目的 defaultEnvironment |
limit |
int | 否 | 临时限制返回行数,必须为正整数;最终取 min(limit, maxRows),不能突破配置上限 |
返回 JSON 示例:
{
"success": true,
"project": "my-project",
"environment": "test",
"databaseType": "SqlServer",
"rowCount": 42,
"maxRows": 1000,
"truncated": false,
"executionTimeMs": 125,
"columns": ["Id", "Name", "CreatedAt"],
"rows": [
[1, "张三", "2024-01-15"],
[2, "李四", "2024-03-22"]
]
}错误以结构化 JSON 返回,不抛到协议层。常见错误码:
| 错误码 | 说明 |
|---|---|
PROJECT_NOT_FOUND |
项目不存在 |
ENVIRONMENT_REQUIRED |
未指定环境且无默认环境 |
ENVIRONMENT_NOT_FOUND |
环境不存在 |
SQL_BLOCKED |
SQL 被安全守卫阻止 |
SQL_PARSE_ERROR |
SQL 为空或无法识别首关键字 |
RATE_LIMITED |
并发达上限,排队等待超时 |
QUERY_CONNECT_TIMEOUT |
建立连接超时(连接池耗尽或网络不可达) |
QUERY_TIMEOUT |
查询执行超时(超过 commandTimeout) |
QUERY_ERROR |
数据库执行错误 |
完整配置见 src/McpDbTools.Server/config.json。核心结构:
{
"defaultDisabledKeywords": ["DROP", "DELETE", "UPDATE"],
"defaultDisabledKeywordsByType": {
"sqlserver": ["BULK INSERT", "xp_cmdshell"],
"mysql": ["LOAD DATA", "FLUSH"],
"oracle": ["FLASHBACK", "PURGE"]
},
// 并发与连接池全局默认(缺省时用内置默认 10/5/100/60)
"defaultMaxConcurrency": 10,
"defaultMaxConcurrencyWaitSeconds": 5,
"defaultMaxPoolSize": 100,
"defaultConnectTimeoutSeconds": 60,
// 运维清理(缺省时全部关闭,由 Admin UI「全局设置」维护)
"maintenance": {
"auditLogAutoCleanup": false,
"auditLogRetentionDays": 30,
"backupAutoCleanup": false,
"backupRetentionDays": 30
},
"databases": {
"<项目>": {
"displayName": "项目显示名",
"defaultEnvironment": "test",
"environments": {
"<环境>": {
"displayName": "环境显示名",
"isProduction": false,
"type": "sqlserver|mysql|oracle",
"connectionString": "...",
"maxRows": 1000,
"commandTimeout": 600,
"maxConcurrency": 10, // 可选,覆盖全局(<=0 回退全局)
"maxPoolSize": 100,
"connectTimeoutSeconds": 60,
"disabledKeywords": []
}
}
}
}
}残留的旧
audit节点会被静默忽略;maintenance缺省时全部关闭,向后兼容。
| 层级 | 字段 | 作用域 |
|---|---|---|
| 全局 | defaultDisabledKeywords |
所有数据库、所有项目、所有环境 |
| 类型 | defaultDisabledKeywordsByType |
按数据库类型追加 |
| 环境 | databases.<项目>.environments.<环境>.disabledKeywords |
单个环境追加 |
最终阻止列表 = 全局 ∪ 按类型 ∪ 环境。全部转大写去重;下层只能追加,不能缩减上层。
为避免高并发下 db_query 因连接池耗尽或线程池饥饿而卡死:
| 配置项 | 全局默认 key | 环境级覆盖 | 内置默认 |
|---|---|---|---|
| 每环境最大并发查询数 | defaultMaxConcurrency |
maxConcurrency |
10 |
| 超载排队最长等待秒数 | defaultMaxConcurrencyWaitSeconds |
—(仅全局) | 5 |
| 连接池上限 | defaultMaxPoolSize |
maxPoolSize |
100 |
| 建立连接超时秒数 | defaultConnectTimeoutSeconds |
connectTimeoutSeconds |
60 |
- 每个
(project, environment)独立并发闸门,慢库不拖累其它环境;超限排队,等待超时返回RATE_LIMITED。 - 连接池上限与建连超时按数据库类型拼接到连接串(如 SQL Server 的
Max Pool Size/Connect Timeout),并作为建连兜底超时。 - 环境级
<=0或留空回退全局;全局未配置用内置默认。旧 config.json 不写这些字段时行为不变,且支持热重载。
审计日志全局开启,记录到 %ProgramData%\McpDbTools\audit.db(SQLite,WAL 模式,与 config.json 同目录),MCP 写入与 Admin 读取可同进程并发。
- 每次成功解析到项目与环境的
db_query都会记录一条(含被阻止与执行失败);早期参数解析错误(项目/环境不存在)不入库。 - 写入经 Channel 入队、单消费者串行落盘,避免高并发下线程池饥饿与写锁竞争。
- 清理策略由「全局设置」的
maintenance节点控制:默认不清理,可开启按保留天数的自动清理(后台服务每小时检查,随 Web 进程常驻运行),也可手动按 10/20/30/50 天清理。 - 「全局设置」的「记录查询结果」开关(
maintenance.auditRecordResults,默认关闭)开启后,成功的db_query会把完整查询结果(columns + rows)以 JSON 存入audit_log_result子表(1:1 关联主表)。结果集不限制大小,关闭开关或失败查询不入子表。审计日志列表不展示结果,点击 SQL 单元格弹窗时按需懒加载渲染为表格(含行号、NULL 灰字、滚动)。开关关闭前的老记录无结果数据,弹窗提示「该记录无查询结果」。开启后请关注audit.db体积,配合自动/手动清理使用。
白名单(按数据库类型):
- 通用:
SELECT、WITH(CTE)、EXEC/EXECUTE - MySQL 额外:
CALL、SHOW、DESCRIBE/DESC、EXPLAIN - Oracle 额外:
CALL、DESCRIBE/DESC - SQL Server 额外:
sp_help、sp_tables、sp_columns等系统存储过程
黑名单:DROP、DELETE、UPDATE、INSERT、ALTER、CREATE、TRUNCATE、MERGE、GRANT、REVOKE 等,外加按类型和环境追加的关键字。
校验:去注释 → 规范化空白 → 首关键字白名单 → 全文黑名单扫描,可拦截 SELECT 1; DROP TABLE x 这类多语句注入。
程序与用户数据物理分离,升级时安装目录可全量替换、用户数据不丢失:
D:\Tools\McpDbTools\ # 安装目录(程序文件,升级时可全量替换)
├── McpDbTools.Server.exe
├── wwwroot\admin\ # SPA 静态资源
└── ...
%ProgramData%\McpDbTools\ # 用户数据目录(跨用户共享,与程序目录分离)
├── config.json # 配置
├── audit.db # 审计日志(首次写入自动创建)
└── backups\ # 配置备份(保存自动生成)
数据目录选用 %ProgramData%\McpDbTools(Windows 跨用户共享数据目录),保证 LocalSystem 服务(NSSM / 计划任务承载的统一 Web 进程)与当前用户进程(开发时手动 dotnet run)读写同一份数据。部署脚本会自动给 Users 组授予 Modify 权限。
数据目录由
DataDirectoryResolver集中解析,优先级:调用方传入 > 环境变量ConfigStore__ConfigPath>%ProgramData%\McpDbTools> exe 同目录。多数情况下无需关心,默认值即可。
从 GitHub Release 下载对应架构的 zip(McpDbTools-vX.Y.Z-win-x64.zip 或 McpDbTools-vX.Y.Z-win-arm64.zip),解压后里面已含 McpDbTools.Server.exe、wwwroot\ 与 install.ps1:
.\install.ps1install.ps1 完成"确认 → 交互询问 → 提权 → 停服 → 迁移数据 → 替换文件 → 安装自启动 → 注册 MCP"全流程,不编译代码,无需 .NET SDK。脚本行为与下方「从源码构建并部署」一致,仅省去构建步骤;可用参数也相同(见参数表)。
发布包仅提供 Windows x64 / arm64。macOS / Linux 请走下方「手动发布」自行构建。
仓库根目录的 [build and install.ps1](build and install.ps1) 完成"确认 → dotnet publish → 委托 install.ps1 完成安装"。编译产物输出到临时目录,确认通过后才构建;安装逻辑全部复用 install.ps1:
.\build and install.ps1脚本行为(build and install.ps1 在确认后多一步 dotnet publish 编译,随后委托 install.ps1 执行下列流程;install.ps1 直接从发布包执行):
- 提权前确认:显示安装目录、数据目录、MCP 名称等部署计划,输入
Y后才继续(源码版先编译再提权) - 交互式询问(提权前完成,答案透传给提权进程):Admin UI 端口(默认
61123);未安装 nssm 时是否用计划任务承载 - 数据迁移:把旧版数据(exe 同目录 或
%USERPROFILE%\.mcpdbtools)搬到%ProgramData%\McpDbTools,幂等 - 全量替换安装目录:用户数据已分离,可无条件清空安装目录后复制新产物
- 自启动安装:有 nssm 则装 Windows 服务(
SERVICE_AUTO_START),否则按选择装计划任务 - 注册 MCP:
claude mcp add把 Server 注册到 Claude Code(默认作用域user)
常用参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
-InstallDir |
E:\Software\FreeInstall\Mcp-db-Tools |
安装目录 |
-McpName |
db-tools |
注册到 Claude Code 的 MCP 名称 |
-McpScope |
user |
MCP 作用域:local / user / project |
-AdminServiceName |
McpDbTools.Admin |
NSSM 服务名 / 计划任务名 |
-PauseOnExit |
关 | 结束时暂停等待回车(便于查看管理员窗口输出) |
示例:
# 自定义安装目录与 MCP 作用域
.\build and install.ps1 -InstallDir D:\Tools\McpDbTools -McpScope local
# 当前已是管理员,跳过 UAC 直接部署
powershell -Verb RunAs -Command ".\build and install.ps1"如不走部署脚本(例如远程机器、便携部署、或非 Windows 平台):
# Windows
dotnet publish src/McpDbTools.Server -c Release
# 指定目标架构(self-contained 单文件,免装运行时)
dotnet publish src/McpDbTools.Server -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish src/McpDbTools.Server -c Release -r win-arm64 --self-contained true -p:PublishSingleFile=true
# 非 Windows(macOS / Linux)—— 官方不发布这些平台的包,需自行构建
dotnet publish src/McpDbTools.Server -c Release -r osx-arm64 --self-contained true -p:PublishSingleFile=true
dotnet publish src/McpDbTools.Server -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true发布产物拷到目标目录后,首次运行会自动在 %ProgramData%\McpDbTools 创建数据目录与空配置。也可用环境变量 ConfigStore__ConfigPath 指定自定义路径。
install.ps1仅适用于 Windows。非 Windows 平台构建产物后需自行配置常驻进程(systemd 单元、launchd 等)与 MCP 客户端连接http://127.0.0.1:<port>/mcp。
HTTP 模式下,MCP 客户端通过 http://127.0.0.1:<port>/mcp 连接服务,服务必须常驻。生产环境推荐用 NSSM 装成 Windows 服务(部署脚本已自动安装),或用登录计划任务承载:
# 前台运行(调试)
McpDbTools.Server.exe --admin-port 5123
# 后台服务(推荐,部署脚本已自动安装)
# 或手工用 nssm:
nssm install McpDbTools.Server "D:\Tools\McpDbTools\McpDbTools.Server.exe" --admin-port 61123
nssm start McpDbTools.Server服务启动后同时暴露 Admin UI(/admin)与 MCP HTTP(/mcp);MCP 客户端只需配置 URL,不感知承载方式。
dotnet build
dotnet test # 全部测试
dotnet test --filter "FullyQualifiedName~SqlGuardTests" # 单个测试类
dotnet run --project src/McpDbTools.Server # 启动 Web 服务(/admin + /mcp)
dotnet run --project src/McpDbTools.Server -- --admin-port 5123 # 指定端口
dotnet publish src/McpDbTools.Server -c Release服务运行时 stdout 不再是协议通道(MCP 改用 HTTP),日志走标准 ASP.NET Core logging 管道。
src/McpDbTools.Server/
├── Admin/ # Admin API、配置读写、测试连接、备份管理、全局设置
├── Audit/ # 审计日志(SQLite + Channel 异步串行写入)
├── Configuration/ # 配置模型、热重载、三层关键字合并、连接串拼接、DataDirectoryResolver 数据目录解析
├── Database/ # 三种数据库 provider + 工厂 + 每环境并发限流器
├── Maintenance/ # 运维清理后台服务(审计日志/备份自动清理)
├── Security/ # SqlGuard SQL 安全守卫
├── Tools/ # db_list / db_query MCP 工具
├── wwwroot/admin/ # 静态 Admin UI(无 npm 构建链 SPA)
└── Program.cs # 运行模式入口
.NET 8、ASP.NET Core Minimal API、原生 HTML/CSS/JS、ModelContextProtocol 1.4.0、SqlClient / MySqlConnector / Oracle.ManagedDataAccess.Core、Microsoft.Data.Sqlite、xUnit。
- 不解析字符串字面量,字符串内的关键字可能被误判(安全工具宁可误拒)
- 不支持存储过程参数化传入,不支持跨环境/多连接 JOIN(同一连接内跨 schema 由数据库决定)
- Admin UI 仅设计为本机访问;远程访问需另行设计认证、授权、TLS 与审计
- 实际数据库连接需在目标环境用真实数据库验证(单测只覆盖纯逻辑层)
{ "databases": { "my-project": { "displayName": "示例项目", "defaultEnvironment": "test", "environments": { "test": { "displayName": "测试环境", "isProduction": false, "type": "sqlserver", "connectionString": "Server=.;Database=MyDb;Trusted_Connection=true;TrustServerCertificate=true;", "maxRows": 1000, "commandTimeout": 30, "disabledKeywords": [] }, "prod": { "displayName": "生产环境", "isProduction": true, "type": "sqlserver", "connectionString": "Server=prod;Database=MyDb;User Id=readonly;Password=***;TrustServerCertificate=true;", "maxRows": 500, "commandTimeout": 30, "disabledKeywords": [] } } } } }