TB

thiccboy-blip/calendar-mcp

Developer tools
0 stars 0 forks Quality 68 Trend 20

MCP server that lets an AI chat client read and book a calendar.

Overview

An MCP server that lets an AI chat client . It exposes two tools over stdio JSON-RPC, so any MCP client (opencode, Claude Desktop, …) can schedule meetings from a normal chat. - check_calendar(start_date, end_date, timezone=None) — busy events and free 30-minute slots per day - book_slot(person, date, start, duration_minutes=30, title=None, timezone=None) — books a slot, with an existing event The server implements the Model Context Protocol by hand with only the Python standard library — except tzdata on Windows for timezone support. State lives in a plain JSON file (calendar.json). The never-double-book rule is enforced , not in a prompt. book_slot takes a cross-process lock, re-reads every event, and refuses overlaps, writing atomically (os.replace) — so a misbehaving model or a concurrent caller cannot create a conflict. Times are timezone-aware (IANA zones), and overlaps are compared as absolute instants (DST-safe). The client launches the server as a stdio process.

README

calendar-mcpAn MCP server that lets an AI chat clientread and book a calendar. It exposes three tools over stdio JSON-RPC, so anyMCP client (opencode, Claude Desktop, …) can schedule meetings from a normalchat.- check_calendar(start_date, end_date, timezone=None) — busy events and free 30-minute slots per day; ind_slot ranks multi-person options with explanations- book_slot(person, date, start, duration_minutes=30, title=None, timezone=None) — books a slot, rejecting any overlap with an existing eventThe server implements the Model Context Protocol by hand with only the Pythonstandard library — nothing to install except tzdata on Windows fortimezone support. State lives in a plain JSON file (calendar.json).## Why it’s differentThe never-double-book rule is enforced in code, not in a prompt. book_slottakes a cross-process lock, re-reads every event, and refuses overlaps, writingatomically (os.replace) — so a misbehaving model or a concurrent caller cannotcreate a conflict. Times are timezone-aware (IANA zones), and overlaps arecompared as absolute instants (DST-safe).## Quick startbashpip install tzdata # Windows only; Linux/macOS already have the tz databasepython seed_calendar.py # write a sample calendar.json (dates relative to today)python mcp_server.py # run the MCP server on stdio (usually launched by a client)## Register with a clientThe client launches the server as a stdio process. Example for opencode’sopencode.json:json{ "$schema": "https://opencode.ai/config.json", "mcp": { "calendar-mcp": { "type": "local", "command": ["python", "calendar-mcp/mcp_server.py"], "enabled": true } }}Claude Desktop uses the same shape in claude_desktop_config.json:json{ "mcpServers": { "calendar-mcp": { "command": "python", "args": ["/absolute/path/to/calendar-mcp/mcp_server.py"] } }}Restart the client, then ask in normal language:> Book 30 minutes with Sam next Tuesday at 10:00.\n\nThe client can call check_calendar to inspect free slots, use find_slot to get a cross-timezone optimal list with explanations, and then book_slot to book.## Tools### find_slot (constraint-aware scheduling)\n\n| field | type | notes |\n| — | — | — |\n| duration_minutes | integer? | meeting length (default 30) |\n| start_date | string? | first day to search (defaults to today, organizer tz) |\n| end_date | string? | last day to search (defaults to +7 days) |\n| max_results | integer? | how many ranked options to return (default 5) |\n| min_notice_minutes | integer? | minimum lead time (default 0) |\n\nReads participants.json (list of people with timezones, working hours, buffers, events, preferences). Returns ranked options with local_times, score_breakdown, and human-readable reasons. Hard constraints (work days/hours, busy+buffer, min notice) are enforced; soft preferences (fairness across timezones, preference fit, compactness, earliness) determine ranking.\n\n### check_calendar| field | type | notes || — | — | — || start_date | string | first day, YYYY-MM-DD || end_date | string | last day, YYYY-MM-DD (inclusive) || timezone | string? | IANA zone to render times in (default: home zone) |Returns, per day: working_day, the busy events, and free_slots (HH:MM).### book_slot| field | type | notes || — | — | — || person | string | who the meeting is with || date | string | day to book, YYYY-MM-DD || start | string | start time, HH:MM (24h) || duration_minutes | integer? | default 30 || title | string? | optional title || timezone | string? | zone that date/start are expressed in |Working days are Mon–Fri, working hours 09:00–17:00. Overlapping bookings arerejected with the conflicting event, so the model can pick another slot.## Configuration- calendar.json — the calendar (created automatically if missing). Set its timezone field to the home IANA zone; working hours are validated there.- seed_calendar.py — writes a sample calendar; CALENDAR_TZ=Asia/Kolkata python seed_calendar.py sets the home zone.## Testsbashpython -m pytestCovers the protocol handshake and tools/list, plus booking, overlap rejection, constraint-aware scheduling, working-hours/weekend rules, and timezone handling in calendar_store.

Multi-person scheduling demo

python seed_participants.py  # create participants.json
python demo_schedule.py --duration 30 --range-days 5
View this README on GitHub

Install

This server does not publish a one-line install command.

Open the repository installation guide