mcp-weather-server
by srathish
README.md
# mcp-weather-server
A Model Context Protocol server that gives Claude (or any MCP client) live weather tools, backed by [Open-Meteo](https://open-meteo.com/) — which is free and needs no API key.
The Model Context Protocol (MCP) is an open standard that lets AI assistants call external tools and data sources through a common interface, instead of every app inventing its own plugin system. A client such as Claude Desktop launches an MCP server as a subprocess and talks to it over JSON-RPC, discovering and invoking whatever tools the server exposes.
## Overview
I built this server to expose three weather tools:
| Tool | What it does |
| --- | --- |
| `geocode_city(name)` | Resolves a city name to coordinates, country, and timezone; lists alternative matches for ambiguous names like "Springfield" |
| `current_weather(city)` | Live conditions: temperature, feels-like, humidity, wind, and a readable sky description with the matching emoji |
| `forecast(city, days=3)` | Daily forecast for 1–16 days: min/max temperature, precipitation total and probability, peak wind |
Everything returns readable structured text, so the model can relay answers directly. Errors come back as plain-language messages ("No place called 'Atlantis' was found…") rather than tracebacks.
## Architecture
```
Claude Desktop / any MCP client
│
│ JSON-RPC over stdio
▼
┌──────────────────────────────────────┐
│ weather_mcp.server (FastMCP) │ thin tool layer:
│ geocode_city · current_weather · │ docstrings, schemas,
│ forecast │ text formatting
└───────────────┬──────────────────────┘
│ typed dataclasses
▼
┌──────────────────────────────────────┐
│ weather_mcp.openmeteo (pure stdlib)│ all domain logic:
│ URL building · timeouts · JSON │ uses weather_mcp.codes
│ parsing · friendly error mapping │ for WMO code → text/emoji
└───────┬──────────────────────┬───────┘
│ HTTPS │ HTTPS
▼ ▼
geocoding-api.open-meteo.com api.open-meteo.com
(city search) (current + daily forecast)
```
## Design decisions
- **Standard-library HTTP instead of `requests`/`httpx`.** The only runtime dependency is the `mcp` SDK itself. It also gives the tests a single seam to mock (`urlopen`), so the whole client is unit-testable offline.
- **All logic lives in `openmeteo.py`; `server.py` stays thin.** The client module never imports `mcp`, so the test suite runs on a bare Python install with nothing pip-installed.
- **Frozen, typed dataclasses at the API boundary.** Tools work with `Location`, `CurrentWeather`, and `DailyForecast` values instead of raw dicts, so a malformed API response fails loudly at parse time, not somewhere downstream.
- **Errors are phrased for end users.** Network failures, timeouts, HTTP errors, and unknown cities all map to `WeatherError` subclasses whose messages the tools return verbatim — an LLM can relay "check the spelling" far more usefully than a stack trace.
- **Open-Meteo as the data source.** No API key, no signup, generous free limits — anyone can clone this repo and have working weather tools in under a minute.
- **Timeouts on every request** (10 s default, overridable per call), so a hung network call can never wedge the server.
## Quickstart
Requires Python 3.11+.
```bash
git clone https://github.com/srathish/mcp-weather-server.git
cd mcp-weather-server
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python -m weather_mcp # starts the server on stdio
```
### Claude Desktop
Add the server to `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows: `%APPDATA%\Claude\claude_desktop_config.json`), using the absolute path to your clone:
```json
{
"mcpServers": {
"weather": {
"command": "/absolute/path/to/mcp-weather-server/.venv/bin/python",
"args": ["-m", "weather_mcp"],
"env": {
"PYTHONPATH": "/absolute/path/to/mcp-weather-server"
}
}
}
}
```
Restart Claude Desktop and ask something like *"What's the weather in Berlin right now?"* — Claude will call `current_weather` for you.
### MCP Inspector
For interactive debugging, the official inspector works out of the box:
```bash
pip install "mcp[cli]"
mcp dev weather_mcp/server.py
```
This opens a web UI where you can invoke each tool by hand and inspect the requests and responses.
## How I know it works
The test suite covers the parts that can actually break: geocoding parsing (including the no-results case), current-weather and forecast parsing, WMO code mapping (including the unknown-code fallback), the mapping of HTTP/network/timeout failures onto friendly messages, and URL construction (parameters and non-ASCII city names encoded correctly).
All HTTP is mocked at the `urlopen` seam, so the tests use only the standard library — no pip installs, no network:
```bash
python3 -m unittest discover -s tests -v
```
28 tests, all passing on Python 3.11+.
## Limitations
- **Geocoding trusts the top match.** `current_weather("Springfield")` picks Open-Meteo's best-ranked Springfield. Use `geocode_city` first when a name is ambiguous.
- **Metric units only.** Temperatures are °C and wind speeds km/h; I have not added unit conversion.
- **No caching or rate limiting.** Every tool call is a fresh API request. Open-Meteo's free tier is generous, but a busy deployment would want a small TTL cache.
- **Forecast only, no history.** The server exposes current conditions and up to 16 days ahead; Open-Meteo's historical archive endpoints are not wired up.
- **Output is text, not JSON.** The tools return human-readable text for the model to relay. If a downstream program needed to parse results, structured output would be the better contract.
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues