Google Calendar MCP

io.github.A1-x-TechPublished by GitHub account A1-x-Techv1.1.2Updated Nov 7, 2026

MCP server for the Google Calendar API: events, recurrence, invitations, availability, calendars.

Overview

AI-generated overview

Local MCP server that lets an assistant read and manage Google Calendar: events, recurring series, guests, free/busy and Out of Office blocks.

What you can do
  • List calendars and read events, single occurrences or expanded recurring series, with guests, Meet links and reminders
  • Create, update, move and delete events, including all-day and recurring ones, optionally with guests and a Google Meet link
  • Expand a recurring series into instances and change or cancel just one occurrence
  • Query free/busy across up to 50 calendars to find a shared slot
  • Block Out of Office and Focus Time on Workspace primary calendars, with optional auto-decline and Chat Do Not Disturb
  • Connect a Google account from the chat, check auth status, log out, or call any Calendar API v3 path directly
When to use it
Useful when you want an assistant to answer schedule questions, book or reschedule meetings with guests, find common free time, or block focus and vacation time in a real Google Calendar. It is not for Gmail, Tasks, Contacts or Meet recordings.
Requirements
Runs locally over stdio via npx, needing Node.js 20+ and a Google account. Access requires OAuth 2.0: either the GOOGLE_CALENDAR_CLIENT_ID, GOOGLE_CALENDAR_CLIENT_SECRET and GOOGLE_CALENDAR_REFRESH_TOKEN variables, or a short-lived GOOGLE_CALENDAR_ACCESS_TOKEN, or an in-chat login with a Desktop-app OAuth client JSON from a Google Cloud project with the Calendar API enabled. Network access to Google is required.
Before you install
The client secret and refresh token are password-equivalent; the server asks for the client JSON by file path so the secret stays out of the chat. Writes hit live calendars: delete has no undo and can cancel a whole series, update replaces nested objects such as the full guest list, and writes are not retried after an ambiguous failure, so a re-sent create can duplicate an event and re-email guests. raw_request can perform destructive API calls. Anonymous telemetry is on unless…

Installation

In SourceWeft

  1. Open Google Calendar MCP in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

[A1] Google Calendar MCP

English | Русский

[npm] [Glama] [CI] [License: MIT]

A1 Google Calendar MCP lets an AI app manage Google Calendar in plain language. Review your week, schedule a meeting with guests and a Google Meet link, reschedule or cancel it, find a slot when everyone is free, and block Out of Office or Focus Time.

It uses the Google Calendar API with your Google account. It distinguishes a whole recurring series from a single occurrence and makes the limits of the Calendar API explicit instead of implying that every calendar task is possible.

  • 19 tools. Inspect calendars, events and free/busy, create and edit events, expand recurring series, and block Out of Office and Focus Time — plus six for connecting your Google account.
  • Sign in from the chat. No credentials file to hand-write: ask the assistant to connect, approve access in the browser, and the very next request works — no restart. The client secret travels as a file path, never through the conversation.
  • Nobody is emailed by accident. The Calendar API's default for invitations, changes and cancellations is silence; guests get email only when you ask for it via send_updates.
  • Writes are never replayed. After an ambiguous failure the server does not retry a write — a duplicated event could re-email every guest.
  • Minimal Google scopes. It uses calendar.events and calendar.readonly, without the broad calendar scope.

Start with a read-only question:

What's on my calendar this week? Point out any overlapping meetings.

Connect the server · Explore use cases · Open technical documentation


See it work in a minute

You: What does my Thursday look like, and when are Anna and I both free?

Assistant: Shows Thursday's events and the free slots you share. Nothing changes.

You: Book a 45-minute design review with Anna in the first shared slot, with a Google Meet link.

Assistant: Shows the proposed time, guest list and Meet link, then asks for confirmation before creating the event.

You: Confirm.

Assistant: Creates the event. Nobody gets an email unless you ask it to send invitations.

Contents

Quick start

You need Node.js 20+, a Google account and OAuth credentials from a Google Cloud project with the Google Calendar API enabled.

  1. Prepare Google OAuth access.
  2. Add the server to your AI app.
  3. Ask the read-only question above.
Codex

In the app: open Settings → MCP servers, select Add server, choose STDIO, enter the command npx -y @a1-x-tech/mcp-google-calendar@latest and environment variables GOOGLE_CALENDAR_CLIENT_ID, GOOGLE_CALENDAR_CLIENT_SECRET, GOOGLE_CALENDAR_REFRESH_TOKEN, then select Save and Restart.

From the command line:

bash
codex mcp add google-calendar \  --env GOOGLE_CALENDAR_CLIENT_ID=your_client_id \  --env GOOGLE_CALENDAR_CLIENT_SECRET=your_client_secret \  --env GOOGLE_CALENDAR_REFRESH_TOKEN=your_refresh_token \  -- npx -y @a1-x-tech/mcp-google-calendar@latest
bash
codex mcp list

Codex MCP documentation

Claude Code
bash
claude mcp add \  --env GOOGLE_CALENDAR_CLIENT_ID=your_client_id \  --env GOOGLE_CALENDAR_CLIENT_SECRET=your_client_secret \  --env GOOGLE_CALENDAR_REFRESH_TOKEN=your_refresh_token \  --transport stdio --scope user google-calendar \  -- npx -y @a1-x-tech/mcp-google-calendar@latest
bash
claude mcp list

Claude Code MCP documentation

Claude Desktop

The current official path is Settings → Extensions. For a custom desktop extension, open Advanced settings → Extension Developer → Install Extension…, select a .mcpb file and follow the prompts.

This repository currently publishes an npm stdio package and does not contain a .mcpb bundle. For Claude Desktop builds that still support local configuration, use the following JSON stdio configuration as a fallback:

json
{  "mcpServers": {    "google-calendar": {      "command": "npx",      "args": ["-y", "@a1-x-tech/mcp-google-calendar@latest"],      "env": {        "GOOGLE_CALENDAR_CLIENT_ID": "your_client_id",        "GOOGLE_CALENDAR_CLIENT_SECRET": "your_client_secret",        "GOOGLE_CALENDAR_REFRESH_TOKEN": "your_refresh_token"      }    }  }}

In those builds, save it to ~/Library/Application Support/Claude/claude_desktop_config.json on macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows.

Claude Desktop MCP documentation

Cursor

Add this to ~/.cursor/mcp.json on macOS/Linux or %USERPROFILE%\.cursor\mcp.json on Windows:

json
{  "mcpServers": {    "google-calendar": {      "type": "stdio",      "command": "npx",      "args": ["-y", "@a1-x-tech/mcp-google-calendar@latest"],      "env": {        "GOOGLE_CALENDAR_CLIENT_ID": "your_client_id",        "GOOGLE_CALENDAR_CLIENT_SECRET": "your_client_secret",        "GOOGLE_CALENDAR_REFRESH_TOKEN": "your_refresh_token"      }    }  }}

Cursor MCP documentation

VS Code

Run MCP: Open User Configuration and add:

json
{  "servers": {    "google-calendar": {      "type": "stdio",      "command": "npx",      "args": ["-y", "@a1-x-tech/mcp-google-calendar@latest"],      "env": {        "GOOGLE_CALENDAR_CLIENT_ID": "${input:calendar_client_id}",        "GOOGLE_CALENDAR_CLIENT_SECRET": "${input:calendar_client_secret}",        "GOOGLE_CALENDAR_REFRESH_TOKEN": "${input:calendar_refresh_token}"      }    }  },  "inputs": [    { "type": "promptString", "id": "calendar_client_id", "description": "Google OAuth client ID" },    { "type": "promptString", "id": "calendar_client_secret", "description": "Google OAuth client secret", "password": true },    { "type": "promptString", "id": "calendar_refresh_token", "description": "Google OAuth refresh token", "password": true }  ]}

Check it with MCP: List Servers.

VS Code MCP documentation

What you can ask it to do

See your schedule

  • What meetings do I have this week? Include the recurring ones.
  • Show tomorrow's 1:1 with its guests, Meet link and reminders.
  • List every occurrence of the team sync in March.

Plan and change meetings

  • Create a 45-minute review on Thursday with two guests and a Google Meet link.
  • Reschedule the retro one hour later and update the guest list — but don't email anyone yet.
  • Move the planning event to the team calendar.
  • Cancel Friday's occurrence of the standup, leaving the rest of the series alone.

Protect your time

  • When are Anna, Boris and I all free for an hour next week?
  • Block Out of Office for my vacation and auto-decline new invitations.
  • Create two hours of Focus Time tomorrow morning and silence Google Chat.

How an event changes

  1. calendar_id: "primary" is your main calendar; other calendars come from list_calendars, and writes need writer access.
  2. A recurring series and a single occurrence have different ids: the series id changes or cancels every occurrence, an instance id (from list_event_instances) exactly one.
  3. update_event changes only the fields you provide, but a nested object replaces its predecessor wholesale — a new attendees list replaces the whole guest list.
  4. No write emails anybody unless send_updates says so — the Calendar API's default is silence.

Out of Office and Focus Time blocks exist only on the primary calendar of a Google Workspace account; consumer Gmail and secondary calendars reject them. Creating an event does not check for conflicts — ask for a free/busy check first. All-day events end on an exclusive date: an event through Friday ends on Saturday's date.

What can change

OperationWhat happensConfirmation boundary
Read calendars, events and free/busyReads schedule data; free/busy shows busy blocks without titlesNo change
Create an eventAdds a timed, all-day or recurring event, optionally with guests and Google MeetChanges a calendar
Create an Out of Office or Focus Time blockAdds a special event that can auto-decline invitations or silence Google ChatChanges a calendar
Update an eventReschedules or edits an event; a series id edits every occurrenceChanges a calendar
Move an eventRe-homes an event to another calendarChanges two calendars
Delete an eventCancels an event or an entire series; there is no undeleteDestructive
Raw API requestCan call API methods without a dedicated toolPotentially destructive

The AI client controls confirmation prompts. The server marks reads, writes and destructive tools so the client can distinguish an inspection from a live change.

Getting access

Access to your own calendars requires OAuth 2.0; an API key is not enough. There are two ways to connect, and the first one needs no configuration file at all.

Sign in from the chat

Start the server with no credentials and ask the assistant to connect. It walks you through it with six built-in tools:

ToolWhat it does
setup_instructionsThe step-by-step checklist for the Google Cloud side, tailored to what is already configured
set_clientReads the OAuth client JSON you downloaded — by file path, so the secret never goes through the chat
start_loginReturns the Google authorization link and waits for the browser
finish_loginConfirms the login and reports which account was connected
auth_statusWhether a login exists, where it came from and when it expires — never the token itself
logoutRevokes the token at Google and deletes the local file

The login takes effect immediately: the next tool call works without restarting the AI client. The token is stored in ~/.config/mcp-google-calendar/credentials.json (on Windows, under %APPDATA%), readable only by your account, and never leaves your machine.

Or configure environment variables

The classic path, and the one to use for CI and headless installs:

  1. Create or select a Google Cloud project and enable Google Calendar API.

  2. Configure the OAuth consent screen and create a Desktop app OAuth client.

  3. Authorize the Google account whose calendars you want to manage. The OAuth 2.0 Playground can obtain the refresh token when Use your own OAuth credentials is enabled.

  4. Request both scopes:

    text
    https://www.googleapis.com/auth/calendar.eventshttps://www.googleapis.com/auth/calendar.readonly

    The broad https://www.googleapis.com/auth/calendar scope is needed only for raw_request calls that manage calendars or sharing rules themselves.

Environment variables always win over a login taken in the chat, so an existing configured install keeps behaving exactly as before.

Testing-mode OAuth refresh tokens can expire after seven days. Publish the OAuth app, or use an Internal app in a Workspace domain, when you need long-lived access. Treat the client secret and refresh token as passwords.

Configuration

VariableRequiredDescription
GOOGLE_CALENDAR_CLIENT_IDYes*OAuth client ID.
GOOGLE_CALENDAR_CLIENT_SECRETYes*OAuth client secret.
GOOGLE_CALENDAR_REFRESH_TOKENYes*OAuth refresh token.
GOOGLE_CALENDAR_ACCESS_TOKENYes*Short-lived (~1 hour) alternative to the OAuth trio.
GOOGLE_CALENDAR_API_BASENoGoogle API base URL override; default https://www.googleapis.com.
GOOGLE_CALENDAR_TIMEOUT_MSNoPer-request timeout; default 60000 ms.
GOOGLE_CALENDAR_MAX_RETRIESNoTemporary-error retries; default 3.

* Provide either the OAuth trio or an access token. Without credentials the server still starts and completes the MCP handshake; the first tool call then names the exact variables to set.

Data, limits and background work

  • Requests go to Google Calendar. The local server refreshes Google OAuth tokens and calls the Calendar API. Its anonymous telemetry contains an installation ID, package version, AI client and platform versions, and tool names — never OAuth tokens, calendar data, tool arguments or prompts. For each tool call it also sends the outcome and, on failure, an excerpt of the error text with e-mails, addresses, tokens, numbers of 4+ digits and quoted text replaced by #; a value from your request can appear in it if the error text contains it. Set ASKADS_TELEMETRY=0 to opt out.
  • Google applies per-project quotas. On 429, the server retries with backoff; reads also retry after network and 5xx errors, while writes are not replayed after an uncertain failure — a duplicated event could re-email every guest.
  • There is no background polling. The server runs only when called. list_events supports incremental checks via updated_min; if your AI app supports scheduled tasks, it can check your calendar periodically.

Technical documentation

Support

Found a bug or need a scenario? Create an issue or write in Telegram.


[Две Моны дают пять]

You made it to the end!

Source: README.md at commit 0028e0d

Tools

19

auth_status

Google connection status

Shows whether this server is connected to Google: token presence and source (env variables or a stored in-chat login), expiry, the Google account email, granted vs missing OAuth scopes, where the credentials file lives and where the OAuth client comes from. Makes no network calls and never returns the token itself. Call it first when other tools report the server is not connected.

Takes no parameters.

setup_instructions

Setup instructions

Step-by-step checklist for connecting this server to Google: creating a Google Cloud project and a Desktop-app OAuth client, publishing the consent screen (mandatory — Testing-mode refresh tokens die after 7 days), downloading the client JSON and handing its PATH to set_client. Works without any credentials; the checklist shortens to 'enable the API + log in' when an OAuth client is already configured (one client serves the whole mcp-google-* line). Never asks the user to paste secrets into the chat.

Takes no parameters.

set_client

Save the OAuth client

Saves the OAuth client credentials from the JSON file downloaded from Google Cloud Console ('Download JSON' on a Desktop-app client). Pass the file PATH — the secret must never be pasted into the chat. The client is stored once in the shared ~/.config/mcp-google-auth/client.json (owner-only) and reused by every mcp-google-* server; tokens stay per-server. After this, call start_login.

Parameterspathrequired

start_login

Start the Google login

First step of connecting from the chat, without editing config files or restarting the client. Returns authorizeUrl — show it to the user as a clickable link and ask them to open it in the browser ON THIS MACHINE, pick the Google account and approve access. A one-shot listener on 127.0.0.1 catches Google's redirect; the code is exchanged locally and never passes through the chat. Does not open the browser itself. The attempt lives 10 minutes; when the browser shows the success page, call finish_login.

Takes no parameters.

finish_login

Finish the Google login

Second step: waits up to 20 s for the browser consent to finish, saves the tokens to an owner-only file and verifies the login with a read-only identity call, returning the account email and the granted scopes. After success every tool works immediately — no client restart. If the user granted only part of the requested permissions, the login is still saved and missingScopes lists what will not work. Logging in under a different Google account replaces the previous login (its refresh token is revoked best-effort) and the response carries previousAccountEmail so the change never goes unnoticed.

Takes no parameters.

logout

Disconnect from Google

Revokes the stored token at Google (oauth2.googleapis.com/revoke) and deletes the local credentials file. Tokens supplied via env variables are NOT touched — remove them from the MCP client config manually; envTokenStillSet in the response says whether any are still in effect.

Takes no parameters.

list_calendars

List calendars

Lists the calendars on the user's calendar list: id (use it as calendar_id in every other tool), summary, description, timeZone (IANA), accessRole (owner/writer/reader/freeBusyReader — writes need writer or owner), primary:true on the main calendar, and hidden/selected flags. The special id "primary" always addresses the main calendar without listing first. Paginate with page_token from nextPageToken. Calendars shared with the user but never added to their list do not appear here — address them by their explicit id.

Parameterspage_tokenmax_resultsshow_hiddenmin_access_role

get_calendar

Get a calendar

Fetches one calendar-list entry: summary, description, timeZone (the calendar's default IANA zone — use it to interpret event times), accessRole, defaultReminders and primary. Works only for calendars on the user's list; for a shared calendar never added to the list, use raw_request with path calendar/v3/calendars/<id> instead.

Parameterscalendar_idrequired

list_events

List events

Lists events on a calendar: id, summary, start/end (all-day events carry date with an EXCLUSIVE end; timed events carry dateTime), status, attendees with responseStatus, organizer, recurrence, hangoutLink, eventType. time_min/time_max bound the window (an event overlapping the window is included). single_events=true expands recurring events into individual instances — required for order_by=start_time and the right choice for questions like "what is on my calendar this week"; without it recurring events appear once as the series master. time_zone only changes how times are RENDERED in the response, never the events themselves. q searches summary/description/location/attendees. updated_min + show_deleted enable incremental polling (cancelled events come back as status=cancelled). Paginate with page_token from nextPageToken.

Parametersqorder_bytime_maxtime_mintime_zonepage_tokencalendar_idrequiredevent_typesmax_resultsupdated_minshow_deletedsingle_events

get_event

Get an event

Fetches one event by id: summary, description, location, start/end, attendees with their responseStatus (accepted/declined/tentative/needsAction), organizer, recurrence rules, recurringEventId (present on instances of a series), conferenceData/hangoutLink (Google Meet), reminders, visibility, transparency and eventType. Works for a series master and for an individual instance id alike.

Parametersevent_idrequiredtime_zonecalendar_idrequired

create_event

Create an event

Creates an event and returns it (id, htmlLink, start/end, attendees, hangoutLink when add_meet). Times: EITHER start_date_time + end_date_time (RFC3339; add time_zone for recurring events) OR start_date + end_date for all-day (end_date is EXCLUSIVE — the day after the last day). recurrence makes it a recurring series. attendees invites guests — but the API sends invitation emails ONLY with send_updates=all (the default notifies nobody). add_meet attaches a Google Meet link (may come back status=pending — re-run get_event for the final URL). This is a plain calendar write: it does not check for conflicts — call query_free_busy first to find a free slot. Never blindly re-send after a timeout or 5xx: the event may already exist — check with list_events first, or you will create a duplicate and re-invite everyone.

Parameterssummaryrequiredadd_meetcolor_idend_datelocationattendeesreminderstime_zonerecurrencestart_datevisibilitycalendar_idrequired+9 more

update_event

Update an event

Partially updates an event (PATCH): only the provided fields change, but a provided nested object REPLACES its predecessor wholesale — attendees replaces the entire guest list (get_event first, send the complete new list), reminders replaces all overrides, and a time change should carry BOTH the new start and end (start_date_time + end_date_time, or start_date + end_date). To reschedule one occurrence of a recurring series, pass that instance's id (from list_event_instances) as event_id; passing the series master id changes every occurrence. Guests hear about the change only with send_updates=all. Also works to update Out of Office / Focus Time blocks. Returns the updated event.

Parameterssummaryadd_meetcolor_idend_dateevent_idrequiredlocationattendeesreminderstime_zonerecurrencestart_datevisibility+10 more

delete_event

Delete an event

Deletes (cancels) an event — there is no undelete. Deleting a series master id cancels the ENTIRE recurring series; deleting one instance id (from list_event_instances) cancels only that occurrence. On an event with guests this cancels the meeting for everyone, but cancellation emails go out only with send_updates=all. Returns {deleted:true}.

Parametersevent_idrequiredcalendar_idrequiredsend_updates

move_event

Move an event to another calendar

Moves an event to a different calendar (changes its organizer calendar; the event id stays the same). Rescheduling to another TIME is update_event, not this. Only regular events can move — Out of Office, Focus Time, working-location and birthday events cannot, and events with attendees can be moved only by their organizer. Needs writer access to both calendars. send_updates=all notifies the guests.

Parametersevent_idrequiredcalendar_idrequiredsend_updatesdestination_calendar_idrequired

list_event_instances

List instances of a recurring event

Expands one recurring event (the series master id) into its individual instances, each with its own id (like masterId_20260901T100000Z) and concrete start/end. Use an instance id with update_event to reschedule a single occurrence, or with delete_event to cancel just that one; exceptions already made to the series show their changed times here. show_deleted=true includes cancelled occurrences. Bound the window with time_min/time_max — an unbounded infinite series is paginated via page_token.

Parametersevent_idrequiredtime_maxtime_mintime_zonepage_tokencalendar_idrequiredmax_resultsshow_deleted

query_free_busy

Query free/busy times

Returns the busy intervals of up to 50 calendars in one time window — the way to find a common free slot before create_event. Input calendar ids (or attendee email addresses, which double as their primary-calendar ids — subject to their sharing settings). The response maps each calendar id to busy:[{start,end}] ranges; gaps between them are free. Only busy blocks come back — never event titles or details — and events marked transparent (free) don't appear. A calendar the user cannot read shows up under errors, not busy. This is a pure read despite being an HTTP POST.

Parameterstime_maxrequiredtime_minrequiredtime_zonecalendar_idsrequired

create_out_of_office

Create an Out of Office block

Creates an Out of Office event that can auto-decline meeting invitations while it lasts (auto_decline: all overlapping meetings, or only new invitations; decline_message customizes the reply). ONLY works on the PRIMARY calendar of a Google Workspace account — consumer Gmail and secondary calendars get HTTP 400. Always timed (start/end date_time), never all-day. Manage it afterwards like any event: update_event to change it, delete_event to remove it, list_events with event_types=["out_of_office"] to find existing blocks. Not retried after an ambiguous failure — check list_events before re-sending.

Parameterssummarytime_zonecalendar_idauto_declinesend_updatesend_date_timerequireddecline_messagestart_date_timerequired

create_focus_time

Create a Focus Time block

Creates a Focus Time event: blocks the slot, can auto-decline conflicting invitations (auto_decline + decline_message) and can flip Google Chat to Do Not Disturb (chat_status). ONLY works on the PRIMARY calendar of a Google Workspace account — consumer Gmail and secondary calendars get HTTP 400. Always timed (start/end date_time), never all-day. Manage it afterwards like any event: update_event / delete_event, and list_events with event_types=["focus_time"] to find existing blocks. Not retried after an ambiguous failure — check list_events before re-sending.

Parameterssummarytime_zonecalendar_idchat_statusauto_declinesend_updatesend_date_timerequireddecline_messagestart_date_timerequired

raw_request

Raw Google Calendar API call

Escape hatch to call any Google Calendar API v3 path directly, for requests the typed tools don't cover — e.g. events.quickAdd ("calendar/v3/calendars/primary/events/quickAdd?text=Lunch tomorrow noon", POST), the colors palette ("calendar/v3/colors"), ACL rules, secondary-calendar creation ("calendar/v3/calendars", POST), removing a Meet conference (PATCH with {"conferenceData":null} and ?conferenceDataVersion=1), watch channels, or an event PUT that replaces every field. The path is relative to https://www.googleapis.com, must stay under calendar/v3/ (other Google APIs on this host — drive/v3, gmail/v1, ... — are rejected before any request is sent) and may carry a query string. The Bearer token is added automatically; the method defaults to GET. Remember: PUT replaces unspecified fields with defaults — prefer PATCH semantics via update_event when possible.

Parametersbodypathrequiredmethod

Version history

6
  1. v1.1.2LatestNov 5, 2026
  2. v1.1.1Oct 31, 2026
  3. v1.1.0Oct 31, 2026
  4. v1.0.0Sep 23, 2026
  5. v0.2.0Sep 20, 2026
  6. v0.1.0Sep 16, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts