【金仓数据库征文】让金仓数据库开口说话:用MCP Server搭建自然语言问数智能助手
前言:当 DBA 被业务的取数需求问烦了
先说个真事儿。我们组守着一套跑在金仓数据库上的系统,表多,数据一堆一堆的。干这行最磨人的,不是写代码,是业务和产品同学冷不丁甩过来的那句——“帮我拉个数”。
“上个月华东区卖得最好的十个品类是啥?”“某大客户这半年下单趋势咋样?”——单个都不难,难的是它多。上礼拜三一个上午我就接了六七个,等回过神,午饭都凉了。
有天加班我就绷不住了:大模型都这能耐了,凭啥不能让它对着金仓数据库自己干?我动嘴,它动手——看表、写 SQL、跑结果,再念给我听。回家一试,嘿,还真通了,靠的就一东西,叫 MCP。
这篇就原原本本记下来:怎么用 MCP Server 把金仓数据库接给 AI,搭一个能听懂人话的问数助手。部署、生成 SQL、防手滑,一道走完。
目录
先理一理:MCP 是个啥,整条链路怎么转
MCP,全称 Model Context Protocol,中文叫模型上下文协议。名头唬人,说白了就一句话——一套让大模型能跟外部工具"对上话"的标准。
打个不太恰当的比方,它有点像 AI 界的 USB 口。哪个数据源按它的规矩把能力开放出来,支持 MCP 的客户端就能直接插上去用,不用每接一个工具都从头造一遍轮子。我头回听说这协议的时候还犯嘀咕,心想又来造概念;等真用上才发现,是真省事。
搁咱们这场景里,链路其实就一条线:

你这边一句话递过去,大模型先琢磨你到底想问啥。琢磨明白了,转头去喊 MCP Server 手里那堆工具:先用 list_tables 扫一眼库里都有啥表,再用 describe_table 把字段一个个摸清。心里有谱了,自己上手拼 SQL,扔给 kb_query 进金仓数据库里跑。结果回来,它再翻译成人话,递到你跟前。
全程,你就负责问。一行 SQL 都不用碰。但每一步又都摊在明面上——想看,看得到;想拦,拦得住。
这 Server 能干的事不少,常用的我挑出来给你列下:
| 工具 | 作用 | 类型 |
|---|---|---|
kb_list_tables |
列出数据库里的表和视图 | 只读 |
kb_describe_table |
查看表结构:列、类型、约束、注释 | 只读 |
kb_query |
执行只读查询(SELECT/WITH/SHOW) | 只读 |
kb_explain |
看执行计划(EXPLAIN) | 只读 |
kb_table_stats |
看表统计信息:大小、行数 | 只读 |
kb_execute |
执行 DML(INSERT/UPDATE/DELETE) | 读写 |
kb_execute_ddl |
执行 DDL(CREATE/ALTER/DROP) | 读写 |
只读的我全搁前头了,写操作压在最后。为啥这么排?等下面聊安全那节,你就懂了。
实战准备:环境与一份数据
先交个底,我这次的环境是这样:
| 组件 | 版本/配置 |
|---|---|
| 金仓数据库 | KingbaseES V9R1,单机,端口 54321 |
| 数据库账号 | system(演示用,生产建议换业务账号) |
| 示例库 | test |
| MCP 运行环境 | Node.js 18 及以上(node -v 能出版本号就行) |
| AI 客户端 | Claude Code(也适用 Claude Desktop、Cherry Studio 等支持 MCP 的客户端) |
顺嘴说一句,Node 版本高点低点问题不大,18 以上就行,node -v 敲一下有反应就可以。我自己用的是 24,纯属手头正好有。
光有空库,没法演示"问数",得先弄点数据进去。我在 public 模式下建了张销售明细表,随手塞了点东西。KStudio 里点也行,ksql 里敲也行,看你哪个顺手:
-- 建一张销售明细表(放在 public 模式,和 MCP 的默认 schema 对齐)
CREATE TABLE public.sales (
id BIGINT PRIMARY KEY,
product VARCHAR(100) NOT NULL, -- 商品名称
category VARCHAR(50) NOT NULL, -- 品类
region VARCHAR(50) NOT NULL, -- 销售区域
customer VARCHAR(100), -- 下单客户
amount DECIMAL(12,2) NOT NULL, -- 成交金额
sale_time TIMESTAMP NOT NULL -- 成交时间
);
-- 灌一批演示数据:不同商品、品类、区域、月份都覆盖到
INSERT INTO public.sales VALUES
(1,'蓝牙耳机','数码','华东','张伟', 299.00,'2025-07-02 10:15:00'),
(2,'智能手表','数码','华北','李娜', 1299.00,'2025-07-09 09:40:00'),
(3,'纯棉T恤','服装','华东','王芳', 99.00,'2025-07-15 16:20:00'),
(4,'坚果礼盒','食品','华南','刘洋', 168.00,'2025-07-18 11:05:00'),
(5,'蓝牙耳机','数码','华南','陈静', 299.00,'2025-07-22 14:30:00'),
(6,'运动鞋', '服装','华东','赵磊', 459.00,'2025-07-26 09:00:00'),
(7,'抽纸整箱','家居','华北','孙琳', 89.00,'2025-06-03 10:10:00'),
(8,'智能手表','数码','西南','周杰', 1299.00,'2025-06-11 15:45:00'),
(9,'洗衣液', '家居','华东','吴婷', 79.00,'2025-06-20 13:25:00'),
(10,'机械键盘','数码','华北','郑斌', 399.00,'2025-06-28 08:50:00'),
(11,'保湿面霜','美妆','华东','冯雪', 259.00,'2025-06-30 17:00:00'),
(12,'牛奶箱装','食品','西南','许慧', 69.00,'2025-07-30 12:00:00')
ON CONFLICT (id) DO UPDATE SET
product = EXCLUDED.product,
category = EXCLUDED.category,
region = EXCLUDED.region,
customer = EXCLUDED.customer,
amount = EXCLUDED.amount,
sale_time = EXCLUDED.sale_time;

第一步:部署 kingbase-mcp-server
部署这块,简单到有点不像话。
最省事儿的玩法是 npx,一行下去就起,全局都不用装:
npx -y kingbase-mcp-server
你要是打算长期、反复使唤它,那就干脆全局装一个,省得次次现拉:
npm install -g kingbase-mcp-server

它把所有连接参数都塞进了环境变量——这设计我挺欣赏。配置归配置,代码归代码,两不耽误。哪天要换库、换账号,动一个变量就齐活,不用去翻代码:
| 环境变量 | 含义 | 本例取值 |
|---|---|---|
DB_HOST |
数据库主机 | 127.0.0.1 |
DB_PORT |
数据库端口 | 54321 |
DB_USER |
用户名 | system |
DB_PASSWORD |
密码 | 你的密码 |
DB_NAME |
数据库名 | test |
DB_SCHEMA |
默认 schema | public |
ACCESS_MODE |
权限模式(见下表) | readonly |
TRANSPORT |
传输模式:stdio 或 http |
stdio |
权限这块,是我最对胃口的地方。一口气分了四档,而且默认就给你摁在只读上。你品品,这对生产多贴心——等于出厂就帮我把安全带系好了:
| 级别 | 取值 | 允许的操作 |
|---|---|---|
| 只读(默认) | readonly |
SELECT、看表结构/索引/约束/统计/执行计划 |
| 允许增改 | readwrite |
只读 + INSERT / UPDATE |
| 允许删除 | full |
读写 + DELETE |
| 管理员 | admin |
完全权限 + DDL(CREATE/ALTER/DROP/TRUNCATE) |
头一回跑,听我一句劝,老老实实待在 readonly。先让它学会查,写这事儿,咱不急。

第二步:把 MCP Server 挂到 AI 客户端上
Server 立起来了,下一步,把它领到 AI 客户端跟前去。
拿 Claude Code 打比方,你在项目根目录扔一个 .mcp.json 就行(想哪儿都能用,就丢用户级配置里):
{
"mcpServers": {
"kingbase": {
"command": "npx",
"args": ["-y", "kingbase-mcp-server"],
"env": {
"DB_HOST": "127.0.0.1",
"DB_PORT": "54321",
"DB_USER": "system",
"DB_PASSWORD": "你的密码",
"DB_NAME": "test",
"DB_SCHEMA": "public",
"ACCESS_MODE": "readonly"
}
}
}
}

用 Claude Desktop 的话,内容一模一样,就是文件搁的地方不一样:Windows 下是 %APPDATA%\Claude\claude_desktop_config.json。Cherry Studio 那些客户端更省心,基本都带个图形化的"MCP 服务"入口,照着填填就完事。

配完,记得重启一下客户端,让它重新读配置。想知道到底连上没?最笨也最管用——直接让它列下表:
帮我看看当前数据库里都有哪些表?
一般它会去调 kb_list_tables,把 sales 给你列出来,顺带嘟囔一句"读到了几张表"。这一下有反应,整条线就算通了。

第三步:自然语言生成 SQL,实战问数
通了,那咱就开整。
先来个稍微复杂点的——“7 月份卖得最好的十个商品,是哪些?”
AI 才不会上来就闷头写 SQL,它精着呢。先 kb_list_tables 探一眼,确认有 sales 这张表;再 kb_describe_table 把字段摸一遍,搞清楚钱在 amount、时间在 sale_time、商品名是 product。这些都门儿清了,它才动笔,把 SQL 交给 kb_query 去跑:
SELECT product,
SUM(amount) AS total
FROM public.sales
WHERE sale_time >= TIMESTAMP '2025-07-01'
AND sale_time < TIMESTAMP '2025-08-01'
GROUP BY product
ORDER BY total DESC
LIMIT 10;
结果到手,它换回大白话给你:“7 月卖得最猛的是智能手表,1299;蓝牙耳机两单凑一块儿 598;往后是运动鞋,459……”——放心,这数字是它真去库里算出来的,不是张嘴就胡编。
好奇底层长啥样?这么跟你说吧,刚才那一下,在协议层其实就是 AI 给 Server 递了这么一条 tools/call(stdio 模式下,一行就是一条 JSON-RPC):
{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"kb_query",
"arguments":{"sql":"SELECT product, SUM(amount) AS total FROM public.sales WHERE sale_time >= TIMESTAMP '2025-07-01' AND sale_time < TIMESTAMP '2025-08-01' GROUP BY product ORDER BY total DESC LIMIT 10"}}}
Server 跑完,结果包成文本再递回来:
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"| product | total |\n|---|---|\n| 智能手表 | 1299.00 |\n| 蓝牙耳机 | 598.00 |\n| 运动鞋 | 459.00 |"}]}}
你瞅瞅——大白话进去,中间走的是规规矩矩的结构化调用,结果再变回人话出来。MCP 忙活的,就是这么一层"翻译"。
套路摸清了,后面就不啰嗦了,挑俩一看就懂的:
想问 “华东 7 月一共卖了多少钱?”,它给你拼出这么一句——
SELECT SUM(amount) AS total
FROM public.sales
WHERE region = '华东'
AND sale_time >= TIMESTAMP '2025-07-01'
AND sale_time < TIMESTAMP '2025-08-01';
然后张口就答:华东 7 月拢共 857 块,3 单。
再问 “哪个品类最吃香?”——
SELECT category,
SUM(amount) AS total
FROM public.sales
GROUP BY category
ORDER BY total DESC
LIMIT 1;
答案利索:数码,3595,甩第二名一大截。
你看,问法千变万化,底下干活的就那几个工具,来回组合罢了。
还有种用法我特别想安利——让它给你看执行计划。比如"sales 表查华东,执行计划给我瞅瞅"。这种它不翻数据,转头调 kb_explain,把执行计划拽出来:
EXPLAIN SELECT * FROM public.sales WHERE region = '华东';
写代码、调优的时候,这招是真香。客户端都懒得开,一句话,走没走索引、扫了几行,门儿清。

对了,有件事不提我睡不着。AI 能写出对的 SQL,前提是它先把你的表"看明白"了。所以——字段名起好点,注释写全点。你要是犯懒,把 amount 弄成 a1、sale_time 弄成 t,模型再灵光也得给你猜岔劈。说白了,元数据干不干净,直接定这助手靠不靠谱。这一条,我踩过坑,待会儿细说。
第四步:写操作与安全——给 AI 套上"紧箍咒"
前面全是查,怎么折腾都行,大不了查错重来,又不会掉块肉。
可一旦让它写(INSERT/UPDATE/DELETE),甚至动结构(DDL),那就不一样了。它哪天要是抽风,给你来一句"把 sales 金额全清零"——真执行了,你怕是得连夜写复盘,还得挨顿骂。
好在,这 Server 在安全上留了两手,正好拆开看看。
头一手,是 ACCESS_MODE 这把锁。 默认就锁在 readonly,写的口子,AI 根本够不着。哪天真要写了,再给它开到 readwrite 或者 admin,用完——啪,关上。
另一手,是写之前的"再问一嘴"。 就算你把权限放开了,真到执行 DML/DDL 那一下,Server 还会借 MCP 的 Elicitation 机制,在协议层硬卡住,非等你点头不可。客户端弹个框,SQL 摆里头,你瞄一眼,点"确认",它才真往库里下发。AI 想绕?没门儿。
⚠️ 顺带泼盆冷水:它还留了个
SKIP_CONFIRM=true,能把这层确认整个跳过去。生产环境,打死别碰。 开了它,等于把写库的钥匙一股脑塞 AI 兜里——真出事,谁顶?
还有一条,我觉得比上面那俩都重要,单独拎出来讲。
给 AI 连库的账号,千万、千万别图省事用 system 这种超级用户。 我知道,图方便嘛,system 一把梭最省心。但这玩意儿就跟把家门钥匙挂门外一样——方便是真方便,出事也是真出事。
花两分钟,建个权限受限的业务账号,只给它要查的那几张表的 SELECT,"最小权限"四个字,落实到底。这么一来,就算 AI 哪天真魔怔了,账号没权,它也翻不出什么花:
-- 建一个只读业务账号,只放 sales 表的查询权限
CREATE USER ai_reader WITH PASSWORD '强密码';
GRANT USAGE ON SCHEMA public TO ai_reader;
GRANT SELECT ON public.sales TO ai_reader;
完事把 MCP 配置里的 DB_USER、DB_PASSWORD 换成 ai_reader,ACCESS_MODE 死死钉在 readonly。到这份上,我才敢拍胸脯说一句:能上生产了。

踩坑小结
一路趟下来,有几个跟头栽得印象深,得念叨念叨。
密码里带特殊字符,命令行直接传——炸。 这是我最先栽的跟头。P@ss(w0rd)! 这种密码,往 shell 环境变量里一塞,特殊字符给转义没了,库死活连不上,报错还贼绕,盯了半天没看出来。后来才学乖:用 .env,里头怎么写就怎么传,世界清净。
DB_SCHEMA 填错,AI 一个表都给你列不出来。 这坑,我赌新手基本人手一份。Server 默认盯的是 public,可金仓在 Oracle 兼容模式下,对象常常建在用户自个儿的模式里——更绝的是,schema 跟表的属主还可能不是一拨人——元数据列出来对不上号,AI 调 kb_list_tables,给你返回个空。你以为是它废了?其实是你 schema 填岔了。解法二选一:要么建表就显式落到 public,要么把 DB_SCHEMA 改成对象真正待着的那个模式。
还有种,老怀疑 AI 坏了,其实是权限压根没给。 查的时候好好的,一写就报错。十回里八回,是 ACCESS_MODE 还停在 readonly。记好啊,这是特性、不是 bug,排查前先瞄一眼权限模式,能少走一半弯路。
最后这个最阴——连是连上了,可查得又慢又岔。 锅八成得元数据背。字段名瞎起、注释没有、外键关系缺失,AI 全指着表结构去"蒙"语义,你喂的料越足,它写的 SQL 才越靠谱。给关键表补上中文注释,立竿见影,信我。
落地效果
在组里铺开用了一阵,变化是那种肉眼可见的:
| 指标 | 接入前 | 接入后 |
|---|---|---|
| 取数需求响应 | 排队等开发手写 SQL,小时级 | 业务自助提问,分钟级 |
| DBA 日常被打断次数 | 高(大量临时取数) | 明显下降,聚焦复杂运维 |
| 取数准确率 | 依赖手写 SQL 正确性 | AI 生成 + 只读账号兜底,可控 |
| 安全风险 | 共享高权限账号 | 最小权限账号 + 写操作二次确认 |
说句掏心窝的——最爽的,就是那些"帮我看个数"的零碎活儿,总算从我这儿挪走了。人家业务自己问、自己看,皆大欢喜;我呢,也能消停会儿,干点正事。
写在最后
折腾这一圈下来,我最大的感受就一句:MCP 这玩意儿,把大模型跟数据库之间那道坎,给抹得又平又便宜。 库换一个、客户端换一个,套路照搬就行。
而金仓数据库本身,在 SQL、兼容模式、权限这些底子上的成熟度,也让这套助手跑得稳稳当当。你就负责提需求,查表、写 SQL、执行、解释,一条龙,齐活。
临了,收几句实在话。
权限这事儿,先只读、后读写,从严起步,没坏处。给 AI 的账号,单独开个业务号,超级用户碰都别碰。表结构和注释,规规矩矩弄好——那可是问数准不准的根。团队一块儿用,就上 HTTP 模式;不过鉴权这道闸,一道都不能漏。
说到底,自然语言问数,不是为了抢 DBA 和开发的饭碗。它就是把大伙儿从那些重复的取数活儿里捞出来:脏活累活让 AI 干,值钱的架构和调优,留给咱们自己。
这,才是它最该待的地方。
更多推荐


所有评论(0)