booking_chest
Allows connecting Apple Calendar integration.
Provides tools to manage scheduling, event types, bookings, calendars, webhooks, and teams through the Cal.com open-source scheduling platform.
Allows connecting Google Calendar to check busy times, set destination calendar, and manage calendar integration.
Required for team creation; integration with Stripe for billing.
Allows creating webhooks to notify Zapier on booking events.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@booking_chest Create a 30-minute consultation event type"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
booking_chest — Cal.com MCP Server
A Model Context Protocol server for Cal.com open-source scheduling. Exposes ~70 MCP tools across 10 resource modules — create schedules, manage event types, book meetings, integrate calendars, configure webhooks, and manage teams — all controllable directly from Claude or any MCP-compatible client.
Features
~70 tools covering the Cal.com API v2
Clean two-layer architecture: pure
calcom_client/package + thin MCP wrapperStatic Bearer token auth (no refresh needed)
Typed exception hierarchy (
APIError,NotFoundError,ValidationError,AuthenticationError)API quirks baked in (correct parameter names, required fields, response envelope unwrapping)
Related MCP server: carly-cli
Resource Modules (10)
Module | Tools | Description |
| 2 | Profile get/update |
| 1 | List all 7,072 city/timezone entries |
| 1 | Rotate API key (warning: invalidates immediately) |
| 5 | Availability schedule CRUD |
| 9 | Event type CRUD + per-type webhooks + private links (Enterprise) |
| 3 | Available slots, reserve, delete reservation |
| 6 | List, get, create, cancel, reschedule, mark no-show |
| 9 | Connect, busy times, destination, selected, ICS feeds |
| 5 | User-level webhook CRUD (21 trigger types) |
| 19 | Team CRUD + memberships + event types + event-type webhooks + invite |
Installation
git clone https://github.com/dsddet/booking_chest
cd booking_chest
pip install -e ".[mcp]"Or with uv (recommended):
uv pip install -e ".[mcp]"Environment Variables
Variable | Required | Description |
| Yes | Cal.com API key (starts with |
| No | Cal.com instance URL (default: |
Create a .env file:
CALCOM_API_KEY=cal_your_api_key_here
CALCOM_BASE_URL=https://api.cal.comFor self-hosted Cal.com instances, set CALCOM_BASE_URL to your instance URL (e.g., http://192.168.0.214).
Getting an API Key
Log into Cal.com Settings → Developer → API Keys
Click "Generate API Key"
Copy the key (starts with
cal_) — it cannot be retrieved later
Claude Desktop Configuration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"booking_chest": {
"command": "uv",
"args": [
"--directory", "/path/to/booking_chest",
"run", "--extra", "mcp", "mcp_server.py"
],
"env": {
"CALCOM_API_KEY": "cal_your_api_key_here",
"CALCOM_BASE_URL": "https://api.cal.com"
}
}
}
}Replace /path/to/booking_chest with the absolute path to your cloned directory.
Usage Examples
Once connected, you can ask Claude:
"Create a 30-minute consultation event type"
"What slots are available this week for event type 1?"
"Book a meeting with john@example.com on March 5th at 2pm Eastern"
"List all my upcoming bookings"
"Cancel booking 42 — attendee has a conflict"
"Connect my Google Calendar and set it as the destination"
"Create a webhook to notify Zapier when bookings are created or cancelled"
"List all team members and their roles"
Architecture
calcom_client/ # Pure API client (no MCP dependency)
├── http.py # httpx + Bearer token auth + response envelope unwrap
├── exceptions.py # APIError, NotFoundError, ValidationError, AuthenticationError
├── me.py # Profile get/update
├── timezones.py # List all timezones
├── api_keys.py # API key rotation
├── schedules.py # Availability schedule CRUD
├── event_types.py # Event type CRUD + webhooks + private links
├── slots.py # Available slots, reserve, delete
├── bookings.py # Booking CRUD (cancel, reschedule, no-show)
├── calendars.py # Calendar integrations (Google, Office 365, Apple)
├── webhooks.py # User-level webhook CRUD
├── teams.py # Team CRUD + memberships + event types + invite
└── __init__.py # CalcomClient facade composing all modules
mcp_server.py # ~70 @mcp.tool() functionsCal.com API Quirks (baked into client code)
API version: Use
cal-api-version: 2024-06-14(broadest support —2024-08-13misses some endpoints)Response envelope: All responses wrapped in
{"status": "success", "data": ...}— unwrapped automaticallySlots params: Use
start/end(NOTstartTime/endTime— those cause 400 errors)Webhook triggers: Use
triggersfield (NOTeventTriggers— old doc error)Calendar connect: Use
google,office365,apple(NOTgoogle-calendar,office365calendar)calendarsToLoadis REQUIRED for busy-times endpoint (400 error without it)isDefaultis REQUIRED when creating schedules (400 error without it)slotIdis REQUIRED when reserving slotsAPI key refresh: Old key invalidated immediately — update env before next request
Team creation needs Stripe — use existing teams or configure Stripe billing
metadata PATCH: Returns null in response but IS saved (verify via team memberships)
No team-level webhooks — webhooks are always scoped to specific event types
License
MIT
Available Tools
68 toolsadd_selected_calendarA
Mark a calendar for conflict detection (POST only, no GET).
To see selected status, use list_calendars() and check connectedCalendars[].calendars[].isSelected.
Inputs: external_id (required), integration (required), credential_id (required). Returns: result
cancel_bookingC
Cancel a booking.
Inputs: booking_id (required), cancellation_reason. Returns: result
check_calendar_connectionA
Check if a calendar type is connected.
Inputs: calendar_type (required). Returns: result
check_ics_feedC
Check ICS calendar feed subscription status.
Inputs: no named parameters. Returns: result
create_bookingC
Create a booking (schedule a meeting).
Inputs: start (required), attendee_name (required), event_type_id (required), attendee_time_zone (required), +5 more. Returns: result
create_event_typeC
Create an event type (meeting type / booking page).
Inputs: slug (required), title (required), length_in_minutes (required), price, +8 more. Returns: result
create_event_type_webhookC
Create a webhook for a specific event type.
Inputs: triggers (required), event_type_id (required), subscriber_url (required), active, +1 more. Returns: result
create_private_linkB
Create a private booking link for an event type (Enterprise).
At least one of expires_at or max_usage_count is required.
Inputs: event_type_id (required), label, expires_at, max_usage_count. Returns: result
create_scheduleC
Create an availability schedule.
Inputs: name (required), time_zone (required), is_default (required), schedule. Returns: result
create_teamA
Create a new team.
WARNING: Requires Stripe billing configuration. Will fail with InternalServerError if Stripe is not set up. For most use cases, use existing teams.
Inputs: name (required), slug (required). Returns: result
create_team_event_typeB
Create a team event type.
scheduling_type is REQUIRED for team event types (API returns validation error without it).
Inputs: slug (required), title (required), team_id (required), scheduling_type (required), +2 more. Returns: result
create_team_event_type_webhookC
Create a webhook for a team event type.
Inputs: team_id (required), triggers (required), event_type_id (required), subscriber_url (required), +1 more. Returns: result
create_team_inviteC
Generate a team join invite link.
Returns a token and inviteLink. Share the inviteLink with users to let them join the team.
Inputs: team_id (required). Returns: result
create_team_membershipC
Add a user to a team.
Inputs: team_id (required), user_id (required), role, accepted. Returns: result
create_webhookA
Create a user-level webhook for real-time event notifications.
IMPORTANT: Use triggers (NOT eventTriggers — that was an old API doc error).
Inputs: triggers (required), subscriber_url (required), active, secret. Returns: result
delete_event_typeC
Delete an event type.
Inputs: event_type_id (required). Returns: result
delete_event_type_webhookC
Delete an event type webhook.
Inputs: webhook_id (required), event_type_id (required). Returns: result
delete_private_linkB
Delete a private booking link (Enterprise).
Inputs: link_id (required), event_type_id (required). Returns: result
delete_scheduleC
Delete a schedule.
Inputs: schedule_id (required). Returns: result
delete_slot_reservationC
Cancel a slot reservation.
Inputs: uid (required). Returns: result
delete_teamC
Delete a team.
Inputs: team_id (required). Returns: result
delete_team_event_typeC
Delete a team event type.
Inputs: team_id (required), event_type_id (required). Returns: result
delete_team_event_type_webhookC
Delete a team event type webhook.
Inputs: team_id (required), webhook_id (required), event_type_id (required). Returns: result
delete_team_membershipB
Remove a member from a team.
Inputs: team_id (required), membership_id (required). Returns: result
delete_webhookC
Delete a webhook.
Inputs: webhook_id (required). Returns: result
get_available_slotsA
Get available booking slots for an event type.
IMPORTANT: Use start/end (NOT startTime/endTime — those return a 400 error).
Inputs: end (required), start (required), duration, time_zone, +4 more. Returns: result
get_bookingB
Get a booking by ID.
Inputs: booking_id (required). Returns: result
get_calendar_busy_timesA
Get busy time ranges across connected calendars.
calendars_to_load is REQUIRED (API returns 400 without it).
Inputs: date_to (required), date_from (required), time_zone (required), calendars_to_load (required). Returns: result
get_calendar_connect_urlB
Get OAuth authorization URL to connect a calendar.
Inputs: calendar_type (required), redirect_url. Returns: result
get_event_typeB
Get an event type by ID.
Inputs: event_type_id (required). Returns: result
get_my_profileA
Get current user profile (name, email, timezone, bio, defaultScheduleId, etc.).
Inputs: no named parameters. Returns: result
get_scheduleB
Get a schedule by ID.
Inputs: schedule_id (required). Returns: result
get_teamB
Get team details by ID.
Inputs: team_id (required). Returns: result
get_team_event_typeA
Get a team event type by ID.
Inputs: team_id (required), event_type_id (required). Returns: result
get_team_event_type_webhookB
Get a webhook for a team event type.
Inputs: team_id (required), webhook_id (required), event_type_id (required). Returns: result
get_team_membershipB
Get a team membership by ID.
Inputs: team_id (required), membership_id (required). Returns: result
get_webhookB
Get a webhook by ID.
Inputs: webhook_id (required). Returns: result
list_bookingsC
List bookings with optional filters.
Inputs: skip, take, status, attendee_email. Returns: result
list_calendarsA
List connected calendars and destination calendar.
Returns connectedCalendars (list of connected accounts) and destinationCalendar (where new bookings are created). Check isSelected on each calendar entry to see which are used for conflict detection.
Inputs: no named parameters. Returns: result
list_event_typesA
List all event types (meeting types).
Inputs: no named parameters. Returns: result
list_event_type_webhooksA
List webhooks for a specific event type.
Inputs: event_type_id (required). Returns: result
list_private_linksB
List private booking links for an event type (Enterprise).
Inputs: event_type_id (required). Returns: result
list_schedulesB
List all availability schedules.
Inputs: no named parameters. Returns: result
list_team_bookingsC
List all bookings for a team's event types.
Inputs: team_id (required). Returns: result
list_team_event_typesB
List event types for a team.
Inputs: team_id (required). Returns: result
list_team_event_type_webhooksA
List webhooks for a team event type.
Note: There are NO team-level webhooks — webhooks are always scoped to event types.
Inputs: team_id (required), event_type_id (required). Returns: result
list_team_membersB
List all members of a team with their roles.
Inputs: team_id (required). Returns: result
list_teamsA
List all teams the current user belongs to.
Inputs: no named parameters. Returns: result
list_team_schedulesB
List availability schedules for team members.
Inputs: team_id (required). Returns: result
list_timezonesA
List all 7,072 available city/timezone entries (no pagination — returns all at once).
Inputs: no named parameters. Returns: result
list_webhooksA
List all user-level webhooks.
Inputs: no named parameters. Returns: result
mark_booking_no_showA
Mark one or more attendees as no-shows for a booking.
Inputs: attendees (required), booking_id (required). Returns: result
refresh_api_keyA
Rotate the current API key.
WARNING: The old key is invalidated IMMEDIATELY. The response contains the new key. You must update CALCOM_API_KEY in your environment before making any further requests.
Inputs: no named parameters. Returns: result
remove_selected_calendarA
Remove a calendar from conflict detection.
Inputs: external_id (required), integration (required), credential_id (required). Returns: result
reschedule_bookingB
Reschedule a booking to a new time slot.
Inputs: start (required), booking_id (required), rescheduling_reason. Returns: result
reserve_slotA
Temporarily reserve a slot before creating a booking.
slotId is REQUIRED (use the slot ID from get_available_slots response). Reservation expires after a short window — create the booking before it lapses.
Inputs: start (required), slot_id (required), event_type_id (required), attendee_time_zone (required). Returns: result
save_ics_feedC
Subscribe to external ICS calendar feeds.
Inputs: urls (required), read_only. Returns: result
set_destination_calendarA
Set the destination calendar where new bookings are created (PUT only, no GET).
To retrieve current destination, use list_calendars() and check destinationCalendar field.
Inputs: external_id (required), integration (required), credential_id (required). Returns: result
update_event_typeB
Update an event type (PATCH — partial update).
Inputs: fields (required), event_type_id (required). Returns: result
update_event_type_webhookC
Update an event type webhook.
Inputs: fields (required), webhook_id (required), event_type_id (required). Returns: result
update_my_profileA
Update current user profile (PATCH — send only fields to change).
Inputs: bio, name, email, locale, +6 more. Returns: result
update_private_linkC
Update a private booking link (Enterprise).
Inputs: fields (required), link_id (required), event_type_id (required). Returns: result
update_scheduleB
Update a schedule (PATCH — send only fields to change).
Inputs: schedule_id (required), name, schedule, time_zone, +1 more. Returns: result
update_teamB
Update team details (PATCH — partial update).
Inputs: fields (required), team_id (required). Returns: result
update_team_event_typeA
Update a team event type (PATCH — partial update).
Inputs: fields (required), team_id (required), event_type_id (required). Returns: result
update_team_event_type_webhookC
Update a team event type webhook.
Inputs: fields (required), team_id (required), webhook_id (required), event_type_id (required). Returns: result
update_team_membershipA
Update a team membership (PATCH — role, accepted, disableImpersonation).
Inputs: fields (required), team_id (required), membership_id (required). Returns: result
update_webhookA
Update a webhook (PATCH — partial update).
Inputs: fields (required), webhook_id (required). Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 68 tools
Most tools target a distinct resource and action, and the descriptions clarify potential overlaps like reserve_slot vs create_booking or the various webhook scopes. However, with 68 tools, there are enough similar list/get/create/update/delete patterns (especially around webhooks and calendars) that an agent may occasionally need to read descriptions carefully.
The toolset predominantly follows a get/list/create/update/delete + resource pattern, with slight deviations like refresh_api_key, set_destination_calendar, check_ics_feed, and add_selected_calendar. These deviations are still readable and mostly action-first, so the naming is fairly consistent overall.
68 tools is an extremely large surface for a single MCP server, well beyond the 50+ threshold for a low score. While the domain is broad, the sheer number will likely overwhelm agents and increase the chance of selecting an irrelevant tool.
The toolset covers most core booking workflows: schedules, event types, availability, bookings, calendars, webhooks, and team management. Minor gaps exist, such as no get_event_type_webhook for non-team event types, no delete/removal for ICS feeds, and limited team booking detail operations, but agents can generally complete end-to-end tasks.
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Hosted Google Calendar MCP server for AI agents. No self-hosting or Google Cloud setup.
Acuity Scheduling MCP server for ChatGPT, Claude and any AI agent: list appointments, check availability, book appointment, reschedule appointment, cancel appointment and block off time in your own Acuity Scheduling account. Cotlet works in the account through your Cloud Browser, a real Chrome where you sign in to Acuity Scheduling yourself; Cotlet does not store your password and you need no Acuity Scheduling API key. About the official Acuity Scheduling API: Acuity Scheduling has a full REST API but no official MCP server (checked 17 Oct 2026). The API uses HTTP Basic auth with your user ID and API key, and Acuity says API access is available on the Premium plan (formerly Powerhouse), so Starter and Standard accounts have no key to give an agent. Setup and FAQ: https://cotlet.dev/integrations/acuity-scheduling-api-mcp-server
Calendar API for AI agents: events, availability, Google/Microsoft setup, scheduling, and iCal.
Related MCP Servers
- PythonMIT
- AlicenseAqualityCmaintenanceAgent-native MCP server for Carly, the AI scheduling assistant. Exposes 11 tools to read and manage booking pages, event types, calendars, bookings, and available slots. Allows you to manage and create booking pages from the command line.134 npm1MIT
- AlicenseAqualityDmaintenanceMCP server for the Cal.com API v2, providing 24 tools for managing bookings, event types, availability slots, schedules, calendars, user profile, and out-of-office entries.244 npm1MIT
- AlicenseNot gradedqualityDmaintenanceExposes Cal.com scheduling tools to AI agents via MCP, enabling listing event types, checking availability, and managing bookings (create, cancel, reschedule).89 npmMIT