Skip to main content
All connectors

Google Calendar

calendar.google.com

  • MCP servers: use Google Calendar tools from ChatGPT, Claude and other MCP clients.
  • Tasks: call Google Calendar from Python in an automation.

About Google Calendar

Google Calendar is the calendar in Google Workspace and personal Google accounts. Its API reads and writes the events on any calendar an account can open and reports when people are busy. Sign in with Google to connect an account. The connector can read and change events on every calendar that account can open, including shared team and room calendars, and can check when coworkers are busy if their calendars share free and busy times. Google emails attendees about a change only when the task asks it to. In Python tasks, the connector can post a morning agenda to Slack, book a follow-up call when a CRM deal moves stage, decline invites that land on a blocked day, or find an hour when several people are free and send the invite with a Google Meet link.

Build a Google Calendar MCP server with qbash

Connect Google Calendar to qbash, pick tools such as list calendars, get calendar and list events, and publish them on a hosted MCP server.

MCP clients such as ChatGPT, Claude, Claude Code, Codex, Cursor, Grok and Muse Code all connect to the same remote endpoint.

Build Tasks with Google Calendar

A qbash Task is a Python script that calls Google Calendar alongside model calls and other connectors. qbash deploys each Task to a managed runtime with version history, run logs and credentials shared across your organization.

Run it on a schedule, call it through an API or webhook, or start it from an MCP client.

Google Calendar Task SDK methods (10)

Call these from Python with qbash.integrations.google_calendar.

qbash.integrations.google_calendar.list_calendars(...)

List the calendars in the connected account's calendar list.

list_calendars(min_access_role: str | None = None, show_hidden: bool = False, max_results: int = 250, page_token: str | None = None)

Parameters

  • min_access_role: str | None = None

    Only calendars with at least this role: freeBusyReader, reader, writer, or owner.

  • show_hidden: bool = False

    Include calendars hidden from the Calendar sidebar.

  • max_results: int = 250

    Items per page, from 1 to 2500.

  • page_token: str | None = None

    next_page_token from the previous page.

Returns

{"status": "success", "calendars": list[dict], "count": int, "next_page_token": str | None}

Notes

Each calendar has id, summary, description, time_zone, access_role, primary, selected, hidden, and background_color. Use the id as calendar_id in the other modes. The primary calendar's id is the account's email address, and "primary" also works.

qbash.integrations.google_calendar.get_calendar(...)

Get one calendar's name, time zone, and the account's access role.

get_calendar(calendar_id: str = "primary")

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

Returns

{"status": "success", "id": str, "summary": str, "description": str | None, "time_zone": str, "access_role": str, "primary": bool, "selected": bool, "hidden": bool, "background_color": str | None}

Notes

The calendar must be in the connected account's calendar list.

qbash.integrations.google_calendar.list_events(...)

List events in a calendar. Recurring events are expanded into single instances by default.

list_events(calendar_id: str = "primary", time_min: str | None = None, time_max: str | None = None, query: str | None = None, single_events: bool = True, order_by: str | None = None, show_deleted: bool = False, updated_min: str | None = None, time_zone: str | None = None, max_results: int = 250, page_token: str | None = None)

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

  • time_min: str | None = None

    Only events ending after this RFC 3339 timestamp, such as 2026-10-22T00:00:00Z.

  • time_max: str | None = None

    Only events starting before this RFC 3339 timestamp.

  • query: str | None = None

    Free-text search over summary, description, location, and attendee names and emails.

  • single_events: bool = True

    Expand recurring events into single instances.

  • order_by: str | None = None

    startTime (needs single_events=True) or updated. Defaults to startTime when single_events is True.

  • show_deleted: bool = False

    Include cancelled events.

  • updated_min: str | None = None

    Only events changed after this RFC 3339 timestamp.

  • time_zone: str | None = None

    IANA time zone for the returned times, such as Australia/Perth. Defaults to the calendar's time zone.

  • max_results: int = 250

    Items per page, from 1 to 2500.

  • page_token: str | None = None

    next_page_token from the previous page.

Returns

{"status": "success", "calendar_id": str, "time_zone": str, "events": list[dict], "count": int, "next_page_token": str | None}

Notes

Pass time_min and time_max to bound the window. Without them Google returns every event in the calendar. Each event has id, status, summary, description, location, html_link, start, end, all_day, organizer, creator, attendees, recurrence, recurring_event_id, meet_link, event_type, visibility, transparency, created, updated, and ical_uid. start and end hold date for all-day events and date_time otherwise. With single_events=True, events are sorted by start time and each instance of a recurring event has its own id and a recurring_event_id. Pass next_page_token back as page_token for the next page.

qbash.integrations.google_calendar.get_event(...)

Get one event by ID, including fields the list view leaves out.

get_event(calendar_id: str = "primary", event_id: str)

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

  • event_id: strrequired

    Event ID from list_events.

Returns

{"status": "success", "calendar_id": str, "event": dict, "raw": dict}

Notes

event uses the same fields as list_events. raw is Google's full event resource, with fields such as reminders, attachments, and extendedProperties.

qbash.integrations.google_calendar.create_event(...)

Create an event. Attendees get no email unless send_updates is all or externalOnly.

create_event(calendar_id: str = "primary", summary: str, start: str, end: str, time_zone: str | None = None, description: str | None = None, location: str | None = None, attendees: list[str] | None = None, recurrence: list[str] | None = None, add_google_meet: bool = False, visibility: str | None = None, transparency: str | None = None, send_updates: str = "none")

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

  • summary: strrequired

    Event title.

  • start: strrequired

    Start date (YYYY-MM-DD) or date-time (ISO 8601).

  • end: strrequired

    End date (YYYY-MM-DD, exclusive) or date-time (ISO 8601).

  • time_zone: str | None = None

    IANA time zone for start and end, such as Australia/Perth.

  • description: str | None = None

    Event description. Google accepts basic HTML.

  • location: str | None = None

    Free-text location.

  • attendees: list[str] | None = None

    Attendee email addresses.

  • recurrence: list[str] | None = None

    RRULE, EXRULE, RDATE, or EXDATE lines.

  • add_google_meet: bool = False

    Attach a new Google Meet link.

  • visibility: str | None = None

    default, public, private, or confidential.

  • transparency: str | None = None

    opaque (shows as busy) or transparent (shows as free).

  • send_updates: str = "none"

    Who Google emails about the change: none, all, or externalOnly.

Returns

{"status": "success", "calendar_id": str, "event": dict}

Notes

start and end are both dates (YYYY-MM-DD) for an all-day event, where end is the day after the last day, or both date-times (2026-10-22T09:00:00 or 2026-10-22T09:00:00+08:00). A date-time without an offset uses time_zone, or the calendar's time zone when time_zone is omitted. Recurring events need recurrence rules such as RRULE:FREQ=WEEKLY;BYDAY=MO.

qbash.integrations.google_calendar.quick_add_event(...)

Create an event from a sentence, such as "Lunch with Sam tomorrow at 12pm".

quick_add_event(calendar_id: str = "primary", text: str, send_updates: str = "none")

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

  • text: strrequired

    Text describing the event.

  • send_updates: str = "none"

    Who Google emails about the change: none, all, or externalOnly.

Returns

{"status": "success", "calendar_id": str, "event": dict}

Notes

Google parses the text in the calendar's time zone and language. Check the returned start and end, since Google picks defaults for anything the text leaves out.

qbash.integrations.google_calendar.update_event(...)

Change fields on an event. Only the fields you pass are changed.

update_event(calendar_id: str = "primary", event_id: str, summary: str | None = None, start: str | None = None, end: str | None = None, time_zone: str | None = None, description: str | None = None, location: str | None = None, attendees: list[str] | None = None, recurrence: list[str] | None = None, add_google_meet: bool = False, visibility: str | None = None, transparency: str | None = None, send_updates: str = "none")

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

  • event_id: strrequired

    Event ID from list_events.

  • summary: str | None = None

    New event title.

  • start: str | None = None

    New start date or date-time.

  • end: str | None = None

    New end date or date-time.

  • time_zone: str | None = None

    IANA time zone for start and end, such as Australia/Perth.

  • description: str | None = None

    Event description. Google accepts basic HTML.

  • location: str | None = None

    Free-text location.

  • attendees: list[str] | None = None

    Attendee email addresses.

  • recurrence: list[str] | None = None

    RRULE, EXRULE, RDATE, or EXDATE lines.

  • add_google_meet: bool = False

    Attach a new Google Meet link.

  • visibility: str | None = None

    default, public, private, or confidential.

  • transparency: str | None = None

    opaque (shows as busy) or transparent (shows as free).

  • send_updates: str = "none"

    Who Google emails about the change: none, all, or externalOnly.

Returns

{"status": "success", "calendar_id": str, "event": dict}

Notes

attendees and recurrence replace the whole list, so read the event first to keep existing entries. start and end follow the same rules as create_event and must be passed together. For one instance of a recurring event, pass that instance's id from list_events with single_events=True.

qbash.integrations.google_calendar.respond_to_event(...)

Accept, decline, or tentatively accept an event the connected account was invited to.

respond_to_event(calendar_id: str = "primary", event_id: str, response: str, comment: str | None = None, send_updates: str = "none")

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

  • event_id: strrequired

    Event ID from list_events.

  • response: strrequired

    accepted, declined, or tentative.

  • comment: str | None = None

    Note shown to the organizer with the response.

  • send_updates: str = "none"

    Who Google emails about the change: none, all, or externalOnly.

Returns

{"status": "success", "calendar_id": str, "event": dict}

Notes

Fails when the connected account is not on the attendee list. The organizer is not emailed unless send_updates is all.

qbash.integrations.google_calendar.delete_event(...)

Delete an event.

delete_event(calendar_id: str = "primary", event_id: str, send_updates: str = "none")

Parameters

  • calendar_id: str = "primary"

    Calendar ID from list_calendars, or primary.

  • event_id: strrequired

    Event ID from list_events.

  • send_updates: str = "none"

    Who Google emails about the change: none, all, or externalOnly.

Returns

{"status": "success", "calendar_id": str, "event_id": str, "deleted": bool}

Notes

Deleting a recurring event's parent id deletes every instance. Pass an instance id to delete one occurrence.

qbash.integrations.google_calendar.query_free_busy(...)

Get busy time ranges for one or more calendars.

query_free_busy(time_min: str, time_max: str, calendar_ids: list[str] = ["primary"], time_zone: str | None = None)

Parameters

  • time_min: strrequired

    Start of the window, as an RFC 3339 timestamp.

  • time_max: strrequired

    End of the window, as an RFC 3339 timestamp.

  • calendar_ids: list[str] = ["primary"]

    Calendar IDs or email addresses to check.

  • time_zone: str | None = None

    IANA time zone for the returned times. Defaults to UTC.

Returns

{"status": "success", "time_min": str, "time_max": str, "calendars": list[dict]}

Notes

Each calendar has calendar_id, busy (a list of start and end times), and errors. A calendar the account cannot see returns an errors entry such as notFound instead of busy times. Up to 50 calendars per call.

Task SDK reference

Connect Google Calendar to qbash

Sign up, connect your Google Calendar account, and use its tools across qbash.

Sign up free