用 FastMCP 封装和风天气 API:一个简单的 MCP 服务获取实践

发布时间:2026/10/12 20:53:51

用 FastMCP 封装和风天气 API:一个简单的 MCP 服务获取实践 1. 从零跑通和风天气 MCP为什么值得折腾和风天气 API 本身不复杂一个 GET 请求就能拿到实时天气。但当你把它接进 Claude Code、Cline 或者自己写的 Agent 时问题就来了AI 工具不认识你的 Python 函数它只认 MCP 协议暴露出来的工具。FastMCP 就是干这个的——把普通函数包装成 MCP 工具让模型能像调用内置能力一样调用你的天气查询。这篇要解决的核心检索词是「和风天气 MCP 服务 FastMCP 封装」。简单说就是让你本地跑一个 MCP ServerAI 客户端连上之后直接问「北京现在天气怎么样」就能拿到结构化结果。适合谁适合正在做本地开发、个人项目、想给 AI 助手加实时数据能力的同学。不需要你懂 MCP 协议细节FastMCP 把装饰器一贴工具就注册好了。我试过的场景是这样的在 Claude Code 里配置好 MCP Server 地址然后让它查天气它会自动调用get_weather工具返回城市、天气现象、温度、湿度。整个过程你只负责写一个几十行的 Python 文件剩下的交给 FastMCP 和 MCP 客户端。这里有个关键点容易被忽略和风天气的 API 需要 Key而 Key 的管理如果散落在各个项目里后期维护很痛苦。所以我会把鉴权通道统一走 TaoToken这样 Base URL、Key、Model ID 三件套集中管理换项目时不用到处改配置。下面从环境准备开始一步步把服务跑起来。2. TaoToken 前置准备统一 Key 与 API 通道在写代码之前先把鉴权通道理清楚。和风天气的 Key 你可以直接在官网申请但如果你同时还在用其他模型 API建议把通道统一到 TaoToken 管理。它的作用是给你一个统一的 API 入口Key 和 Base URL 集中配置MCP 服务里读环境变量就行不用硬编码。你需要准备三样东西Base URL、API Key、Model ID。这三件套在 TaoToken 控制台都能拿到。具体路径是登录后进控制台在 API Keys 页面创建 Key然后复制 Base URL。Model ID 根据你实际调用的模型填比如做天气查询这种工具调用场景选一个支持 function calling 的模型即可。配置方式我推荐用环境变量避免把 Key 写进代码提交到仓库。你可以在项目根目录建一个.env文件TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_API_KEY你的Key TAOTOKEN_MODEL_ID你的模型ID HEFENG_API_KEY你的和风天气Key HEFENG_HOST你的和风天气API Host注意和风天气的 Host 不是固定的api.heweather.net新版控制台会给你分配专属 Host这个必须从控制台复制用错了会返回 401 或者 403。我踩过的坑就是直接用了文档里的示例域名结果一直报鉴权失败换成控制台里的专属 Host 才通。如果你还没创建 Key可以先去控制台把 Key 建好顺手把接入文档看一遍里面写了不同语言的调用示例。对于 MCP 服务来说你只需要保证 Python 进程能读到这几个环境变量就行。用python-dotenv加载.env是最省事的做法from dotenv import load_dotenv import os load_dotenv() HEFENG_API_KEY os.getenv(HEFENG_API_KEY) HEFENG_HOST os.getenv(HEFENG_HOST)这样代码里不出现明文 Key换环境时只改.env。TaoToken 的通道管理也是同理Base URL 和 Key 都从环境变量读MCP 服务本身不关心你用的是哪个模型它只负责把工具暴露出去。3. 可复制配置FastMCP 服务端与工具函数注册现在进入核心部分。先装依赖pip install fastmcp requests python-dotenv然后建一个weather_mcp.py完整代码如下。这段代码可以直接复制运行只需要改.env里的值。import csv import os import requests from fastmcp import FastMCP from dotenv import load_dotenv load_dotenv() HEFENG_API_KEY os.getenv(HEFENG_API_KEY) HEFENG_HOST os.getenv(HEFENG_HOST) weather FastMCP(search_weather) CITY_CSV_PATH China-City-List-latest.csv def load_city_map(): city_map {} with open(CITY_CSV_PATH, rt, encodingutf-8) as f: reader csv.reader(f) for row in reader: if len(row) 2: city_map[row[1].strip()] row[0].strip() return city_map CITY_MAP load_city_map() weather.tool() def get_weather(city: str) - str: 查询指定城市的实时天气。city 传中文城市名例如 北京、上海。 city city.strip() location_id CITY_MAP.get(city) if not location_id: return f城市未找到{city} url fhttps://{HEFENG_HOST}/v7/weather/now params { location: location_id, key: HEFENG_API_KEY, } try: resp requests.get(url, paramsparams, timeout10) data resp.json() now data[now] return ( f{city} 天气{now[text]} f温度{now[temp]}℃ f湿度{now[humidity]}% ) except Exception as e: return f获取失败{e} if __name__ __main__: weather.run(transportsse, host0.0.0.0, port9080)几个关键点说明。第一城市 ID 映射我改成了启动时加载一次而不是每次查询都读 CSV这样并发请求时不会反复开文件。第二weather.tool()装饰器把get_weather注册成 MCP 工具函数签名和 docstring 会被 MCP 客户端读取所以 docstring 要写清楚参数含义模型靠这个决定怎么传参。第三传输方式用 SSE端口 9080这样 MCP 客户端可以通过 HTTP 连过来。城市列表 CSV 从 GitHub 上的 LocationList 仓库下载放到项目根目录文件名保持China-City-List-latest.csv。这个文件里第一列是 Location ID第二列是城市名我的load_city_map就是按这个结构解析的。如果你用的是 Claude CodeMCP 配置写在settings.json里路径和原文一致{ mcpServers: { weather: { url: http://127.0.0.1:9080/sse } } }Cline 的 MCP 配置类似在 MCP Servers 面板里填 URL 就行。Codex 的话auth.json里配好 Base URL 和 KeyMCP 部分单独在配置文件里指向 SSE 地址。三件套Base URL、Key、Model ID在 TaoToken 控制台拿MCP 服务本身不直接调模型所以 Model ID 是给客户端用的。4. 验证请求从启动服务到拿到天气结果服务写好了先本地启动python weather_mcp.py看到类似Uvicorn running on http://0.0.0.0:9080的输出就说明 SSE 服务起来了。这时候别急着连客户端先用 curl 验证一下 MCP 端点是否可达curl -N http://127.0.0.1:9080/sse正常会返回一串 SSE 事件流包含event: endpoint之类的信息。如果连接被拒绝检查端口是否被占用或者防火墙是否拦了 9080。接下来在 MCP 客户端里测试。以 Claude Code 为例配置好settings.json后重启然后输入「查一下北京现在的天气」。客户端会调用get_weather工具传参{city: 北京}服务端返回类似北京 天气晴 温度26℃ 湿度45%如果返回「城市未找到」说明 CSV 里没有匹配到该城市名。你可以打开 CSV 确认一下有些城市在列表里是「北京市」而不是「北京」这时候要么改传参要么在load_city_map里做一次别名映射。验证模型通道是否正常可以单独发一个请求到 TaoToken 的模型对话接口确认 Base URL 和 Key 没问题。这一步和 MCP 服务是独立的但建议做一次避免后面排查时分不清是 MCP 的问题还是鉴权的问题。实测下来整个链路跑通后查询延迟在 300ms 到 800ms 之间主要取决于和风天气 API 的响应速度。SSE 长连接保持住之后后续调用不需要重新建连体验比较顺。5. 常见报错排查401、local proxy failed 与 choices 读取失败这一节列几个真实遇到过的报错和排查思路。401 Unauthorized最常见。先确认HEFENG_API_KEY是否正确然后确认HEFENG_HOST是不是控制台里的专属 Host。很多人直接用api.heweather.net这个在新版控制台里已经不对了。另外检查 Key 是否过期和风天气的 Key 有有效期过期后需要重新生成。local proxy failed这个通常出现在 MCP 客户端连接 SSE 端点时。原因可能是服务没启动或者端口不对。先curl一下http://127.0.0.1:9080/sse如果本地能通但客户端报这个错检查客户端配置里的 URL 是不是写成了localhost而服务绑定的是0.0.0.0有些环境里localhost解析有问题换成127.0.0.1试试。reading choices 失败这个报错一般出现在模型调用环节不是 MCP 服务本身。说明客户端在解析模型返回的choices字段时出错。排查方向是检查 TaoToken 的 Base URL 是否带上了正确的路径以及 Model ID 是否填对。如果 Base URL 少了/v1或者多了斜杠都可能导致返回结构异常。OAuth 相关报错如果你在客户端里配了 OAuth 鉴权但 MCP 服务本身没做 OAuth会报这个。MCP 的 SSE 端点默认不需要 OAuth把客户端里的 OAuth 配置去掉直接用 URL 连接即可。城市 ID 匹配失败CSV 文件路径不对或者编码不是 UTF-8。确认文件在项目根目录且用encodingutf-8打开。如果 CSV 里有 BOM 头第一列会带\ufeff可以在读取时用utf-8-sig编码。排查顺序建议先确认服务启动 → curl 验证 SSE → 客户端连上 → 调用工具 → 检查返回。每一步单独验证不要跳步。6. 把天气 MCP 接进你的工作流服务跑通之后你可以把它常驻在本地作为 AI 助手的实时数据源。启动命令可以写成 systemd 服务或者用nohup挂后台nohup python weather_mcp.py weather_mcp.log 21 这样关掉终端也不会断。日志里能看到每次工具调用的记录方便排查。如果你想让 MCP 服务更稳可以在get_weather里加一层缓存比如用functools.lru_cache或者简单的字典缓存避免短时间内重复请求和风天气 API。和风天气的免费额度有限缓存能省不少调用量。另外TaoToken 的 Coding Plan 适合长期跑 Agent 的场景如果你打算把天气查询和其他工具串起来做自动化可以考虑把通道统一到 Coding Plan 管理。模型对话接口可以用来单独测试模型是否正常响应接入文档里有各语言的示例API Keys 页面管理你的 Key。最后一步把.env加入.gitignore别把 Key 提交上去。服务端代码可以开源配置自己留着。这样一套下来你就有个能随时问天气的 MCP 服务了。
延伸阅读

更多相关文章

2026/10/12 20:48:49

从零搭建音视频通话:为什么我选实时音视频SDK而非自研

1. 从零搭建一个可用的音视频通话:为什么我选了实时音视频SDK而不是自研做音视频通话这件事,听起来好像就是“打开摄像头、采集麦克风、编码、推流、拉流、解码、播放”这么一条链路,但真正动过手的人都知道,这条链路上随便一个环…

2026/10/12 20:48:49

从零手写Huffman编码:设计、实现与避坑指南

1. 从一个压缩场景说起:为什么还要手写Huffman前阵子帮一个做嵌入式日志系统的朋友看代码,他们设备端每天要往Flash里写几十万条运行日志,存储芯片容量有限,日志又不能随便丢,于是想在写入前做一层无损压缩。他一开始想…

2026/10/12 20:48:49

S/4HANA 1909实操指南:从安装、升级到Fiori与HANA调优

简介:面向SAP实施顾问、企业财务负责人及信息化决策者,这份PDF资料围绕S/4HANA本地部署版1909的联合企业会计(JVA)模块,系统梳理了其功能全景、演进路线与实施要点。内容依托石油天然气等行业的联合经营场景&#xff0…

2026/10/12 22:09:29

在Coding Agent外挂一层快速决策层:Jev调度Claude Code与Codex的工程实践

1. 为什么要在 Coding Agent 外面再套一层决策层1.1 从两个真实痛点说起先说一个我踩过的坑。去年有一段时间,我同时用两个 Coding Agent 处理日常开发任务:一个负责偏工程化的重构和脚本生成,另一个负责偏探索性的代码理解和方案推演。用着用…

2026/10/12 22:09:29

workbuddy-to-dsh 实战:协作数据转换结构化格式的完整指南

1. 从零上手 workbuddy-to-dsh:这个工具到底解决什么问题第一次看到 workbuddy-to-dsh 这个名字,很多人会以为是某个小众的命令行玩具。实际上,它是一套把「工作协同数据」转换成「结构化数据交换格式」的桥接方案,核心作用就一句…

2026/10/12 22:09:29

支付宝已开放Scheme大全:移动开发者的唤起清单与实战指南

简介:面向移动端开发者的支付宝scheme汇总,整理自支付宝APK的预装应用信息,覆盖大量已开放的跳转规则。通过替换URL中的saId参数,可直达扫一扫、蚂蚁森林等指定功能,省去手动查找页面入口的步骤,适用于快捷…

2026/10/12 22:04:29

C语言单链表实战:从内存管理到工程化实现

1. 项目概述:为什么单链表是C语言学习绕不开的“成人礼”单链表不是教科书里一个冷冰冰的数据结构名词,它是C语言开发者真正开始“和内存对话”的第一个实战关口。我带过不少刚学完语法基础的学员,一上来就写printf("Hello World")…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/12 0:04:22

绝缘子缺陷检测数据集清洗与工业级训练实战指南

简介:本资源是面向电力AI研发人员、工业视觉工程师及智能巡检系统开发者的绝缘子缺陷检测专用YOLO格式数据集,解决无人机航拍场景下绝缘子破损、污闪、积雪等9类典型缺陷的精准识别与定位难题。数据集共2139张真实巡检图像(含训练/验证/测试集…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑