从零开发MCP插件:手把手实现AI天气助手工具
引言
如果你最近关注过AI工具生态,一定听说过MCP(Model Context Protocol)。这个由Anthropic推出的开放协议,为大语言模型和外部工具之间搭起了一座标准化的桥梁。借助MCP,AI助手不再只能依赖静态的训练数据,而可以实时调用你开发的插件——查询数据库、操作文件、访问API,甚至控制硬件设备。
本文将从零开始,带你一步步开发一个实用的MCP插件:一个天气查询工具。你将看到完整的Python代码、环境搭建过程以及调试技巧。读完本文,你不仅能拥有一个可运行的MCP服务器,还将理解MCP的核心概念,为开发更复杂的AI插件打下坚实基础。
所有代码均经过验证,可以直接复制运行。让我们现在开始。
核心概念:MCP的“三角关系”
在动手写代码之前,我们需要先理解MCP的体系结构。一个完整的MCP交互包含三个角色:
- MCP Host(宿主应用):例如Claude Desktop、VS Code插件等,这些应用内置了MCP客户端,负责与用户交互并调用工具。
- MCP Client(客户端):嵌入在Host中,负责与服务器建立连接、发送请求、接收结果。
- MCP Server(服务器/插件):我们即将开发的部分。它暴露一组工具(Tools)、资源(Resources)或提示(Prompts),供AI模型发现和调用。
在这个体系中,AI模型本身并不直接调用外部函数,而是通过以下流程:
- AI模型生成一个“工具调用”请求(包含函数名和参数),交给客户端。
- 客户端将此请求标准化,通过协议(stdio或SSE)发送给服务器。
- 服务器执行对应的Python函数,并把结果返回给客户端。
- 客户端将结果注入回模型的上下文中,模型据此生成最终回答。
因此,我们的工作就是实现一个MCP Server,定义一个或多个工具函数,并让它们能被AI安全地调用。
实战示例:开发天气查询MCP服务器
我们的目标是:当用户在Claude Desktop中询问“北京今天天气怎么样?”时,Claude能够自动调用我们的MCP插件,获取实时天气数据,并给出友好回答。
我们将使用FastMCP库,它是基于官方MCP SDK的高级封装,能极大简化服务器的创建。最终效果如下(在Claude Desktop中):
用户:杭州现在多少度?
Claude:[调用get_current_weather工具,参数:city="杭州"]
工具返回:杭州当前温度18°C,多云,湿度65%...
Claude:杭州现在的温度是18°C,多云,湿度65%,体感比较舒适。
1. 环境准备
首先确保你安装了Python 3.10+,然后创建项目并安装依赖:
mkdir mcp-weather-plugin cd mcp-weather-plugin python -m venv venv source venv/bin/activate # Windows用 venv\Scripts\activate pip install fastmcp==1.3.0 httpx python-dotenvhttpx用于异步HTTP请求,python-dotenv管理API密钥。我们将使用OpenWeatherMap的免费API,你需要先注册获取一个API key。当然,也可以换成任何其他天气API逻辑。
创建.env文件保存密钥:
OPENWEATHER_API_KEY=你的真实API密钥2. 编写工具函数
新建weather.py,定义获取天气的异步函数:
import os import httpx from dotenv import load_dotenv load_dotenv() # 加载 .env 文件 API_KEY = os.getenv("OPENWEATHER_API_KEY") BASE_URL = "https://api.openweathermap.org/data/2.5/weather" async def fetch_weather(city: str) -> dict: """使用OpenWeatherMap API获取当前天气""" if not API_KEY: return {"error": "未配置API密钥,请检查 .env 文件"} params = { "q": city, "appid": API_KEY, "units": "metric", # 摄氏度 "lang": "zh_cn" # 中文描述 } async with httpx.AsyncClient() as client: try: resp = await client.get(BASE_URL, params=params, timeout=10.0) resp.raise_for_status() data = resp.json() except httpx.HTTPStatusError as e: return {"error": f"API请求失败:{e.response.status_code}"} except Exception as e: return {"error": f"请求异常:{str(e)}"} # 提取我们需要的信息 try: description = data["weather"][0]["description"] temp = data["main"]["temp"] feels_like = data["main"]["feels_like"] humidity = data["main"]["humidity"] wind_speed = data["wind"]["speed"] city_name = data["name"] result = { "城市": city_name, "天气": description, "温度(℃)": temp, "体感温度(℃)": feels_like, "湿度(%)": humidity, "风速(m/s)": wind_speed } return result except KeyError: return {"error": "未找到该城市信息,请检查城市名称"}这段代码包含了错误处理和结构化输出,AI模型可以轻松提取其中的字段给用户。
3. 创建FastMCP服务器
新建server.py,使用FastMCP快速搭建服务器,并将上面的fetch_weather注册为工具:
#!/usr/bin/env python3 from fastmcp import FastMCP from weather import fetch_weather import json # 创建一个MCP服务器实例,命名为"Weather Assistant" mcp = FastMCP("Weather Assistant") # 注册工具:get_current_weather @mcp.tool() async def get_current_weather(city: str) -> str: """查询指定城市的实时天气情况 Args: city: 城市名称,支持中文或英文,例如 "北京" 或 "Beijing" """ weather_data = await fetch_weather(city) # 将字典转为格式化的JSON字符串,方便AI解析 return json.dumps(weather_data, ensure_ascii=False, indent=2) if __name__ == "__main__": # 以标准I/O方式启动服务器,这是桌面应用最常用的连接方式 mcp.run(transport="stdio")这就是完整的MCP服务器!让我们剖析一下关键点:
FastMCP("Weather Assistant"):实例化时指定服务器名称,客户端会以此标识插件。@mcp.tool()装饰器:将函数注册为MCP工具。函数名、参数列表和docstring自动成为工具的元数据,AI模型会据此理解工具的用途。- 工具函数必须异步,返回类型建议为
str,因为客户端与服务器之间传递的是文本。我们使用json.dumps将字典序列化。 mcp.run(transport="stdio"):启动一个基于标准输入输出的服务器,这是MCP最常见的传输方式,Claude Desktop、Cursor等客户端支持通过stdio与子进程通信。
4. 配置Claude Desktop使用插件
启动服务器只是第一步,我们还需要让Claude Desktop知道它。编辑(或创建)Claude Desktop的配置文件:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
添加如下配置项:
{ "mcpServers": { "weather": { "command": "python", "args": ["/完整路径/mcp-weather-plugin/server.py"], "env": { "OPENWEATHER_API_KEY": "你的API密钥" } } } }注意:command可以指定为虚拟环境中的Python解释器,例如"venv/bin/python"。env中直接注入环境变量,避免依赖.env文件。保存后完全退出并重启Claude Desktop。
检查是否成功:打开Claude Desktop,点击输入框左侧的🔌图标(或直接输入斜线/),你应该能看到可用的工具get_current_weather。如果出现,说明插件已加载成功。
5. 测试与交互
现在向Claude提问:“帮我查一下深圳现在的天气”,Claude会自动判断需要调用工具,并生成如下调用:
Tool: get_current_weather Arguments: {"city": "深圳"}我们的服务器会执行函数,返回类似:
{ "城市": "深圳", "天气": "多云", "温度(℃)": 26.1, "体感温度(℃)": 27.3, "湿度(%)": 78, "风速(m/s)": 3.2 }Claude据此回答:“深圳当前多云,气温26.1摄氏度,体感温度27.3度,湿度78%,风速3.2米每秒,出门记得带伞哦~”
你也可以测试未配置API密钥时的错误情况,会看到工具返回{"error": ...},Claude会友好地提示用户检查配置。
常见问题与注意事项
1. 服务器启动失败或工具不显示
- 检查
claude_desktop_config.json路径和格式是否正确,JSON必须合法。 - 确保Python环境中有
fastmcp及其依赖。最稳妥的方式是使用虚拟环境并指定完整Python路径。 - 查看Claude Desktop的开发者控制台(macOS:
Cmd+Option+I),Console面板会显示服务器连接错误日志。 - 常见问题:Windows下路径分隔符需使用双反斜杠或正斜杠。
2. 传输方式选择
stdio:适合本地子进程,Claude Desktop、Continue等客户端采用这种方式。配置简单,无需网络。SSE(Server-Sent Events):适用于远程服务器或多人共享的工具。需要监听HTTP端点。FastMCP也支持,只需将transport改为"sse"并指定端口。本文为简化演示使用stdio。
3. 安全与最佳实践
- 不要在代码中硬编码API密钥,使用环境变量或配置文件注入。
- 做好输入校验:我们的
city参数直接传入API,虽然天气服务无害,但其他工具(如数据库操作)要防止注入。 - 工具函数应设计为幂等且无副作用,除非明确需要写操作。
- 返回信息要结构化(JSON),方便AI模型解析,同时对用户友好。
4. 调试工具
除了依赖Claude Desktop的日志,还可以使用官方的mcpCLI工具进行独立测试。安装pip install mcp,然后运行:
mcp dev server.py这会启动一个交互式的校验器,你可以在命令行中模拟客户端调用工具,查看返回值。
5. 扩展思路
学会了天气查询,你可以举一反三:
- 写一个文件管理插件,让AI读写本地文件。
- 对接数据库,用自然语言进行SQL查询。
- 连接智能家居API,实现语音控制家电。
FastMCP还支持资源(提供文件内容、数据库表结构等上下文)和提示(可复用的对话模板),让你的插件功能更加立体。
总结
本文我们从零开始,完整实现了一个MCP天气查询插件。核心步骤包括:理解MCP的三层架构、用FastMCP编写工具函数、配置Claude Desktop作为宿主、以及调试排错。你收获的不仅仅是一个天气工具,更是一套开发任何MCP插件的通用流程。
MCP正在快速成长为AI应用的“USB-C接口”,它让各类工具和模型能够即插即用。现在就开始构建你的第一个MCP插件吧,让AI助手真正能为你做事。
完整代码已经准备好,你可以直接克隆这个GitHub仓库(替换为实际链接)或复制文中的代码动手实践。有任何问题欢迎在评论区交流,我会尽量回复。
写作不易,如果文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续分享的最大动力。