weather-packing-bot
MCP server exposing Open-Meteo weather forecast tools, including a text chart renderer, for itinerary-aware packing recommendations.
README
weather-packing-bot
A scheduled bot that posts a Slack message with a multi-day weather forecast and a packing recommendation for a recurring three-city travel route. It is also a small reference implementation of an MCP (Model Context Protocol) server and client pair: the forecast data is served by a standalone MCP server and consumed by an MCP client, rather than being fetched directly by the bot script.
Overview
The bot runs on a weekly schedule (Fridays, 15:00 CEST) and posts a Slack message covering the weather from that day through the following Monday evening. The forecast and packing recommendation are itinerary-aware: they account for which of three cities the traveler is expected to be in on each day of that window, rather than showing all locations' weather indiscriminately.
GitHub Actions (scheduled, Fridays)
│
▼
bot/packing_advisor.py MCP client
│ spawns as subprocess, communicates over stdio
▼
mcp_server/weather_server.py MCP server, queries Open-Meteo
│
▼
Slack incoming webhook
Why an MCP server and client
The server exposes weather tools without any knowledge of who calls them
or why - it could be this bot, an IDE assistant, or any other MCP-capable
client. The client does not import the server's Python functions directly;
it discovers available tools at runtime (session.list_tools()) and
invokes them by name over the protocol (session.call_tool(...)). This
separation is what distinguishes the design from simply calling a function
in the same process.
Components
mcp_server/weather_server.py
An MCP server (using the MCPServer class from the mcp package) that
wraps the Open-Meteo API and exposes four tools:
| Tool | Description |
|---|---|
list_cities() |
Returns the configured city names. |
get_forecast(city, days=3) |
Daily weather summary for one city. |
get_forecast_all(days=3) |
Daily weather summary for every configured city. |
render_temperature_chart(days=4) |
A compact per-city, per-day text chart (temperature bar, weather icon, precipitation), formatted for a Slack code block. |
Cities are defined in the COORDINATES dict and can be extended freely.
bot/packing_advisor.py
An MCP client that:
- Computes the forecast window - the current date through the following
Monday, inclusive - via
forecast_window(). - Spawns
weather_server.pyas a subprocess, performs the MCP handshake, and callsget_forecast_allandrender_temperature_chartfor that window. - Matches each date in the window against
WEEKLY_ITINERARY, a dict mapping weekday to the city (or cities) the traveler is expected to be in that day, so that only relevant locations inform the output. - Passes the matched days to
recommend_packing(), a rule-based function using temperature and precipitation thresholds (no external AI call). - Formats a Slack Block Kit message - day-by-day breakdown, packing list, and chart - and posts it via an incoming webhook.
Travel itinerary
WEEKLY_ITINERARY in bot/packing_advisor.py encodes a recurring weekly
route:
WEEKLY_ITINERARY = {
4: [("Nijmegen", "arrival")], # Friday
5: [("Nijmegen", "")], # Saturday
6: [("Nijmegen", "")], # Sunday
0: [("Den Bosch", "day"), ("Kerpen", "evening, back home")], # Monday
}
Monday has two entries because it is a transition day: the itinerary places the traveler in Den Bosch during the day and back in Kerpen by evening. This dict is the single place to edit if the route changes.
The chart
render_temperature_chart produces a plain-text, monospace chart rather
than an image. This is a deliberate constraint: a Slack incoming webhook
can only post text or Block Kit JSON - it cannot upload a binary file.
Posting an actual image would require a Slack bot token (an installed
Slack App with the files:write scope) and a call to Slack's files.upload
Web API instead of the webhook. That is a viable extension but requires
managing an additional credential; the current implementation avoids that
requirement entirely.
Setup
Prerequisites
- A Slack app with an incoming webhook URL.
- A GitHub repository to host the code and run the scheduled workflow.
Local run
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # fill in SLACK_WEBHOOK_URL
export $(grep -v '^#' .env | xargs)
python bot/packing_advisor.py
SIMULATE_DATE (see .env.example) can be set to an ISO date to exercise
the itinerary/forecast-window logic without waiting for an actual Friday.
The MCP server can also be inspected on its own:
pip install "mcp[cli]"
mcp dev mcp_server/weather_server.py
This opens the MCP Inspector in a browser, useful for viewing tool schemas
and calling tools such as get_forecast or render_temperature_chart
directly.
GitHub repository configuration
- Add
SLACK_WEBHOOK_URLas a repository secret (Settings → Secrets and variables → Actions → Secrets). - No other repository configuration is required; the itinerary is defined in code rather than as a repository variable.
Schedule
.github/workflows/weekly-forecast.yml runs every Friday at 13:00 UTC
(15:00 CEST) via cron: "0 13 * * 5". Cron schedules in GitHub Actions do
not observe daylight saving time, so during the CET (winter) period this
fires at 14:00 local time instead of 15:00; the cron expression can be
adjusted seasonally if that offset matters. The workflow also supports
manual triggering (workflow_dispatch) with an optional simulate_date
input, useful for testing before relying on the schedule.
Known limitations and possible extensions
- The Slack message includes a text-based chart rather than an image, for
the reason described above. A PNG chart via matplotlib, combined with a
Slack bot token and
files.upload, is a possible follow-up. recommend_packing()is rule-based. Replacing it with a call to an LLM (e.g. the Anthropic API) would allow more natural-language output; the MCP tool results are plain dicts, so they can be passed directly into such a call.- The itinerary is a fixed weekly pattern. A calendar-integration source (e.g. reading actual travel dates from a calendar) would generalize it beyond a repeating weekly route.
Notes on the source material
The original draft server script had several issues that were corrected during development of this implementation:
- An unused, non-existent
httpx2import. get_params()built a parameters dict but did not return it.- The Open-Meteo client was constructed only inside
if __name__ == "__main__", making it unavailable to the tool functions that referenced it at module scope. process_responseattempted to assign into alistusing adict_keysobject as an index, which is not valid.- Tool functions returned pandas
DataFrameobjects and numpy scalar types, which are not JSON-serializable; MCP tool results must be serializable, since they are transmitted as JSON.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.