惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
V
Vulnerabilities – Threatpost
A
Arctic Wolf
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
H
Hacker News: Front Page
D
Docker
人人都是产品经理
人人都是产品经理
Attack and Defense Labs
Attack and Defense Labs
Forbes - Security
Forbes - Security
I
InfoQ
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
aimingoo的专栏
aimingoo的专栏
C
Cybersecurity and Infrastructure Security Agency CISA
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Simon Willison's Weblog
Simon Willison's Weblog
腾讯CDC
WordPress大学
WordPress大学
T
Tenable Blog
P
Proofpoint News Feed
月光博客
月光博客
T
Tor Project blog
The Cloudflare Blog
罗磊的独立博客
S
Secure Thoughts
Application and Cybersecurity Blog
Application and Cybersecurity Blog
The Hacker News
The Hacker News
P
Palo Alto Networks Blog
I
Intezer
小众软件
小众软件
N
News | PayPal Newsroom
V
Visual Studio Blog
L
LINUX DO - 最新话题
W
WeLiveSecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Troy Hunt's Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
D
DataBreaches.Net
P
Privacy International News Feed
博客园 - 三生石上(FineUI控件)
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
Security Affairs
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
阮一峰的网络日志
阮一峰的网络日志

XINDOO

关于内卷,几个值得深想的洞察 当创作被 Skill 化:我用 AI 写了一部 320 章的长篇网文 AI第一剑,先斩程序员 AI 也会偷懒?这个 PUA 工具专治“摸鱼式编程” Gstack 深度解析:YC CEO 开源的 AI 工程团队 GitHub Trending霸榜!深度解析AI Coding辅助神器 Superpowers 深度探讨:从 OpenClaw 爆火,看 AI Agent 的真相与程序员的未来 我复刻了NotebookLM的信息图功能 我用AI写了部小说,这里是整个过程 [翻译]我在谷歌14年学到的21堂课 2万字吊打40万字:为什么我的“牛马Agent”比“数字分身”更聪明? 最近AI领域爆火的 Agent Skills 是什么? 从计算机科学的视角来看拖延症 一周改6个库后我悟了:AI时代,程序员正在退化成“甲方” 使用n8n做一个自动同步更新的Github项目问答机器人 Agent设计模式——第 20 章:优先级排序 Agent设计模式——第 1 章:提示词链 Agent设计模式——附录 D - 使用 AgentSpace 构建 Agent Agent设计模式——第 19 章:评估和监控 Agent设计模式——第 10 章:模型上下文协议 (MCP) Agent设计模式——第 21 章:探索和发现 Agent设计模式——智能体设计模式 Agent设计模式——第 11 章:目标设定和监控 Agent设计模式——第 9 章:学习和适应 Agent设计模式——第 16 章:资源感知优化 Agent设计模式——附录 G - 编码 Agent Agent设计模式——第 13 章:人机协同 Agent设计模式——第 17 章:推理技术 Agent设计模式——附录 F - 深入剖析:Agent 推理引擎的内部运作机制 Agent设计模式——章节目录 Agent设计模式—— Agent设计模式——第 7 章:多 Agent 协作 Agent设计模式——附录 E - 命令行界面中的 AI Agent Agent设计模式——附录 C - Agentic 框架快速概览 Agent设计模式——第 3 章:并行化 Agent设计模式——**常见问题解答:Agentic 设计模式** Agent设计模式——第 14 章:知识检索(RAG) Agent设计模式——第 18 章:Guardrails/安全模式 Agent设计模式——第 15 章:Agent 间通信(A2A) Agent设计模式——第 8 章:内存管理 Agent设计模式——第 12 章:异常处理和恢复 Agent设计模式——第 4 章:反思 Agent设计模式——附录 B - AI Agentic 交互:从图形界面到现实世界环境 Agent设计模式——第 5 章:工具使用(函数调用) Agent设计模式——结论 Agent设计模式——第 6 章:规划 Agent设计模式——第 2 章:路由 从经验主义到贝叶斯理论:如何排查线上问题 我用AI为自己造了一把安全的开发者“瑞士军刀”” 从LLM和MCP的协同过程看如何做优化 一文了解知识库背后的技术RAG AI应用的五个级别:从入门到专家的进阶之路 一文入门AI圈最近爆火的MCP协议 HTTP/3:性能改进(第 2 部分) deepseek-r1祛魅:从过度热捧到理性认知⁠ 为什么AI智能体需要工作流 如何用GPT-4o解读视频 json命令行处理神器jq介绍 OpenAI的结构化浅析 从大模型的原理到提示词优化 从经济学原理看团队分工合作 [翻译]关于人工智能的30个思考 从马斯洛需求层次理论谈职场激励 知识与智慧 如何使用大语言模型绘制专业图表 两个开源项目打造自己的大模型聚合平台 我让gpt4o给我推荐了一千多次书 得到了这些数据 用Langchain创建一个可以总结网页内容的Agent 推荐一个好用的命令行工具ShellGPT 关于ffmpeg height not divisible by 2的错误 使用Certbot解决https证书自动更新的问题 Spring Cache简明教程 软件开发中的抓大放小vs极致细节思维 OpenAI Assistants-API简明教程 OpenAI的多函数调用(Multiple Function Calling)简介 如何使用ffmpeg制作透明背景的视频 spring-kafka中ContainerProperties.AckMode详解 如何在地图上寻找最密集点的位置? IO密集型服务提升性能的三种方法 职场中的基本归因错误和自利归因 使用javax.validation.constraints校验参数合法性 Java Optional:让你的代码更优雅 ChatGPT函数调用初体验:让ChatGPT具备抓取网页文本的能力 如何使用ChatGPT提升自己的“码”力? 使用ffmpeg拼接两张图片 ThreadPoolExecutor——高效处理并发任务的必备良器 从CPU的视角看 多线程代码为什么那么难写! 使用ffmpeg缩小视频体积的几种方式 Linux parallel 命令使用手册 为什么说过早优化是万恶之源? Linux xargs命令介绍 深入理解Spring的事件通知机制 Java高并发之CyclicBarrier简介 聊一聊过度设计! 详解Redisson分布式限流的实现原理 Java中使用HashMap时指定初始化容量性能一定会更好吗? 如何用ffmpeg截取视频片段&截取时间不准确的坑 XINDOO的2022年年终总结 使用ffmpeg将视频转成HLS(m3u8)格式 谷歌Guava LoadingCache介绍
打通Dify与AI工具生态:将Workflow转为MCP工具的实践
xindoo · 2025-06-29 · via XINDOO

背景

  我们公司部署了自己的Dify平台,已有大量构建好的Workflow工作流。这些工作流涵盖了知识库检索、文档分析等核心业务场景,具有很高的复用价值。然而,我司的Dify平台本身并未提供直接将Workflow转换为MCP(Model Context Protocol)的功能,这限制了我们在各种支持MCP的AI工具中使用这些现有资产。

 为了解决这个问题,我自己调研开发一个中间件,让Dify的Workflow能够以MCP工具的形式被各种AI应用调用。

什么是MCP?

 首先简单介绍下MCP,MCP(Model Context Protocol)是Anthropic推出的开放协议,用于连接AI助手与各种数据源和工具,具体可以看下我之前的文章《一文入门AI圈最近爆火的MCP协议》。通过MCP,我们可以让AI工具访问本地文件、数据库、API等资源,大大扩展其能力边界。目前已有越来越多的AI应用开始支持MCP协议,包括Claude、各种AI开发框架等。

解决方案设计

我的解决思路是开发一个轻量级的HTTP服务,作为Dify Workflow和MCP协议之间的桥梁:

AI工具 ←→ MCP协议 ←→ 我们的服务 ←→ Dify API ←→ Workflow

完整代码实现

"""
Dify Workflow转MCP工具的中间件服务

功能说明:
1. 将Dify平台的Workflow转换为符合MCP协议的工具
2. 支持多个Workflow并行服务,每个通过不同路径访问
3. 实现完整的MCP协议:初始化、工具列表、工具调用
4. 异步处理,支持高并发访问

架构设计:
AI工具 ←→ MCP协议 ←→ 本服务 ←→ Dify API ←→ Workflow

使用方法:
1. 修改get_config函数中的配置信息
2. 替换API_KEY为实际的Dify API密钥
3. 运行服务:python workflow_mcp_server.py
4. 在支持MCP的AI工具中配置服务地址
"""

from starlette.applications import Starlette
from starlette.routing import Mount
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
import uvicorn
import asyncio
import logging
import json
import requests

def get_config(workflowId):
    """
    获取Workflow配置信息

    参数说明:
    - name: 工具名称,会显示在AI工具中
    - prefix: 路径前缀,用于区分不同的workflow
    - tenantId: Dify租户ID
    - workflowId: Dify工作流ID
    - description: 工具描述,帮助AI理解工具用途

    注意:实际使用时应该从数据库或配置文件动态获取
    """
    return {
        "name": "资金存管知识库检索",
        "prefix": "04633c4f-8638-43a3-a02e-af23c29f821f",
        "tenantId": "04633c4f-8638-43a3-a02e-af23c29f821f",
        "workflowId": "WKFL-fa2bb193-3c2e-467f-ba39-5fc27ae4798a",
        "description": "调用知识库获取资金存管相关信息"
    }

def make_workflow_request(query, config):
    """
    调用Dify Workflow API

    参数:
    - query: 用户输入的查询内容
    - config: workflow配置信息

    返回:
    - Workflow执行结果
    """
    url = "https://dify.example.com/v1//workflow/run"
    payload = json.dumps({
        "tenantId": config['tenantId'],
        "workflowId": config['workflowId'],
        "inputs": {},
        "responseMode": "blocking",  # 阻塞模式,等待结果返回
        "userId": "1000123",
        "query": query
    })
    headers = {
        # 注意:这里需要替换为实际的API密钥
        'Authorization': 'Bearer ${API_KEY}',
        'Content-Type': 'application/json'
    }

    try:
        response = requests.post(url, headers=headers, data=payload)
        print(f"Dify API响应: {response.text}")
        return json.loads(response.text)['data']['outputs']
    except Exception as e:
        logger.error(f"调用Dify API失败: {e}")
        return response.text

async def handle_request(scope, receive, send):
    """
    处理HTTP请求的核心函数

    实现MCP协议的三个主要方法:
    1. initialize - 初始化握手
    2. tools/list - 返回可用工具列表
    3. tools/call - 执行工具调用
    """
    request = Request(scope, receive)
    path = request.url.path
    config = get_config(path)

    try:
        if scope["method"] == "POST":
            # 读取请求体
            body = b""
            more_body = True
            while more_body:
                message = await receive()
                body += message.get("body", b"")
                more_body = message.get("more_body", False)

            try:
                request_data = json.loads(body.decode())
                logger.info(f"收到MCP请求: {request_data}")

                # MCP协议处理 - 初始化
                if request_data.get("method") == "initialize":
                    """
                    MCP初始化握手
                    返回协议版本、服务能力和服务器信息
                    """
                    response_data = {
                        "jsonrpc": "2.0",
                        "id": request_data.get("id"),
                        "result": {
                            "protocolVersion": "2024-11-05",
                            "capabilities": {
                                "tools": {}  # 声明支持工具调用
                            },
                            "serverInfo": {
                                "name": config['name'],
                                "version": "1.0.0"
                            }
                        }
                    }
                    response = JSONResponse(response_data)
                    await response(scope, receive, send)
                    return

                # MCP协议处理 - 工具列表
                elif request_data.get("method") == "tools/list":
                    """
                    返回可用工具列表
                    每个工具包含名称、描述和输入参数schema
                    """
                    tools = [{
                        "name": config.get('name'),
                        "description": config['description'],
                        "inputSchema": {
                            'properties': {
                                'query': {
                                    'description': '用户输入', 
                                    'type': 'string'
                                }
                            }, 
                            'required': ['query'], 
                            'type': 'object'
                        }
                    }]

                    response_data = {
                        "jsonrpc": "2.0",
                        "id": request_data.get("id"),
                        "result": {"tools": tools}
                    }
                    response = JSONResponse(response_data)
                    await response(scope, receive, send)
                    return

                # MCP协议处理 - 工具调用
                elif request_data.get("method") == "tools/call":
                    """
                    执行工具调用
                    提取参数,调用Dify Workflow,返回结果
                    """
                    tool_name = request_data["params"]["name"]
                    arguments = request_data["params"].get("arguments", {})

                    # 调用Dify Workflow
                    result = make_workflow_request(arguments['query'], config)

                    response_data = {
                        "jsonrpc": "2.0",
                        "id": request_data.get("id"),
                        "result": {
                            "content": [
                                {
                                    "type": "text",
                                    "text": str(result)
                                }
                            ]
                        }
                    }
                    logger.info(f"工具调用结果: {result}")
                    response = JSONResponse(response_data)
                    await response(scope, receive, send)
                    return

            except json.JSONDecodeError:
                response = JSONResponse({"error": "Invalid JSON"}, status_code=400)
                await response(scope, receive, send)
                return

        # 默认GET请求响应,用于健康检查
        response = JSONResponse({
            "status": "MCP Server Running", 
            "prefix": config.get('prefix', ''),
            "service": "Dify Workflow to MCP Bridge"
        })
        await response(scope, receive, send)
        return

    except Exception as e:
        logger.error(f"处理请求时出错: {e}")
        response = Response("Internal Server Error", status_code=500)
        await response(scope, receive, send)

# 创建Starlette应用
app = Starlette(routes=[
    Mount("/", app=handle_request)
])

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

async def main():
    """
    启动服务器

    服务配置:
    - 端口:8081
    - 主机:0.0.0.0 (允许外部访问)
    - 访问地址示例:http://127.0.0.1:8081/04633c4f-8638-43a3-a02e-af23c29f821f
    """
    logger.info("正在启动Dify Workflow MCP服务器...")
    logger.info("服务端口: 8081")
    logger.info("访问地址: http://127.0.0.1:8081/04633c4f-8638-43a3-a02e-af23c29f821f")

    config = uvicorn.Config(
        app=app,
        host="0.0.0.0",
        port=8081,
        log_level="info",
        access_log=True
    )
    server = uvicorn.Server(config)
    await server.serve()

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("服务器已被用户停止")
    except Exception as e:
        logger.error(f"服务器错误: {e}")

使用方法

1. 配置修改

  • get_config函数中更新你的Workflow信息
  • 替换make_workflow_request中的${API_KEY}为实际的Dify API密钥
  • 根据需要修改Dify API地址

2. 启动服务

python workflow_mcp_server.py

3. 在AI工具中配置

{
  "mcpServers": {
    "dify-workflow": {
      "type": "streamableHttp",
      "url": "http://127.0.0.1:8081/04633c4f-8638-43a3-a02e-af23c29f821f" 
    }
  }
}

优势与效果

  1. 资产复用:直接复用现有Dify Workflow,无需重新构建
  2. 无缝集成:支持所有兼容MCP协议的AI工具
  3. 灵活扩展:可轻松添加多个Workflow支持
  4. 统一管理:工作流维护仍在Dify平台进行

总结

  在这个项目里,我做了一个转换工具,让公司现有 Dify 平台里的Workflow能够被其他支持 MCP 标准的应用调用。这解决了我们当前 Dify 版本的一个功能限制,让我们之前做好的工作流能继续发挥作用。其实,新版的 Dify 本身已经支持 MCP 标准了,那样集成会更方便。只是我们现在用的平台还没升级到新版本。所以,未来等平台升级了,我这个转换工具可能就用不着了。

  不过,做这个项目还是很有意义的:首先,它马上解决了我们眼下的问题,让工作流在新需求到来前就能投入使用。其次,动手做这个工具,让我对 MCP 标准具体是怎么运作的有了更深的了解,这对以后处理类似的技术对接肯定有帮助。对于其他团队,如果也遇到旧版 Dify 需要对接 MCP 应用的情况,这个方案可以作为一个临时的解决办法。另外,如果开发者想研究 MCP 标准的具体实现,我这个工具的代码也可以当作一个参考例子。