calendar-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| HOST | No | Default for --host in HTTP mode. | 127.0.0.1 |
| PORT | No | Default for --port in HTTP mode. | 8000 |
| CALENDAR_SCOPES | No | Scope requested. Use .../auth/calendar.readonly for read-only. | https://www.googleapis.com/auth/calendar |
| TOKEN_FILE_PATH | No | Where the default account's OAuth token is cached. | .gcp-saved-tokens.json |
| GOOGLE_CLIENT_ID | Yes | OAuth client ID (required). | |
| OAUTH_CALLBACK_PORT | No | Local port for the OAuth callback during calendar-mcp auth. | 8080 |
| GOOGLE_CLIENT_SECRET | Yes | OAuth client secret (required). | |
| CALENDAR_MCP_LOG_FILE | No | Mirror the stderr log to this file. | |
| CALENDAR_MCP_LOG_LEVEL | No | DEBUG/INFO/WARNING/ERROR/CRITICAL. Overrides --log-level. | INFO |
| CALENDAR_MCP_CONFIG_DIR | No | Directory holding per-account tokens (accounts/) and preferences.json. | |
| CALENDAR_MCP_DEFAULT_ACCOUNT | No | Account used when a tool's account argument is omitted. | default |
| CALENDAR_MCP_ALLOW_BROWSER_AUTH | No | Set to 1 to let the server itself open a browser when no token exists. Off by default so a stdio server never hangs. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_accountsA | List the Google accounts calendar-mcp can use, and which is the default. Every other tool takes an optional |
| get_preferencesA | Read the user's scheduling preferences: working hours, lunch, buffers, focus. Consult this before proposing meeting times or hunting for focus blocks, rather than assuming a nine-to-five. Never configured returns the defaults (Mon-Fri 09:00-17:00, no lunch break, no buffer), which is a reasonable guess but worth confirming with the user before you rely on it. |
| set_preferencesA | Update the user's scheduling preferences and save them. Returns the merged result. Only the arguments you pass change; everything else keeps its current value, so a single correction ("I actually start at 8") does not have to restate the whole schedule. The merged result is validated before it is written, so a rejected change leaves the saved preferences untouched. Args:
timezone: IANA timezone the working hours are expressed in, e.g.
'Europe/Berlin'. Must be a real zone name.
working_hours: Whole-schedule replacement, keyed by weekday
('mon'..'sun'), each value a list of ['HH:MM', 'HH:MM'] pairs. Days
you omit become non-working, so pass every working day at once, e.g.
{"mon": [["09:00", "12:00"], ["13:00", "18:00"]], "fri": [["09:00", "15:00"]]}.
buffer_minutes: Minimum gap to leave before and after each meeting when
proposing times. 0 disables it.
min_focus_block_minutes: Shortest free stretch that still counts as
usable focus time.
lunch: Daily lunch break as ['HH:MM', 'HH:MM'], carved out of the
working hours.
focus_calendar_id: Calendar that focus blocks are booked on; 'primary'
for the user's own.
clear_lunch: Set true to remove an existing lunch break (pass this
instead of |
| analyze_busynessA | Summarise how loaded each day is: event count and total scheduled minutes. Use this to answer "how busy is my week" without listing every event. Args: time_min: Start of the window, ISO 8601. time_max: End of the window, ISO 8601. calendar_id: Calendar to analyse. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| project_recurring_eventsA | Compute future occurrences of recurring events from their recurrence rules. Unlike Args: time_min: Start of the projection window, ISO 8601. time_max: End of the projection window, ISO 8601. calendar_id: Calendar whose recurring events should be projected. event_query: Only project recurring events matching this text, e.g. 'Birthday'. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| time_auditA | Report where the user's time went: meeting hours, who with, and what focus time is left. Answers "how much of my week is meetings?", "who am I spending my time with?" and "where did my focus time go?" in one pass. Working hours, lunch, buffer and the minimum focus block come from the saved preferences (see get_preferences), so the percentages reflect this user's actual day. Declined meetings, events marked 'free', and all-day entries are excluded by default; the 'excluded' field says how many were skipped. Args: time_min: Start of the window to audit, ISO 8601. time_max: End of the window to audit, ISO 8601. calendar_ids: Calendars to include. Defaults to ['primary']. group_by: Break the window down by 'day' or by ISO 'week'. include_all_day: Count all-day events as meeting time. include_declined: Count meetings the user declined. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| list_calendarsA | List the calendars the signed-in user can see, with their IDs and timezones. Start here whenever the user mentions a calendar other than their own: the
Args: min_access_role: Only return calendars where the user has at least this role: 'freeBusyReader', 'reader', 'writer' or 'owner'. Omit for all. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| create_calendarA | Create a new secondary calendar owned by the user. Args: summary: Name for the new calendar, e.g. 'Client work'. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| find_focus_timeA | Find the uninterrupted blocks in a window that could be used for deep work. Searches inside the user's working hours ( Availability must be readable for every requested calendar; otherwise this
returns an error rather than unverified free time.
Read-only: use Args: time_min: Start of the window to search, ISO 8601. Without a UTC offset it is read in the calendar's own timezone. time_max: End of the window to search, ISO 8601. hours_needed: How many focus hours the user is trying to find. Used to report whether the window can supply them; pass 0 to just look. calendar_ids: Calendars whose events count as busy. Omit for every calendar the account has selected. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| block_focus_timeA | Book the best free blocks in a window as focus time, until the hours add up. Takes the blocks Run it with Args:
time_min: Start of the window to book inside, ISO 8601.
time_max: End of the window, ISO 8601.
hours_needed: How many focus hours to book.
title: Title for the blocks. Default 'Focus time'.
calendar_id: Calendar to book on. Omit for the user's configured
focus_calendar_id (see |
| detect_conflictsA | Find double-booked events in a window, across every signed-in account. Reports two things. Events the user declined, events marked free, cancelled events and (unless
Args: time_min: Start of the window to check, ISO 8601. time_max: End of the window to check, ISO 8601. accounts: Account names to check. Omit for every signed-in account, which is the point of the tool -- a work meeting clashing with a personal one is invisible from either calendar alone. calendar_ids: Restrict to these calendars (in every account checked). Omit for each account's selected calendars. include_all_day: True to let all-day events clash with timed ones. max_events_per_calendar: Safety limit per calendar. Default 250. |
| suggest_rescheduleA | Propose better times for an existing meeting, ranked, keeping its length. Reads the event, then looks for slots of the same duration inside the user's working hours where the organiser is free, and ranks them: fewest attendee conflicts first, the event's current day next, then earliest. Slots that sit closer to another meeting than the user's buffer allows are penalised, not hidden. Read-only by default -- it suggests, the user decides. Set Args:
event_id: The event to reschedule (from |
| find_eventsA | Search a calendar for events, expanding recurring series into instances. Use this before any tool that needs an Args: calendar_id: Calendar to search. 'primary' is the user's own calendar. time_min: Inclusive start of the window, ISO 8601 with a UTC offset. Without an offset it is read in the calendar's own timezone. time_max: Exclusive end of the window, ISO 8601. query: Free-text search over title, description, location and attendees. max_results: Maximum events to return (default 50). account: Account name from 'calendar-mcp accounts'; omit for the default. |
| check_attendee_statusA | Report who has accepted, declined or not yet answered an event invitation. Args:
event_id: The event to inspect (from |
| create_eventA | Create an event with explicit start and end times, and optional attendees. For a one-line natural-language description ("coffee with Sam tomorrow at 3")
prefer Args: calendar_id: Calendar to create the event on. summary: Event title. Required. start_time: Start, ISO 8601 with a UTC offset (e.g. '2026-03-14T15:00:00-04:00'). Without an offset it is read in the calendar's own timezone. end_time: End, ISO 8601, same convention as start_time. description: Longer notes for the event body. location: Free-text location or meeting link. attendee_emails: People to invite. They receive an invitation email unless send_notifications is false. send_notifications: Whether Google emails the attendees. Default true. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| quick_add_eventA | Create an event from a plain-English phrase, parsed by Google. Google interprets the date, time and title itself, in the calendar's own timezone. Check the returned start/end and tell the user what was booked -- the parser guesses, and does not handle attendees or descriptions. Args: text: The phrase to parse, e.g. 'Dentist Thursday 9am' or 'Team sync every Monday at 10 for 30 minutes'. calendar_id: Calendar to create the event on. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| update_eventA | Change fields on an existing event. Omitted fields are left untouched. To reschedule while keeping the duration, use Args:
calendar_id: Calendar the event lives on.
event_id: The event to update (from |
| move_eventA | Reschedule an event, and/or move it to a different calendar. Supplying only Args:
event_id: The event to move (from |
| add_attendeeA | Invite one or more people to an existing event. Existing attendees are kept; the new addresses are appended. Args:
event_id: The event to invite people to (from |
| respond_to_eventA | Set the user's own RSVP on an invitation they have received. Only works on events the user is an attendee of; it does not change anyone else's response. Args:
event_id: The invitation to answer (from |
| delete_eventA | Permanently delete an event. This cannot be undone. Clients that support elicitation are asked to confirm first; if the user
declines, nothing is deleted and Args:
event_id: The event to delete (from |
| query_free_busyA | Get busy intervals for one or more calendars, without revealing event details. Works for other people's calendars addressed by email, which is how you check whether someone is free before proposing a time. Args: calendar_ids: Calendar IDs or attendee email addresses to check. time_min: Start of the window, ISO 8601 with a UTC offset. time_max: End of the window, ISO 8601 with a UTC offset. account: Account name from 'calendar-mcp accounts'; omit for the default. |
| schedule_mutualA | Find the first slot where everyone is free, then book the meeting there. Reads each attendee's free/busy inside the window, picks the earliest gap
that fits By default the search obeys the user's own settings from Args: attendee_calendar_ids: Attendee email addresses whose availability matters. time_min: Earliest the meeting may start, ISO 8601 with a UTC offset. time_max: Latest the meeting may end, ISO 8601 with a UTC offset. duration_minutes: Length of the meeting in minutes. summary: Title for the meeting. description: Optional agenda or notes. location: Optional location or meeting link. organizer_calendar_id: Calendar the meeting is created on. working_hours_start: Optional daily earliest start, 'HH:MM' local to the calendar, e.g. '09:00'. working_hours_end: Optional daily latest end, 'HH:MM', e.g. '17:00'. send_notifications: Whether Google emails the attendees. Default true. respect_preferences: Obey the user's saved working hours, lunch and buffer. Set false to search the whole window instead. account: Account name from 'calendar-mcp accounts'; omit for the default. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 23 tools
Most tools target distinct resource+action pairs, and descriptions proactively cross-reference potential confusions (create_event vs quick_add_event, move_event vs update_event, find_focus_time vs block_focus_time). A few genuine overlaps remain (suggest_reschedule's apply flag vs move_event, analyze_busyness vs time_audit), but they are clearly delineated in the text.
Strong verb_noun pattern throughout (find_events, create_event, update_event, delete_event, list_calendars, get_preferences, set_preferences). Minor deviations like quick_add_event, time_audit and schedule_mutual break the pattern slightly but remain readable and unambiguous.
23 tools is at the heavy end of the scale for a calendar server. Each tool is well-scoped and justified (event CRUD, focus time, preferences, analytics, cross-account conflict detection), but the surface is large enough that an agent must sift through several near-neighbors.
Covers event lifecycle (create/quick_add/find/update/move/delete), calendars (list/create), attendees (add/respond/status), free/busy, focus time, preferences and analytics. Minor gaps: no remove_attendee, no update_calendar or delete_calendar, which an agent would need for full calendar management.