跳转到内容

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 传输。但这会限制交互模式和工具能力。

参考来源