Skip to content

fix: correct MCP tool schemas against Cal.com API v2 spec#74

Merged
sahitya-chandra merged 1 commit intomainfrom
devin/1775576994-fix-mcp-400-errors
Apr 9, 2026
Merged

fix: correct MCP tool schemas against Cal.com API v2 spec#74
sahitya-chandra merged 1 commit intomainfrom
devin/1775576994-fix-mcp-400-errors

Conversation

@sahitya-chandra
Copy link
Copy Markdown
Member

@sahitya-chandra sahitya-chandra commented Apr 7, 2026

Summary

Audited all MCP tool schemas against the Cal.com API v2 OpenAPI spec (calcom/cal) and fixed every confirmed mismatch:

schedules.ts

  • availability slots: Changed day (singular string) → days (array of day-name strings) to match ScheduleAvailabilityInput_2024_06_11. This was causing 400 errors on every schedule create/update with availability.
  • overrides: Made startTime and endTime required (spec: required: ["date", "startTime", "endTime"]). To mark a date unavailable, set both to "00:00".

event-types.ts

  • bookingLimitsCount: Replaced z.record() with PER_DAY/PER_WEEK description → typed z.object({ day, week, month, year }) matching BookingLimitsCount_2024_06_14.
  • bookingWindow: Replaced z.record() → typed z.object({ type: enum["businessDays"|"calendarDays"|"range"], value, rolling }) matching BookingWindow_2024_06_14.
  • destinationCalendar: Replaced z.record() → typed z.object({ integration, externalId }) matching DestinationCalendar_2024_06_14.
  • recurrence description: Corrected example field countoccurrences (matching Recurrence_2024_06_14).

bookings.ts

  • allowConflicts / allowBookingOutOfBounds descriptions: Clarified these are host-only and ignored for non-hosts.

Verification

  • All changes verified against calcom/cal source types (packages/platform/types/)
  • Full test suite passes: 125 tests across 10 files

Open with Devin

@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
cal-companion-chat Ignored Ignored Apr 9, 2026 0:51am

Request Review

- schedules: availability uses 'days' array not 'day' string (ScheduleAvailabilityInput_2024_06_11)
- schedules: override startTime/endTime are required per spec, not optional
- event-types: bookingLimitsCount uses day/week/month/year keys (not PER_DAY etc.)
- event-types: bookingWindow typed with businessDays/calendarDays/range enum
- event-types: destinationCalendar typed with integration + externalId fields
- event-types: recurrence description corrects 'count' to 'occurrences'
- bookings: allowConflicts/allowBookingOutOfBounds descriptions clarify host-only behavior
@sahitya-chandra sahitya-chandra force-pushed the devin/1775576994-fix-mcp-400-errors branch from 7a1ddf4 to 96c8021 Compare April 9, 2026 12:50
@sahitya-chandra sahitya-chandra changed the title fix: correct MCP server schemas and request formats causing 400 errors fix: correct MCP tool schemas against Cal.com API v2 spec Apr 9, 2026
@dhairyashiil dhairyashiil marked this pull request as ready for review April 9, 2026 13:03
@sahitya-chandra sahitya-chandra merged commit 4d6292f into main Apr 9, 2026
14 of 15 checks passed
@sahitya-chandra sahitya-chandra deleted the devin/1775576994-fix-mcp-400-errors branch April 9, 2026 13:05
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +220 to +224
bookingWindow: z.object({
type: z.enum(["businessDays", "calendarDays", "range"]).describe("Window type"),
value: z.union([z.number(), z.array(z.string())]).describe("Number of days (for businessDays/calendarDays) or date range array ['2030-09-05', '2030-09-09'] (for range)"),
rolling: z.boolean().optional().describe("If true the window rolls forward keeping 'value' days available. Only for businessDays/calendarDays."),
}).optional().describe("Limit how far in the future this event can be booked."),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 bookingWindow schema rejects { disabled: true }, breaking ability to remove booking window restrictions

The bookingWindow field in both createEventTypeSchema and updateEventTypeSchema was changed from z.record(z.unknown()) (which accepted any object, including { disabled: true }) to a z.object with type and value as required fields. According to the OpenAPI spec (docs/api-reference/v2/openapi.json), bookingWindow accepts a oneOf that includes Disabled_2024_06_14 (i.e. { disabled: true }) to reset/remove a previously configured booking window. With the new strict schema, passing { disabled: true } will fail zod validation because required fields type and value are missing. This is a regression — users can no longer disable booking windows through the MCP tool. The mobile app actively uses this pattern at apps/mobile/components/event-type-detail/utils/buildPartialUpdatePayload.ts:641.

Prompt for agents
The bookingWindow field in both createEventTypeSchema and updateEventTypeSchema now uses z.object with required type and value fields, which makes it impossible to pass { disabled: true } to reset/remove a booking window. The Cal.com API v2 spec uses a oneOf that includes the Disabled_2024_06_14 variant ({ disabled: true }) alongside the BusinessDays/CalendarDays/Range window variants.

To fix this, the zod schema should use z.union (or z.discriminatedUnion) to accept either the current window object OR a disabled object. For example:

bookingWindow: z.union([
  z.object({
    type: z.enum(["businessDays", "calendarDays", "range"]),
    value: z.union([z.number(), z.array(z.string())]),
    rolling: z.boolean().optional(),
  }),
  z.object({ disabled: z.literal(true) }),
]).optional()

This needs to be applied in both createEventTypeSchema (around line 105) and updateEventTypeSchema (around line 220) in apps/mcp-server/src/tools/event-types.ts. The corresponding TypeScript type annotations for the params of createEventType and updateEventType functions should also be updated to include the disabled variant.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants