【金仓数据库征文】给金仓装上“嘴替“:用 MCP Server 让 AI Agent 说人话查数据库
我给国产数据库接上了AI然后亲手攻击了它五次事情是这样的。做数据库这行的朋友大概都接过这种活。业务方隔三差五在群里丢来一句上周谁买得最多就这么一句话DBA就得放下手里的活给他写一段SQL。我一直觉得这事特别拧巴。这类临时取数占用的是团队里最贵的人力产出的却是最标准化的东西。问题用中文描述答案就躺在数据库里中间缺的其实就是一个翻译。这个翻译的活以前只能人来干。直到2025年下半年一个叫MCP的协议把这件事的解法给定了型。MCPModel Context ProtocolAnthropic提出来的现在OpenAI、Google这些主流玩家全都跟进了。你可以把它理解成AI应用和外部工具之间的USB-C接口。你把数据库的能力包装成一个MCP Server任何兼容MCP的AI客户端Cline也好各家自研的Agent也好插上来就能用。大模型自己决定该查哪张表、该写什么SQL查完再用大白话把结果讲给你听。道理听着都顺。但你如果关注这个领域的话会发现网上聊MCP概念的文章一大堆真正把它落到一个国产数据库上、从头到尾跑通给你看的不多。所以我干脆自己来。手边正好有台鲲鹏服务器上面跑着KingbaseES我就亲手给它写了一个MCP Server把中文问数这条链路完完整整跑了一遍。先把结论放这链路通了而且通得很顺。但我跟你说这篇文章真正想聊的不是怎么跑通跑通是最容易的部分。真正花心思的地方是安全。这个先按下不表后面细说。先说结构。整条链路只有三个角色AI客户端MCP Server金仓数据库。中间那个MCP Server是我写的满打满算100行Python。怎么说呢它就是个翻译官把大模型的意图翻译成数据库听得懂的话。它向AI暴露四个工具。list_tables列出库里有哪些业务表、各有多少行让Agent先看清战场再动手。describe_table看某张表的结构顺带给3行示例数据Agent知道了字段名和类型SQL才写得对。run_query执行一条只读的SELECT这是核心能力也是安全防线所在。最后一个db_info返回数据库版本和连接身份用来验明后端的真身。驱动用的是金仓官方推荐的PG生态驱动psycopg2连54321端口。Server本身用Anthropic官方mcp SDK里的FastMCP一个装饰器就能把普通Python函数变成MCP工具大概长这样。frommcp.server.fastmcpimportFastMCP mcpFastMCP(kingbase)mcp.tool()defrun_query(sql:str)-str:执行一条只读 SELECT 查询并返回结果最多 50 行。...# 三道安全闸 psycopg2 执行后面细说写的过程里有个细节我觉得特别有意思。工具函数的docstring就是上面那行「执行一条只读SELECT查询」它不是注释是给大模型看的说明书。Agent就是靠读这段话来判断什么时候该调哪个工具。也就是说你写的注释第一次有了一个AI读者。这是写MCP Server和写普通后端接口最不一样的地方。接口文档以前是写给人看的人看不懂大不了来问你。AI看不懂它就直接用错。好Server写完了。但光我自己说它是MCP Server不算数得拿协议说话。我用官方mcp SDK写了一个真正的MCP协议客户端去连它走完整的initialize、tools/list、tools/call握手流程。截图里的每一行都是真实的协议往返。握手成功协议版本2025-11-25Server名kingbase。这说明它是标准MCP不是我自己发明的野接口。客户端自动拉到了4个工具和它们的说明这就是Agent「知道自己能干什么」的来源。db_info吐出来一行东西KingbaseES V009R003C018 | ai_ro | test。后端确实是金仓而且注意连接身份是一个叫ai_ro的只读账号。这个ai_ro你先记住它待会它是主角。然后run_query跑了一条GROUP BY聚合真实返回了消费额排名。最后我故意喂了它一条DELETE服务端直接回了一句已拒绝只允许SELECT/WITH查询。到这一步事情就有意思了。任何MCP兼容的AI应用都能用完全相同的协议接进这台金仓Server。我用SDK客户端能连上Cline自然也能连上。接下来就是最好玩的部分了。库里是一套电商味的测试数据一张member会员表一张orders订单表。我给Agent出了三个纯中文的问题让它自己翻译成SQL、经MCP查金仓、再用中文把答案讲出来。第一问谁是消费冠军一共花了多少钱Agent生成了一条单表聚合select member_name, sum(amount) s from orders group by member_name order by s desc limit 1然后回答消费冠军是赵敏累计消费10556.00元。规规矩矩热身题。第二问我加了点难度7月1号以来销售额最高的三样商品是什么这次它得自己想明白时间过滤怎么写。回答7月以来销售额Top3游戏显卡5999元NAS存储4599元4K显示器3299元。第三问才是真正的考验积分最高的会员是谁他买过东西吗这题阴就阴在积分在member表订单在orders表它必须自己意识到这得做两表JOIN。结果Agent老老实实写出了member m left join orders o on o.member_name m.name这样的连接然后回答积分最高的是赵敏25999分他有4笔订单。三个问题层层递进单表聚合、时间过滤、两表JOIN它都正确地组织了SQL。而且我想强调一句答案里的每一个数字10556.00也好25999也好4笔也好全部来自金仓的真实返回没有一处硬编码。看到这你可能觉得这不就成了吗接上生产库开用啊。先别急。我知道很多DBA朋友读到这里心里其实已经开始发毛了。让一个大模型直连我管的库它今天能写SELECT明天会不会给我来一句DROP我特别理解这种警惕。坦率的讲如果有人要往我负责的生产库上接一个AI我的第一反应也是拒绝。而且很多人以为这套东西的难点是让AI把SQL写对。真不是写对SQL是现在这批大模型的强项难的是让它写不了不该写的东西。一个能连生产库、还听大模型指挥的服务如果只做到「能查」那不是功能。是事故。所以这套东西里我真正花心思的部分不是问数演示是三道互相独立的安全闸门任何一道都能单独兜底。第一道闸数据库账号本身只读。还记得让你记住的那个ai_ro吗MCP Server连库用的就是它这个账号只被GRANT SELECT。截图第一行是我做的一个实验绕过所有代码直接拿ai_ro连上数据库执行DELETE金仓在权限层就把它顶了回来ERROR: permission denied for table orders。这是最硬的一道。它的意义在于就算我代码里的防线全被绕过数据库自己也不会让AI写入一个字节。第二道闸会话级只读。代码里conn.set_session(readonlyTrue)再加一句SET statement_timeout5s防止AI写出慢查询把库拖垮。第三道闸应用层SQL白名单。run_query只放行单条SELECT或WITH开头的语句并且用正则扫描写操作关键字。这道闸严不严得打过才知道。我让Agent对着它发起了五种攻击。先来最直白的delete from orders。拒绝只允许SELECT/WITH查询。升级一点drop table member。拒绝理由同上。换个思路多语句注入select 1; drop table member前半句人畜无害后半句图穷匕见。拒绝只允许单条语句。再阴一点大小写绕过UpDaTe这种写法赌你的正则只认小写。想多了照样拒绝。最后一招是我自己都觉得有点损的子查询藏写select (delete ... returning 1)把DELETE藏进一个SELECT的壳里。还是被拒检测到写操作关键字。五连败。而作为对照组一条正常的select count(*)顺利放行返回20。该拦的全拦住该放的一条没误伤。写这三道闸的时候我脑子里总飘着一个两千多年前的工程都江堰。李冰治水没有修一道无坚不摧的大坝去硬堵而是修了鱼嘴、飞沙堰、宝瓶口三道结构各管一段互相独立哪一道出了状况剩下的照样能把水安顿好。真正让人放心的系统从来不是靠一堵完美的墙是靠几道互不依赖的防线一层一层把风险卸掉。数据库安全这块我觉得是一个道理。正则可能有疏漏会话设置可能被重置但只要ai_ro这个账号在权限层是只读的天塌下来数据还在。安全之外还有一件事我觉得从第一版就得立住。留痕。生产环境绕不开一个问题出了事能不能查清是谁、在什么时候、让AI对数据库做了什么。所以我给每个工具都加了审计日志。一次问数会话加越权尝试跑完calls.log里完整记下了每一次调用三条正常的业务查询SQL以及两条被拒的drop table和delete。注意被拦截的攻击也照样留痕。这正是安全审计最想要的东西不仅记成功更要记下「有人试图越权」这件事本身。说实话这个日志模块就是个40行的毛坯生产上肯定还要接统一日志平台、加调用方身份、做异常告警。但「每一次AI触达数据库都可回溯」这个原则从第一版就得立住后面才有得谈。最后说说怎么用起来。这可能是整套东西里最让我舒服的部分在真实工位上接入它不需要写一行胶水代码。任何MCP客户端配置里加一段就行。{mcpServers:{kingbase:{command:ssh,args:[root服务器,python3,/root/mcp/kingbase_mcp.py]}}}重启客户端kingbase就出现在工具列表里了。之后你对着聊天框问一句这个月各产品卖了多少大模型会自动调list_tables摸清有哪些表调describe_table看清字段再调run_query执行查询最后把结果讲给你听。MCP的价值就在这Server写一次所有AI客户端通用。聊到这这趟折腾算是可以收尾了。100行Python我给KingbaseES装上了一个中文入口。业务方说人话大模型经MCP把它翻译成SQL去查金仓再用人话把答案讲回来。但如果这篇文章只能留下一句话我希望是这句。让AI连上生产数据库从来不是技术上能不能做到的问题而是敢不敢让它做以及出了事能不能兜得住的问题。敢不是胆子大是每一道防线都亲手打过、确认它接得住之后的踏实。金仓在权限层顶回DELETE的那一下就是这套方案敢称「可上生产」的地基。MCP把AI和数据库的连接方式标准化了。而从这一路跑下来的结果看金仓完全站得进这个新生态。回到开头那句「上周谁买得最多」。下次业务方再丢来这么一句话DBA可以不用放下手里的活了。让AI去查让闸门守着底线让日志记下一切。这篇里所有的判断没有一条是从别人文章里抄来的都是在那台鲲鹏服务器上一条命令一条命令敲出来的。亲自去做然后才敢下判断。我觉得这就是笃行的意思。谢谢你看我的文章我们下次再见。/ 作者笃行其道