MewCP Cal.com MCP
About
Hosted, Stateless & Multitenant Cal.com MCP server enables AI assistants to manage scheduling, bookings, and calendar availability through Cal.com.
Details
- Author
- asthetech
- Categories
- Developer Tools, Other, Productivity, Automation
Jump to
Setup
Install MewCP Cal.com MCP in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/asthetech/mewcp-cal
Follow the installation instructions in the repository README, then restart your MCP client.
Calendar scheduling, bookings, and availability for AI agents
A Model Context Protocol (MCP) server that exposes Cal.com's v2 API for managing event types, bookings, schedules, availability, and organization membership.
The MewCP Cal MCP Server provides programmatic access to a Cal.com scheduling account:
- Read and create event types, and inspect the authenticated user's profile
- Create, retrieve, reschedule, confirm, cancel, and mark bookings absent
- Manage availability schedules and query open time slots and busy times
- List organization memberships and routing forms
- Automating meeting booking and rescheduling workflows
- Building scheduling assistants that surface open slots and busy times
- Managing team and organization scheduling resources programmatically
Get authenticated user profile from Cal.com
{ id?: number | null; username?: string | null; email?: string | null; name?: string | null; timeZone?: string | null; weekStart?: string | null; locale?: string | null; timeFormat?: number | null; defaultScheduleId?: number | null; organizationId?: number | null; organization?: object | null; avatarUrl?: string | null; bio?: string | null; // additional upstream fields may be present }
{ count: number; event_types: { id?: number | null; title?: string | null; slug?: string | null; lengthInMinutes?: number | null; length?: number | null; description?: string | null; hidden?: boolean | null; ownerId?: number | null; // additional upstream fields may be present }[]; // additional upstream fields may be present }
- event_type_id (integer, required) — The event type ID: the numeric Cal.com identifier of the event type to retrieve, as an integer (e.g. 123456). Required — the call fails with a validation error if omitted.
{ id?: number | null; title?: string | null; slug?: string | null; lengthInMinutes?: number | null; length?: number | null; description?: string | null; hidden?: boolean | null; ownerId?: number | null; // additional upstream fields may be present }
- title (string, required) — Title of the event type: the display name for the new event type, as a plain non-empty string (e.g. '30 Minute Meeting'). Required — the call fails with a validation error if omitted or blank.
{ id?: number | null; title?: string | null; slug?: string | null; lengthInMinutes?: number | null; length?: number | null; description?: string | null; hidden?: boolean | null; ownerId?: number | null; // additional upstream fields may be present }
{ count: number; bookings: { id?: number | null; uid?: string | null; title?: string | null; description?: string | null; status?: string | null; start?: string | null; end?: string | null; duration?: number | null; eventTypeId?: number | null; meetingUrl?: string | null; location?: string | null; absentHost?: boolean | null; cancellationReason?: string | null; rescheduledFromUid?: string | null; rescheduledToUid?: string | null; attendees?: { name?: string | null; email?: string | null; timeZone?: string | null; phoneNumber?: string | null; language?: string | null; absent?: boolean | null; }[] | null; hosts?: object[] | null; // additional upstream fields may be present }[]; // additional upstream fields may be present }
- booking_id (string, required) — The booking ID to retrieve, as a plain string (e.g. '12345'). Required.
{ id?: number | null; uid?: string | null; title?: string | null; description?: string | null; status?: string | null; start?: string | null; end?: string | null; duration?: number | null; eventTypeId?: number | null; meetingUrl?: string | null; location?: string | null; absentHost?: boolean | null; cancellationReason?: string | null; rescheduledFromUid?: string | null; rescheduledToUid?: string | null; attendees?: { name?: string | null; email?: string | null; timeZone?: string | null; phoneNumber?: string | null; language?: string | null; absent?: boolean | null; }[] | null; hosts?: object[] | null; // additional upstream fields may be present }
- event_type_id (integer, required) — Event type ID to book, as an integer (e.g. 42). Required. - start (string, required) — Booking start datetime in ISO 8601 / RFC 3339 UTC format (e.g. '2024-08-13T09:00:00Z'). Required. - attendee_name (string, required) — Attendee full name as a plain string (e.g. 'Ada Lovelace'). Required. - attendee_email (string, required) — Attendee email address as a plain string (e.g. 'ada@example.com'). Required.
{ id?: number | null; uid?: string | null; title?: string | null; description?: string | null; status?: string | null; start?: string | null; end?: string | null; duration?: number | null; eventTypeId?: number | null; meetingUrl?: string | null; location?: string | null; absentHost?: boolean | null; cancellationReason?: string | null; rescheduledFromUid?: string | null; rescheduledToUid?: string | null; attendees?: { name?: string | null; email?: string | null; timeZone?: string | null; phoneNumber?: string | null; language?: string | null; absent?: boolean | null; }[] | null; hosts?: object[] | null; // additional upstream fields may be present }
DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Cancel a booking. Permanently cancels the booking identified bybooking_id, releasing its time slot and notifying the host and every attendee. This action is irreversible — the cancelled booking and its confirmed slot cannot be recovered. NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly which booking will be cancelled and that it is permanent, and wait for their explicit written confirmation before proceeding. The response includes the booking's state before cancellation.
- booking_id (string, required) — The booking ID to cancel, as a plain string (e.g. '12345'). Required.
{ before?: { id?: number | null; uid?: string | null; title?: string | null; description?: string | null; status?: string | null; start?: string | null; end?: string | null; duration?: number | null; eventTypeId?: number | null; meetingUrl?: string | null; location?: string | null; absentHost?: boolean | null; cancellationReason?: string | null; rescheduledFromUid?: string | null; rescheduledToUid?: string | null; attendees?: { name?: string | null; email?: string | null; timeZone?: string | null; phoneNumber?: string | null; language?: string | null; absent?: boolean | null; }[] | null; hosts?: object[] | null; } | null; after?: { / same shape as before / } | null; // additional upstream fields may be present }
Reschedule an existing booking. Only the fields you provide are changed — others keep their current value. NOTE: this overwrites the current start and end times — the original state is not stored after the call. The response includes both the before and after state so you have a full record of what changed.
- booking_id (string, required) — The booking ID to reschedule, as a plain string (e.g. '12345'). Required. - start (string, required) — New start time in ISO 8601 / RFC 3339 UTC format (e.g. '2024-08-13T09:00:00Z'). Required. - end (string, required) — New end time in ISO 8601 / RFC 3339 UTC format (e.g. '2024-08-13T09:30:00Z'). Required.
{ before?: { id?: number | null; uid?: string | null; title?: string | null; description?: string | null; status?: string | null; start?: string | null; end?: string | null; duration?: number | null; eventTypeId?: number | null; meetingUrl?: string | null; location?: string | null; absentHost?: boolean | null; cancellationReason?: string | null; rescheduledFromUid?: string | null; rescheduledToUid?: string | null; attendees?: { name?: string | null; email?: string | null; timeZone?: string | null; phoneNumber?: string | null; language?: string | null; absent?: boolean | null; }[] | null; hosts?: object[] | null; } | null; after?: { / same shape as before / } | null; // additional upstream fields may be present }
Confirm a pending booking. Only the fields you provide are changed — others keep their current value. NOTE: this overwrites the booking's current status — the original state is not stored after the call. The response includes both the before and after state so you have a full record of what changed.
- booking_id (string, required) — ID of the pending booking to confirm, as a plain string (e.g. '12345'). Required.
{ before?: { id?: number | null; uid?: string | null; title?: string | null; description?: string | null; status?: string | null; start?: string | null; end?: string | null; duration?: number | null; eventTypeId?: number | null; meetingUrl?: string | null; location?: string | null; absentHost?: boolean | null; cancellationReason?: string | null; rescheduledFromUid?: string | null; rescheduledToUid?: string | null; attendees?: { name?: string | null; email?: string | null; timeZone?: string | null; phoneNumber?: string | null; language?: string | null; absent?: boolean | null; }[] | null; hosts?: object[] | null; } | null; after?: { / same shape as before / } | null; // additional upstream fields may be present }
Mark a booking as absent. Only the fields you provide are changed — others keep their current value. NOTE: this overwrites the booking's current attendance state — the original state is not stored after the call. The response includes both the before and after state so you have a full record of what changed.
- booking_id (string, required) — ID of the booking to mark as absent, as a plain string (e.g. '12345'). Required.
{ before?: { id?: number | null; uid?: string | null; title?: string | null; description?: string | null; status?: string | null; start?: string | null; end?: string | null; duration?: number | null; eventTypeId?: number | null; meetingUrl?: string | null; location?: string | null; absentHost?: boolean | null; cancellationReason?: string | null; rescheduledFromUid?: string | null; rescheduledToUid?: string | null; attendees?: { name?: string | null; email?: string | null; timeZone?: string | null; phoneNumber?: string | null; language?: string | null; absent?: boolean | null; }[] | null; hosts?: object[] | null; } | null; after?: { / same shape as before / } | null; // additional upstream fields may be present }
{ count: number; schedules: { id?: number | null; ownerId?: number | null; name?: string | null; timeZone?: string | null; isDefault?: boolean | null; availability?: { days?: string[] | null; startTime?: string | null; endTime?: string | null; }[] | null; overrides?: object[] | null; // additional upstream fields may be present }[]; // additional upstream fields may be present }
- schedule_id (string, required) — The schedule ID identifying the schedule to retrieve. Plain string containing the Cal.com numeric schedule identifier (for example "12345"). Required — the call fails with a validation error if omitted or blank.
{ id?: number | null; ownerId?: number | null; name?: string | null; timeZone?: string | null; isDefault?: boolean | null; availability?: { days?: string[] | null; startTime?: string | null; endTime?: string | null; }[] | null; overrides?: object[] | null; // additional upstream fields may be present }
{ id?: number | null; ownerId?: number | null; name?: string | null; timeZone?: string | null; isDefault?: boolean | null; availability?: { days?: string[] | null; startTime?: string | null; endTime?: string | null; }[] | null; overrides?: object[] | null; // additional upstream fields may be present }
- name (string, required) — Name of the schedule to create, as shown in Cal.com. Plain free-text string (for example "Working Hours"). Required — the call fails with a validation error if omitted or blank.
{ id?: number | null; ownerId?: number | null; name?: string | null; timeZone?: string | null; isDefault?: boolean | null; availability?: { days?: string[] | null; startTime?: string | null; endTime?: string | null; }[] | null; overrides?: object[] | null; // additional upstream fields may be present }
- date (string, required) — Calendar day to look up available slots for, as a plain string in YYYY-MM-DD format (ISO 8601 calendar date). Required — there is no default, and the call fails with VALIDATION_ERROR if it is omitted or not in YYYY-MM-DD format.
{ date?: string | null; timeZone?: string | null; count: number; slots: { start?: string | null; end?: string | null; time?: string | null; attendees?: number | null; bookingUid?: string | null; // additional upstream fields may be present }[]; // additional upstream fields may be present }
{ count: number; busy_times: { start?: string | null; end?: string | null; source?: string | null; title?: string | null; // additional upstream fields may be present }[]; // additional upstream fields may be present }
{ count: number; memberships: { id?: number | null; userId?: number | null; teamId?: number | null; organizationId?: number | null; role?: string | null; accepted?: boolean | null; disableImpersonation?: boolean | null; user?: { id?: number | null; email?: string | null; username?: string | null; name?: string | null; } | null; // additional upstream fields may be present }[]; // additional upstream fields may be present }
{ count: number; routing_forms: { id?: string | null; name?: string | null; description?: string | null; disabled?: boolean | null; position?: number | null; userId?: number | null; teamId?: number | null; routes?: any; fields?: any; createdAt?: string | null; updatedAt?: string | null; // additional upstream fields may be present }[]; // additional upstream fields may be present }
Every tool returns the same top-level envelope. Onlydatavaries per tool.
// Success { "success": true, "statusCode": 200, "retriable": false, "retry_after_seconds": null, "error": null, "data": { ... } } // Error { "success": false, "statusCode": 400, "retriable": false, "retry_after_seconds": null, "error": { "code": "VALIDATION_ERROR", "message": "description", "details": {} }, "data": null }
- retriable—truewhen it is safe to retry (rate limit, network error, 503).falsefor validation and auth errors.
- retry_after_seconds— seconds to wait before retrying; present only whenretriableistrueand the upstream specifies a delay.
- error.code— machine-readable string:VALIDATION_ERROR,AUTH_ERROR,UPSTREAM_ERROR,SERVER_ERROR.
This server uses static API-key authentication. Add your Cal.com API key to your MewCP account as theapi_keycredential field. The server sends it upstream to the Cal.com v2 API as:
Authorization: Bearer <api_key> cal-api-version: 2024-06-11
ISO 8601 / RFC 3339 UTC Example: 2024-08-13T09:00:00Z
YYYY-MM-DD (ISO 8601 calendar date) Example: 2024-08-13
- Cause:API key not provided in request headers or incorrect format
- Solution:
- VerifyAuthorization: Bearer YOUR_API_KEYandX-Mewcp-Credential-Id: CREDENTIAL-IDheaders are present
- Check API key is active in your MewCP account
- Cause:API calls have exceeded your request limits
- Solution:
- Check credit usage in your Curious Layer dashboard
- Upgrade to a paid plan or add credits for higher limits
- Contact support for credit adjustments
- Cause:No Cal.com credential linked to your account
- Solution:
- Go toCredentialsin your MewCP dashboard
- Add your Cal.com API key (static) in theapi_keycredential field
- Retry the request with the correctX-Mewcp-Credential-Idheader
- Cause:JSON payload is invalid or missing required fields
- Solution:
- Validate JSON syntax before sending
- Ensure all required tool parameters are included
- Check parameter types match expected values
- Cause:Incorrect server name in the API endpoint
- Solution:
- Verify endpoint format:{server-name}/mcp/{tool-name}
- Use correct server name from documentation
- Check available servers in your Curious Layer account
- Cause:Upstream Cal.com API returned an error
- Solution:
- Check Cal.com service status atCal.com Status Page
- Verify your credential has the required permissions
- Review the error message for specific details
- Cal.com API Documentation— Official API reference
- Cal.com API Reference— Complete endpoint reference
- FastMCP Docs— FastMCP specification
- FastMCP Credentials— FastMCP Credentials package for credential handling
This is a web browser that enables your coding agent, such as Claude Code, to visit websites on your behalf and assist you in identifying bugs or creating UI test cases.
Connect AI clients to Cal.com scheduling through the Model Context Protocol using the hosted server at mcp.cal.com or a local instance.
Sync Calendars, Scheduling Links, AI Executive Scheduling Assistant, Unified Calendar
Zo is your personal vibe server in the cloud with 50+ tools and integrations. Add texting, email, calendar, research and more to your harness easily.
Calendrz: Mirror Your Availability Across Every Calendar, Automatically.
Provides various DingTalk services including contacts, department management, robot messaging, calendar, and tasks.
Connects AI agents to the Feishu/Lark platform for automating tasks like document processing, conversation management, and calendar scheduling.
Connect AI agents with the Feishu/Lark platform for automation, including document processing, conversation management, and calendar scheduling.
Connect AI agents with the Feishu/Lark platform for automation, including document processing, conversation management, and calendar scheduling.
Connects AI agents to the Feishu/Lark platform via its OpenAPI to automate tasks like document processing, conversation management, and calendar scheduling.
Interact with Google Calendar APIs to manage events and calendars.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





