holiplan
An MCP server for planning a family's year around school holidays and a limited leave allowance.
Assistants are good at suggesting destinations and bad at remembering that Whit Monday is a public holiday, that five carried-over days expire in June, and that you already said no drive over three and a half hours. This server does the parts that should be calculated; the assistant does the parts that need judgement.
Holiday data comes from OpenHolidays (CC BY 4.0), which covers public and school holidays for a growing list of countries, with no API key.
Status
Pre-release (0.1). Stateless: your ledger is a JSON file you keep, and the server stores nothing. See PRIVACY.md for exactly what goes where, and docs/examples.md for what a conversation looks like.
Use it in Claude Desktop
Install uv, then add holiplan to
claude_desktop_config.json and restart Claude:
{
"mcpServers": {
"holiplan": {
"command": "uvx",
"args": ["holiplan"]
}
}
}
uvx fetches holiplan from PyPI and runs it; there is nothing else to install. Without uv,
pip install holiplan and use "command": "holiplan" with no args.
Start with the Set up my family profile prompt, which builds a ledger with you one
question at a time, or copy examples/ledger.example.json to my-ledger.json and edit it.
Tell Claude where the file is, and save the updated ledger whenever Claude hands it back.
A conversation then looks like:
Here's my ledger. What do the 2027 school holidays look like, and what can I afford?
Add two weeks on the Danish coast from 17 July.
What needs booking next?
docs/examples.md has these conversations in full, with real figures.
Tools
| Tool | Purpose |
|---|---|
get_holiday_windows |
School holidays (official and effective dates), single-day closures, and public holidays marked local, half-day and observed |
calculate_leave_cost |
Leave days a given trip needs, with the holidays inside it listed |
find_bridge_days |
The leave days that buy the most time off, and whether the kids are off too |
get_year_budget |
Planned versus available leave, including carryover expiry |
upsert_trip |
Add or update a trip, then re-check the ledger |
check_ledger |
Overlaps, budget breaches, bad dates, trips outside school holidays |
list_deadlines |
Booking deadlines and cancel-by dates, soonest first |
summarise_plan |
The whole plan at a glance, for a brief to your partner |
export_ics |
The plan as a calendar file |
Resources: JSON schemas for the ledger, profile and trip (holiplan://schema/...), and a blank
starter ledger (holiplan://ledger/starter).
Prompts: Set up my family profile, Plan my year, Plan this holiday window, What needs doing next?, Make a brief for my partner.
Design notes
- The ledger is the source of truth. Tools take it in and hand it back, so the plan doesn't drift between conversations.
- Intent decides leave. A week with intent
homeorcampoccupies a school holiday window without costing leave. Override withtakes_leave. - Carryover is spent first, but only by trips ending before the expiry date, so "these days expire in June" shows up as a warning while you can still act on it.
- A trip over New Year costs each year only its own days.
- Local holidays follow your home town. Some holidays cover only part of a region, like
Augsburg's Peace Festival in Bavaria. With the profile's
homeset to a town, only that town's local holidays count as days off; without a home they all do. Setlocal_holidaysto"include"or"exclude"to override.ignore_holidays("MM-DD") covers what the data can't tell apart, such as Assumption Day ("08-15"), which is only a holiday in Catholic-majority Bavarian towns. - School windows include the free days around them. The official Monday-to-Friday dates are stretched over adjacent weekends and public holidays before trips are checked against them. School holidays of two school days or fewer, like All Souls' Day in Austria, are listed separately as closures.
- Half-day holidays cost half a day. Zürich's Sechseläuten afternoon is a half day off, not a full one.
- Regions accept ISO codes. OpenHolidays uses its own codes where they differ (Vienna is
AT-WI, notAT-9); either works, and an unknown region is an error rather than a quietly incomplete year. - Ledgers are versioned. Older ledgers are migrated when read, a newer one is refused, and a malformed one gets an error naming the trip and field at fault.
- When OpenHolidays is down, the server serves the last copy it fetched, or says plainly that it can't check dates right now. It never guesses.
- No real names. Children are identified by alias and interests only.
- The server never books anything. It knows what needs booking and by when; you book it and record the result.
Roadmap
- Drive-time filtering (OpenRouteService or self-hosted OSRM)
- Remote deployment over Streamable HTTP
- Publish to the MCP registry
- School holiday windows by school type, where the data supports it (Zürich splits primary, secondary and vocational; windows already list the types they apply to)
Development
git clone https://github.com/adekola/holiplan.git
cd holiplan
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
python -m unittest discover -s tests # offline
To run your working copy in Claude Desktop, point command at the venv's Python
(.venv/bin/python, or .venv\Scripts\python.exe on Windows) with
"args": ["-m", "holiplan.server"].
Licence
MIT, see LICENSE. Holiday data: OpenHolidays, CC BY 4.0.
Metadata
Release files for holiplan 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| holiplan-0.1.0.tar.gz | 56.9 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| holiplan-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 87.4 kB
Release files / holiplan-0.1.0.tar.gz
| Download URL | holiplan-0.1.0.tar.gz |
|---|---|
| Size | 56.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d3bfbe9c57d48960d01dd231c803655efc3dea96ccb00a5f6d58996a59c0114e
|
|
BLAKE2b-256 checksum How to use checksums |
ed058291fba672c1d00982f5789bb4328ea9d4fd3c015fb15881a7c2d3f80cd2
|
| 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 30, 2026.
Transparency logRelease files / holiplan-0.1.0-py3-none-any.whl
| Download URL | holiplan-0.1.0-py3-none-any.whl |
|---|---|
| Size | 30.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6f1fef5997c7be942f41dd218a4ea345242aec372981b293c14aff041e79395e
|
|
BLAKE2b-256 checksum How to use checksums |
5451ab8d25e54483d12f2d21a1946764dee879c1dccda7f82caca3b94c9d74ef
|
| 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 30, 2026.
Transparency logSecurity for holiplan 0.1.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for holiplan-0.1.0.tar.gz
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 30, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.