Skip to content

NimbleBrainInc/mcp-openweathermap

Repository files navigation

OpenWeatherMap MCP Server

NimbleTools Registry NimbleBrain Platform Discord

Python 3.13+ License: MIT CI

About

Production-ready MCP server for accessing comprehensive weather data from OpenWeatherMap.

Features

  • Hybrid Tool Design: 5 tools balancing convenience with LLM reasoning capability
  • Graceful Degradation: Automatically uses One Call API when available, falls back to free tier
  • Smart Fallback Pattern: When location lookup fails, error message guides LLM to use search_location
  • Flexible Input: All weather tools accept either location string OR direct lat/lon coordinates
  • Strongly Typed: All responses use Pydantic models with full type safety
  • HTTP & Stdio Transport: Supports both streamable-http and stdio for Claude Desktop
  • Async/Await: Built on aiohttp for high performance
  • Type Safe: Full mypy strict mode compliance
  • Comprehensive Tests: Full coverage with pytest + AsyncMock
  • Built-in Skill Resource: Serves a skill://openweathermap/usage resource that teaches LLMs location resolution patterns and tool selection

Architecture

src/mcp_openweathermap/
├── __init__.py          # Package exports
├── server.py            # FastMCP server with 4 intent-based tools
├── api_client.py        # OpenWeatherMapClient with graceful degradation
├── api_models.py        # Pydantic models for type safety
└── utils.py             # Helper functions

tests/
├── test_server.py       # MCP tool tests
└── test_api_client.py   # API client tests

Installation

Prerequisites

Using uv (recommended)

# Install dependencies
uv pip install -e .

# Install with dev dependencies
uv pip install -e . --group dev

Using pip

pip install -e .

Configuration

Set your API key as an environment variable:

export OPENWEATHERMAP_API_KEY=your_api_key_here

Or create a .env file:

OPENWEATHERMAP_API_KEY=your_api_key_here

Running the Server

Stdio Mode (for Claude Desktop)

# Using make
make run

# Or directly
uv run python -m mcp_openweathermap.server

HTTP Mode (for web applications)

# Using make
make run-http

# Or directly
uv run uvicorn mcp_openweathermap.server:app --host 0.0.0.0 --port 8000

Docker

# Build image
make docker-build

# Run container
make docker-run OPENWEATHERMAP_API_KEY=your_key

# Or using docker directly
docker build -t mcp-openweathermap .
docker run -p 8000:8000 -e OPENWEATHERMAP_API_KEY=your_key mcp-openweathermap

Available MCP Tools

1. search_location

Resolve location query to coordinates. Use when direct location lookup fails or for ambiguous queries.

Parameters:

  • query (str): Location search query (city name, landmark, etc.)
  • limit (int, default=5): Max results to return

Returns: List of matching locations with name, state, country, lat, lon

Example:

# Disambiguate "Springfield" (exists in many US states)
search_location(query="Springfield")
# Returns multiple candidates - LLM picks the right one

# Find Waimea in Hawaii (direct lookup fails for "Waimea, HI")
search_location(query="Waimea")
# Returns candidates in Hawaii and elsewhere

2. check_weather

Get current weather conditions. Pass location string OR lat/lon coordinates.

Parameters:

  • location (str, optional): City name (e.g., 'London', 'Tokyo')
  • lat (float, optional): Latitude (use with lon instead of location)
  • lon (float, optional): Longitude (use with lat instead of location)
  • units (str, default='metric'): Temperature units ('metric', 'imperial', 'standard')

Returns: Current temperature, humidity, wind, weather conditions, and location info

Example:

# By city name (fast path)
check_weather(location="London")

# By coordinates (precise path - use after search_location)
check_weather(lat=20.02, lon=-155.66)

# With imperial units
check_weather(location="Tokyo", units="imperial")

Fallback Pattern: If location lookup fails, error suggests using search_location first.

3. get_forecast

Get weather forecast. Pass location string OR lat/lon coordinates.

Parameters:

  • location (str, optional): City name
  • lat (float, optional): Latitude
  • lon (float, optional): Longitude
  • units (str, default='metric'): Temperature units

Returns: Forecast data with source field indicating tier:

  • one_call: Hourly (48h) + daily (8-day) forecasts with weather alerts
  • free_tier: 5-day forecast with 3-hour intervals (automatic fallback)

Example Response (One Call):

{
  "source": "one_call",
  "hourly": [...],
  "daily": [...],
  "alerts": [],
  "timezone": "Europe/London"
}

Example Response (Free Tier Fallback):

{
  "source": "free_tier",
  "forecast_list": [...],
  "city": {"name": "London"},
  "alerts": [],
  "note": "Hourly forecast and alerts require One Call API subscription"
}

4. check_air_quality

Get air quality index and pollutant levels. Pass location string OR lat/lon coordinates.

Parameters:

  • location (str, optional): City name
  • lat (float, optional): Latitude
  • lon (float, optional): Longitude

Returns: Air Quality Index (1=Good to 5=Very Poor) and concentrations of CO, NO, NO2, O3, SO2, PM2.5, PM10, NH3

5. get_historical_weather

Get historical weather data for a past date. Requires One Call API subscription.

Parameters:

  • date (str, required): Date in YYYY-MM-DD format (within approximately last 5 days)
  • location (str, optional): City name
  • lat (float, optional): Latitude
  • lon (float, optional): Longitude
  • units (str, default='metric'): Temperature units

Returns: Historical weather data or helpful error if subscription not available

Example Response (Success):

{
  "source": "one_call",
  "lat": 51.5,
  "lon": -0.1,
  "timezone": "Europe/London",
  "current": {"temp": 12.5, ...}
}

Example Response (No Subscription):

{
  "error": "Historical weather requires One Call API subscription",
  "subscription_url": "https://openweathermap.org/api/one-call-3"
}

LLM Fallback Pattern

The tools are designed so that when direct location lookup fails, the LLM can reason about alternatives:

  1. Try direct: check_weather(location="Waimea, HI") → fails with hint
  2. Search: search_location(query="Waimea") → returns candidates
  3. Pick & retry: check_weather(lat=20.02, lon=-155.66) → succeeds

This pattern handles:

  • US state abbreviations ("HI" vs "Hawaii")
  • Country code variations ("UK" vs "GB")
  • Ambiguous locations (multiple "Springfield"s)

API Tiers

Feature Free Tier One Call API
Current weather Yes Yes
5-day/3-hour forecast Yes Yes
Hourly forecast (48h) No Yes
Daily forecast (8 days) No Yes
Weather alerts No Yes
Historical data No Yes
Air quality Yes Yes
Rate limit 1M calls/month 1000 free/day

The server automatically detects your API tier and uses the best available data.

Development

Available Make Commands

make help          # Show all commands
make install       # Install dependencies
make dev-install   # Install with dev dependencies
make format        # Format code with ruff
make lint          # Lint code with ruff
make lint-fix      # Lint and auto-fix issues
make typecheck     # Type check with mypy
make test          # Run tests
make test-cov      # Run tests with coverage
make clean         # Clean up artifacts
make run           # Run server (stdio)
make run-http      # Run server (HTTP)
make check         # Run all checks (lint + typecheck + test)
make all           # Full workflow

Running Tests

# Run all tests
make test

# Run with coverage
make test-cov

# Run specific test file
uv run pytest tests/test_server.py -v

# Run specific test
uv run pytest tests/test_server.py::TestMCPTools::test_get_solar_radiation -v

Code Quality

# Format code
make format

# Lint code
make lint

# Type check
make typecheck

# Run all quality checks
make check

API Documentation

For detailed OpenWeatherMap API documentation:

Requirements

  • Python >=3.10
  • aiohttp >=3.12.15
  • fastapi >=0.117.1
  • fastmcp >=2.12.4
  • pydantic >=2.0.0
  • uvicorn >=0.32.1

Rate Limits

  • Free Tier: 1,000,000 calls/month, 60 calls/minute
  • One Call API: 1,000 free calls/day, then pay-per-call

For pricing details, see OpenWeatherMap pricing.

Health Check

When running in HTTP mode, a health check endpoint is available:

curl http://localhost:8000/health
# {"status": "healthy", "service": "openweathermap-mcp"}

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run make check to ensure quality
  5. Submit a pull request

Support

For issues or questions:

License

MIT

Links

Part of the NimbleTools Registry - an open source collection of production-ready MCP servers. For enterprise deployment, check out NimbleBrain.