Everything else about this is unremarkable in the good sense — five clear tools over the Calendar API, tokens refreshed without asking. What catches people is Google's own rule: an OAuth app left in testing mode expires its tokens after a week, so a server that worked all week stops on day eight until you re-authorise or get the app verified. The image-to-event path is the genuinely distinctive part: a screenshot of an invitation becomes a calendar entry without transcription.
A local MCP server over the Google Calendar API. It lists calendars and events, creates, updates and deletes them, and handles the OAuth flow itself: on first run it opens a browser, saves the tokens, and refreshes them in the background from then on.
- `list-calendars` returns the calendars the account can see
- `list-events` reads events from one of them
- `create-event` adds a new event, `update-event` edits an existing one, `delete-event` removes it
- Events from images — hand it a PNG, JPEG or GIF screenshot containing a date, time, location and description, and it creates the event from what it reads
- Cross-calendar questions in one thread, such as which of tomorrow's events still have unaccepted invitations, or when you are free across a personal and a work calendar
- Token handling that stays out of the way: tokens refresh before expiry, are validated before each API call, and are stored with restricted file permissions
Node.js 16 or higher and TypeScript 5.3 or higher. You supply the Google side: a Google Cloud project with the Calendar API enabled and OAuth 2.0 desktop credentials, downloaded as `gcp-oauth.keys.json` into the project root, with your own address added as a test user on the consent screen. After `npm install` and `npm run build`, the first launch starts an auth server on ports 3000-3004 and opens the browser; tokens land in `.gcp-saved-tokens.json`. While the OAuth app is in testing rather than production, the token expires after 7 days and the flow has to be repeated.
Build from source — clone the repository and build it, then point your client at the binary
