# MCP Server Weather ![Python](https://img.shields.io/badge/python-3.13%2B-blue) ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg) A simple weather microservice built with FastMCP, providing weather forecasts and current weather data using the Open-Meteo API. --- ## Table of Contents - [Features](#features) - [Requirements](#requirements) - [Installation](#installation) - [Usage](#usage) - [API & Tool Schema](#api--tool-schema) - [Project Structure](#project-structure) - [Architecture](#architecture) - [Tutorial](#tutorial) - [Contributing](#contributing) - [License](#license) - [Author](#author) --- ## Features - **Get weather forecast** for any location (latitude/longitude) - **Get current weather** for any location (latitude/longitude) - Asynchronous HTTP requests for fast responses - Easy integration as an MCP tool ## Requirements - Python >= 3.13 - httpx >= 0.28.1 - mcp[cli] >= 1.9.2 ## Installation 1. Clone the repository: ```bash git clone https://github.com/yourusername/mcp-server-weather.git cd mcp-server-weather ``` 2. (Optional) Create and activate a virtual environment: ```bash python3 -m venv .venv source .venv/bin/activate ``` 3. Install dependencies: ```bash pip install -r requirements.txt # or, if using pyproject.toml pip install . ``` ## Usage Run the server: ```bash python server.py ``` The server exposes two main tools: ### 1. Get Forecast Fetches a daily weather forecast for a given latitude and longitude. ```python @mcp.tool() async def get_forecast(latitude: float, longitude: float) -> str ``` - **Returns:** Formatted string with daily max/min temperature, precipitation, and weather code. **Example Output:** ``` Date: 2024-06-01 Max Temperature: 22°C Min Temperature: 14°C Precipitation: 0.5 mm Weather Code: 2 --- Date: 2024-06-02 Max Temperature: 20°C Min Temperature: 13°C Precipitation: 1.2 mm Weather Code: 3 ``` ### 2. Get Current Weather Fetches current weather data for a given latitude and longitude. ```python @mcp.tool() async def get_current_weather(latitude: float, longitude: float) -> str ``` - **Returns:** JSON string with current weather details (temperature, wind, humidity, etc.) **Example Output:** ```json { "current": { "temperature_2m": 21.3, "is_day": 1, "showers": 0.0, "cloud_cover": 45, "wind_speed_10m": 5.2, "wind_direction_10m": 180, "pressure_msl": 1012.3, "snowfall": 0.0, "precipitation": 0.0, "relative_humidity_2m": 60, "apparent_temperature": 21.0, "rain": 0.0, "weather_code": 2, "surface_pressure": 1012.3, "wind_gusts_10m": 8.0 } } ``` ## API & Tool Schema - [Open-Meteo API Documentation](https://open-meteo.com/) ### get_forecast - **Input:** - `latitude` (float) - `longitude` (float) - **Output:** - Formatted string with daily weather data (see example above) ### get_current_weather - **Input:** - `latitude` (float) - `longitude` (float) - **Output:** - JSON object with current weather data (see example above) ## Project Structure ``` . ├── server.py # Main server code, defines weather tools ├── pyproject.toml # Project metadata and dependencies ├── README.md # Project documentation ├── project.md # Project code summary ├── .gitignore # Git ignore file ├── .python-version # Python version file ├── uv.lock # Lock file for uv package manager ├── .venv/ # Virtual environment (not committed) └── __pycache__/ # Python cache files ``` ## Architecture ```mermaid graph TD; A[Client (Claude Desktop, etc)] -- stdio --> B(MCP Server: server.py) B -- HTTPX async requests --> C(Open-Meteo API) B -- Exposes tools --> D[LLM/Client] B -- Returns weather data --> A ``` - **Client**: Connects to the MCP server via stdio (e.g., Claude Desktop) - **MCP Server**: Handles requests, exposes tools, fetches data from Open-Meteo - **Open-Meteo API**: Provides weather and forecast data - **LLM/Client**: Consumes the data and generates responses --- # Tutorial Creating an MCP Server Using Python and the Open-Meteo API > **MCP servers extend the capabilities of language models by connecting them to data sources and services.** MCP servers expose three main primitives: ### Resources (client-controlled) - Exposes data to be used as context to clients on request. - Use a resource when you want to passively expose data or content to an MCP client and let the client choose when to access it. ### Tools (model-controlled) - Exposes executable functionality to client models. - Use a tool when you want the client to perform an action, for example to request content from an API, transform data, or send an email. ### Prompts (user-controlled) - Exposes reusable prompts and workflows to users. - Use a prompt when you want the client to surface prompts and workflows to the user, for example to streamline interaction with a resource or tool. ## Example: Weather Data to Natural Language LLMs are great for transforming data into natural language. For example, they can translate weather data like temperature, wind speed, dew point, etc. into descriptions of what the weather will feel like and recommendations on what type of clothing to wear. ## Step-by-Step Tutorial ### 0. Requirements - Claude.ai account (MCP support is available for all account types) - Claude Desktop app (macOS/Windows) - Code editor (e.g., VS Code) - uv (Rust-based Python package manager) - macOS: `brew install uv` - Windows: `winget install --id=astral-sh.uv -e` ### 1. Setting up the project To set up your project, open your code editor to the folder you want to add your project. Then follow these steps to set up your project: Create a new folder called mcp-server-weather using the editor tools or terminal: ```bash mkdir mcp-server-weather ``` Navigate to the folder in terminal: ```bash cd mcp-server-weather ``` Initiate a new uv project: ```bash uv init ``` Create a virtual environment using uv: ```bash uv venv ``` Start the virtual environment: ```bash source .venv/bin/activate ``` Note: To stop the virtual environment, run deactivate in terminal. Install the Python MCP SDK with the CLI extension and additional Python dependencies in the virtual environment: ```bash uv add "mcp[cli]" httpx ``` ### 2. Building the weather MCP server Create `server.py` and add the following scaffolding: ```python from typing import Any import httpx from mcp.server.fastmcp import FastMCP # Initialize FastMCP server mcp = FastMCP("weather") # ... your code here ... if __name__ == "__main__": mcp.run(transport='stdio') ``` #### Add constants and helper function ```python OPENMETEO_API_BASE = "https://api.open-meteo.com/v1" USER_AGENT = "weather-app/1.0" # Helper function to make a request to the Open-Meteo API async def make_openmeteo_request(url: str) -> dict[str, Any] | None: """Make a request to the Open-Meteo API with proper error handling.""" headers = { "User-Agent": USER_AGENT, "Accept": "application/json" } async with httpx.AsyncClient() as client: try: response = await client.get(url, headers=headers, timeout=30.0) response.raise_for_status() return response.json() except Exception: return None ``` #### Add tools ```python @mcp.tool() async def get_forecast(latitude: float, longitude: float) -> str: # ... @mcp.tool() async def get_current_weather(latitude: float, longitude: float) -> str: """Get current weather for a location. Args: latitude: Latitude of the location longitude: Longitude of the location """ url = f"{OPENMETEO_API_BASE}/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m,is_day,showers,cloud_cover,wind_speed_10m,wind_direction_10m,pressure_msl,snowfall,precipitation,relative_humidity_2m,apparent_temperature,rain,weather_code,surface_pressure,wind_gusts_10m" data = await make_openmeteo_request(url) if not data: return "Unable to fetch current weather data for this location." return data ``` ### 3. Testing and running the MCP server ```bash mcp dev server.py ``` - Open http://localhost:5173 in your browser - Connect, list tools, and test with latitude/longitude ### 4. Extending the MCP server - Add more tools (e.g., get_location) - Use the Open-Meteo Geocoding API for location search --- ## Contributing Contributions are welcome! Please open an issue or submit a pull request for improvements, bug fixes, or new features. ## License MIT ## Author - ONE-FRONT tech by [Michael Wybraniec](https://www.one-front.com/) - MCP Hands-On by [Morten Rand-Hendriksen](https://www.linkedin.com/learning-login/share?forceAccount=false&redirect=https%3A%2F%2Fwww.linkedin.com%2Flearning%2Fmodel-context-protocol-mcp-hands-on-with-agentic-ai%3Ftrk%3Dshare_ent_url%26shareId%3DUtpyZDvtQty%252B%252BH6bnA1v6A%253D%253D)