Swiss Weather MCP Server
A Model Context Protocol (MCP) server that exposes Swiss weather forecast data as callable tools. It fetches data from the official MeteoSwiss meteodata-lab, caches it locally, and serves predictions such as rainfall, sunshine, temperature, etc. The prediction data is from the ICON-CH2-EPS forecast system that produces data for up to 5 days ahead.
Additionally there is also an MCP client that can be run to test the server using the stdio transport.
Note: This project is not an official MeteoSwiss product. All forecast data are from the MeteoSwiss Open Data portal. Source: MeteoSwiss
Table of Contents
- Project Structure
- Quick Start
- Installation
- Configuration
- Usage
- Available Tools
- Example Usage with LMStudio
- Tests
- Releasing
- Resources
- License
Project Structure
swiss-weather-mcp/
├── src/swiss_weather_mcp/
│ ├── server.py # MCP server
│ ├── predictions.py # Data fetching logic
│ └── client.py # MCP client (optional)
├── tests/swiss_weather_mcp/ # Pytest suite
├── .github/workflows/ # CI and release pipelines
├── docs/ # Documentation
├── pyproject.toml # Project metadata and dependencies
├── uv.lock # Pinned, reproducible dependency set
├── .env # NOMINATIM_USER_AGENT (not committed)
└── Dockerfile
Caches live outside the project, under your OS's standard cache directory (see Installation).
Quick Start
1. Installation
Install the server globally to run it anywhere on your system:
uv tool install swiss-weather-mcp
2. Configuration
Create a .env file with your Nominatim user agent (see Configuration):
echo 'NOMINATIM_USER_AGENT="YourWeatherMCPServer/1.0 (yourname@example.com)"' > .env
3. Execution
Run the server from the directory containing your .env file:
swiss-weather-mcp-server
Installation
As a Global CLI Tool
uv tool install swiss-weather-mcp
# With the optional MCP client, which pulls in the OpenAI SDK
uv tool install 'swiss-weather-mcp[client]'
As a Library Dependency
# Using uv
uv add swiss-weather-mcp
# Using pip
pip install swiss-weather-mcp
# With the optional MCP client, which pulls in the OpenAI SDK
uv add 'swiss-weather-mcp[client]'
pip install 'swiss-weather-mcp[client]'
From Source
git clone https://github.com/cuolm/swiss-weather-mcp.git
cd swiss-weather-mcp
# Using uv (Recommended)
uv sync --extra client
# Using pip
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -e ".[client]"
Note:
uv syncinstalls the server only.--extra clientadds the OpenAI SDK needed byswiss-weather-mcp-client.
Note:
llama-servermust already be running when you startswiss-weather-mcp-client, which talks to it but never starts it. The MCP server itself does not need it.- The
.envfile is read from the current working directory, so run the server from the directory holding it. ExportingNOMINATIM_USER_AGENTworks when you start the server yourself, but not throughswiss-weather-mcp-client: the MCP stdio transport forwards only a fixed list of variables.- A
.envfile is read only by the two entry points, not when the package is imported as a library.MeteoSwissPredictionstakesNOMINATIM_USER_AGENTfrom the environment, and the calling application decides how it gets there.- Caches live in your OS cache directory (via platformdirs, e.g.
~/Library/Caches/swiss-weather-mcpon macOS,~/.cache/swiss-weather-mcpon Linux), independent of where the server runs, so forecasts and geocoded locations are reused. DeleteEarthKitCache/ornominatim_geocode_cache.jsonto clear them.
Configuration
Create a .env file in the directory you'll run the server from, specifying an environment variable that tells Nominatim (the geocoding service) who is making the call.
echo 'NOMINATIM_USER_AGENT="YourWeatherMCPServer/1.0 (yourname@example.com)"' > .env
Note: Replace the name and address with your own. The Nominatim usage policy requires a user agent identifying a real application and contact address, and blocks requests without one. Keep lookups to at most one per second. Results are cached, so only new locations reach the service.
Usage
Running the Server
If installed via uv tool install or pip:
# stdio (default)
swiss-weather-mcp-server
# streamable-http
swiss-weather-mcp-server --transport=streamable-http --host=localhost --port=8050
If running within the source repository cloned from GitHub:
# Using uv (Recommended)
uv run swiss-weather-mcp-server
# Using pip, with the virtual environment activated
swiss-weather-mcp-server
Optional flags: --help
Running the Server with Docker
Images are built and published automatically by GitHub Actions to the project's GitHub Container Registry, tagged :latest (newest release) and by version.
- Create a
.envfile containing your Nominatim user agent environment variable (replace"YourWeatherMCPServer/1.0 (yourname@example.com)"):echo 'NOMINATIM_USER_AGENT="YourWeatherMCPServer/1.0 (yourname@example.com)"' > .env
- Run the published image, passing the
.envfile and mapping port 8050:docker run --env-file .env -p 8050:8050 ghcr.io/cuolm/swiss-weather-mcp:latest
- Access the server at:
http://localhost:8050/mcp/
Manual Build
docker build -t swiss-weather-mcp .
docker run --env-file .env -p 8050:8050 swiss-weather-mcp
Running the MCP Client using Stdio Transport
The bundled MCP client can be used to test the server over the stdio transport. It requires the client extra (see Installation). The client starts the MCP server itself, but not the model server, which has to be running first.
- Install llama.cpp, which provides
llama-server:brew install llama.cpp
- Start it in its own terminal, downloading the model on first use:
llama-server --jinja --no-mmproj -hf unsloth/Qwen3.5-4B-GGUF --port 8080
- Run the client against it in a second terminal:
swiss-weather-mcp-client --model=unsloth/Qwen3.5-4B-GGUF --base-url=http://localhost:8080/v1 # From a source checkout, using uv uv run --extra client swiss-weather-mcp-client --model=unsloth/Qwen3.5-4B-GGUF --base-url=http://localhost:8080/v1
Note:
--jinjaapplies the model's chat template, without which tool calling is unsupported, and--no-mmprojskips the vision projector that-hfdownloads alongside some models.--base-urldefaults tollama-server's address, and any other OpenAI compatible backend works by pointing it elsewhere, for example LM Studio or vLLM. Pass--modelexactly as the server reports it under/v1/models.
Available Tools
| Tool | Purpose | Example Call |
|---|---|---|
current_date_and_time() |
Current date and time (weekday day.month.year hour:minute:second) in Swiss local time | current_date_and_time() |
total_rainfall(location, lead_time_start_swiss, lead_time_end_swiss) |
Total rainfall (mm) for a period | total_rainfall("Zurich", 24, 48) |
sunshine_hours(location, lead_time_start_swiss, lead_time_end_swiss) |
Sunshine hours for a period | sunshine_hours("Zurich", 24, 48) |
temperature(location, lead_time_swiss) |
Max temperature (°C) at a specific lead time | temperature("Zurich", 36) |
wind_speed(location, lead_time_swiss) |
Wind speed (m/s) at a specific lead time | wind_speed("Zurich", 36) |
pressure_msl(location, lead_time_swiss) |
Sea‑level pressure (Pa) at a specific lead time | pressure_msl("Zurich", 36) |
total_cloud_cover(location, lead_time_swiss) |
Cloud cover (%) at a specific lead time | total_cloud_cover("Zurich", 36) |
snow_depth(location, lead_time_swiss) |
Snow depth (m) at a specific lead time | snow_depth("Zurich", 36) |
precipitation_rate(location, lead_time_swiss) |
Precipitation rate (mm/s) at a specific lead time | precipitation_rate("Zurich", 36) |
Lead Time
- Lead time is the number of hours counted from Swiss local time 00:00, internally converted to UTC (the ICON-CH2-EPS forecast system uses UTC).
- Example: A lead time of 36 hours returns the forecast for 12:00 Swiss local time tomorrow.
- Minimum lead time: 2 hours, maximum lead time: 121 hours.
Example Usage with LMStudio
Using the streamable-http transport layer
Configure the mcp.json file in LMStudio:
{
"mcpServers": {
"swiss_weather_mcp_server": {
"url": "http://localhost:8050/mcp/"
}
}
}
Run the MCP server with the streamable-http transport layer:
uv run swiss-weather-mcp-server --transport=streamable-http --host=localhost --port=8050
Using the stdio transport layer
Configure the mcp.json file in LMStudio. Replace <path-to-the-project> with your actual local path:
{
"mcpServers": {
"swiss_weather_mcp_server": {
"command": "<path-to-the-project>/.venv/bin/swiss-weather-mcp-server"
}
}
}
Tests
Run the test suite from the project root with:
uv run pytest
# Or, with an activated virtual environment
pytest
Every push and pull request runs the suite plus a Docker build check via the Tests workflow.
Releasing
Versions are derived from Git tags by hatch-vcs — there is no version string to bump by hand.
- Pushing a pre-release tag (e.g.
0.2.0rc1) triggersrelease_test.yaml: tests, publish to TestPyPI, push a versioned image to GHCR, and create a prerelease GitHub Release. - Pushing a final tag (e.g.
0.2.0) triggersrelease.yaml: tests, publish to PyPI, push:<version>and:latestimages to GHCR, and create a GitHub Release.
Both publish jobs use PyPI trusted publishing via the pypi / testpypi GitHub environments — no API tokens are stored in the repository.
Resources
License
Licensed under the Apache License 2.0.
Release files for swiss-weather-mcp 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| swiss_weather_mcp-0.1.1.tar.gz | 365.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| swiss_weather_mcp-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 387.4 kB
Release files / swiss_weather_mcp-0.1.1.tar.gz
| Download URL | swiss_weather_mcp-0.1.1.tar.gz |
|---|---|
| Size | 365.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7e4b88039fb6d3be781769f5f64d47117be28436902e26a6e594a11dbe2b945
|
|
BLAKE2b-256 checksum How to use checksums |
706cc9ae52325d4430a7560ea512208b2a446b88c39bd60477ae674d9aad21d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency logRelease files / swiss_weather_mcp-0.1.1-py3-none-any.whl
| Download URL | swiss_weather_mcp-0.1.1-py3-none-any.whl |
|---|---|
| Size | 21.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
23ddd61c610a4f664ed6e16bb3a9bd38b98309d1cbc2ce7031cae1751d7fe0be
|
|
BLAKE2b-256 checksum How to use checksums |
b29af9bad52097838224d5391b82995344cad9dafa8d9688ccb0f0f64eedf2b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency log