weather-mcp
weather-mcp 是一个独立的 Capability Service(能力服务),对外提供“天气查询”这一 MCP 能力。
为什么要拆成 weather-mcp
在已有后台系统中:
admin:唯一的用户与认证来源(登录、签发 Token、/api/v1/auth/me)weather-mcp:只负责能力提供,不做用户系统
拆分的目标:
清晰边界:避免多套用户体系
能力可复用:MCP 层独立于 HTTP,可被编排/复用
可演进:未来接入更多 MCP(空气质量/预报/第三方数据源)
与 admin 的关系(文字关系图)
Client ->
weather-mcp:携带Authorization: Bearer <JWT>weather-mcp:验证 Token 是否可信(第一版为本地 HS256 验签)admin:身份真实性与用户语义的权威来源
鉴权设计
第一版采用 方案 A:本地 HS256 验签(与 admin 使用同一套 SECRET_KEY)。
Header 读取:
Authorization: Bearer <token>解析规则:
算法:HS256
sub:user_id不依赖
roles/scopes
工程化要求:
鉴权逻辑在
app/core/auth/与app/auth_client/中API 层通过
Depends(get_auth_context)获取AuthContexthandler 不直接处理 token、不写鉴权逻辑
可替换性:
通过
WEATHER_MCP_AUTH_MODE切换local_jwt:本地验签admin_introspect:调用 admin 的GET /api/v1/auth/me(已预留实现)
MCP 设计理念
MCP 是独立于 HTTP 的“能力协议层”:
输入输出是结构化 DTO(Pydantic Model)
不依赖 FastAPI
Request易于单测与复用
目录:
app/mcp/:MCP 抽象与实现(例如WeatherMCP)app/schemas/:MCP 输入输出结构(与 HTTP 无关)app/api/:HTTP API 层(校验/鉴权/调用 MCP)
运行
依赖
使用 uv 管理依赖:
uv sync
环境变量
WEATHER_MCP_SECRET_KEY:与 admin 一致的 HS256 对称密钥WEATHER_MCP_AUTH_MODE:默认local_jwt
和风天气(QWeather)Web API:
WEATHER_MCP_QWEATHER_API_HOST:你的 QWeather API Host(在 QWeather Console -> Setting 查看)WEATHER_MCP_QWEATHER_API_KEY:你的 QWeather API Key(务必只放在环境变量/密钥管理中)WEATHER_MCP_QWEATHER_TIMEOUT_SECONDS:HTTP 超时(秒)
启动
uv run uvicorn app.main:app --reload --port 9001
API
GET /health
MCP 能力:实时天气(Current Weather)
本服务通过 QWeather GET /v7/weather/now 提供实时天气能力,并将返回结构映射成统一的 MCP 输出。
1) MCP 直连路由(兼容/调试)
GET /mcp/weather?location=...&lang=...&unit=m|i
说明:
location支持多种输入形式(统一为一个字符串参数):城市名称(例如
北京/Beijing)经纬度(格式
longitude,latitude,例如116.41,39.92)Location ID(和风天气城市码,例如
101010100)
lang:天气描述语言(默认zh,例如返回多云)unit:单位(m=metric,i=imperial;默认m)
城市名解析策略:
当
location不是纯数字(LocationID)且不是lon,lat时,会先调用 QWeather GeoAPIGET /geo/v2/city/lookup做解析,取 Top-1 结果。解析时会使用英文
geo_lang=en获取标准化地点名称(例如输出Beijing),而天气接口仍使用lang=zh以保证天气状态中文显示。
2) Tool 路由(推荐对外使用)
POST /tools/weather.current
请求示例:
返回示例:
字段映射说明(QWeather -> MCP):
now.obsTime->observed_atnow.temp->temperaturenow.text->conditionnow.humidity->humiditynow.windSpeed->wind_speednow.windDir->wind_dir完整原始响应 ->
raw
错误处理(HTTP 层):
401:缺少/无效 JWT(由
get_auth_context处理)500:服务端缺少 QWeather 配置(host/key)
400:无效地点(上游返回 400/404)
429:上游限流
502:上游网络或权限问题(QWeather 返回 401/403 等)
MCP 能力:每日天气预报(Daily Forecast)
本服务通过 QWeather GET /v7/weather/{days} 提供每日天气预报能力,并将返回结构映射成统一的 MCP 输出。
Tool 路由
POST /tools/weather.forecast.daily
请求示例:
参数说明:
location:城市名称 /lon,lat/ LocationIDdays:仅支持3|7|10|15(对应上游3d/7d/10d/15d)lang:天气描述语言(默认zh)unit:单位(m=metric,i=imperial;默认m)
返回示例:
字段映射说明(QWeather -> MCP):
daily.fxDate->forecasts[].datedaily.tempMax->forecasts[].temp_maxdaily.tempMin->forecasts[].temp_mindaily.textDay->forecasts[].condition_daydaily.textNight->forecasts[].condition_nightdaily.humidity->forecasts[].humiditydaily.windSpeedDay->forecasts[].wind_speeddaily.windDirDay->forecasts[].wind_dir完整原始响应 ->
raw
MCP 能力:每小时天气预报(Hourly Forecast)
本服务通过 QWeather GET /v7/weather/{hours} 提供每小时天气预报能力,并将返回结构映射成统一的 MCP 输出。
Tool 路由
POST /tools/weather.forecast.hourly
请求示例:
参数说明:
location:城市名称 /lon,lat/ LocationIDhours:仅支持24|72|168(对应上游24h/72h/168h)lang:天气描述语言(默认zh)unit:单位(m=metric,i=imperial;默认m)
返回示例:
字段映射说明(QWeather -> MCP):
hourly.fxTime->hourly[].timehourly.temp->hourly[].temperaturehourly.text->hourly[].conditionhourly.windSpeed->hourly[].wind_speedhourly.windDir->hourly[].wind_dirhourly.humidity->hourly[].humidity完整原始响应 ->
raw
MCP 能力:空气质量(Current Air Quality)
本服务通过 QWeather Air Quality v1 GET /airquality/v1/current/{latitude}/{longitude} 提供空气质量能力。
说明:
该能力需要经纬度。若传入的是城市名或 LocationID,会先调用 GeoAPI 获取
lat/lon。
Tool 路由
POST /tools/air_quality.current
请求示例:
返回示例:
字段映射说明(QWeather -> MCP):
indexes[0].aqi->aqi(优先选择code=us-epa)indexes[0].category->categoryindexes[0].primaryPollutant.name(或.code)->primary_pollutantpollutants[].concentration.value(按code匹配)->pm2p5/pm10/o3/no2/so2/co完整原始响应 ->
raw
MCP 能力:极端天气预警(Weather Alerts)
本服务通过 QWeather GET /v7/warning/now 提供天气预警能力。
说明:
QWeather 文档中标注该接口为“弃用”,但目前仍可按现有返回结构使用。
当查询地区当前没有预警信息时,上游返回
warning=[],本服务返回alerts=[]。
Tool 路由
POST /tools/weather.alerts
请求示例:
返回示例:
字段映射说明(QWeather -> MCP):
warning.typeName(或warning.type)->alerts[].typewarning.severityColor(或warning.severity)->alerts[].levelwarning.title->alerts[].titlewarning.text->alerts[].descriptionwarning.startTime->alerts[].startwarning.endTime->alerts[].end完整原始响应 ->
raw
测试
依赖由 uv 管理,推荐直接运行:
uv run pytest -q
后续演进方向
多 MCP:
AirQualityMCP、ForecastMCPMCP 编排:一个请求触发多个 MCP,或链式执行
内部 RPC / Agent 化:HTTP 之外的复用入口
可观测性:日志/trace、限流、缓存与熔断