☰
如何在服务器部署MCP服务(stdio转成sse)给Dify调用:TaoToken统一Key接入与Supergateway配置实战
2026/9/29 20:58:11 网站建设 项目流程

1. 为什么 stdio 型 MCP 服务在 Dify 里总是接不上

如果你最近在折腾 Dify 的 MCP 插件,大概率会遇到一个很尴尬的情况:社区里能直接填 URL 的远程 SSE 服务一抓一大把,但真正想用的开源 MCP 服务,翻开源码一看,启动方式全是stdio。Dify 的 MCP 插件只认sse或streamableHttp这类网络端点,它没法帮你在服务器上拉起一个子进程再喂标准输入输出。于是你手里明明有一堆好用的 MCP 工具,却卡在“协议对不上”这一步。

这个问题的本质是传输层不匹配。stdio型 MCP 服务是给本地客户端(比如 Claude Desktop、Cursor)设计的,客户端负责 fork 进程、通过 stdin/stdout 收发 JSON-RPC 消息。而 Dify 作为 Web 端的编排平台,只能通过 HTTP 去访问一个已经监听端口的服务。中间缺的这层“翻译”,就是 Supergateway 要干的事——它把 stdio 子进程包装成一个 SSE 服务,对外暴露/sse和/message端点,Dify 就能像调用普通远程 MCP 一样调用它。

这篇内容面向的是已经在服务器上有 Dify、想把手头 stdio 型 MCP 服务接进去的人。我会把整条链路拆开:从 TaoToken 统一 Key 的接入准备,到 Supergateway 的启动命令,再到 Dify 侧填地址、curl 验证、以及几个我实际踩过的坑。你跟着做,最后应该能拿到一个稳定的 SSE 端点,并且知道出问题时该看哪一行日志。

需要先说明一点:Supergateway 本身不解决模型调用的问题,它只管传输转换。真正让 MCP 工具背后的大模型跑起来,还需要一个统一的 API 通道。我这边用的是 TaoToken 来做 Key 和通道的统一管理,后面会讲怎么把它和 MCP 服务的环境变量串起来。

2. TaoToken 前置:统一 Key 与 API 通道准备

在动手转 SSE 之前,先把“模型侧”的接入理清楚,否则 MCP 工具调通了、背后模型却连不上,排查起来会两头乱。TaoToken 在这里的角色是提供一个统一的 API 入口和 Key 管理,你不需要在每台服务器、每个 MCP 服务里散落不同的厂商 Key。

先到官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册并登录,然后在控制台里创建一个 API Key。这个 Key 就是你后面所有请求的凭证。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,Key 管理页在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。创建完之后先复制出来存好,页面刷新后就不再完整显示了。

API 的基础地址是 https://taotoken.net/api ,注意这个地址不带任何查询参数,直接作为base_url用。如果你用的是 OpenAI 兼容的 SDK,把base_url指向它、api_key填刚才创建的 Key 就行。想先确认模型通不通,可以直接去模型对话页 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 发一条测试消息,能正常返回就说明 Key 和通道没问题。

这里有个关键点:MCP 服务本身通常不直接调模型,它只是暴露工具。真正调模型的是 Dify 里的 Agent 或工作流节点。所以 TaoToken 的 Key 主要配在 Dify 的模型供应商设置里,而不是配在 Supergateway 里。但有些 MCP 服务(比如带摘要、带检索增强的)会自己发起模型请求,这时候就需要通过环境变量把OPENAI_BASE_URL和OPENAI_API_KEY传给它。两种场景我都会在配置章节里给出写法。

如果你后面要长期跑编码类 Agent,或者想让 MCP 工具链和 Coding 场景打通,可以了解一下 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。它和本篇的 SSE 转换不冲突,属于上层用法。

3. 可复制配置:Supergateway 启动与 MCP 服务骨架

这一章是核心,所有命令都可以直接复制改路径使用。整体思路是:用 pm2 守护一个 Supergateway 进程,Supergateway 再去拉起真正的 stdio MCP 服务。

3.1 环境准备与目录创建

先确认服务器上有 Node.js(建议 18 以上)和 npm。然后创建工作目录,这个目录是给 filesystem 这类需要读写文件的 MCP 服务用的,其他服务可以换成自己的路径。

mkdir -p /opt/mcp/my-folder sudo chmod o+w /opt/mcp/my-folder npm install -g pm2

chmod o+w是为了让以非 root 身份运行的 MCP 进程有写权限。如果你用 root 跑,可以跳过,但不建议长期用 root 跑 MCP 服务。

3.2 Supergateway 启动命令拆解

官方最简命令长这样,我把它拆成带注释的版本,方便你替换参数:

pm2 start --name mcp-filesystem \ npx -- -y supergateway \ --port 8951 \ --baseUrl http://127.0.0.1:8951 \ --ssePath /sse \ --messagePath /message \ --stdio "npx -y @modelcontextprotocol/server-filesystem /opt/mcp/my-folder"

逐项说明:

参数作用建议值
--portSupergateway 监听的端口8951,按需改
--baseUrl对外暴露的基础地址内网用 127.0.0.1 或内网 IP
--ssePathSSE 端点路径/sse
--messagePath消息回传路径/message
--stdio要拉起的 stdio MCP 命令完整命令字符串

--baseUrl这个参数容易被忽略。如果你 Dify 和 MCP 在同一台机器,填http://127.0.0.1:8951就行;如果 Dify 在另一台内网机器,要填这台机器的内网 IP,否则 SSE 事件里返回的 message 地址会指向 localhost,Dify 那边就回传不了消息。

3.3 带 TaoToken 环境变量的 MCP 服务骨架

有些 MCP 服务启动时需要模型凭证。以需要调用模型的场景为例,可以在 pm2 启动时注入环境变量:

pm2 start --name mcp-custom \ --env OPENAI_BASE_URL=https://taotoken.net/api \ --env OPENAI_API_KEY=你的TaoTokenKey \ npx -- -y supergateway \ --port 8952 \ --baseUrl http://内网IP:8952 \ --stdio "npx -y 你的-mcp-包名"

注意OPENAI_BASE_URL填的是https://taotoken.net/api,不要加多余路径。Key 就是第 2 章创建的那个。这样 MCP 服务内部如果走 OpenAI 兼容协议,就会自动走 TaoToken 通道。

3.4 查看启动状态

pm2 logs mcp-filesystem --lines 50

看到类似Server is running on port 8951以及 stdio 子进程启动成功的日志,就说明 Supergateway 已经把 MCP 服务拉起来了。如果日志里出现spawn npx ENOENT,说明服务器 PATH 里找不到 npx,用绝对路径替换npx即可。

4. 验证请求:curl 测 SSE 端点与 Dify 调用成功检查

配置写完不能直接扔给 Dify,先用 curl 确认 SSE 端点活着。

4.1 curl 验证 SSE 端点

curl -N http://127.0.0.1:8951/sse

-N是关闭缓冲,让你能实时看到事件流。正常情况会先返回一行event: endpoint,后面跟着data: /message?sessionId=xxxx。这个 sessionId 很关键,它是后续消息回传的会话标识。如果你只看到连接建立但没有 endpoint 事件,多半是--baseUrl配错了,或者端口被防火墙拦了。

拿到 sessionId 后,可以进一步测消息通道是否通:

curl -X POST "http://127.0.0.1:8951/message?sessionId=上一步的sessionId" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

如果返回工具列表的 JSON,说明整条 stdio 到 SSE 的链路是通的。这一步能过,Dify 那边基本不会出问题。

4.2 Dify 侧填写 SSE 地址

在 Dify 的 MCP 插件配置里,填写的结构是这样的:

{ "mcpServers": { "filesystem": { "type": "sse", "url": "http://你的服务器内网IP:8951/sse" } } }

几个要点:type必须是sse;url用内网 IP,不要用127.0.0.1,除非 Dify 和 MCP 在同一台机器且同网络命名空间;端口要和 Supergateway 的--port一致。保存后 Dify 会去连这个地址,连接成功的话插件状态会变成已连接,并且能列出该 MCP 服务暴露的工具。

4.3 调用成功的检查动作

连接成功后,在 Dify 的 Agent 或工作流里挂上这个 MCP 工具,发一条会触发工具调用的指令。比如 filesystem 服务,让它读某个文件。观察两个地方:一是 Dify 的运行日志里有没有工具调用记录,二是服务器上pm2 logs mcp-filesystem有没有对应的请求日志。两边都有记录,才算真正打通。只看到 Dify 显示连接成功但调用无反应,通常是--baseUrl导致 message 回传地址不对。

5. 本篇常见错排查

这一章列几个我实际遇到过的报错,按出现频率排序。

连接超时或 Dify 一直转圈:先确认 Dify 所在机器能不能curl通 MCP 服务器的端口。内网不通多半是安全组或防火墙没放行。云服务器记得在控制台放行对应端口,本机ufw或firewalld也要检查。

SSE 连上了但工具调用无返回:九成是--baseUrl填了127.0.0.1,而 Dify 在另一台机器。SSE 事件里返回的 message 地址是127.0.0.1,Dify 回传消息时打到了自己身上。把--baseUrl改成 MCP 服务器的内网 IP 重启即可。

spawn npx ENOENT:pm2 启动时的 PATH 和登录 shell 不一样。用which npx找到绝对路径,把--stdio里的npx换成绝对路径,比如/usr/local/bin/npx。

端口被占用:pm2 delete mcp-filesystem后换端口重启。注意 pm2 的进程名不要重复,重复了会启动失败但日志不明显。

MCP 服务需要写权限却报 EACCES:检查工作目录权限,以及 pm2 是以哪个用户跑的。pm2 startup配的开机自启默认可能用 root,和手动启动的用户不一致,权限会错乱。

TaoToken Key 报 401:确认OPENAI_BASE_URL是https://taotoken.net/api,没有多余斜杠或路径;Key 没有多余空格;如果 Key 是在控制台刚创建的,确认复制完整。可以先用模型对话页发一条消息验证 Key 本身有效。

Dify 插件保存时报 JSON 格式错误:mcpServers的 JSON 结构对缩进不敏感,但对引号和逗号敏感。建议在本地用 JSON 校验工具过一遍再粘贴。

6. 后续接入与统一通道建议

把 stdio 转 SSE 这件事跑通一次之后,后面再接其他 MCP 服务就是复制粘贴改参数。我的做法是每个 MCP 服务分配一个独立端口,pm2 进程名带服务名,日志分开看,互不干扰。端口规划上留出区间,比如 8951 到 8999,避免和现有服务撞车。

模型通道这边,统一用 TaoToken 的 Key 之后,Dify 的模型供应商配置和 MCP 服务内部的环境变量可以共用同一个 Key,换 Key 时只改一处。Dify 侧接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有 base_url 和鉴权的完整说明。如果你用的是 Claude Code 这类编码工具,Anthropic 兼容的接入方式在 https://taotoken.net/claudecode-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode-anthropic&utm_campaign=rewrite 有单独说明,和本篇的 SSE 转换是两条并行的链路。

最后提醒一个实操细节:Supergateway 拉起的 stdio 子进程如果崩了,pm2 默认不会自动重启子进程,只会重启 Supergateway 本身。可以在--stdio命令外面套一层重试脚本,或者用 pm2 的--restart-delay配合健康检查。这个坑在多服务并行时比较隐蔽,日志里表现为 SSE 端点还在但工具列表为空,重启 pm2 进程就能恢复。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询