// Google Calendar MCP tools
import { z } from 'zod';
import type { CalendarService } from '../services/calendar.js';
// ─────────────────────────────────────────────────────────────────────────────
// SCHEMAS
// ─────────────────────────────────────────────────────────────────────────────
// Common schemas
const EventDateTimeSchema = z.object({
dateTime: z.string().optional().describe('RFC3339 timestamp (e.g., 2025-01-15T10:00:00-05:00)'),
date: z.string().optional().describe('Date for all-day events (YYYY-MM-DD)'),
timeZone: z.string().optional().describe('IANA timezone (e.g., America/New_York)'),
});
const AttendeeSchema = z.object({
email: z.string().describe('Attendee email'),
displayName: z.string().optional().describe('Attendee display name'),
optional: z.boolean().optional().describe('Is optional attendee'),
});
const ReminderSchema = z.object({
method: z.enum(['email', 'popup']).describe('Reminder method'),
minutes: z.number().min(0).max(40320).describe('Minutes before event (max 4 weeks)'),
});
// Event schemas
export const CreateCalendarEventSchema = z.object({
calendarId: z.string().optional().describe('Calendar ID (defaults to primary)'),
summary: z.string().describe('Event title'),
description: z.string().optional().describe('Event description'),
location: z.string().optional().describe('Event location'),
start: EventDateTimeSchema.describe('Start time'),
end: EventDateTimeSchema.describe('End time'),
attendees: z.array(AttendeeSchema).optional().describe('List of attendees'),
recurrence: z.array(z.string()).optional().describe('RRULE strings for recurring events'),
reminders: z.object({
useDefault: z.boolean().describe('Use default calendar reminders'),
overrides: z.array(ReminderSchema).optional().describe('Custom reminders (max 5)'),
}).optional().describe('Reminder settings'),
colorId: z.string().optional().describe('Event color ID (1-11)'),
visibility: z.enum(['default', 'public', 'private', 'confidential']).optional(),
transparency: z.enum(['opaque', 'transparent']).optional().describe('opaque=busy, transparent=free'),
sendUpdates: z.enum(['all', 'externalOnly', 'none']).optional().describe('Send notifications'),
createMeetLink: z.boolean().optional().describe('Create Google Meet link'),
});
export const GetCalendarEventSchema = z.object({
calendarId: z.string().optional().describe('Calendar ID (defaults to primary)'),
eventId: z.string().describe('Event ID'),
});
export const ListCalendarEventsSchema = z.object({
calendarId: z.string().optional().describe('Calendar ID (defaults to primary)'),
timeMin: z.string().optional().describe('Start of time range (RFC3339)'),
timeMax: z.string().optional().describe('End of time range (RFC3339)'),
q: z.string().optional().describe('Search query'),
maxResults: z.number().optional().describe('Max results (default 50, max 2500)'),
pageToken: z.string().optional().describe('Page token for pagination'),
singleEvents: z.boolean().optional().describe('Expand recurring events (default true)'),
orderBy: z.enum(['startTime', 'updated']).optional().describe('Sort order'),
showDeleted: z.boolean().optional().describe('Include deleted events'),
timeZone: z.string().optional().describe('Timezone for response'),
});
export const UpdateCalendarEventSchema = z.object({
calendarId: z.string().optional().describe('Calendar ID (defaults to primary)'),
eventId: z.string().describe('Event ID to update'),
summary: z.string().optional().describe('New title'),
description: z.string().optional().describe('New description'),
location: z.string().optional().describe('New location'),
start: EventDateTimeSchema.optional().describe('New start time'),
end: EventDateTimeSchema.optional().describe('New end time'),
attendees: z.array(AttendeeSchema).optional().describe('Updated attendees'),
colorId: z.string().optional().describe('Event color ID'),
visibility: z.enum(['default', 'public', 'private', 'confidential']).optional(),
transparency: z.enum(['opaque', 'transparent']).optional(),
sendUpdates: z.enum(['all', 'externalOnly', 'none']).optional(),
});
export const DeleteCalendarEventSchema = z.object({
calendarId: z.string().optional().describe('Calendar ID (defaults to primary)'),
eventId: z.string().describe('Event ID to delete'),
sendUpdates: z.enum(['all', 'externalOnly', 'none']).optional().describe('Send cancellation notifications'),
});
export const QuickAddEventSchema = z.object({
calendarId: z.string().optional().describe('Calendar ID (defaults to primary)'),
text: z.string().describe('Natural language event text (e.g., "Lunch with John tomorrow at noon")'),
sendUpdates: z.enum(['all', 'externalOnly', 'none']).optional(),
});
export const MoveCalendarEventSchema = z.object({
eventId: z.string().describe('Event ID to move'),
sourceCalendarId: z.string().optional().describe('Source calendar (defaults to primary)'),
destinationCalendarId: z.string().describe('Destination calendar ID'),
sendUpdates: z.enum(['all', 'externalOnly', 'none']).optional(),
});
export const GetEventInstancesSchema = z.object({
calendarId: z.string().optional().describe('Calendar ID (defaults to primary)'),
eventId: z.string().describe('Recurring event ID'),
timeMin: z.string().optional().describe('Start of time range'),
timeMax: z.string().optional().describe('End of time range'),
maxResults: z.number().optional().describe('Max instances to return'),
});
// Calendar schemas
export const ListCalendarsSchema = z.object({
minAccessRole: z.enum(['freeBusyReader', 'reader', 'writer', 'owner']).optional()
.describe('Minimum access role filter'),
});
export const GetCalendarSchema = z.object({
calendarId: z.string().describe('Calendar ID'),
});
export const CreateCalendarSchema = z.object({
summary: z.string().describe('Calendar name'),
description: z.string().optional().describe('Calendar description'),
timeZone: z.string().optional().describe('IANA timezone'),
location: z.string().optional().describe('Geographic location'),
});
export const UpdateCalendarSchema = z.object({
calendarId: z.string().describe('Calendar ID'),
summary: z.string().optional().describe('New name'),
description: z.string().optional().describe('New description'),
timeZone: z.string().optional().describe('New timezone'),
location: z.string().optional().describe('New location'),
});
export const DeleteCalendarSchema = z.object({
calendarId: z.string().describe('Calendar ID to delete'),
});
// CalendarList schemas
export const AddCalendarToListSchema = z.object({
calendarId: z.string().describe('Calendar ID to add'),
colorId: z.string().optional().describe('Color ID'),
backgroundColor: z.string().optional().describe('Background color (hex)'),
foregroundColor: z.string().optional().describe('Foreground color (hex)'),
hidden: z.boolean().optional().describe('Hide from list'),
selected: z.boolean().optional().describe('Show in UI'),
summaryOverride: z.string().optional().describe('Custom display name'),
});
export const UpdateCalendarInListSchema = z.object({
calendarId: z.string().describe('Calendar ID'),
colorId: z.string().optional(),
backgroundColor: z.string().optional(),
foregroundColor: z.string().optional(),
hidden: z.boolean().optional(),
selected: z.boolean().optional(),
summaryOverride: z.string().optional(),
});
export const RemoveCalendarFromListSchema = z.object({
calendarId: z.string().describe('Calendar ID to remove'),
});
// ACL schemas
export const ShareCalendarSchema = z.object({
calendarId: z.string().describe('Calendar ID'),
scopeType: z.enum(['default', 'user', 'group', 'domain']).describe('Scope type'),
scopeValue: z.string().optional().describe('Email or domain (not needed for default)'),
role: z.enum(['none', 'freeBusyReader', 'reader', 'writer', 'owner']).describe('Permission level'),
sendNotifications: z.boolean().optional().describe('Send notification email'),
});
export const GetCalendarPermissionsSchema = z.object({
calendarId: z.string().describe('Calendar ID'),
});
export const UpdateCalendarPermissionSchema = z.object({
calendarId: z.string().describe('Calendar ID'),
ruleId: z.string().describe('ACL rule ID'),
role: z.enum(['none', 'freeBusyReader', 'reader', 'writer', 'owner']).describe('New role'),
sendNotifications: z.boolean().optional(),
});
export const RemoveCalendarPermissionSchema = z.object({
calendarId: z.string().describe('Calendar ID'),
ruleId: z.string().describe('ACL rule ID to remove'),
});
// Freebusy schema
export const CheckAvailabilitySchema = z.object({
timeMin: z.string().describe('Start of time range (RFC3339)'),
timeMax: z.string().describe('End of time range (RFC3339)'),
calendars: z.array(z.string()).describe('Calendar IDs to check'),
timeZone: z.string().optional().describe('Timezone for response'),
});
// Colors schema
export const GetCalendarColorsSchema = z.object({});
// Settings schema
export const GetCalendarSettingsSchema = z.object({
settingId: z.string().optional().describe('Specific setting ID (lists all if omitted)'),
});
// ─────────────────────────────────────────────────────────────────────────────
// TOOL DEFINITIONS
// ─────────────────────────────────────────────────────────────────────────────
export const calendarTools = [
// Events
{
name: 'createCalendarEvent',
description: 'Create a new calendar event. Supports timed events, all-day events, recurring events, and Google Meet integration.',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID (defaults to primary)' },
summary: { type: 'string', description: 'Event title' },
description: { type: 'string', description: 'Event description' },
location: { type: 'string', description: 'Event location' },
start: {
type: 'object',
description: 'Start time (use dateTime for timed events, date for all-day)',
properties: {
dateTime: { type: 'string', description: 'RFC3339 timestamp' },
date: { type: 'string', description: 'YYYY-MM-DD for all-day events' },
timeZone: { type: 'string', description: 'IANA timezone' },
},
},
end: {
type: 'object',
description: 'End time',
properties: {
dateTime: { type: 'string' },
date: { type: 'string' },
timeZone: { type: 'string' },
},
},
attendees: {
type: 'array',
description: 'List of attendees',
items: {
type: 'object',
properties: {
email: { type: 'string' },
displayName: { type: 'string' },
optional: { type: 'boolean' },
},
},
},
recurrence: {
type: 'array',
description: 'RRULE strings (e.g., RRULE:FREQ=WEEKLY;BYDAY=MO,WE)',
items: { type: 'string' },
},
colorId: { type: 'string', description: 'Event color ID (1-11)' },
visibility: { type: 'string', enum: ['default', 'public', 'private', 'confidential'] },
transparency: { type: 'string', enum: ['opaque', 'transparent'], description: 'opaque=busy, transparent=free' },
sendUpdates: { type: 'string', enum: ['all', 'externalOnly', 'none'] },
createMeetLink: { type: 'boolean', description: 'Create Google Meet link' },
},
required: ['summary', 'start', 'end'],
},
},
{
name: 'getCalendarEvent',
description: 'Get details of a specific calendar event',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID (defaults to primary)' },
eventId: { type: 'string', description: 'Event ID' },
},
required: ['eventId'],
},
},
{
name: 'listCalendarEvents',
description: 'List events from a calendar with optional filters for time range, search query, etc.',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID (defaults to primary)' },
timeMin: { type: 'string', description: 'Start of time range (RFC3339)' },
timeMax: { type: 'string', description: 'End of time range (RFC3339)' },
q: { type: 'string', description: 'Search query' },
maxResults: { type: 'number', description: 'Max results (default 50)' },
pageToken: { type: 'string', description: 'Pagination token' },
singleEvents: { type: 'boolean', description: 'Expand recurring events (default true)' },
orderBy: { type: 'string', enum: ['startTime', 'updated'] },
showDeleted: { type: 'boolean' },
timeZone: { type: 'string' },
},
required: [],
},
},
{
name: 'updateCalendarEvent',
description: 'Update an existing calendar event. Only provide fields you want to change.',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID (defaults to primary)' },
eventId: { type: 'string', description: 'Event ID to update' },
summary: { type: 'string', description: 'New title' },
description: { type: 'string', description: 'New description' },
location: { type: 'string', description: 'New location' },
start: {
type: 'object',
properties: {
dateTime: { type: 'string' },
date: { type: 'string' },
timeZone: { type: 'string' },
},
},
end: {
type: 'object',
properties: {
dateTime: { type: 'string' },
date: { type: 'string' },
timeZone: { type: 'string' },
},
},
attendees: { type: 'array', items: { type: 'object' } },
colorId: { type: 'string' },
visibility: { type: 'string', enum: ['default', 'public', 'private', 'confidential'] },
transparency: { type: 'string', enum: ['opaque', 'transparent'] },
sendUpdates: { type: 'string', enum: ['all', 'externalOnly', 'none'] },
},
required: ['eventId'],
},
},
{
name: 'deleteCalendarEvent',
description: 'Delete a calendar event',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID (defaults to primary)' },
eventId: { type: 'string', description: 'Event ID to delete' },
sendUpdates: { type: 'string', enum: ['all', 'externalOnly', 'none'], description: 'Send cancellation notifications' },
},
required: ['eventId'],
},
},
{
name: 'quickAddEvent',
description: 'Create an event from natural language text (e.g., "Lunch with John tomorrow at noon")',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID (defaults to primary)' },
text: { type: 'string', description: 'Natural language event description' },
sendUpdates: { type: 'string', enum: ['all', 'externalOnly', 'none'] },
},
required: ['text'],
},
},
{
name: 'moveCalendarEvent',
description: 'Move an event to a different calendar',
inputSchema: {
type: 'object' as const,
properties: {
eventId: { type: 'string', description: 'Event ID to move' },
sourceCalendarId: { type: 'string', description: 'Source calendar (defaults to primary)' },
destinationCalendarId: { type: 'string', description: 'Destination calendar ID' },
sendUpdates: { type: 'string', enum: ['all', 'externalOnly', 'none'] },
},
required: ['eventId', 'destinationCalendarId'],
},
},
{
name: 'getEventInstances',
description: 'Get all instances of a recurring event within a time range',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID (defaults to primary)' },
eventId: { type: 'string', description: 'Recurring event ID' },
timeMin: { type: 'string', description: 'Start of time range' },
timeMax: { type: 'string', description: 'End of time range' },
maxResults: { type: 'number', description: 'Max instances to return' },
},
required: ['eventId'],
},
},
// Calendars
{
name: 'listCalendars',
description: 'List all calendars accessible to the user',
inputSchema: {
type: 'object' as const,
properties: {
minAccessRole: {
type: 'string',
enum: ['freeBusyReader', 'reader', 'writer', 'owner'],
description: 'Minimum access role filter',
},
},
required: [],
},
},
{
name: 'getCalendar',
description: 'Get metadata for a specific calendar',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID' },
},
required: ['calendarId'],
},
},
{
name: 'createCalendar',
description: 'Create a new secondary calendar',
inputSchema: {
type: 'object' as const,
properties: {
summary: { type: 'string', description: 'Calendar name' },
description: { type: 'string', description: 'Calendar description' },
timeZone: { type: 'string', description: 'IANA timezone' },
location: { type: 'string', description: 'Geographic location' },
},
required: ['summary'],
},
},
{
name: 'updateCalendar',
description: 'Update calendar metadata',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID' },
summary: { type: 'string', description: 'New name' },
description: { type: 'string', description: 'New description' },
timeZone: { type: 'string', description: 'New timezone' },
location: { type: 'string', description: 'New location' },
},
required: ['calendarId'],
},
},
{
name: 'deleteCalendar',
description: 'Delete a secondary calendar (cannot delete primary)',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID to delete' },
},
required: ['calendarId'],
},
},
// CalendarList
{
name: 'addCalendarToList',
description: 'Add an existing calendar to the user\'s calendar list',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID to add' },
colorId: { type: 'string', description: 'Color ID' },
backgroundColor: { type: 'string', description: 'Background color (hex)' },
foregroundColor: { type: 'string', description: 'Foreground color (hex)' },
hidden: { type: 'boolean', description: 'Hide from list' },
selected: { type: 'boolean', description: 'Show events in UI' },
summaryOverride: { type: 'string', description: 'Custom display name' },
},
required: ['calendarId'],
},
},
{
name: 'updateCalendarInList',
description: 'Update display preferences for a calendar in the list',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID' },
colorId: { type: 'string' },
backgroundColor: { type: 'string' },
foregroundColor: { type: 'string' },
hidden: { type: 'boolean' },
selected: { type: 'boolean' },
summaryOverride: { type: 'string' },
},
required: ['calendarId'],
},
},
{
name: 'removeCalendarFromList',
description: 'Remove a calendar from the user\'s calendar list',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID to remove' },
},
required: ['calendarId'],
},
},
// ACL
{
name: 'shareCalendar',
description: 'Share a calendar with a user, group, or domain',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID' },
scopeType: { type: 'string', enum: ['default', 'user', 'group', 'domain'], description: 'Scope type' },
scopeValue: { type: 'string', description: 'Email or domain (not needed for default)' },
role: { type: 'string', enum: ['none', 'freeBusyReader', 'reader', 'writer', 'owner'], description: 'Permission level' },
sendNotifications: { type: 'boolean', description: 'Send notification email' },
},
required: ['calendarId', 'scopeType', 'role'],
},
},
{
name: 'getCalendarPermissions',
description: 'Get all sharing permissions for a calendar',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID' },
},
required: ['calendarId'],
},
},
{
name: 'updateCalendarPermission',
description: 'Update a sharing permission on a calendar',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID' },
ruleId: { type: 'string', description: 'ACL rule ID' },
role: { type: 'string', enum: ['none', 'freeBusyReader', 'reader', 'writer', 'owner'] },
sendNotifications: { type: 'boolean' },
},
required: ['calendarId', 'ruleId', 'role'],
},
},
{
name: 'removeCalendarPermission',
description: 'Remove a sharing permission from a calendar',
inputSchema: {
type: 'object' as const,
properties: {
calendarId: { type: 'string', description: 'Calendar ID' },
ruleId: { type: 'string', description: 'ACL rule ID to remove' },
},
required: ['calendarId', 'ruleId'],
},
},
// Freebusy
{
name: 'checkAvailability',
description: 'Check free/busy status of one or more calendars in a time range',
inputSchema: {
type: 'object' as const,
properties: {
timeMin: { type: 'string', description: 'Start of time range (RFC3339)' },
timeMax: { type: 'string', description: 'End of time range (RFC3339)' },
calendars: { type: 'array', items: { type: 'string' }, description: 'Calendar IDs to check' },
timeZone: { type: 'string', description: 'Timezone for response' },
},
required: ['timeMin', 'timeMax', 'calendars'],
},
},
// Colors
{
name: 'getCalendarColors',
description: 'Get available color palette for calendars and events',
inputSchema: {
type: 'object' as const,
properties: {},
required: [],
},
},
// Settings
{
name: 'getCalendarSettings',
description: 'Get user calendar settings (timezone, locale, etc.)',
inputSchema: {
type: 'object' as const,
properties: {
settingId: { type: 'string', description: 'Specific setting ID (lists all if omitted)' },
},
required: [],
},
},
];
// ─────────────────────────────────────────────────────────────────────────────
// HANDLERS
// ─────────────────────────────────────────────────────────────────────────────
export function createCalendarHandlers(calendarService: CalendarService) {
return {
// Events
createCalendarEvent: async (args: z.infer<typeof CreateCalendarEventSchema>) => {
const params = CreateCalendarEventSchema.parse(args);
return calendarService.createEvent(params);
},
getCalendarEvent: async (args: z.infer<typeof GetCalendarEventSchema>) => {
const params = GetCalendarEventSchema.parse(args);
return calendarService.getEvent(params.calendarId, params.eventId);
},
listCalendarEvents: async (args: z.infer<typeof ListCalendarEventsSchema>) => {
const params = ListCalendarEventsSchema.parse(args);
return calendarService.listEvents(params);
},
updateCalendarEvent: async (args: z.infer<typeof UpdateCalendarEventSchema>) => {
const params = UpdateCalendarEventSchema.parse(args);
return calendarService.updateEvent(params);
},
deleteCalendarEvent: async (args: z.infer<typeof DeleteCalendarEventSchema>) => {
const params = DeleteCalendarEventSchema.parse(args);
return calendarService.deleteEvent(params.calendarId, params.eventId, params.sendUpdates);
},
quickAddEvent: async (args: z.infer<typeof QuickAddEventSchema>) => {
const params = QuickAddEventSchema.parse(args);
return calendarService.quickAdd(params.calendarId, params.text, params.sendUpdates);
},
moveCalendarEvent: async (args: z.infer<typeof MoveCalendarEventSchema>) => {
const params = MoveCalendarEventSchema.parse(args);
return calendarService.moveEvent(
params.eventId,
params.sourceCalendarId,
params.destinationCalendarId,
params.sendUpdates
);
},
getEventInstances: async (args: z.infer<typeof GetEventInstancesSchema>) => {
const params = GetEventInstancesSchema.parse(args);
return calendarService.getEventInstances(
params.calendarId,
params.eventId,
params.timeMin,
params.timeMax,
params.maxResults
);
},
// Calendars
listCalendars: async (args: z.infer<typeof ListCalendarsSchema>) => {
const params = ListCalendarsSchema.parse(args);
return calendarService.listCalendars(params.minAccessRole);
},
getCalendar: async (args: z.infer<typeof GetCalendarSchema>) => {
const params = GetCalendarSchema.parse(args);
return calendarService.getCalendar(params.calendarId);
},
createCalendar: async (args: z.infer<typeof CreateCalendarSchema>) => {
const params = CreateCalendarSchema.parse(args);
return calendarService.createCalendar(
params.summary,
params.description,
params.timeZone,
params.location
);
},
updateCalendar: async (args: z.infer<typeof UpdateCalendarSchema>) => {
const params = UpdateCalendarSchema.parse(args);
const { calendarId, ...updates } = params;
return calendarService.updateCalendar(calendarId, updates);
},
deleteCalendar: async (args: z.infer<typeof DeleteCalendarSchema>) => {
const params = DeleteCalendarSchema.parse(args);
return calendarService.deleteCalendar(params.calendarId);
},
// CalendarList
addCalendarToList: async (args: z.infer<typeof AddCalendarToListSchema>) => {
const params = AddCalendarToListSchema.parse(args);
const { calendarId, ...options } = params;
return calendarService.addCalendarToList(calendarId, options);
},
updateCalendarInList: async (args: z.infer<typeof UpdateCalendarInListSchema>) => {
const params = UpdateCalendarInListSchema.parse(args);
const { calendarId, ...updates } = params;
return calendarService.updateCalendarInList(calendarId, updates);
},
removeCalendarFromList: async (args: z.infer<typeof RemoveCalendarFromListSchema>) => {
const params = RemoveCalendarFromListSchema.parse(args);
return calendarService.removeCalendarFromList(params.calendarId);
},
// ACL
shareCalendar: async (args: z.infer<typeof ShareCalendarSchema>) => {
const params = ShareCalendarSchema.parse(args);
return calendarService.shareCalendar(
params.calendarId,
{ type: params.scopeType, value: params.scopeValue },
params.role,
params.sendNotifications
);
},
getCalendarPermissions: async (args: z.infer<typeof GetCalendarPermissionsSchema>) => {
const params = GetCalendarPermissionsSchema.parse(args);
return calendarService.getCalendarPermissions(params.calendarId);
},
updateCalendarPermission: async (args: z.infer<typeof UpdateCalendarPermissionSchema>) => {
const params = UpdateCalendarPermissionSchema.parse(args);
return calendarService.updateCalendarPermission(
params.calendarId,
params.ruleId,
params.role,
params.sendNotifications
);
},
removeCalendarPermission: async (args: z.infer<typeof RemoveCalendarPermissionSchema>) => {
const params = RemoveCalendarPermissionSchema.parse(args);
return calendarService.removeCalendarPermission(params.calendarId, params.ruleId);
},
// Freebusy
checkAvailability: async (args: z.infer<typeof CheckAvailabilitySchema>) => {
const params = CheckAvailabilitySchema.parse(args);
return calendarService.checkAvailability(
params.timeMin,
params.timeMax,
params.calendars,
params.timeZone
);
},
// Colors
getCalendarColors: async () => {
return calendarService.getColors();
},
// Settings
getCalendarSettings: async (args: z.infer<typeof GetCalendarSettingsSchema>) => {
const params = GetCalendarSettingsSchema.parse(args);
return calendarService.getSettings(params.settingId);
},
};
}