目录
- MCP 是什么
- Dify 作为 Client:调用外部 MCP 工具
- 搭建 MCP 天气服务端
- 在 Dify 中接入“天气感知”能力
- Dify 作为 Server:被外部应用调用
- 搭建“翻译专家”工作流
- 启用 MCP 服务
- 在外部 AI 应用中调用
在之前的博客中已经介绍了 MCP 的概念,以及在 LangChain 中如何使用 MCP 协议。今天这篇博客,将带大家实战如何在 Dify 中实现 MCP 场景。在开始正式的内容前,还是先简单的介绍一下 MCP。
MCP 是什么
想象一下,你想要构建一个超级 AI 助手,它不仅能陪你聊天,还能帮你查询实时天气、读取本地数据库里的库存信息等。为了实现这些功能,在过去,你需要为每一个外部工具编写特定的“适配器”。AI 模型本该是通用的智能大脑,但连接外部世界(工具和数据)的方式却极其割裂和破碎,需要花费大量时间在“对齐接口”这种低效的重复劳动上,MCP 协议应运而生。可以把 MCP 想象成 AI 世界的 USB 接口。USB 的出现改变了一切,它提供了一个统一的标准:无论你是鼠标、键盘还是 U 盘,只要符合 USB 协议,插上就能用。MCP 就是要成为 AI 与外部数据/工具连接的 USB 标准。它将世界分成了两端:
- Host (主机端):需要使用工具的 AI 应用,比如 Claude Desktop 客户端、Dify。
- Server (服务端):提供特定能力的工具,比如一个能查天气的 Python 脚本,或者一个连接 MySQL 数据库的服务。
只要 Host 和 Server 都支持 MCP 协议,它们就能瞬间“握手”成功,Host 能够自动理解 Server 提供了什么工具,需要什么参数,而无需人工再去编写复杂的接口定义。
Dify 在 MCP 的生态中,它既可以是“插U盘的主机”,也可以是“被别人插的U盘”。
- Dify 作为 Client (主机端):调用外部能力。
- Dify 作为 Server (服务端):暴露自身能力。 这可能是更有趣的一点,比如在 Dify 里精心编排了一个复杂的工作流,这个工作流本身可以被封装成一个标准的 MCP 工具。这意味着,在其他 AI 应用中,可以直接调用在 Dify 里搭建好的这个强大的 Agent。
Dify 作为 Client:调用外部 MCP 工具
在这一部分,想让 Dify 的 AI 助手拥有“感知”当下天气的能力,而不是在那胡诌过去的训练数据。即将 Dify 作为一个“主机”,让它去连接一个 MCP Server。
搭建 MCP 天气服务端
首先,需要一个能够“说” MCP 协议的服务端。这里用到了 Python 的 mcp 库。创建一个 Python 文件 weather_server.py 实现天气查询的 MCP 服务,不需要手写复杂的协议握手代码,只需要用几个简单的装饰器即可。使用免费的 Open-Meteo API 进行天气查询。
[code]import httpxfrom mcp.server.fastmcp import FastMCP# 初始化 FastMCP 服务器mcp = FastMCP("Weather Service", host="0.0.0.0", port=8000)async def _get_lat_long(city_name: str): """ 内部辅助函数:使用 Open-Meteo Geocoding API 将城市名称转换为经纬度。 """ url = "https://geocoding-api.open-meteo.com/v1/search" params = {"name": city_name, "count": 1, "language": "zh", "format": "json"} async with httpx.AsyncClient() as client: response = await client.get(url, params=params) data = response.json() if not data.get("results"): return None location = data["results"][0] return { "name": location["name"], "latitude": location["latitude"], "longitude": location["longitude"], "timezone": location.get("timezone", "UTC") }@mcp.tool()async def get_weather(city_name: str) -> str: """ 获取指定城市的当前天气情况。 输入城市名称(如 'Beijing', 'San Francisco', '上海'),返回温度、风速等信息。 """ # 1. 首先获取经纬度 location = await _get_lat_long(city_name) if not location: return f"错误:未找到城市 '{city_name}'。请尝试使用更具体的名称或英文名称。" # 2. 构建 Open-Meteo API 请求 url = "https://api.open-meteo.com/v1/forecast" params = { "latitude": location["latitude"], "longitude": location["longitude"], "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m"], "timezone": location["timezone"] } async with httpx.AsyncClient() as client: response = await client.get(url, params=params) weather_data = response.json() # 3. 解析并返回数据 current = weather_data.get("current", {}) units = weather_data.get("current_units", {}) # 将天气代码 (WMO Code) 转换为文字描述 (简化版) weather_code = current.get("weather_code") weather_desc = "未知" if weather_code == 0: weather_desc = "晴朗" elif weather_code in [1, 2, 3]: weather_desc = "多云/阴" elif weather_code in [45, 48]: weather_desc = "有雾" elif 51 |