乐于分享
好东西不私藏

让 AI 直接查数据库:我写了个 MCP 工具服务

让 AI 直接查数据库:我写了个 MCP 工具服务

让 AI 直接查数据库:我写了个 MCP 工具服务

9个数据库工具,STDIO 接入 WorkBuddy,AI 说"帮我查一下"就够了

起因

每次查数据都要:打开数据库客户端 → 选库 → 写 SQL → 执行 → 复制结果 → 粘贴到聊天里。

尤其是那种"帮我看看 users 表最近7天新增了多少"的临时查询,来回切换工具很烦。

于是我想:能不能让 AI 直接查?我只需要说一句话,它帮我去库里查完告诉我。

MCP 是什么

MCP(Model Context Protocol)是 Anthropic 提出的一个协议,让 AI 能调用外部工具。

类比一下:

概念
类比
MCP Server
一个"工具箱",里面装着各种工具
MCP Client
AI 助手,需要用工具时从工具箱里拿
Tool
具体的一个工具(比如"查表结构")
STDIO 传输
AI 和工具箱之间的"管道",标准输入输出

简单说:你写一个 MCP Server,把数据库操作封装成"工具",AI 就能直接调用。不用写 API,不用部署服务,本地跑就行。

我的9个工具

连接的是 monitor_db(PostgreSQL,14张表),封装了日常数据库操作:

#
工具名
干什么
1
list_schemas
列出所有 Schema
2
list_tables
列出指定 Schema 的所有表
3
describe_table
查看表结构(列名、类型、注释)
4
list_indexes
查看表的所有索引
5
execute_query
执行 SELECT 查询(只读)
6
execute_update
执行 INSERT/UPDATE/DELETE
7
export_data
导出查询结果为 CSV/JSON
8
pool_status
查看连接池状态
9
slow_queries
分析慢查询记录

怎么实现的

技术栈

组件
选型
语言
Java
MCP SDK
官方 Java SDK(io.modelcontextprotocol.sdk)
数据库连接
HikariCP 连接池
目标数据库
PostgreSQL(14张表)
传输方式
STDIO(标准输入输出)

核心代码结构

db-mcp-server/ ├── src/main/java/ │   ├── DbMcpServer.java          // 入口,启动STDIO Server│   ├── DatabaseService.java      // 数据库操作核心逻辑│   └── tools/│       ├── ListSchemasTool.java │       ├── ListTablesTool.java │       ├── DescribeTableTool.java │       ├── ExecuteQueryTool.java │       └── ...                             // 共9个├── src/main/resources/ │   └── application.yml       // 数据库连接配置└── pom.xml

工具注册示例

// 注册一个"查看表结构"的工具server.addTool("describe_table",    "查看指定表的结构,包含列名、数据类型、是否可空、默认值、注释、主键标识",     Map.of(        "schema""Schema名称",        "tableName""表名称"     ),     (args) -> {         String schema = args.get("schema").toString();         String table = args.get("tableName").toString();        return databaseService.describeTable(schema, table);     } );

每个工具就是:名字 + 描述 + 参数 + 执行逻辑。AI 根据描述自己判断什么时候该用哪个工具,不需要你硬编码调用关系。

接入 WorkBuddy

写好 MCP Server 后,在 WorkBuddy 的 MCP 配置里加上:

// ~/.workbuddy/mcp.json{  "mcpServers": {    "db-mcp": {      "command""java",      "args": ["-jar""/path/to/db-mcp-server.jar"],      "env": {        "DB_URL""jdbc:postgresql://localhost:5432/monitor_db",        "DB_USER""readonly",        "DB_PASSWORD""***"       }     }   } }

配完之后,AI 就多了9个数据库工具。直接对话:

👤 我:

帮我看看 monitor_db 里有哪些表

🤖 AI:

调用 list_tables 工具查询...

monitor_db 共有 14 张表:sys_user、sys_role、sys_menu、gateway_route、gateway_log...

👤 我:

gateway_log 表最近7天有多少条记录

🤖 AI:

调用 describe_table + execute_query...

gateway_log 最近7天新增 12,847 条记录,日均 1,835 条。

踩的几个坑

坑1:STDIO 协议初始化

MCP 的 STDIO 通信不是随便读写 stdin/stdout 就行的。必须按协议握手:

  • 客户端发 initialize 请求
  • 服务端回 initialize 响应 + capabilities
  • 客户端发 initialized 通知
  • 之后才是正常的工具调用

用官方 Java SDK 可以省掉这些细节,但了解原理有助于排查问题。

坑2:日志不能走 stdout

STDIO 模式下,stdout 是通信通道,只有 MCP 协议消息能走 stdout。

如果你的应用用 System.out.println 或 Logback 输出到 stdout,AI 客户端解析协议时直接报错。

解决:所有日志输出重定向到 stderr,或者配置 Logback 只输出到文件。

# logback-spring.xml<appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>logs/db-mcp-server.log</file></appender><root level="INFO"><!-- 不要写 <appender-ref ref="STDOUT"/> --><appender-ref ref="FILE"/></root>

坑3:SQL 注入防护

execute_query 接受用户输入的 SQL,直接拼到 Statement 里等于裸奔。

防护措施:

  • execute_query 只允许 SELECT,正则检测开头关键字
  • 强制加 LIMIT,防止一次查出百万行
  • execute_update 需要二次确认,工具描述里标注"⚠️ 危险操作"
  • 数据库用户用只读账号连接,从源头杜绝写操作
// 只允许SELECTString upperSql = sql.trim().toUpperCase();if (!upperSql.startsWith("SELECT")) {    throw new IllegalArgumentException("只允许SELECT查询"); }// 强制LIMITif (!upperSql.contains("LIMIT")) {     sql = sql + " LIMIT 1000"; }

坑4:连接池泄露

AI 一次对话可能调用多个工具,如果每次都新建连接,连接很快就用完了。

解决:HikariCP 连接池,最大连接数设小一点(10就够了),配合 pool_status 工具随时监控。

实际效果

用了两个月,几个真实场景:

场景
以前
现在
查表结构
打开客户端→找表→右键→查看结构
一句话:"describe gateway_route"
慢查询分析
连数据库→查pg_stat_statements→手动排序
一句话:"帮我分析慢查询"
数据导出
写SQL→复制结果→粘贴到Excel
"导出最近7天的gateway_log"

还能做什么

MCP 不只是数据库,任何"AI 不方便直接操作但你能写代码包一层"的场景都适合:

  • Redis MCP
    ——让 AI 直接查缓存、看队列长度
  • 文件系统 MCP
    ——让 AI 读写特定目录的文件
  • Git MCP
    ——让 AI 帮你看 diff、查 log
  • K8s MCP
    ——让 AI 查 Pod 状态、看日志

MCP 的本质就是:给 AI 一双手。它本来只能说话,有了 MCP 工具它就能动手干活了。

总结

  • MCP 不复杂——一个 Server + 几个 Tool,Java 写完打包成 jar
  • STDIO 模式最省事——不用部署服务,本地跑就行
  • 安全要重视——只读账号、SQL 过滤、强制 LIMIT
  • 日志别走 stdout——这是 STDIO 模式最大的坑
  • 连接池控制好——10 个连接够用,多了浪费

最难的不是写代码,是想清楚哪些操作值得封装成工具、工具的粒度怎么定。太粗不好用,太细 AI 不知道调哪个。我的经验:一个工具干一件事,描述写清楚,AI 自己会选。