weather-taipei
README.md
# 台北市中山區 天氣回報 MCP Server
> A simple **MCP (Model Context Protocol) server** that reports the weather for
> Zhongshan District, Taipei, Taiwan — adapted from the official MCP tutorial,
> but using the free, key-less, global **Open-Meteo API** so it works outside the US.
這是一個 **MCP 天氣伺服器**:裝到 Claude 桌面版(或其他 MCP 客戶端)後,你用中文問
「中山區現在天氣如何?」、「未來三天會下雨嗎?」,AI 就會自動呼叫這個伺服器回報。
本專案改寫自 MCP 官方教學 [Build an MCP server](https://modelcontextprotocol.io/docs/develop/build-server)。
官方範例用美國國家氣象局 API(只能查美國),本專案改用 **Open-Meteo**(免費、免申請
金鑰、支援全球),因此可以查到台灣的天氣。
---
## 什麼是 MCP?
MCP(Model Context Protocol)是一套讓 AI 助理能「呼叫外部工具」的標準。
你可以把 MCP server 想成幫 AI 裝的**外掛**:AI 本身不會查天氣,但透過這個外掛,
它就能去 Open-Meteo 拿即時天氣資料回來給你。
一個 MCP server 可提供三種能力,本專案聚焦在 **Tools(工具)**:
| 能力 | 說明 |
|------|------|
| Tools | 可被 AI 呼叫的函式(需使用者同意)← 本專案使用 |
| Resources | 可被讀取的類檔案資料 |
| Prompts | 預先寫好的提示樣板 |
---
## 架構示意圖
整體運作流程:你用自然語言問 Claude,Claude 透過 MCP 協定呼叫本伺服器的工具,
伺服器再去 Open-Meteo 拿即時資料,格式化後一路回傳給你。
```mermaid
flowchart LR
U(["👤 使用者"]) -->|"問:中山區會下雨嗎?"| C["Claude 桌面版<br/>(MCP Host)"]
C -->|"回答"| U
C <-->|"MCP 協定 / stdio"| S
subgraph S ["weather-taipei MCP Server"]
direction TB
T1["get_zhongshan_weather<br/>中山區天氣"]
T2["get_weather_by_city<br/>各縣市天氣"]
T3["get_weather_by_coords<br/>經緯度天氣"]
T4["get_hourly_rain<br/>逐小時降雨"]
end
S -->|"HTTPS 查詢"| A[("🌤️ Open-Meteo API")]
A -->|"天氣 JSON"| S
```
> GitHub 會自動把上面的 `mermaid` 區塊渲染成圖。若在不支援 Mermaid 的檢視器,
> 它會以文字方式呈現,內容一樣看得懂。
---
## 提供的工具(Tools)
| 工具名稱 | 參數 | 功能 |
|----------|------|------|
| `get_zhongshan_weather` | 無 | 回報台北市中山區「目前天氣」+「未來 3 天預報」 |
| `get_weather_by_city` | `city` | 用**台灣縣市名稱**查天氣(台北、台中、高雄、宜蘭…,支援關鍵字) |
| `get_weather_by_coords` | `latitude`, `longitude` | 依經緯度查任一地點的天氣+未來 3 天預報 |
| `get_hourly_rain` | `city`, `hours` | **逐小時降雨**:未來數小時(1~48)的雨量與降雨機率 |
回報內容包含:天氣狀況(中文)、溫度、體感溫度、相對濕度、降雨量、風速,
以及未來三天的高低溫與降雨機率;逐小時降雨則列出每小時的雨量與降雨機率。
支援的縣市:台北市中山區、台北市、新北市、基隆市、桃園市、新竹市/縣、苗栗縣、
台中市、彰化縣、南投縣、雲林縣、嘉義市/縣、台南市、高雄市、屏東縣、宜蘭縣、
花蓮縣、台東縣、澎湖縣、金門縣、連江縣。
**輸出範例:**
```
📍 台北市中山區 目前天氣(2026-07-05T16:00)
天氣狀況:毛毛雨(中)
溫度:31.8°C(體感 37.5°C)
相對濕度:63%
降雨量:0.2 mm
風速:1.7 km/h
未來 3 天預報:
2026-07-05:毛毛雨(中),26.7~33.3°C,降雨機率 99%
2026-07-06:毛毛雨(中),25.9~34.1°C,降雨機率 69%
2026-07-07:雷雨,25.1~32.8°C,降雨機率 97%
```
**逐小時降雨範例(`get_hourly_rain`):**
```
📍 台北市中山區 未來 6 小時逐小時降雨
17:00 0.1 mm 降雨機率 98% ☔
18:00 0.1 mm 降雨機率 90% ☔
19:00 0.0 mm 降雨機率 77%
20:00 0.1 mm 降雨機率 63% ☔
21:00 0.0 mm 降雨機率 48%
22:00 0.0 mm 降雨機率 33%
這段期間預估總雨量約 0.3 mm。
```
---
## 程式碼解說(`weather_taipei.py`)
程式很短,分成五個部分。以下逐段說明。
### 1. 初始化與常數
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-taipei") # 建立一個名為 weather-taipei 的伺服器
OPEN_METEO_BASE = "https://api.open-meteo.com/v1/forecast"
ZHONGSHAN_LAT = 25.0637 # 中山區大約緯度
ZHONGSHAN_LON = 121.5265 # 中山區大約經度
```
`FastMCP` 是官方提供的框架,會**自動**根據函式的型別註記與 docstring 產生工具定義,
不必手寫繁瑣的設定。
### 2. 天氣代碼轉中文
Open-Meteo 用「WMO 天氣代碼」(數字)表示天氣,例如 `0`=晴天、`61`=小雨、`95`=雷雨。
我們用一個字典把數字翻成中文:
```python
WEATHER_CODES = {0: "晴天", 1: "大致晴朗", 2: "局部多雲", 3: "陰天",
61: "小雨", 63: "中雨", 65: "大雨", 95: "雷雨", ...}
def describe_code(code: int) -> str:
return WEATHER_CODES.get(code, f"未知天氣(代碼 {code})")
```
### 3. 向 Open-Meteo 發出請求(含錯誤處理)
```python
async def make_request(params: dict) -> dict | None:
async with httpx.AsyncClient() as client:
try:
resp = await client.get(OPEN_METEO_BASE, params=params, timeout=30.0)
resp.raise_for_status() # 若 HTTP 狀態非 2xx 會丟出例外
return resp.json()
except Exception:
return None # 出錯就回 None,交給上層處理
```
用 `httpx` 的非同步(`async`)方式連網,速度快且不會卡住整個伺服器。
### 4. 查詢並排版天氣(核心邏輯)
`fetch_weather()` 組好查詢參數(座標、時區、要哪些欄位、預報幾天),呼叫 API,
再把結果排成好讀的文字。關鍵在於同時要了「目前(current)」與「每日(daily)」兩組資料:
```python
params = {
"latitude": lat, "longitude": lon, "timezone": "Asia/Taipei",
"current": "temperature_2m,relative_humidity_2m,apparent_temperature,"
"precipitation,weather_code,wind_speed_10m",
"daily": "weather_code,temperature_2m_max,temperature_2m_min,"
"precipitation_probability_max",
"forecast_days": 3,
}
```
### 5. 縣市名稱查座標 & 逐小時降雨
為了支援「用縣市名稱查天氣」,程式內建一份台灣各縣市的座標表 `TAIWAN_LOCATIONS`,
再用 `resolve_location()` 把名稱對應到座標(支援關鍵字,例如「高雄」→「高雄市」):
```python
def resolve_location(name: str) -> tuple[float, float, str] | None:
if name in TAIWAN_LOCATIONS:
lat, lon = TAIWAN_LOCATIONS[name]
return lat, lon, name
for key, (lat, lon) in TAIWAN_LOCATIONS.items():
if name and name in key: # 部分關鍵字也能對應
return lat, lon, key
return None
```
逐小時降雨 `fetch_hourly_rain()` 則向 API 要 `hourly=precipitation,precipitation_probability`,
再從「現在」這個時間點往後取 N 小時:
```python
now = data.get("current", {}).get("time", "")
start = next((i for i, t in enumerate(times) if t >= now), 0) # 只看未來時段
for i in range(start, start + hours):
... # 印出每小時的雨量與降雨機率
```
### 6. 用 `@mcp.tool()` 把函式變成 AI 可呼叫的工具
只要在函式上加 `@mcp.tool()`,它就會被登錄為工具;函式的 docstring 會成為
AI 看到的「工具說明」,所以描述要寫清楚。本專案共登錄四個工具:
```python
@mcp.tool()
async def get_zhongshan_weather() -> str:
"""取得台灣台北市中山區目前的天氣與未來 3 天預報。"""
return await fetch_weather(ZHONGSHAN_LAT, ZHONGSHAN_LON, "台北市中山區")
@mcp.tool()
async def get_weather_by_city(city: str) -> str:
"""用台灣縣市名稱查詢天氣與未來 3 天預報。"""
...
@mcp.tool()
async def get_weather_by_coords(latitude: float, longitude: float) -> str:
"""依經緯度取得任一地點的天氣與未來 3 天預報。"""
...
@mcp.tool()
async def get_hourly_rain(city: str = "台北市中山區", hours: int = 12) -> str:
"""取得台灣某地未來數小時的逐小時降雨(雨量與降雨機率)。"""
...
```
最後用 stdio 方式啟動,讓 Claude 桌面版能連上:
```python
if __name__ == "__main__":
mcp.run(transport="stdio")
```
---
## 安裝與使用
### 1. 先決條件
- Python 3.10 以上
- 安裝套件:`pip install "mcp[cli]" httpx`
### 2. 設定 Claude 桌面版
打開(或新建)設定檔:
`%APPDATA%\Claude\claude_desktop_config.json`(Windows)
把下列內容加入(路徑請改成你電腦上的實際路徑):
```json
{
"mcpServers": {
"weather-taipei": {
"command": "python",
"args": ["C:/路徑/weather-taipei/weather_taipei.py"]
}
}
}
```
存檔後**完全關閉並重開** Claude 桌面版,再於對話中詢問天氣即可。
可參考本專案的 `claude_desktop_config.sample.json`。
設定完成後,可以這樣問 Claude:
- 「中山區現在天氣如何?」→ `get_zhongshan_weather`
- 「台中市未來三天會下雨嗎?」→ `get_weather_by_city`
- 「中山區未來 6 小時會下雨嗎?」→ `get_hourly_rain`
- 「幫我查緯度 24.15、經度 120.67 的天氣」→ `get_weather_by_coords`
### 3. 不透過 Claude、直接用指令測試
```bash
python -c "import asyncio, weather_taipei as w; print(asyncio.run(w.fetch_weather(w.ZHONGSHAN_LAT, w.ZHONGSHAN_LON, '台北市中山區')))"
```
---
## 資料來源與致謝
- 天氣資料:[Open-Meteo](https://open-meteo.com)(免費、免金鑰、CC BY 4.0)
- 架構參考:[MCP 官方教學](https://modelcontextprotocol.io/docs/develop/build-server)
## 授權
MIT License,詳見 [LICENSE](LICENSE)。
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues