Dify 基于 MCP 接入 SQLBot:config.toml 骨架与连通性验证
1. 为什么要在 Dify 里用 MCP 接 SQLBot如果你正在做「让业务同事用自然语言查数据库」这件事大概率绕不开两个东西一个是 Dify 的工作流编排另一个是能把自然语言稳定翻译成 SQL 的引擎。Dify 自带的 Database 插件确实能跑 text2sql但它本质是「把表结构塞给 LLM让模型直接写 SQL」表一多、字段一杂模型幻觉就上来了生成的 SQL 经常字段名对不上、JOIN 写错甚至编出不存在的表。SQLBot 这类专门做 text-to-SQL 的服务走的是 LLM RAG 检索增强的路线先把库表结构、字段注释、样例数据做成向量索引用户提问时先检索相关 schema再让模型基于检索结果生成 SQL准确率比纯 LLM 硬写高一个档次。更关键的是它原生支持 MCP 协议可以被 Dify 通过 MCP 工具节点直接调用不用你自己写 HTTP 适配层。这篇要解决的就是落地环节最卡人的一步Dify 通过 MCP 接入 SQLBot 时config.toml骨架到底怎么写、TaoToken 的统一 Key/API 通道放在哪个位置、以及怎么用一次连通性验证确认接入真的生效了。适合已经在 Dify 里搭过工作流、想把手写 SQL 节点换成 SQLBot 的开发者。下面所有配置我都按可复制的方式给你改掉 IP 和端口就能用。2. 前置准备SQLBot 服务与 TaoToken 通道2.1 SQLBot 侧要暴露 MCP 端点SQLBot 用容器方式起最省事关键是它要同时暴露 Web 端口和 MCP 端口。我实测下来MCP 服务默认挂在8001端口的/mcp路径上走 SSE 传输。启动命令大致是这样docker run -d \ --name sqlbot \ --restart unless-stopped \ -p 8000:8000 \ -p 8001:8001 \ -e SERVER_IMAGE_HOSThttp://你的宿主机IP:8001/images/ \ -v ./data/sqlbot/excel:/opt/sqlbot/data/excel \ -v ./data/sqlbot/file:/opt/sqlbot/data/file \ -v ./data/sqlbot/images:/opt/sqlbot/images \ -v ./data/sqlbot/logs:/opt/sqlbot/logs \ -v ./data/postgresql:/var/lib/postgresql/data \ --privilegedtrue \ dataease/sqlbot起来之后进http://宿主机IP:8000完成初始化配好要查询的 MySQL/PostgreSQL 数据源再在「AI 模型」里挂一个可用的对话模型。SQLBot 自己需要模型来生成 SQL这一步别跳过否则 MCP 调过去也是空转。2.2 TaoToken 统一 Key 放在哪一层这里有个容易搞混的点TaoToken 的统一 Key/API 通道是给「需要调用大模型」的环节用的不是给 MCP 传输层用的。也就是说SQLBot 内部生成 SQL 时如果走的是 OpenAI 兼容接口那它的模型配置里填的 Base URL 和 Key 就应该指向 TaoToken 的通道而 Dify 调 SQLBot 的 MCP 端点走的是内网 HTTP跟 TaoToken 无关。TaoToken 的 API 入口是https://taotoken.net/api兼容 OpenAI 的/v1/chat/completions格式。你在 SQLBot 的模型配置里把 Base URL 填成这个地址Key 填你在控制台生成的令牌即可。这样 SQLBot 生成 SQL 用的模型就走统一通道换模型、看用量都在一个地方管。如果你还没建 Key去控制台建一个https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 建完在 API Keys 页面复制https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。想先确认模型通不通可以直接在模型对话页试一句https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。2.3 Dify 侧要装的 MCP 插件Dify 调 MCP 靠的是 marketplace 里的mcp_sse插件插件 ID 形如junjiem/mcp_sse。装完之后工作流里会多出一个「调用 MCP 工具」的节点它的参数里有一个servers_config字段这就是我们要写config.toml骨架的地方——准确说Dify 的 MCP 节点用的是 JSON 形式的 servers 配置但很多团队会把它抽成一个config.toml统一管理下面我给两种写法。3. 可复制的 config.toml 骨架3.1 独立 config.toml 写法如果你是在 Dify 之外先用命令行工具比如 mcp 客户端验证 SQLBotconfig.toml可以这样写。注意transport必须是sseURL 指向 SQLBot 的 MCP 端点# config.toml —— SQLBot MCP 接入骨架 [mcp_servers.sqlbot_mcp] url http://host.docker.internal:8001/mcp transport sse timeout 50 sse_read_timeout 50 # 如果 SQLBot 需要鉴权头在这里加 [mcp_servers.sqlbot_mcp.headers] # Authorization Bearer your-token几个参数的含义对照一下参数作用建议值urlSQLBot MCP 端点地址http://host.docker.internal:8001/mcptransport传输协议固定ssetimeout单次调用超时秒50sse_read_timeoutSSE 长连接读超时秒50headers自定义请求头按需无鉴权可留空注意host.docker.internal是容器访问宿主机的别名。如果你的 Dify 和 SQLBot 都在同一台宿主机上跑容器用这个最稳如果 SQLBot 在另一台机器直接换成那台机器的内网 IP。3.2 Dify MCP 节点里的 JSON 等价写法Dify 的 MCP 工具节点不直接读 toml它要的是 JSON 字符串。把上面的骨架翻译过去就是{ sqlbot_mcp: { url: http://host.docker.internal:8001/mcp, transport: sse, headers: {}, timeout: 50, sse_read_timeout: 50 } }这个 JSON 填在 MCP 节点的servers_config参数里。我建议你把它存成一个环境变量或者工作流变量别硬编码在节点里后面换环境只改一处。3.3 两个 MCP 工具节点的参数差异SQLBot 的 MCP 暴露了两个关键工具mcp_start和mcp_question。前者用来拿access_token和chat_id后者用来真正提问。它们的arguments参数结构不一样这是最容易配错的地方。mcp_start的 arguments{ username: admin, password: SQLBot123456 }mcp_question的 arguments{ chat_id: {{#conversation.chat_id#}}, question: {{#sys.query#}}, token: {{#conversation.access_token#}} }看到区别了吗mcp_start只要账号密码mcp_question要的是上一轮拿到的chat_id和token。所以工作流里必须先调mcp_start用代码节点把返回的data.chat_id和data.access_token解析出来赋值给会话变量再传给mcp_question。4. 工作流串接与连通性验证4.1 完整节点链路一个能跑通的最小链路是这样的开始节点收 username/password→ 条件分支判断 access_token 是否为空→ MCP 工具mcp_start→ 代码节点解析 token 和 chat_id→ 变量赋值节点写入会话变量→ MCP 工具mcp_question→ 直接回复。条件分支的作用是第一次进来access_token为空走mcp_start拿 token后续对话 token 已存在直接跳到mcp_question省一次登录。代码节点解析返回的 Python 逻辑import json def main(arg1: str) - dict: json_obj json.loads(arg1) return { chat_id: json_obj[data][chat_id], access_token: json_obj[data][access_token] }变量赋值节点把chat_id和access_token分别写进conversation.chat_id和conversation.access_token这样下一轮对话还能复用。4.2 一次连通性验证动作配完之后别急着接业务先做一次最小验证。在 Dify 工作流里手动触发username 填adminpassword 填你 SQLBot 的密码query 填一句最简单的查一下 smart_vision 库里有多少张表预期返回分两段。第一段是mcp_start的返回结构大致是{ data: { chat_id: 0, access_token: eyJhbGciOi... } }第二段是mcp_question的返回里面会带 SQLBot 生成的 SQL 和查询结果形如{ data: { sql: SELECT COUNT(*) FROM information_schema.tables WHERE table_schemasmart_vision, result: [{count: 12}] } }只要你能看到access_token是一串非空的 JWT并且mcp_question返回里带sql字段就说明 MCP 链路通了。如果mcp_question返回空或者报错八成是chat_id/token没传对回去检查变量赋值节点。4.3 用 curl 单独验证 MCP 端点不想在 Dify 里反复点也可以先用 curl 确认 SQLBot 的 MCP 端点活着curl -N -H Accept: text/event-stream \ http://宿主机IP:8001/mcp正常的话会挂住并持续输出 SSE 事件流能看到event: endpoint之类的行。如果直接 connection refused说明 SQLBot 的 8001 端口没起来或者被防火墙挡了先解决这个再谈 Dify 接入。5. 本篇常见错排查5.1 host.docker.internal 解析失败这是最高频的坑。Dify 容器里访问host.docker.internal报Name or service not known说明你的容器运行时没给这个别名。两个解法一是启动 Dify 容器时加--add-hosthost.docker.internal:host-gateway二是干脆把 URL 换成宿主机的真实内网 IP比如http://192.168.27.161:8001/mcp。后者更省事我一般直接用 IP。5.2 MCP 节点报 transport 不支持如果你把transport写成了http或者streamable-httpDify 的 mcp_sse 插件会直接拒绝。SQLBot 这个版本走的是 SSEtransport必须是小写sse。另外 URL 结尾的/mcp不能少少了会 404。5.3 mcp_question 返回 token 无效多半是mcp_start和mcp_question用了不同的servers_config导致两次调用连到了不同的 SQLBot 实例token 自然对不上。检查两个 MCP 节点的servers_config是否完全一致。还有一种情况是会话变量没写进去{{#conversation.access_token#}}取到空字符串回去看变量赋值节点的write_mode是不是over-write。5.4 SQLBot 生成 SQL 但执行报错这通常不是 MCP 的问题而是 SQLBot 侧的数据源配置或模型能力问题。先确认 SQLBot 里配的数据源能正常连通再确认挂的模型能稳定输出 SQL。如果模型走的是 TaoToken 通道去模型对话页发一句「写一条查询 users 表前 10 行的 SQL」看返回质量https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。模型本身写 SQL 就不稳换更强的模型比调 MCP 参数有用。5.5 超时设置太短导致长查询中断复杂查询 SQLBot 要检索 schema 再生成 SQL耗时可能超过 30 秒。timeout和sse_read_timeout都建议给到 50 秒以上。如果还是断看 SQLBot 容器日志里有没有模型调用超时那就要从模型通道侧找原因。6. 接入之后怎么继续往下走链路通了只是第一步。真正上生产你还要考虑几件事SQLBot 的账号密码别硬编码在工作流里用 Dify 的环境变量或者密钥管理chat_id和access_token的会话变量要设过期策略避免长期复用失效 tokenMCP 调用失败要有兜底分支别让整个对话直接崩掉。如果你打算把 SQLBot 接进更复杂的 Agent 流程或者需要长期跑编码类任务可以看看 Coding Plan 的额度方案https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入细节和参数说明都在文档里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。Claude Code 相关的接入配置参考https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。最后留一个我踩过的坑Dify 工作流调试时MCP 节点的输出经常是一大坨 JSON直接看很痛苦。建议在代码节点里加一行print或者把关键字段单独输出调试效率能高不少。