{
  "markdown": "# au-weather-mcp\n\nmcp-name: io.ausdata/au-weather-mcp\n\n[![PyPI](https://img.shields.io/pypi/v/au-weather-mcp.svg)](https://pypi.org/project/au-weather-mcp/)\n[![Python](https://img.shields.io/pypi/pyversions/au-weather-mcp.svg)](https://pypi.org/project/au-weather-mcp/)\n[![License](https://img.shields.io/pypi/l/au-weather-mcp.svg)](https://github.com/Bigred97/au-weather-mcp/blob/main/LICENSE)\n[![Tests](https://github.com/Bigred97/au-weather-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/Bigred97/au-weather-mcp/actions/workflows/test.yml)\n[![CodeQL](https://github.com/Bigred97/au-weather-mcp/actions/workflows/codeql.yml/badge.svg)](https://github.com/Bigred97/au-weather-mcp/actions/workflows/codeql.yml)\n[![Glama MCP server quality](https://glama.ai/mcp/servers/Bigred97/au-weather-mcp/badges/score.svg)](https://glama.ai/mcp/servers/Bigred97/au-weather-mcp)\n\n**Ask Claude about Australian weather and air quality and get real, current numbers** — not \"I don't have access to that data.\" This MCP server gives Claude (and other MCP clients like Cursor) live access to Australian weather + air-quality data via [Open-Meteo](https://open-meteo.com), which aggregates Bureau of Meteorology observations under licence. 45 curated locations (every state capital + every regional centre over ~25k), postcode and place-name lookup, current observations, 16-day forecasts, 80+ years of historical data, and multi-location comparison.\n\n> **Hosted access?** For cross-source queries, webhooks, an always-on REST API, and a uniform response envelope across all 9 sources, see **[ausdata.io](https://ausdata.io)** — free tier available (500 calls/mo, no card).\n\nCompanion to [abs-mcp](https://github.com/Bigred97/abs-mcp) (ABS macro stats), [rba-mcp](https://github.com/Bigred97/rba-mcp) (Reserve Bank), and [ato-mcp](https://github.com/Bigred97/ato-mcp) (tax + charity register) — together the four cover Australia's most-asked public data.\n\n## What you can ask\n\nOnce installed, your LLM can answer questions like:\n\n| Question | Real response |\n|---|---|\n| What's the weather in Sydney right now? | Current temperature, humidity, wind, rain, pressure with the time stamped |\n| Forecast for Melbourne next week? | 7-day daily forecast with max/min temps and rain |\n| How was Sydney summer in January 2020? | Historical daily data from Open-Meteo's archive (1940+) |\n| Compare rainfall in Cairns vs Brisbane this year | Multi-location queries with provenance per row |\n| Tropical Queensland weather today | Search fuzzy by region/state/description |\n\nEvery response carries a CC-BY 4.0 attribution string and a direct Open-Meteo URL the agent can cite back to the user.\n\n## Why Open-Meteo (not BOM directly)\n\nBOM publishes their own JSON/XML endpoints, but they actively 403 non-browser User-Agents and have no documented commercial-use path below their ~$5k/yr Registered User Service. Open-Meteo:\n\n- Aggregates BOM data under their existing licensing arrangements with national meteorological services\n- Free tier is explicit and generous; commercial use is $30/mo with public terms\n- Returns clean, versioned, schema-stable JSON with units alongside every value\n- Covers historical data back to 1940 via their archive endpoint\n- No API key, no User-Agent gymnastics\n\nWe attribute both Open-Meteo and BOM in every response.\n\n## Install\n\n```bash\n# After publish:\nuvx au-weather-mcp\n\n# Local dev:\nuv pip install -e .\n```\n\n### Claude Desktop\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"weather\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--upgrade\", \"au-weather-mcp\"]\n    }\n  }\n}\n```\n\nThe `--upgrade` flag makes uvx re-check PyPI on each Claude Desktop launch, so bug fixes propagate without manual cache refresh. Costs ~100ms at startup.\n\nFor a local checkout (before PyPI publish):\n\n```json\n{\n  \"mcpServers\": {\n    \"weather\": {\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"--directory\", \"/absolute/path/to/au-weather-mcp\", \"au-weather-mcp\"]\n    }\n  }\n}\n```\n\n### Cursor\n\nAdd to `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"weather\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--upgrade\", \"au-weather-mcp\"]\n    }\n  }\n}\n```\n\n## Tools\n\n| Tool | What it does |\n|---|---|\n| `search_locations(query, limit=10)` | Fuzzy-search the 45 curated AU locations by name, state, or description. |\n| `describe_location(location)` | Lat/lng, timezone, elevation, nearest BOM station, and the canonical Open-Meteo URL. |\n| `latest(location)` | Current weather observation — temp, humidity, wind, rain, pressure. 15-min cache. |\n| `get_weather(location, start_date, end_date, granularity)` | Time-series query. Auto-routes to historical archive (1940+) or forecast (today + 16 days). Daily or hourly granularity. |\n| `air_quality(location)` | Current PM2.5, PM10, ozone, NO₂, SO₂, CO + European & US AQI with plain-English labels. *(v0.4.0)* |\n| `compare_locations([locs])` | Side-by-side current weather for 2–10 locations in one call. Fans out concurrently. *(v0.4.0)* |\n| `list_curated()` | All 45 supported location IDs. |\n\n## Accepts almost any input shape\n\nThe `location` parameter on every tool resolves six different input shapes — agents and users don't need to know the curated key format:\n\n| Input shape | Example | Resolves via |\n|---|---|---|\n| Curated ID | `\"sydney\"`, `\"gold_coast\"` | Direct curated lookup (fast) |\n| Place name, any case | `\"Sydney\"`, `\"Gold Coast\"`, `\"GOLD COAST\"` | Normalised curated lookup |\n| State code or full name | `\"NSW\"`, `\"Queensland\"`, `\"Western Australia\"` | State → capital alias |\n| Raw coordinates | `\"-33.87,151.21\"` | Direct lat/lng (AU bbox enforced) |\n| **AU postcode** | `\"2026\"` (Bondi Beach), `\"4217\"` (Gold Coast), `\"6160\"` (Fremantle) | **OpenStreetMap Nominatim** |\n| Any AU place name | `\"Byron Bay\"`, `\"Margaret River\"`, `\"Toowoomba\"` | Open-Meteo geocoding (AU-filtered, population-sorted) |\n| Typo of a curated name | `\"Sydny\"`, `\"Melbourn\"` | High-confidence fuzzy match |\n\nEvery response includes a `location_resolution` field with one of `curated`, `state_alias`, `raw_coordinates`, `geocoded`, or `fuzzy_curated` — so the agent (and the user) can see HOW the input was interpreted.\n\n## Curated locations\n\n**45 curated locations** covering all 8 state/territory capitals plus 37 major regional centres (every AU population centre over ~25k). Anything outside the curated set still works via the place-name geocoder or postcode lookup.\n\n| Region | Locations |\n|---|---|\n| **Capitals (8)** | `sydney` · `melbourne` · `brisbane` · `perth` · `adelaide` · `hobart` · `darwin` · `canberra` |\n| **NSW regional (10)** | `newcastle` · `wollongong` · `tamworth` · `wagga_wagga` · `albury` · `orange` · `bathurst` · `dubbo` · `coffs_harbour` · `port_macquarie` |\n| **QLD regional (9)** | `gold_coast` · `sunshine_coast` · `cairns` · `townsville` · `mackay` · `toowoomba` · `rockhampton` · `bundaberg` · `hervey_bay` |\n| **VIC regional (6)** | `geelong` · `ballarat` · `bendigo` · `mildura` · `shepparton` · `warrnambool` |\n| **WA regional (5)** | `broome` · `bunbury` · `geraldton` · `albany` · `kalgoorlie` |\n| **SA regional (2)** | `mount_gambier` · `whyalla` |\n| **TAS regional (3)** | `launceston` · `devonport` · `burnie` |\n| **NT regional (2)** | `alice_springs` · `katherine` |\n\nCoordinates are anchored to the canonical BOM observation point for each city (e.g. Sydney = Observatory Hill, Melbourne = Olympic Park) so cross-checking against BOM's official observations is straightforward. See [src/au_weather_mcp/data/curated/locations.yaml](src/au_weather_mcp/data/curated/locations.yaml) for the full registry.\n\n## Worked examples\n\n**\"What's the weather in Sydney right now?\"**\n\n```\nlatest(location=\"sydney\")\n```\n\nReturns:\n\n```json\n{\n  \"location_id\": \"sydney\",\n  \"location_name\": \"Sydney\",\n  \"state\": \"NSW\",\n  \"latitude\": -33.8607,\n  \"longitude\": 151.205,\n  \"timezone\": \"Australia/Sydney\",\n  \"period\": {\"start\": \"2026-05-12T11:30\", \"end\": \"2026-05-12T11:30\"},\n  \"current\": {\n    \"time\": \"2026-05-12T11:30\",\n    \"temperature_c\": 19.7,\n    \"apparent_temperature_c\": 18.1,\n    \"relative_humidity_pct\": 67,\n    \"precipitation_mm\": 0.0,\n    \"cloud_cover_pct\": 43,\n    \"pressure_msl_hpa\": 1034.5,\n    \"wind_speed_kmh\": 18.4,\n    \"wind_direction_deg\": 149,\n    \"wind_gusts_kmh\": 43.2,\n    \"weather_code\": 1,\n    \"weather_description\": \"Mainly clear\"\n  },\n  \"source\": \"Open-Meteo (aggregates Bureau of Meteorology data under licence)\",\n  \"attribution\": \"Weather data by Open-Meteo.com (https://open-meteo.com), licensed under CC BY 4.0...\",\n  \"source_url\": \"https://api.open-meteo.com/v1/forecast?latitude=-33.8607&...\",\n  \"server_version\": \"<package version, e.g. 0.3.3>\",\n  \"location_resolution\": \"curated\",\n  \"location_input\": \"sydney\"\n}\n```\n\n**\"How was Sydney in January 2020?\"**\n\n```\nget_weather(\n  location=\"sydney\",\n  start_date=\"2020-01-01\",\n  end_date=\"2020-01-31\",\n  granularity=\"daily\"\n)\n```\n\nReturns 31 `DailyAggregate` rows with `temperature_max_c`, `temperature_min_c`, `precipitation_sum_mm`, and weather descriptions per day.\n\n**\"7-day Melbourne forecast, hourly detail\"**\n\n```\nget_weather(\n  location=\"melbourne\",\n  start_date=\"2026-05-12\",\n  end_date=\"2026-05-19\",\n  granularity=\"hourly\"\n)\n```\n\nReturns 168 hourly rows.\n\n## Date formats\n\n`start_date` and `end_date` must be `YYYY-MM-DD`. The server validates both the regex and the semantic date — `2024-13-40` raises a clean `ValueError` rather than silently failing.\n\n| Date range | Routes to | Coverage |\n|---|---|---|\n| `end_date >= today - 5 days` | Open-Meteo forecast endpoint | Today + 16 days |\n| `end_date < today - 5 days` | Open-Meteo historical archive | 1940-01-01 onwards |\n\n## Trust contract\n\nEvery response carries:\n\n- `source_url` — the exact Open-Meteo URL the data came from\n- `attribution` — CC-BY 4.0 notice for both Open-Meteo and BOM\n- `retrieved_at` — UTC timestamp when we fetched\n- `server_version` — which wheel served the call (debugging stale `uvx` caches)\n- `stale` — true if we're serving cached data because upstream failed; comes with `stale_reason`\n\nSanity validators reject upstream values outside the plausible Australian range (temperature outside −30°C to +55°C, humidity outside 0-100%, pressure outside 850-1080 hPa). Rather than silently passing bad data to your agent, we raise an explicit validation error so the agent can degrade gracefully.\n\n## Development\n\n```bash\ngit clone https://github.com/Bigred97/au-weather-mcp.git\ncd au-weather-mcp\nuv sync --extra dev\nuv pip install -e .\n\n# Unit tests (no network)\nuv run pytest\n\n# Live integration tests (hits Open-Meteo)\nuv run pytest -m live\n```\n\nThe SQLite cache lives at `~/.au-weather-mcp/cache.db`. Current observations refresh every 15 minutes (matching Open-Meteo's update cadence), forecasts every 1 hour, historical never (a year-old day in the archive doesn't change). Delete the file to force a refresh.\n\n## Sister MCPs (Australian Public Data portfolio)\n\nThe portfolio runs side-by-side in any MCP client; Claude disambiguates via the server prefix (`weather:latest` vs `abs:latest` vs `rba:latest` vs `ato:get_data`).\n\n> **Want all 9 sources behind one REST API?** The hosted gateway at **[ausdata.io](https://ausdata.io)** adds cross-source joins, full history, webhooks, and HMAC-signed responses on top of these MCPs — free tier (500 calls/mo, no card).\n\n- [abs-mcp](https://pypi.org/project/abs-mcp/) — Australian Bureau of Statistics (CPI, unemployment, ERP, building approvals)\n- [rba-mcp](https://pypi.org/project/rba-mcp/) — Reserve Bank of Australia (cash rate, lending stats, exchange rates)\n- [ato-mcp](https://pypi.org/project/ato-mcp/) — Australian Taxation Office (tax stats, ACNC charities)\n- [apra-mcp](https://pypi.org/project/apra-mcp/) — Australian Prudential Regulation Authority (banking, insurance, super)\n- [aihw-mcp](https://pypi.org/project/aihw-mcp/) — Australian Institute of Health and Welfare\n- [asic-mcp](https://pypi.org/project/asic-mcp/) — Australian Securities and Investments Commission (company registers)\n- [aemo-mcp](https://pypi.org/project/aemo-mcp/) — Australian Energy Market Operator (NEM dispatch, spot prices, generation)\n- **au-weather-mcp** — this one. Open-Meteo (Bureau of Meteorology aggregator).\n- [wgea-mcp](https://pypi.org/project/wgea-mcp/) — Workplace Gender Equality Agency\n- [aus-identity](https://pypi.org/project/aus-identity/) — Postcode / state / ABN normalisation helper used by all sisters\n\n## Data attribution\n\nWeather data is provided by [Open-Meteo](https://open-meteo.com), licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). The underlying observations include data from the [Australian Bureau of Meteorology](https://www.bom.gov.au) under Open-Meteo's licensing arrangement.\n\n**Postcode resolutions** (when `location_resolution == \"postcode\"`) additionally use [OpenStreetMap](https://www.openstreetmap.org/copyright) via the Nominatim service, licensed under the [Open Database Licence (ODbL)](https://opendatacommons.org/licenses/odbl/). The OSM attribution is automatically appended to the response's `attribution` field for any postcode lookup, so redistribution is licence-compliant out of the box.\n\nIf you redistribute responses, credit Open-Meteo + BOM (always) and OpenStreetMap (when postcode lookup was used).\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for release history.\n\n## License\n\nMIT — Harry Vass, 2026.\n",
  "bytes": 13414,
  "sha": "4b48a4ee357c5cc2dda24eadf1c591218c65a0c760baa62d21902b98eea48686",
  "repo_slug": "bigred97/au-weather-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_ausdata_au_weather_mcp_4af9d8b1/readme"
}