Skip to main content
Glama
holiplan
by adekola

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.6). 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.

Related MCP server: Apple Calendar MCP Server

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 home or camp occupies a school holiday window without costing leave. Override with takes_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 home set to a town, only that town's local holidays count as days off; without a home they all do. Set local_holidays to "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.

  • One school type's holidays. Where a region's dates differ by school type (general and vocational schools in Mecklenburg-Vorpommern, primary and secondary in Zürich), the profile's school_group picks one; without it, the general schools'. get_holiday_windows lists the region's groups.

  • A drafted year to start from. holiplan.service.draft_year places one trip in each school holiday, summer first with two weeks, where each costs the least leave, and never over budget. Every drafted trip is an idea to keep, move or delete.

  • 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, not AT-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 holidays that differ by municipality (Appenzell Innerrhoden, Graubünden), chosen by the profile's home

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.

Available Tools

9 tools
calculate_leave_costB

Leave days needed to be away from start to end (inclusive).

Accounts for weekends, public holidays inside the trip, and any half days, part-time pattern or local-holiday settings in the ledger's profile.

Inputs: end (required), start (required), country (required), ledger, +1 more. Returns: object

check_ledgerA

Validate the whole ledger: overlaps, budget breaches, bad dates, and trips that fall outside the school holidays.

Run this before telling the user a plan works.

Inputs: ledger (required). Returns: object

export_icsB

The ledger as an .ics calendar file the user can import.

Returns file contents -- tell the user to save it and import it.

Inputs: ledger (required), include_deadlines. Returns: result

find_bridge_daysC

The leave days that buy the most time off, best value first.

Each option says which days to take off, the stretch that buys, days off per leave day, the public holidays that make it a bridge, and school: "holiday" when the children are off school for all of it, "partly", or "term". Pass the ledger so the parent's work pattern, half days and local holidays count. Options can overlap -- they are alternatives.

Inputs: year (required), country (required), limit, ledger, +2 more. Returns: object

get_holiday_windowsA

School holiday windows and public holidays for a region and year.

Use this to frame the year before discussing destinations. region is a subdivision code such as "DE-BY" (Bavaria) or "AT-WI" (Vienna; the ISO code "AT-9" works too). Pass the profile's home (the family's town) when known.

Each school window has its official dates and its effective dates, stretched over the weekends and public holidays that touch it -- the days the family can actually be away. Holidays of two school days or fewer are listed separately as school_closures. Public holidays marked local apply to only part of the region; observed says whether the home keeps them, and is null when there is no home to check -- then ask the family.

Inputs: year (required), country (required), home, region. Returns: object

get_year_budgetB

Leave planned versus available for a year, including carryover expiry.

Answers "can we afford all of this?" -- call it after every change.

Inputs: year (required), ledger (required). Returns: object

list_deadlinesB

Dated actions the plan implies: booking deadlines and cancel-by dates.

Use it to answer "what needs doing next?".

Inputs: ledger (required), today. Returns: result

summarise_planB

The whole plan at a glance, for a brief to a partner or a quick recap.

Returns the family, leave per year, every trip with its leave cost and booking state, each school window with the plans in it, open_windows still to decide, issues, and overdue and upcoming deadlines. Turn it into prose; don't recalculate any figure in it.

Inputs: ledger (required), today. Returns: object

upsert_tripB

Add or update one trip in the ledger, then re-check the whole ledger.

Returns the updated ledger plus any issues. Hand the ledger back to the user so they can save it.

Inputs: trip (required), ledger (required). Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 9 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes: holiday lookup, leave-cost calculation, bridge-day discovery, budgeting, trip upsert, validation, deadlines, summarisation, and export. Some overlap exists among get_year_budget, check_ledger, and summarise_plan, since all can surface budget or ledger issues, but their primary intents are different enough that an agent should usually choose correctly.

    Naming Consistency5/5

    All tool names use snake_case with a consistent verb_noun or verb_object pattern: get_holiday_windows, calculate_leave_cost, find_bridge_days, upsert_trip, check_ledger, list_deadlines, summarise_plan, export_ics. The only minor variation is export_ics being noun-oriented rather than verb_noun, but it still fits the convention and is unambiguous.

    Tool Count5/5

    Nine tools is well-scoped for a holiday/leave planning server. Each tool covers a distinct part of the workflow, and there is no obvious bloat or missing core capability that would require several extra tools.

    Completeness4/5

    The surface covers the main lifecycle: holiday windows, leave cost, bridge days, budget, trip upsert, validation, deadlines, summary, and calendar export. The main gap is the absence of an explicit delete_trip or remove operation, though upsert_trip may allow updates and agents can likely work around this for most planning tasks.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      MCP server for business-day arithmetic with country-aware holiday calendars. It offers tools to check, calculate, and list business days and holidays for over 60 countries.
      9
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      MCP server for personal finance management. Enables natural language expense logging, budgeting, recurring charge detection, and statement import with deterministic local calculations.
      -
    • F
      license
      Not graded
      quality
      C
      maintenance
      An MCP server for agent-bookable holiday lets, enabling AI assistants to check availability, get signed quotes, and request bookings with mandatory owner approval.
      -