open-meteo-mcp-server
Version:
Model Context Protocol server for Open-Meteo weather APIs
644 lines (489 loc) • 22.6 kB
Markdown
# Open-Meteo MCP Server
[](https://badge.fury.io/js/open-meteo-mcp-server)
[](https://github.com/cmer81/open-meteo-mcp/releases)
[](https://github.com/cmer81/open-meteo-mcp/pkgs/container/open-meteo-mcp)
A comprehensive [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that provides access to Open-Meteo weather APIs for use with Large Language Models.
## Features
This MCP server provides complete access to Open-Meteo APIs, including:
### Core Weather APIs
- **Weather Forecast** (`weather_forecast`) - Forecasts up to 16 days (7 by default) with hourly and daily resolution
- **Weather Archive** (`weather_archive`) - Historical ERA5 data from 1940 to present
- **Air Quality** (`air_quality`) - PM2.5, PM10, ozone, nitrogen dioxide, pollen, European/US AQI indices, UV index and other pollutants
- **Marine Weather** (`marine_weather`) - Wave height, wave period, wave direction and sea surface temperature
- **Elevation** (`elevation`) - Digital elevation model data for given coordinates
- **Geocoding** (`geocoding`) - Search locations worldwide by name or postal code, get coordinates and detailed location information
### Specialized Weather Models
- **DWD ICON** (`dwd_icon_forecast`) - German weather service high-resolution model for Europe
- **NOAA GFS** (`gfs_forecast`) - US weather service global model with high-resolution North America data
- **Météo-France** (`meteofrance_forecast`) - French weather service AROME and ARPEGE models
- **ECMWF** (`ecmwf_forecast`) - European Centre for Medium-Range Weather Forecasts
- **JMA** (`jma_forecast`) - Japan Meteorological Agency high-resolution model for Asia
- **MET Norway** (`metno_forecast`) - Norwegian weather service for Nordic countries
- **Environment Canada GEM** (`gem_forecast`) - Canadian weather service model
### Advanced Forecasting Tools
- **Flood Forecast** (`flood_forecast`) - River discharge and flood forecasts from GloFAS (Global Flood Awareness System)
- **Seasonal Forecast** (`seasonal_forecast`) - Long-range forecasts up to ~7 months ahead
- **Climate Projections** (`climate_projection`) - CMIP6 climate change projections for different warming scenarios
- **Ensemble Forecast** (`ensemble_forecast`) - Multiple model runs showing forecast uncertainty
## Installation
### Requirements
- Node.js >= 22.0.0
### Method 1: Using npx (Recommended)
No installation required! The server will run directly via npx.
### Method 2: Global Installation via npm
```bash
npm install -g open-meteo-mcp-server
```
### Method 3: From Source (Development)
```bash
# Clone the repository
git clone https://github.com/cmer81/open-meteo-mcp.git
cd open-meteo-mcp
# Install dependencies
npm install
# Build the project
npm run build
```
## Configuration
### Claude Desktop Configuration
#### Simple Configuration (Recommended)
Add the following configuration to your Claude Desktop config file:
```json
{
"mcpServers": {
"open-meteo": {
"command": "npx",
"args": ["-y", "-p", "open-meteo-mcp-server", "open-meteo-mcp-server"]
}
}
}
```
#### Full Configuration (with environment variables)
```json
{
"mcpServers": {
"open-meteo": {
"command": "npx",
"args": ["-y", "-p", "open-meteo-mcp-server", "open-meteo-mcp-server"],
"env": {
"OPEN_METEO_API_URL": "https://api.open-meteo.com",
"OPEN_METEO_AIR_QUALITY_API_URL": "https://air-quality-api.open-meteo.com",
"OPEN_METEO_MARINE_API_URL": "https://marine-api.open-meteo.com",
"OPEN_METEO_ARCHIVE_API_URL": "https://archive-api.open-meteo.com",
"OPEN_METEO_SEASONAL_API_URL": "https://seasonal-api.open-meteo.com",
"OPEN_METEO_ENSEMBLE_API_URL": "https://ensemble-api.open-meteo.com",
"OPEN_METEO_GEOCODING_API_URL": "https://geocoding-api.open-meteo.com",
"OPEN_METEO_FLOOD_API_URL": "https://flood-api.open-meteo.com",
"OPEN_METEO_CLIMATE_API_URL": "https://climate-api.open-meteo.com"
}
}
}
}
```
#### Local Development Configuration
If you're developing locally or installed from source:
```json
{
"mcpServers": {
"open-meteo": {
"command": "node",
"args": ["/path/to/open-meteo-mcp/dist/index.js"],
"env": {
"OPEN_METEO_API_URL": "https://api.open-meteo.com",
"OPEN_METEO_AIR_QUALITY_API_URL": "https://air-quality-api.open-meteo.com",
"OPEN_METEO_MARINE_API_URL": "https://marine-api.open-meteo.com",
"OPEN_METEO_ARCHIVE_API_URL": "https://archive-api.open-meteo.com",
"OPEN_METEO_SEASONAL_API_URL": "https://seasonal-api.open-meteo.com",
"OPEN_METEO_ENSEMBLE_API_URL": "https://ensemble-api.open-meteo.com",
"OPEN_METEO_GEOCODING_API_URL": "https://geocoding-api.open-meteo.com",
"OPEN_METEO_FLOOD_API_URL": "https://flood-api.open-meteo.com",
"OPEN_METEO_CLIMATE_API_URL": "https://climate-api.open-meteo.com"
}
}
}
}
```
### Custom Instance Configuration
If you're using your own Open-Meteo instance:
```json
{
"mcpServers": {
"open-meteo": {
"command": "npx",
"args": ["-y", "-p", "open-meteo-mcp-server", "open-meteo-mcp-server"],
"env": {
"OPEN_METEO_API_URL": "https://your-meteo-api.example.com",
"OPEN_METEO_AIR_QUALITY_API_URL": "https://air-quality-api.example.com",
"OPEN_METEO_MARINE_API_URL": "https://marine-api.example.com",
"OPEN_METEO_ARCHIVE_API_URL": "https://archive-api.example.com",
"OPEN_METEO_SEASONAL_API_URL": "https://seasonal-api.example.com",
"OPEN_METEO_ENSEMBLE_API_URL": "https://ensemble-api.example.com",
"OPEN_METEO_GEOCODING_API_URL": "https://geocoding-api.example.com",
"OPEN_METEO_FLOOD_API_URL": "https://flood-api.example.com",
"OPEN_METEO_CLIMATE_API_URL": "https://climate-api.example.com"
}
}
}
}
```
### Streamable HTTP Transport
The server also supports Streamable HTTP transport for remote deployments. Set the `TRANSPORT` environment variable to `http`:
```bash
TRANSPORT=http PORT=3000 npx open-meteo-mcp-server
```
This starts an Express server on the specified port (default: 3000) with the MCP endpoint at `/mcp`. The HTTP transport supports session management with unique session IDs per client.
> **The server binds to `127.0.0.1` by default**, so it is reachable only from the local machine. To accept connections from other hosts, set `HOST=0.0.0.0` explicitly. The Docker image already does this, so published ports work without extra configuration.
For production deployments, bind to a reachable interface and enable authentication and rate limiting:
```bash
HOST=0.0.0.0 API_KEY=your-secret-key RATE_LIMIT_RPM=60 TRANSPORT=http PORT=3000 npx open-meteo-mcp-server
```
If a browser-based client connects to the server, list its origin in `ALLOWED_ORIGINS` — requests carrying an unlisted `Origin` header are rejected with `403` as DNS rebinding protection.
Clients must then include the key in every request:
```
Authorization: Bearer your-secret-key
# or
X-API-Key: your-secret-key
```
#### Using npm scripts
```bash
# Start in HTTP mode (production)
npm run start:http
# Development with auto-reload in HTTP mode
npm run dev:http
```
### Docker Deployment
The server can be easily deployed using Docker.
#### Using Pre-built Image from GitHub Container Registry (Recommended)
Pull and run the official image:
```bash
# Pull the latest image
docker pull ghcr.io/cmer81/open-meteo-mcp:latest
# Run the container
docker run -d \
--name open-meteo-mcp \
-p 3000:3000 \
ghcr.io/cmer81/open-meteo-mcp:latest
# Check health
curl http://localhost:3000/health
```
Available tags (no `v` prefix — the git tag `v2.0.0` publishes the image as `2.0.0`):
- `latest` - Latest stable release
- `2.0.0` - Specific version
- `2.0` - Latest 2.0.x release
- `2` - Latest 2.x.x release
#### Using Docker Compose
The repository includes two Docker Compose configurations:
**Production (uses pre-built image):**
```bash
# Start with pre-built image from GitHub Container Registry
docker compose up -d
# View logs
docker compose logs -f
# Stop the server
docker compose down
```
**Development (builds from source):**
```bash
# Build and start from local source
docker compose -f docker-compose.dev.yml up -d
# Rebuild after code changes
docker compose -f docker-compose.dev.yml up -d --build
```
#### Building from Source
If you prefer to build the image yourself:
```bash
# Build the image
npm run docker:build
# or
docker build -t open-meteo-mcp-server .
# Run the container
npm run docker:run
# or
docker run -p 3000:3000 open-meteo-mcp-server
```
#### Environment Configuration
Copy `.env.example` to `.env` and customize as needed:
```bash
cp .env.example .env
# Edit .env with your configuration
```
Then update `docker-compose.yml` to use the `.env` file or pass environment variables directly.
#### Health Check
The HTTP server includes a health check endpoint:
```bash
curl http://localhost:3000/health
# Response: {"status":"ok"}
```
This endpoint is used by Docker's `HEALTHCHECK` and can be integrated with container orchestration platforms (Kubernetes, Docker Swarm, etc.).
### Environment Variables
All environment variables are optional and have sensible defaults:
- `OPEN_METEO_API_URL` - Base URL for Open-Meteo forecast API (default: https://api.open-meteo.com)
- `OPEN_METEO_AIR_QUALITY_API_URL` - Air quality API URL (default: https://air-quality-api.open-meteo.com)
- `OPEN_METEO_MARINE_API_URL` - Marine weather API URL (default: https://marine-api.open-meteo.com)
- `OPEN_METEO_ARCHIVE_API_URL` - Historical data API URL (default: https://archive-api.open-meteo.com)
- `OPEN_METEO_SEASONAL_API_URL` - Seasonal forecast API URL (default: https://seasonal-api.open-meteo.com)
- `OPEN_METEO_ENSEMBLE_API_URL` - Ensemble forecast API URL (default: https://ensemble-api.open-meteo.com)
- `OPEN_METEO_GEOCODING_API_URL` - Geocoding API URL (default: https://geocoding-api.open-meteo.com)
- `OPEN_METEO_FLOOD_API_URL` - Flood forecast API URL (default: https://flood-api.open-meteo.com)
- `OPEN_METEO_CLIMATE_API_URL` - Climate projection API URL (default: https://climate-api.open-meteo.com)
- `TRANSPORT` - Transport mode: `http` for Streamable HTTP, omit for stdio (default: stdio)
- `PORT` - HTTP server port when using HTTP transport (default: 3000)
- `HOST` - Interface the HTTP transport binds to (default: `127.0.0.1`, loopback only). Set to `0.0.0.0` to accept connections from other machines. The Docker image sets this to `0.0.0.0` already, so published ports work out of the box.
#### HTTP Transport Security (optional)
- `API_KEY` - When set, all requests to `/mcp` must include this key via `Authorization: Bearer <key>` or `X-API-Key: <key>`. Leave unset for open access (local/dev mode). Enforced on `GET`, `POST` and `DELETE` alike.
- `RATE_LIMIT_RPM` - Maximum requests per minute per IP (default: `60`). HTTP transport only.
- `TRUSTED_PROXIES` - Comma-separated list of trusted proxy IPs or CIDR ranges (e.g. `10.0.0.0/8,172.16.0.0/12`). When set, `X-Forwarded-For` is honoured only for requests originating from these addresses. Leave unset to always use the direct connection IP.
- `ALLOWED_ORIGINS` - Comma-separated list of browser origins permitted to reach the server (e.g. `http://localhost:5173,https://app.example`). Protects against DNS rebinding: any request carrying an `Origin` header that is not listed is rejected with `403`. Requests without an `Origin` header — CLI clients and SDK transports — are unaffected. Empty by default.
`/health` stays reachable without a key and without rate limiting, so container probes keep working.
## Skills
The `skills/` directory contains SKILL.md files that help AI assistants use this MCP server effectively. They act as contextual guides — the AI reads the relevant skill to know which tool to call and how to use its parameters.
### Available skills
| Skill | File | Best for |
|-------|------|----------|
| `open-meteo` | `skills/open-meteo/SKILL.md` | Everyday weather: forecasts, historical data, air quality, marine conditions, elevation |
| `open-meteo-advanced` | `skills/open-meteo-advanced/SKILL.md` | Specific models (ECMWF, GFS, DWD ICON…), ensemble uncertainty, seasonal outlooks, climate projections |
### Using with Claude Code (CLI)
Copy the skill(s) to your Claude skills directory:
```bash
cp -r skills/open-meteo ~/.claude/skills/
cp -r skills/open-meteo-advanced ~/.claude/skills/
```
This installs them at `~/.claude/skills/open-meteo/SKILL.md` and `~/.claude/skills/open-meteo-advanced/SKILL.md`. Claude Code will load the relevant skill automatically when you ask weather-related questions.
### Using with Claude Desktop
Upload the SKILL.md file directly as a document in your Claude Desktop conversation:
- For everyday weather questions: upload `skills/open-meteo/SKILL.md`
- For model selection, ensemble, or climate projections: upload `skills/open-meteo-advanced/SKILL.md`
Upload one skill per conversation. The AI will use it as a reference guide throughout the session.
## Usage Examples
### Geocoding and Location Search
```
Find the coordinates for Paris, France
```
```
Search for locations named "Berlin" and return the top 5 results
```
```
What are the coordinates for postal code 75001?
```
```
Search for "Lyon" in France only (countryCode: FR) with results in French (language: fr)
```
```
Find all cities named "London" in the United Kingdom with English descriptions
```
### Basic Weather Forecast
```
Can you get me the weather forecast for Paris (48.8566, 2.3522) with temperature, humidity, and precipitation for the next 3 days?
```
### Historical Weather Data
```
What were the temperatures in London during January 2023?
```
### Air Quality Monitoring
```
What's the current air quality in Beijing with PM2.5 and ozone levels?
```
```
Give me the current European AQI, UV index, and pollen levels (birch, grass, ragweed) in Paris.
```
### Marine Weather
```
Get me the wave height and sea surface temperature for coordinates 45.0, -125.0 for the next 5 days.
```
### Flood Monitoring
```
Check the river discharge forecast for coordinates 52.5, 13.4 for the next 30 days.
```
### Seasonal Forecast
```
Give me the weekly and monthly temperature outlook for Madrid over the next 4 months.
```
### Ensemble Forecast
```
Compare the ICON and GFS ensemble forecasts for Berlin over the next 5 days and show the spread across members.
```
### Climate Projections
```
Show me temperature projections for New York from 2050 to 2070 using CMIP6 models.
```
## API Parameters
### Required Parameters
- `latitude` : Latitude in WGS84 coordinate system (-90 to 90)
- `longitude` : Longitude in WGS84 coordinate system (-180 to 180)
### Hourly Weather Variables
- `temperature_2m` : Temperature at 2 meters
- `relative_humidity_2m` : Relative humidity
- `precipitation` : Precipitation
- `wind_speed_10m` : Wind speed at 10 meters
- `wind_direction_10m` : Wind direction
- `pressure_msl` : Mean sea level pressure
- `cloud_cover` : Cloud cover percentage
- `weather_code` : Weather condition code
- `visibility` : Visibility
- `uv_index` : UV index
- And many more...
### Daily Weather Variables
- `temperature_2m_max/min` : Maximum/minimum temperatures
- `precipitation_sum` : Total precipitation
- `wind_speed_10m_max` : Maximum wind speed
- `sunrise/sunset` : Sunrise and sunset times
- `weather_code` : Weather condition code
- `uv_index_max` : Maximum UV index
### Air Quality Variables
- `pm10` : PM10 particles
- `pm2_5` : PM2.5 particles
- `carbon_monoxide` : Carbon monoxide
- `nitrogen_dioxide` : Nitrogen dioxide
- `ozone` : Ozone
- `sulphur_dioxide` : Sulfur dioxide
- `ammonia` : Ammonia
- `dust` : Dust particles
- `alder_pollen` : Alder pollen (Europe only)
- `birch_pollen` : Birch pollen (Europe only)
- `grass_pollen` : Grass pollen (Europe only)
- `mugwort_pollen` : Mugwort pollen (Europe only)
- `olive_pollen` : Olive pollen (Europe only)
- `ragweed_pollen` : Ragweed pollen (Europe only)
- `european_aqi` : European Air Quality Index
- `european_aqi_pm2_5` : European AQI for PM2.5
- `european_aqi_pm10` : European AQI for PM10
- `european_aqi_nitrogen_dioxide` : European AQI for NO₂
- `european_aqi_ozone` : European AQI for ozone
- `european_aqi_sulphur_dioxide` : European AQI for SO₂
- `us_aqi` : US Air Quality Index
- `us_aqi_pm2_5` : US AQI for PM2.5
- `us_aqi_pm10` : US AQI for PM10
- `us_aqi_nitrogen_dioxide` : US AQI for NO₂
- `us_aqi_ozone` : US AQI for ozone
- `us_aqi_sulphur_dioxide` : US AQI for SO₂
- `us_aqi_carbon_monoxide` : US AQI for CO
- `uv_index` : UV index
- `uv_index_clear_sky` : UV index under clear sky conditions
### Marine Weather Variables
- `wave_height` : Wave height
- `wave_direction` : Wave direction
- `wave_period` : Wave period
- `wind_wave_height` : Wind wave height
- `swell_wave_height` : Swell wave height
- `sea_surface_temperature` : Sea surface temperature
### Formatting Options
- `temperature_unit` : `celsius`, `fahrenheit`
- `wind_speed_unit` : `kmh`, `ms`, `mph`, `kn`
- `precipitation_unit` : `mm`, `inch`
- `timezone` : `Europe/Paris`, `America/New_York`, etc.
### Time Range Options
- `forecast_days` : Number of forecast days (varies by API)
- `past_days` : Include past days data
- `start_date` / `end_date` : Date range for historical data (YYYY-MM-DD format)
## Development Scripts
```bash
# Development with auto-reload
npm run dev
# Build TypeScript
npm run build
# Start production server
npm start
# Run tests
npm test
# Type checking
npm run typecheck
# Linting
npm run lint
```
## Evaluations
The `evals/` directory holds an LLM-usability benchmark for this server's tools — a different check than `npm test`. Unit tests verify the code is correct; this verifies that an LLM given *only* this server's tools (no other context) can actually complete realistic tasks with them.
- `evals/evaluation.xml` — 10 independent, read-only question/answer pairs built on stable historical data (ERA5 archive, CMIP6 projections, geocoding, elevation), so the expected answers never change over time.
- `evals/scripts/evaluation.py` — harness that launches the server, lets an agent answer each question using only its tools, and compares the answer against the expected one.
### Running the evaluation
```bash
npm run build
pip install -r evals/scripts/requirements.txt
export ANTHROPIC_API_KEY=your_api_key_here
npm run eval
# or directly:
python3 evals/scripts/evaluation.py -t stdio -c node -a dist/index.js evals/evaluation.xml
```
This calls the real Anthropic API for every question, so it consumes tokens/credits — it's a manual quality check for tool design, not part of CI.
When adding, removing, or renaming a tool, or materially changing a tool's description or schema, consider adding or updating a `qa_pair` in `evals/evaluation.xml` that exercises it.
## Project Structure
```
src/
├── index.ts # MCP server entry point
├── client.ts # HTTP client for Open-Meteo API
├── tools.ts # MCP tool definitions
├── types.ts # Zod validation schemas
├── truncation.ts # Response size capping and serialization
└── security.ts # Auth, origin validation, rate limiter, IP extraction
```
## API Coverage
This server provides access to all major Open-Meteo endpoints:
### Weather Data
- Current weather conditions
- Hourly forecasts (up to 16 days)
- Daily forecasts (up to 16 days)
- Historical weather data (1940-present)
### Specialized Models
- High-resolution regional models (DWD ICON, Météo-France AROME)
- Global models (NOAA GFS, ECMWF)
- Regional specialists (JMA for Asia, MET Norway for Nordics)
### Environmental Data
- Air quality forecasts
- Marine and ocean conditions
- River discharge and flood warnings
- Climate change projections
### Advanced Features
- Ensemble forecasts for uncertainty quantification
- Seasonal forecasts for long-term planning
- Multiple model comparison
- Customizable units and timezones
## Error Handling
The server provides comprehensive error handling with detailed error messages for:
- Invalid coordinates
- Missing required parameters
- API rate limits
- Network connectivity issues
- Invalid date ranges
### Response Size Limits
Tool responses are capped at 25,000 characters so a single wide query cannot overflow an LLM's context. When a response exceeds the limit, the time-series arrays (`hourly`, `daily`, `minutely_15`) are shortened by an equal ratio — keeping every parallel series aligned on the same timestamps — and two fields are added:
```json
{
"truncated": true,
"truncation_message": "Response truncated from 95538 characters to stay within the 25000-character limit. Narrow the request (start_date/end_date, forecast_days, past_days, or fewer variables) to retrieve the full data."
}
```
To get complete data, narrow the request: shorter date range, fewer `forecast_days`/`past_days`, or fewer variables.
## Performance
- Efficient HTTP client with connection pooling
- Optimized data serialization
- Minimal memory footprint
## API Documentation
For detailed API documentation, refer to the `openapi.yml` file and the [Open-Meteo API documentation](https://open-meteo.com/en/docs).
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
### Development Setup
1. Fork the repository
2. Clone your fork: `git clone https://github.com/your-username/open-meteo-mcp.git`
3. Install dependencies: `npm install`
4. Create a feature branch: `git checkout -b feature/amazing-feature`
5. Make your changes and add tests
6. Run tests: `npm test`
7. Commit your changes: `git commit -m 'Add amazing feature'`
8. Push to the branch: `git push origin feature/amazing-feature`
9. Open a Pull Request
### Releasing
This project uses automated releases via GitHub Actions. To create a new release:
```bash
# For a patch release (1.0.0 -> 1.0.1)
npm run release:patch
# For a minor release (1.0.0 -> 1.1.0)
npm run release:minor
# For a major release (1.0.0 -> 2.0.0)
npm run release:major
```
The GitHub Action will automatically:
- Run tests and build the project
- Publish to npm with provenance
- Create a GitHub release
- Update version badges
## License
MIT