当前位置: 首页 > news >正文

别再手动查天气了!用Python和MCP给Claude做个专属天气助手(附完整代码)

打造智能天气助手:Python与MCP的无缝集成实战

每次出门前都要打开天气应用查看预报?在不同工具间反复切换查询天气信息?这种低效操作已经成为过去式。今天我们将用Python和MCP协议为Claude打造一个专属天气助手,让你直接通过对话获取精准天气信息。这个项目不仅适合Python中级开发者练手,更能让你深入理解AI助手的扩展机制。

1. 环境准备与项目初始化

在开始编码前,我们需要搭建好开发环境。这个天气助手项目基于Python 3.10+,使用MCP 1.2.0协议实现与Claude的通信。

核心依赖工具:

  • Python 3.10+(推荐使用pyenv管理多版本)
  • UV包管理器(替代pip的现代工具)
  • FastMCP框架(简化MCP服务器开发)
  • HTTPX库(异步HTTP客户端)
# 创建项目目录并初始化虚拟环境 mkdir weather_assistant && cd weather_assistant python -m venv .venv source .venv/bin/activate # Linux/Mac # .venv\Scripts\activate # Windows # 安装核心依赖 uv install "mcp[cli]" httpx python-dotenv

提示:建议使用.env文件管理API密钥等敏感信息,避免硬编码在代码中

项目结构设计遵循模块化原则:

weather_assistant/ ├── .env # 环境变量配置 ├── config.py # 配置文件 ├── services/ # 服务模块 │ ├── weather.py # 天气数据获取 │ └── mcp_server.py # MCP服务主文件 └── tools/ # 辅助工具 └── formatters.py # 数据格式化

2. MCP服务器核心架构设计

MCP(Model Context Protocol)协议的核心价值在于标准化AI模型与外部服务的交互方式。我们的天气服务器需要实现两个核心功能:

  1. 天气预报查询:根据经纬度获取未来5天预报
  2. 天气警报查询:按地区代码获取极端天气预警
# services/mcp_server.py from typing import Optional import httpx from mcp.server.fastmcp import FastMCP from config import settings from tools.formatters import format_forecast mcp = FastMCP("weather_assistant") @mcp.tool() async def get_forecast(lat: float, lon: float) -> str: """获取指定位置的天气预报""" async with httpx.AsyncClient() as client: try: response = await client.get( f"{settings.WEATHER_API}/forecast", params={"lat": lat, "lon": lon}, timeout=10.0 ) return format_forecast(response.json()) except httpx.RequestError: return "无法获取天气预报数据"

关键设计考量:

  • 异步IO处理避免阻塞主线程
  • 完善的错误处理机制
  • 数据格式化提升可读性
  • 类型注解增强代码可维护性

3. 天气数据获取与处理

我们选择心知天气API作为数据源,它提供全球范围的天气数据且支持中文响应。相比美国国家气象局(NWS)API,更适合国内开发者使用。

API响应示例:

{ "results": [{ "location": {"name": "北京"}, "daily": [{ "date": "2023-07-15", "text_day": "多云", "high": "32", "low": "25", "wind_direction": "东南风" }] }] }

数据处理函数需要将原始JSON转换为易读的自然语言:

# tools/formatters.py def format_forecast(data: dict) -> str: """格式化天气预报数据""" if not data.get('results'): return "未找到该位置的天气信息" location = data['results'][0]['location']['name'] daily = data['results'][0]['daily'][:5] # 取最近5天 forecast_lines = [f"{location}未来5天天气预报:"] for day in daily: forecast_lines.append( f"{day['date']}: {day['text_day']}, " f"气温{day['low']}~{day['high']}℃, " f"{day['wind_direction']}" ) return "\n".join(forecast_lines)

4. Claude客户端集成实战

完成服务器开发后,需要配置Claude桌面客户端识别我们的天气服务。不同操作系统的配置路径有所差异:

操作系统配置文件路径
macOS~/Library/Application Support/Claude/config.json
Windows%APPDATA%\Claude\config.json
Linux~/.config/claude/config.json

配置文件示例:

{ "mcpServers": { "weather": { "command": "python", "args": [ "-m", "uvicorn", "services.mcp_server:mcp", "--reload" ], "environment": { "WEATHER_API_KEY": "your_api_key_here" } } } }

常见集成问题排查:

  1. 服务未显示

    • 检查配置文件路径是否正确
    • 确认Claude版本支持MCP插件
    • 查看服务启动日志是否有错误
  2. 权限问题

    chmod +x services/mcp_server.py # 确保文件有执行权限
  3. 网络连接问题

    # 测试API连通性 async def test_connection(): async with httpx.AsyncClient() as client: try: await client.get("https://api.seniverse.com/v3") return True except httpx.ConnectError: return False

5. 功能扩展与优化思路

基础功能实现后,可以考虑以下增强功能:

5.1 多数据源容灾

async def get_weather_multi_sources(lat, lon): """从多个数据源获取天气,提高可靠性""" sources = [SeniverseAPI(), OpenWeatherMap(), AccuWeather()] for source in sources: try: return await source.get_forecast(lat, lon) except APIError: continue raise AllAPIsDownError()

5.2 天气缓存机制

from datetime import datetime, timedelta from cachetools import TTLCache weather_cache = TTLCache(maxsize=1000, ttl=timedelta(minutes=30)) async def get_forecast_with_cache(lat, lon): cache_key = f"{lat},{lon}" if cache_key in weather_cache: return weather_cache[cache_key] data = await get_weather(lat, lon) weather_cache[cache_key] = data return data

5.3 用户偏好记忆

user_preferences = { "user123": { "location": (39.9042, 116.4074), "units": "metric", "alerts_threshold": "orange" } } async def get_personalized_weather(user_id): prefs = user_preferences.get(user_id, {}) forecast = await get_forecast(*prefs.get('location', (0,0))) return adjust_units(forecast, prefs.get('units'))

6. 性能监控与日志记录

生产环境部署需要完善的监控体系:

# 监控装饰器示例 def monitor_performance(func): async def wrapper(*args, **kwargs): start = time.time() try: result = await func(*args, **kwargs) duration = time.time() - start log_metric(func.__name__, "success", duration) return result except Exception as e: log_metric(func.__name__, "failure", 0) raise e return wrapper # 应用监控 @monitor_performance @mcp.tool() async def get_alerts(region: str): # 原有实现...

日志配置建议:

import logging from logging.handlers import RotatingFileHandler logging.basicConfig( handlers=[ RotatingFileHandler('weather.log', maxBytes=1e6, backupCount=3), logging.StreamHandler() ], level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' )

7. 安全加固措施

对外提供服务必须考虑安全性:

7.1 输入验证

from pydantic import BaseModel, confloat class Coordinates(BaseModel): lat: confloat(ge=-90, le=90) lon: confloat(ge=-180, le=180) @mcp.tool() async def get_forecast(lat: float, lon: float): coords = Coordinates(lat=lat, lon=lon) # 处理逻辑...

7.2 API限流

from fastapi import Request from slowapi import Limiter from slowapi.util import get_remote_address limiter = Limiter(key_func=get_remote_address) @mcp.tool() @limiter.limit("10/minute") async def get_alerts(request: Request, region: str): # 实现...

7.3 敏感数据保护

import ssl from httpx import AsyncClient async with AsyncClient( verify=ssl.CERT_REQUIRED, timeout=10.0, limits=httpx.Limits(max_connections=100) ) as client: # 安全请求...

8. 实际应用场景演示

完成所有开发后,让我们看看如何在Claude中使用这个天气助手:

用户:上海明天会下雨吗? Claude: [调用天气助手] 上海明日天气预报: 2023-07-16: 雷阵雨转多云, 气温26~32℃, 东南风3-4级 建议携带雨具出门

高级查询示例:

用户:对比北京和广州未来三天的天气 Claude: [并行调用两地天气接口] 北京 vs 广州未来3天天气预报: 北京: 7/16: 晴, 28~35℃ 7/17: 多云, 27~34℃ 7/18: 雷阵雨, 26~32℃ 广州: 7/16: 暴雨, 25~29℃ 7/17: 中雨, 26~30℃ 7/18: 阵雨, 27~31℃

企业级应用场景:

  • 物流公司整合到运输调度系统
  • 外卖平台为骑手提供实时天气预警
  • 旅游APP的行程推荐引擎
  • 智能家居的自动化控制条件

开发这类AI扩展服务时,最常遇到的坑是异步IO的异常处理不完善导致服务假死。我在初期版本中就遇到过因为未设置HTTP超时,导致整个服务卡在某个外部API调用上的情况。现在所有外部调用都明确设置了超时限制,并添加了熔断机制,当连续失败达到阈值时会自动切换备用数据源。

http://www.cnnetsun.cn/news/1470941.html

相关文章:

  • oauth2-server-php自定义开发:如何扩展Grant Types和Response Types
  • ComfyUI-WanVideoWrapper技术解析:构建高效AI视频生成解决方案
  • SASM汇编语言IDE:终极免费解决方案,5分钟搞定汇编开发环境
  • C51单片机程序执行机制与LED异常现象解析
  • Cosmos-Reason1-7B在Git协作中的智能代码评审应用
  • ReasonReact部署最佳实践:从开发到生产的完整流程
  • 5分钟快速集成Material CalendarView:终极入门指南
  • Windows Community Toolkit终极指南:从零开始掌握UWP开发神器
  • 注册表编辑安全防护:PowerToys Registry Preview完全指南
  • 终极C反射操作指南:如何用Masuit.Tools快速掌握动态对象创建和属性操作技巧
  • SDMatte镜像定制化扩展指南:如何接入自有API、对接OSS存储与CDN分发
  • MicroNMEA:超轻量NMEA解析库,专为MCU低内存场景设计
  • 深入浅出Versal NoC:像理解计算机网络一样玩转AXI NoC与VD100开发板DDR4配置
  • Qwen-Image-2512-SDNQ与CNN结合:提升图像生成质量的技术实践
  • 2026-03-25 全国各地响应最快的 BT Tracker 服务器(联通版)
  • C++ WinPcap实战:从零构建网络抓包工具与协议解析引擎
  • QChart避坑指南:为什么你的悬停提示总是不灵敏?(附精准检测优化方案)
  • 突破Windows远程限制:RDP Wrapper多用户并发实战全攻略
  • WordPress建站新手必看:手把手教你用宝塔面板搞定子比主题Zibll 8.0的本地授权(附SSL证书配置)
  • 重装系统后快速恢复Ostrakon-VL-8B开发环境:依赖与配置备份指南
  • AI净界RMBG-1.4在电商场景的应用:主图换底、素材制作全搞定
  • 无线设备信号接收灵敏度 <-94dBm @ 1Mbps解析
  • 从零构建MCP兼容SDK:手写IDL解析器、自动生成Binding、动态ABI对齐——1个周末搞定3语言支持
  • Tweakly库:Arduino非阻塞实时控制与响应式编程框架
  • 执法资产处置漏洞下的域名劫持与加密货币钓鱼攻击研究
  • ESP32+MQTT阿里云+手机APP,实现智能家居控制
  • 11.2版本:使用Flow3D进行高能量密度下选区激光熔化(SLM)数值模拟与计算流体动力学(...
  • 论文合规双检新标杆:paperzz 查重系统,一站式破解本科毕业双重检测焦虑
  • 谷歌在其营销平台中新增了由 Gemini 驱动的人工智能工具
  • Stable Diffusion XL 1.0开源大模型应用:灵感画廊在数字策展中的落地