1. 为什么要在终端里跑数据库 Agent:KES MCP 与 kes-cli 的真实场景
数据库排查这件事,从来不是一条命令能解决的。你平时遇到一个慢查询,流程大概是:先确认能不能连上库,再看有哪些 schema 和表,然后看表结构、查几条数据;如果发现 SQL 慢,还要继续看执行计划、索引、慢 SQL、锁等待;最后如果要复盘,还得把查过的东西整理成一份报告。这些事单独看都不复杂,但分散在数据库客户端、命令行、文档、聊天工具之间,就会变得很烦。
我想要的终端数据库 Agent 效果很明确:启动 kes-cli 后,直接在终端里聊天。输入「看下我都有哪些表」「查一下 orders 前 5 条」「这个 SQL 为什么慢」「帮我看看数据库健康吗」,它能自己判断我要做什么,再通过 KES MCP Server 去拿真实结果,最后把结果整理出来。这里最关键的一点是:它不是让大模型自己猜数据库结构,也不是让大模型随便执行 SQL。模型负责理解问题和整理回答,MCP 负责连接数据库和采集证据,本地代码负责路由、安全限制和终端体验。这样分工清楚,工具用起来也放心。
KES MCP 在这里扮演的是「数据库工具层」。你不用自己重新写一堆数据库采集逻辑,而是通过 MCP 工具拿到 schema、表结构、查询结果、执行计划、健康检查这些证据。kes-cli 则是终端里的 AI 客户端和数据库开发入口:先把模型和 KES MCP Server 配好,再确认数据库能连、工具能加载,然后用自然语言完成结构查询、只读查询、SQL 分析、运维诊断,最后把排查证据导出来。
这套工作流适合谁?适合每天要和数据库打交道的后端、DBA、运维,也适合想把数据库排查从「翻客户端 + 查文档 + 拼 SQL」变成「一句话问清楚」的开发者。它覆盖的不是某一个小功能,而是从「能连接数据库」到「能安全、稳定地完成数据库任务」的完整过程。而模型侧的凭据管理,我用 TaoToken 统一 Key/API 通道来解决,避免每个工具各配一套环境变量。
2. TaoToken 前置准备:统一 Key 与 API 通道管理模型侧凭据
在动手配 kes-cli 之前,先把模型侧的凭据理顺。终端数据库 Agent 需要调用大模型做意图识别和结果整理,如果每个工具都单独配一套 Key,后面换模型、换通道会非常痛苦。我的做法是用 TaoToken 统一管理模型侧凭据,一个 Key 走 API 通道,kes-cli 里只认 Base URL + Key + Model ID 三件套。
TaoToken 的定位是模型 API 的统一接入层,你可以把它理解成「模型侧凭据的集中管理处」。它本身不碰你的数据库,也不做任何数据库代理,只负责把模型请求转发到对应的模型服务。数据库连接始终由 KES MCP Server 在本地通过 stdio 完成,两者职责完全分开。
第一步,打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册并登录。登录后进入控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,在「API Keys」页面创建一个新的 Key。创建时建议按用途命名,比如kes-cli-agent,方便后面区分是哪个工具在用。
第二步,拿到 Key 之后,去 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 确认 Key 状态正常。这里要注意:Key 只在创建时完整显示一次,复制后妥善保存。如果你后面要在多台机器上跑 kes-cli,建议每台机器单独建一个 Key,方便单独吊销。
第三步,确认你要用的模型。TaoToken 支持多种模型,你可以在模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 先试一下目标模型能不能正常对话。这一步很关键,因为 kes-cli 的意图识别对模型的 JSON 输出稳定性有要求,先用对话页面确认模型可用,再去配 kes-cli,能省掉很多排查时间。
关于 Base URL,TaoToken 的 API 入口是 https://taotoken.net/api ,注意这个地址不带 UTM 参数,直接写进配置即可。kes-cli 里配置模型时,Base URL 填这个,Key 填你刚创建的,Model ID 填你在对话页面验证过的模型名。
如果你后面要做长期编码或 Agent 工作流,可以了解一下 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,它更适合高频调用的场景。不过对于本篇的终端数据库 Agent 验证,先用按量 Key 就够了。
这里有个我踩过的坑:一开始我把模型 Key 直接写进 kes-cli 的 config.toml,后来换模型时发现要改好几个地方。正确做法是让 kes-cli 只读一份配置,Key 和 Base URL 都从这份配置里取,换模型时只改 Model ID。TaoToken 的好处就是 Base URL 固定,你换模型不用换通道,只改 Model ID 就行。
3. 可复制配置:kes-cli 初始化与 KES MCP Server 注册
这一节是整篇的核心,所有配置片段都可以直接复制。kes-cli 的配置文件在 Windows 下是%APPDATA%\kes-cli\config.toml,Linux/macOS 下是~/.config/kes-cli/config.toml。第一次启动如果没有配置,会进入/configure-model引导。
先看模型配置部分。kes-cli 支持百炼、DeepSeek 和 GPT 兼容接口三个方向。因为我们用 TaoToken 统一通道,所以选「gpt」这个兼容方向,然后把 Base URL 指向 TaoToken 的 API 入口。配置保存后,后面启动会自动读取。
[model] provider = "gpt" model = "你的模型ID" base_url = "https://taotoken.net/api" api_key = "你的TaoToken Key"这里provider = "gpt"表示走 OpenAI 兼容协议,TaoToken 的 API 入口兼容这个协议,所以直接填就行。model填你在模型对话页面验证过的模型 ID。api_key填你在 API Keys 页面创建的 Key。
接下来是 KES MCP Server 的注册。这里我只把 KES MCP Server 当作数据库工具层来接入,不单独展开 KES 本身。配置用 stdio 传输,本地调试比较省事,不用额外开端口。restricted模式很重要,因为这个工具不是为了让 AI 随便改库,而是先把只读查询和诊断场景跑顺。
[mcp.servers.kingbase] transport = "stdio" command = "uv" args = [ "--directory", "D:\\AI-project\\kingbase-mcp", "run", "kingbase-mcp", "--access-mode", "restricted" ] access_mode = "restricted" [mcp.servers.kingbase.env] DATABASE_URI = "kingbase://user:password@127.0.0.1:54321/kes_cli_demo"几个参数说明一下。transport = "stdio"表示通过标准输入输出和 MCP Server 通信,适合本地进程。command = "uv"是用 uv 来启动 MCP Server,--directory指向 kingbase-mcp 的项目目录,run kingbase-mcp是启动命令。--access-mode restricted和access_mode = "restricted"双重限制,确保只读。DATABASE_URI里的 user、password、host、port、dbname 换成你自己的。
如果你用的是 Cline MCP 或 Claude Code 这类客户端,配置格式略有不同,但三件套是一样的:Base URL、Key、Model ID。以 Cline MCP 为例,它的 MCP 配置里同样需要指定 command 和 args,模型侧则在 Cline 的设置里填 TaoToken 的 Base URL 和 Key。Codex 的auth.json也是类似逻辑,把模型凭据集中到一处。
配置写完后,启动 kes-cli:
uv run kes启动后进入 Textual 终端界面,你可以直接输入自然语言,也可以输入/打开技能菜单。第一次启动如果模型没配好,会先引导你走/configure-model。配置结束后会打印配置文件路径,后面要换模型,重新进/configure-model就行。
这里有个细节:配置模型的时候不能让终端卡住,也不能配置完以后用户不知道保存到哪里。所以配置结束后会打印配置文件路径。这个功能不算复杂,但对工具可用性很重要,否则每次启动都要用户检查环境变量,体验会很差。
4. 验证请求:一次完整的 KES MCP 查询链路
配置完成后,不要急着问业务问题,先验证 MCP 链路。我会先在终端里问一句:
先帮我检查一下 KES MCP Server 是否连接正常,工具都加载了吗如果这里能看到工具加载成功,后面的表结构、查询、执行计划才有意义。否则模型再会说,也只是空聊。所以我把 MCP 状态检查放在很靠前的位置。它不只是看「连没连上」,还要看工具有没有加载出来。比如DATABASE_URI写错了,MCP Server 可能能启动,但工具调用时会失败;如果 uv 启动目录不对,工具根本加载不出来;如果数据库权限不足,部分诊断结果也可能采集不到。
配置验证我拆成几项来看:MCP Server 是否启动、transport 是否正常、工具数量是否符合预期、restricted 模式是否生效、数据库连接串是否能真正访问目标库。只要其中一步失败,就把失败作为结构化证据返回。
链路通了之后,做一次完整查询验证。输入:
看下我都有哪些表 看下 orders 有哪些字段,顺便说明主键、外键和索引 查一下 orders 前 5 条 统计一下 orders 有多少条数据这里最明显的变化是,不再靠模型猜字段。Agent 会通过 MCP 工具先采集结构,再组织回答。查数据也是一样,安全范围内能确定是只读查询,就直接执行,不再只给一段 SQL 让用户自己复制。
背后的调用链是这样的:用户输入自然语言,IntentClassifier 先输出结构化意图对象,比如:
{ "skill_command": "/database", "tool_name": "mcp.schema", "entities": { "schema": "kes_mcp_demo", "table": "orders" }, "safety": "readonly" }然后/database根据tool_name分发到具体工具:
def _database_assistant_tool(ctx: ToolContext) -> ToolEvidence: tool_name = ctx.intent.tool_name if ctx.intent is not None else None if tool_name == "mcp.schema": return mcp_schema_tool(ctx.settings, ctx.message, ctx.intent) if tool_name == "mcp.query": return mcp_query_tool(ctx.settings, ctx.message, ctx.intent) if tool_name == "mcp.explain": return mcp_explain_sql_tool(ctx.settings, ctx.message, ctx.intent) if tool_name == "mcp.index_advice": return mcp_index_advice_tool(ctx.settings, ctx.message, ctx.intent) if tool_name == "mcp.health": return mcp_health_tool(ctx.settings, ctx.message, ctx.intent)重点是证据先落地,再交给模型总结。比如用户问表结构,先通过 MCP 拿字段、主键、外键和索引;用户问执行计划,先拿数据库返回的计划;用户问健康检查,先拿 MCP 的诊断结果。这样回答就不是模型拍脑袋,而是有真实依据。
安全边界这块,默认只让只读任务自动执行。SELECT、SHOW、WITH、EXPLAIN 可以走自动链路,UPDATE、DELETE、CREATE、DROP、VACUUM 这些都不自动执行。自然语言查询可以由模型生成readonly_sql,但模型只负责「提出候选 SQL」,不能决定是否执行。真正执行前还要经过本地 SQL guard:
READ_ONLY_PREFIXES = ("select", "show", "with", "explain") BLOCKED_KEYWORDS = ( "alter", "analyze", "call", "copy", "create", "delete", "drop", "execute", "grant", "insert", "merge", "reindex", "revoke", "truncate", "update", "vacuum", ) def assert_read_only_sql(sql: str) -> None: if not is_read_only_sql(sql): raise UnsafeSqlError("只允许执行单条只读 SQL:SELECT / SHOW / WITH / EXPLAIN")这样即使模型输出了 DELETE、CREATE INDEX 之类的内容,也会在工具层被拦住。数据库里的变更操作跟普通代码生成不一样,执行错了就可能影响真实数据。默认只读是这次工具的底线。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
配置和验证过程中,最容易卡在几个报错上。这一节按真实报错来对照排查。
401 Unauthorized。这个基本是模型侧 Key 的问题。先检查 kes-cli 的config.toml里api_key是不是填对了,有没有多余空格。然后去 TaoToken 的 API Keys 页面确认 Key 状态正常、没有过期。如果 Key 没问题,检查base_url是不是https://taotoken.net/api,注意不要带 UTM 参数,也不要漏掉/api。还有一种情况是 Key 有额度但模型 ID 写错了,某些通道会返回 401 而不是 404,所以顺手确认model字段。
local proxy failed。这个报错通常出现在 MCP Server 启动阶段。先检查command = "uv"在终端里能不能直接执行,uv --version有没有输出。然后检查--directory指向的 kingbase-mcp 目录是否存在,路径里的反斜杠在 TOML 里要写成双反斜杠\\。如果 uv 能跑但 MCP 起不来,试着在终端里手动执行一遍 args 里的命令,看具体报什么错。还有一种情况是DATABASE_URI里的数据库地址不通,MCP Server 启动时不会立刻报错,但工具调用时会失败,所以状态检查那一步一定要做。
reading choices 相关报错。这个一般出现在模型返回结构不符合预期时。kes-cli 的意图识别依赖模型输出结构化 JSON,如果模型返回的choices字段为空或者格式不对,解析层就会报错。排查方向:先确认模型本身可用,去模型对话页面发一条消息看能不能正常返回;然后确认model字段填的是支持结构化输出的模型。如果模型有时候返回数组、有时候返回字符串,解析层做了容错:
@field_validator("conditions", mode="before") def _coerce_conditions(cls, value: Any) -> dict[str, Any]: if value is None: return {} if isinstance(value, dict): return value return {"raw": str(value)}如果第一次分类结果是/chat,但用户其实是在说「直接看下表不就得了」这种口语表达,还会让模型做一次重试。第二次提示里会明确要求它从最接近的安全只读工具里选,而不是轻易要求用户澄清。
OAuth 相关报错。如果你用的是 Claude Code 或 Codex 这类带 OAuth 的客户端,报 OAuth 错误通常是凭据文件路径不对或 token 过期。以 Codex 的auth.json为例,确认文件在正确的位置,里面的 token 没有过期。如果是 Claude Code,检查它的 settings 里 Base URL 和 Key 是否指向 TaoToken。这里要注意,OAuth 报错和 API Key 报错是两套体系,不要混着排查。如果你在 kes-cli 里遇到 OAuth 字样,先确认是不是误配了某个客户端的凭据文件。
工具加载不出来。状态检查时如果工具数量是 0,先看 MCP Server 日志。常见原因是--access-mode restricted和access_mode = "restricted"不一致,或者 kingbase-mcp 版本不匹配。还有一种情况是数据库连接串能连上,但当前用户没有权限访问目标 schema,工具会加载但调用时返回空。
排查顺序建议:先确认模型侧(401、reading choices),再确认 MCP 侧(local proxy failed、工具加载),最后确认数据库侧(权限、连接串)。每一层都有独立的验证动作,不要跳步。
6. 语义一致 CTA:把终端数据库 Agent 跑成日常工具
链路跑通之后,你会发现这套工作流的价值不在某一次查询,而在于它把「连接数据库」到「安全完成数据库任务」变成了一个连续过程。开发一个接口前,我先问有哪些表,再问 orders 表有哪些字段,然后查几条样例数据,整个排查过程都在终端里完成,不用在客户端、命令行、文档之间来回切。
如果你要复现这套工作流,模型侧凭据统一走 TaoToken:API 入口是 https://taotoken.net/api ,Key 在 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 创建,接入细节可以看接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。验证模型可用性去模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite ,长期编码或 Agent 工作流可以看 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。
最后分享一个实用技巧:kes-cli 的/report可以把当前会话的诊断证据导出。我习惯在每次排查完慢查询后导出一份,里面包含 MCP 工具调用记录和数据库返回的原始证据。这样复盘的时候不用凭记忆,直接看报告就行。另外,/mcp状态检查建议每次启动后先跑一遍,尤其是换了数据库连接串或升级了 kingbase-mcp 之后,能提前暴露问题,而不是等到查表的时候才报一个模糊错误。