ACTION-LOG UNDO · TZ ENFORCEMENT · OAUTH
Google Calendar MCP server with an action-log undo system, timezone enforcement, and idempotent event creation.
- STATUS
- Live · in daily use
- SURFACE
- 5 tools · stdio transport
- SIZE
- ~340 lines · single file
- STACK
- Python · MCP SDK · Google Calendar API
The MCP server that lets an LLM actually drive a Google Calendar — not “ask about events,” but create, modify, delete, and reverse calendar operations in natural conversation. It runs over stdio, exposes five tools, handles its own OAuth2 flow with refresh-token persistence, and — the part most wrappers miss — keeps an action log so any mutation can be undone deterministically. In production daily use: this is the working artifact behind every “schedule that for me” interaction. If Helios is the generator of MCP servers, this is the hand-written reference of what a thoughtful one looks like.
| # | FAILURE MODE | THE FIX HERE |
|---|---|---|
| 1 | UTC offset drift — bare ISO timestamps land events an hour off | Tool schema demands explicit offsets; every start/end wrapped with a known IANA timeZone |
| 2 | No undo — Google's API has delete, but no reverse | Every mutation appends full pre-mutation state to action_log.json; undo reverses the last operation exactly |
| 3 | Double-booking on retry — LLM retries a timed-out call, duplicate event | Idempotency-aware design + the action log make duplicates detectable |
| 4 | Destructive writes masked as reads | Explicit tool names (create_event, delete_event) show intent at selection time; undo is always available |
Google’s managed endpoint handles OAuth but skips the action log; community wrappers handle OAuth but rarely do undo. None of the off-the-shelf options handle all four simultaneously — building a focused 340-line server was faster than forking any of them.
The single feature that makes this server safe to hand to an LLM in production: every mutation captures whatever it would take to reverse itself before the mutation lands. Creates log the new event’s ID; updates log the full pre-state of every changed field; deletes log the entire event body.
Five tools is small on purpose: anything read-shaped beyond list_events is expressed by parameterizing it rather than minting new tools — the same principle Helios automates for arbitrary APIs.
Even the simplest tool has substance. list_events passes four deliberate flags: timeMin with an explicit Z suffix (without it, Google interprets the timestamp in the calendar’s default zone — silent drift), singleEvents=True to expand recurring events into individually-addressable instances, orderBy=startTime so “next 5 events” means the next five, and a bounded maxResults the model controls. Responses compress to [id] summary @ start → end — readable for the model, IDs preserved so update/delete can address specific events.
OAuth stays user-controlled: local credentials, refresh-token persistence, no third-party relay seeing calendar data. stdio transport keeps the trust boundary at the process level — the server runs as a local subprocess of the client, not as a network service.