MCP 协议双向集成
学习目标
- 理解 Dify 中 MCP 协议的双向角色(客户端发现工具 + 服务端暴露工具)
- 掌握 MCP 工具如何集成到 Dify 的统一工具系统中
- 学会分析 Streamable HTTP 传输模式的实现要点
前置知识
本章涉及 MCP 协议的通用原理,建议先阅读:
下文假设你已理解 MCP 协议的通用概念,直接聚焦 Dify 的具体实现。
项目实践
MCP 双向角色
Dify 同时实现了 MCP 的客户端和服务端两个角色:
| 角色 | 实现位置 | 功能 |
|---|---|---|
| MCP 客户端 | api/core/mcp/client/ | 连接外部 MCP Server,发现并调用其工具 |
| MCP 服务端 | api/core/mcp/server/streamable_http.py | 将 Dify 内部工具暴露为 MCP Tool,供外部调用 |
MCP 客户端实现
MCP 客户端负责从外部 MCP Server 发现工具并集成到 Dify 工具系统中:
# 伪代码,基于源码结构的抽象class MCPClient: async def connect(self, server_url: str): # 1. 建立 Streamable HTTP 连接到 MCP Server # 2. 初始化 Session # 3. 调用 tools/list 获取可用工具
async def call_tool(self, tool_name: str, arguments: dict): # 调用 MCP Server 上的工具 # 返回结果转换为 Dify ToolInvokeMeta 格式认证模块(api/core/mcp/auth/):
- 支持多种认证方式(API Key、OAuth 等)
- 认证客户端封装在
auth_client.py中 - 认证信息持久化存储
会话管理(api/core/mcp/session/):
- MCP Session 管理连接生命周期
- 会话状态存储在 Redis 中(支持多实例部署)
MCP 服务端实现
Dify 通过 streamable_http.py 实现了 MCP Streamable HTTP 传输模式的服务端:
# 伪代码,展示服务端传输层@router.post("/mcp")async def handle_mcp_request(request: Request): # 1. 解析 MCP JSON-RPC 请求 # 2. 路由到对应的处理器(tools/list、tools/call 等) # 3. 执行操作并返回结果 # 4. 支持 SSE 流式响应(用于长操作)关键特性:
- Streamable HTTP 传输:支持请求-响应和 SSE 流式两种模式
- 工具暴露:将 Dify 内部工具(Builtin、API、Workflow 等)转换为 MCP Tool 格式
- 协议兼容:遵循 MCP 协议的 JSON-RPC 规范
MCP 工具在 Dify 工具系统中的集成
MCP 工具通过 MCPToolProviderController 集成到统一工具系统:
# 伪代码class MCPToolProviderController(ToolProviderController): def __init__(self, server_config: MCPServerConfig): self.client = MCPClient(server_config) self.tools = [] # 从 MCP Server 发现的工具列表
def discover_tools(self) -> list[MCPTool]: # 调用 MCP Server 的 tools/list # 返回 MCPTool 实例列表
def get_tool(self, tool_name: str) -> MCPTool: # 获取指定工具的引用MCPTool 实现了 Dify 的 Tool 接口:
# 伪代码class MCPTool(Tool): def invoke(self, tool_parameters: dict) -> ToolInvokeMeta: # 1. 将 Dify 格式的参数转换为 MCP 格式 # 2. 通过 MCPClient 调用远程工具 # 3. 将 MCP 响应转换为 Dify ToolInvokeMeta 格式MCP 工具管理服务(services/tools/mcp_tools_manage_service.py):
- MCP Server 配置的增删改查
- 工具发现的定时刷新
- 连接健康检查
问题与规避
陷阱 1:MCP Server 连接超时
外部 MCP Server 可能响应慢或不可达,导致工具发现或调用超时。
Dify 的规避策略:
- Streamable HTTP 连接设置超时时间
- MCP Session 管理连接生命周期(超时自动重连)
- 工具发现失败不影响 Dify 核心工具的可用性
陷阱 2:MCP 工具返回格式不兼容
不同 MCP Server 可能返回不同格式的数据。
Dify 的规避策略:
MCPTool.invoke()中将 MCP 响应统一转换为ToolInvokeMeta格式- 类型校验和转换在工具调用层完成
- 不兼容的响应格式通过异常机制报告
陷阱 3:认证凭据管理
MCP Server 可能需要不同的认证方式(API Key、OAuth 等)。
Dify 的规避策略:
api/core/mcp/auth/模块封装多种认证方式- 认证凭据加密存储
- 认证失败后自动触发重新认证流程
设计取舍
Streamable HTTP vs SSE-only 传输
Dify 的 MCP 服务端选择实现 Streamable HTTP 传输模式:
优势:
- Streamable HTTP 支持双向通信(客户端可发送消息,服务端可推送事件)
- 比纯 SSE 更灵活,支持请求-响应和流式两种交互模式
- 是 MCP 协议推荐的传输方式
代价:
- 实现复杂度高于纯 SSE
- 需要处理 HTTP 长连接管理和 SSE 流式响应
- 部分旧版 MCP 客户端可能只支持 SSE
替代方案:仅实现 SSE 传输。但这会限制交互模式和工具能力。
参考来源
- MCP Streamable HTTP Transport
- Dify MCP 模块源码:
api/core/mcp/