honest-calendar-mcp
# honest-calendar-mcp
Local Google Calendar MCP server. Your calendar data never leaves your machine except to Google. No third party in the middle.
Companion project to [honest-gmail-mcp](https://github.com/bartosz-kuc/honest-gmail-mcp).
## Why
Most Calendar integrations for AI assistants route your event data through a hosted service that sees everything: meetings, attendees, locations, private descriptions. This one doesn't.
**Data flow:** `You ↔ this server (on your Mac) ↔ Google Calendar API`. That's it.
**You can read the entire server** — one file, ~250 lines of Python — and confirm exactly what it can and cannot do.
## Features
Six tools exposed over MCP:
- `list_calendars` — all calendars available on this account
- `list_events` — events in a calendar within a time range, with optional free-text search
- `get_event` — full details of a single event
- `create_event` — new event (timed or all-day), with attendees, description, location, timezone, recurrence (RRULE), transparency (busy/free), and reminders
- `update_event` — partial patch of an existing event
- `delete_event` — delete an event
All tools that send invites accept a `send_updates` parameter (`none` by default — no email is sent unless you explicitly ask for it).
## Requirements
- Python 3.10+
- A Google account you want to give it access to
- A one-time setup in Google Cloud Console (~10 min, can reuse the OAuth client from honest-gmail-mcp if you already set that up)
## Setup
### 1. Clone + install
```bash
git clone https://github.com/bartosz-kuc/honest-calendar-mcp.git
cd honest-calendar-mcp
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
```
### 2. Get Google OAuth credentials
Same process as honest-gmail-mcp — a Desktop-app OAuth client from your own Google Cloud project. If you already have a project set up, just enable the Calendar API on it:
1. https://console.cloud.google.com/ (signed in with the account you want to authorize)
2. Select existing project (or create new one)
3. **APIs & Services → Library** → search **Google Calendar API** → **Enable**
4. Reuse existing OAuth consent screen / client, OR create new — Desktop app type
5. Save `credentials.json` in this repo's root directory
### 3. First run (does the OAuth dance)
```bash
./venv/bin/python server.py
```
Browser opens → sign in → **Allow**. Token saved locally as `token.json`. Press Ctrl+C after.
### 4. Register with your MCP client
**Claude Code:**
```bash
claude mcp add calendar-personal /absolute/path/to/venv/bin/python /absolute/path/to/server.py
```
**Claude Desktop:** edit `claude_desktop_config.json`:
```json
{
"mcpServers": {
"calendar-personal": {
"command": "/absolute/path/to/venv/bin/python",
"args": ["/absolute/path/to/server.py"]
}
}
}
```
### 5. Multiple accounts (optional)
Run one server instance per Google account, each with its own token file — no code changes. Three env vars override the defaults:
| Env var | Default | Purpose |
|---|---|---|
| `CALENDAR_TOKEN_PATH` | `token.json` | per-account token file |
| `CALENDAR_CREDENTIALS_PATH` | `credentials.json` | OAuth client (can be shared across accounts) |
| `CALENDAR_SERVER_NAME` | `calendar-personal` | MCP server name |
Authorize a second account (writes a separate token; sign in as that account in the browser):
```bash
CALENDAR_TOKEN_PATH="$PWD/token.work.json" ./venv/bin/python authorize.py
```
Then register a second instance pointing at that token, e.g. in `claude_desktop_config.json`:
```json
{
"mcpServers": {
"calendar-personal": {
"command": "/absolute/path/to/venv/bin/python",
"args": ["/absolute/path/to/server.py"]
},
"calendar-work": {
"command": "/absolute/path/to/venv/bin/python",
"args": ["/absolute/path/to/server.py"],
"env": {
"CALENDAR_TOKEN_PATH": "/absolute/path/to/token.work.json",
"CALENDAR_SERVER_NAME": "calendar-work"
}
}
}
}
```
## Example usage
> "What's on my calendar tomorrow?"
AI calls `list_events` with tomorrow's time range → gets back events with summary, start, end, attendees.
> "Book a 1h call with alice@example.com next Thursday at 15:00."
AI calls `create_event` with summary, start, end, attendees, `send_updates: "all"` if you want Alice invited.
> "Add my Tuesday 19:30 kettlebells class every week, mark me free, no reminders."
AI calls `create_event` with `recurrence: ["RRULE:FREQ=WEEKLY"]`, `transparency: "transparent"`, and `reminders: {"useDefault": false}`.
## Data flow (detail)
```
Your AI client (Claude Code / Claude Desktop)
↕ MCP protocol over stdio (local process pipe)
This server (Python, on your machine)
↕ HTTPS to googleapis.com
Google Calendar API
```
No cloud middle. No telemetry. `credentials.json` and every `token*.json` stay on your disk and are `.gitignore`d.
## Security notes
- **You own the OAuth client.** Nobody else can revoke, rotate, or misuse it.
- **Revoke anytime** at https://myaccount.google.com/permissions.
- **Scope requested:** `calendar` (full read/write on all your calendars). Google does not offer read-only + write-only splits for the standard Calendar scope; the write-heavy nature of a calendar-editing tool needs full scope.
- **No secrets in git.** `.gitignore` blocks `credentials.json`, `token.json`, per-account `token.*.json`, and virtualenvs.
- **send_updates defaults to "none"** — the AI cannot accidentally spam attendees. You must explicitly ask for updates to be sent.
## Author
**Bartosz Kuć** — Warsaw-based developer, JDG owner running skanfirmy.pl.
- Site: https://skanfirmy.pl
- GitHub: https://github.com/bartosz-kuc
- Email: firma@bartosza.pl
## Consulting
Available for consulting on Polish tax and business integrations (KSeF, GUS/NFZ/GIOŚ APIs, mBank data), MCP server design, and AI-assisted tooling for JDGs and small teams. See **[skanfirmy.pl/uslugi](https://skanfirmy.pl/uslugi)** for productized packages (audit 3k PLN, setup 8-15k PLN, retainer 2-4k PLN/mo), or reach out via email.
## License
MIT — see [LICENSE](LICENSE).
TDQS
Scored across 6 tools
Each tool targets a distinct resource and action: listing calendars vs. events, and get/create/update/delete for events. There is no overlap between any pair of tools, so an agent can select correctly without hesitation.
All names follow a strict snake_case verb_noun pattern: list_calendars, list_events, get_event, create_event, update_event, delete_event. There are no deviations in style or verb forms.
Six tools is well-scoped for a calendar server, covering the essential read/write/delete operations without bloat. Every tool has a clear place in the surface.
Event lifecycle is fully covered with list, get, create, update, and delete. Minor gaps exist such as no search/free-busy query and no calendar management beyond listing, but core calendar workflows are complete and workable.