list_calendar_events
Retrieve events from Fastmail calendars with optional calendar ID, date range (ISO 8601), and limit filters. Default returns up to 50 events.
Instructions
List events from a calendar
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| calendarId | No | ID of the calendar (optional, defaults to all calendars) | |
| startDate | No | Filter events starting from this date (ISO 8601, e.g. 2026-03-23T00:00:00Z) | |
| endDate | No | Filter events ending before this date (ISO 8601, e.g. 2026-03-30T00:00:00Z) | |
| limit | No | Maximum number of events to return (default: 50) |
Implementation Reference
- src/index.ts:491-516 (registration)Tool registration + schema definition for 'list_calendar_events' in the ListTools handler. Defines name, description, and inputSchema with calendarId, startDate, endDate, limit.
{ name: 'list_calendar_events', description: 'List events from a calendar', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'ID of the calendar (optional, defaults to all calendars)', }, startDate: { type: 'string', description: 'Filter events starting from this date (ISO 8601, e.g. 2026-03-23T00:00:00Z)', }, endDate: { type: 'string', description: 'Filter events ending before this date (ISO 8601, e.g. 2026-03-30T00:00:00Z)', }, limit: { type: 'number', description: 'Maximum number of events to return (default: 50)', default: 50, }, }, }, }, - src/index.ts:1318-1332 (handler)Handler for 'list_calendar_events' in the CallTool switch. Extracts args (calendarId, limit, startDate, endDate), tries JMAP ContactsCalendarClient first, falls back to CalDAVCalendarClient.
case 'list_calendar_events': { const { calendarId, limit = 50, startDate, endDate } = args as any; try { const contactsClient = initializeContactsCalendarClient(); const events = await contactsClient.getCalendarEvents(calendarId, limit); return { content: [{ type: 'text', text: JSON.stringify(events, null, 2) }] }; } catch { const davClient = initializeCalDAVClient(); if (!davClient) { throw new McpError(ErrorCode.InvalidRequest, 'JMAP calendars not available and CalDAV not configured. Set FASTMAIL_CALDAV_USERNAME and FASTMAIL_CALDAV_PASSWORD to use CalDAV.'); } const events = await davClient.getCalendarEvents(calendarId, limit, startDate, endDate); return { content: [{ type: 'text', text: JSON.stringify(events, null, 2) }] }; } } - src/contacts-calendar.ts:150-184 (handler)JMAP implementation: ContactsCalendarClient.getCalendarEvents() - calls CalendarEvent/query then CalendarEvent/get.
async getCalendarEvents(calendarId?: string, limit: number = 50): Promise<any[]> { // Check permissions first const hasPermission = await this.checkCalendarsPermission(); if (!hasPermission) { throw new Error('Calendar access not available. This account may not have JMAP calendar permissions enabled. Please check your Fastmail account settings or contact support to enable calendar API access.'); } const session = await this.getSession(); const filter = calendarId ? { inCalendar: calendarId } : {}; const request: JmapRequest = { using: ['urn:ietf:params:jmap:core', 'urn:ietf:params:jmap:calendars'], methodCalls: [ ['CalendarEvent/query', { accountId: session.accountId, filter, sort: [{ property: 'start', isAscending: true }], limit }, 'query'], ['CalendarEvent/get', { accountId: session.accountId, '#ids': { resultOf: 'query', name: 'CalendarEvent/query', path: '/ids' }, properties: ['id', 'title', 'description', 'start', 'end', 'location', 'participants'] }, 'events'] ] }; try { const response = await this.makeRequest(request); return this.getListResult(response, 1); } catch (error) { throw new Error(`Calendar events access not supported: ${error instanceof Error ? error.message : String(error)}. Try checking account permissions or enabling calendar API access in Fastmail settings.`); } } - src/caldav-client.ts:226-263 (handler)CalDAV fallback implementation: CalDAVCalendarClient.getCalendarEvents() - fetches calendar objects via DAVClient, parses iCalendar VEVENT data.
async getCalendarEvents(calendarId?: string, limit: number = 50, startDate?: string, endDate?: string): Promise<CalendarEvent[]> { const client = await this.getClient(); if (!this.calendars) { this.calendars = await client.fetchCalendars(); } let targetCalendars = this.calendars.filter( c => c.displayName !== 'DEFAULT_TASK_CALENDAR_NAME' ); if (calendarId) { targetCalendars = targetCalendars.filter( c => c.url === calendarId || c.displayName === calendarId ); } const fetchOptions: any = {}; if (startDate || endDate) { fetchOptions.timeRange = { start: startDate || '1970-01-01T00:00:00Z', end: endDate || '2099-12-31T23:59:59Z', }; } const allEvents: CalendarEvent[] = []; for (const cal of targetCalendars) { const objects = await client.fetchCalendarObjects({ calendar: cal, ...fetchOptions }); for (const obj of objects) { allEvents.push(parseCalendarObject(obj)); } if (allEvents.length >= limit) break; } // Sort by start date ascending allEvents.sort((a, b) => (a.start || '').localeCompare(b.start || '')); return allEvents.slice(0, limit); }