Calendar Week View
calendar_week_viewDisplay a weekly calendar with events for any 7-day period, starting from a specified date.
Instructions
Display an interactive calendar week view showing events for a 7-day period.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| startDate | No | Start date (YYYY-MM-DD). Defaults to current week's Monday. |
Implementation Reference
- src/apps/tools.ts:221-236 (handler)The async handler function for calendar_week_view. It computes the week start via getWeekMonday, queries Apple Calendar events using listEventsScript, and returns a JSON response with weekStart and events array.
async ({ startDate }) => { const weekStart = getWeekMonday(startDate); const weekEnd = new Date(weekStart); weekEnd.setDate(weekEnd.getDate() + 7); const endStr = weekEnd.toISOString().slice(0, 10); const raw = await runJxa(listEventsScript(weekStart, endStr, 50, 0)); const parsed = typeof raw === "string" ? JSON.parse(raw) : raw; return { content: [ { type: "text" as const, text: JSON.stringify({ weekStart, events: parsed.events ?? [] }), }, ], }; }, - src/apps/tools.ts:205-220 (schema)The tool registration with input schema and metadata. The schema accepts an optional startDate string (YYYY-MM-DD). Annotations mark it as read-only, idempotent, non-destructive. Metadata links to a UI resource 'ui://airmcp/calendar-week'.
registerAppTool( s, "calendar_week_view", { title: "Calendar Week View", description: "Display an interactive calendar week view showing events for a 7-day period.", inputSchema: { startDate: z .string() .max(64) .optional() .describe("Start date (YYYY-MM-DD). Defaults to current week's Monday."), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }, _meta: { ui: { resourceUri: "ui://airmcp/calendar-week" } }, }, - src/apps/tools.ts:203-237 (registration)The tool is registered inside the 'registerApps' function under the 'if (opts.calendar)' block. It uses registerAppTool from @modelcontextprotocol/ext-apps/server to bind the name 'calendar_week_view' to its schema and handler.
if (opts.calendar) { // Calendar Week View registerAppTool( s, "calendar_week_view", { title: "Calendar Week View", description: "Display an interactive calendar week view showing events for a 7-day period.", inputSchema: { startDate: z .string() .max(64) .optional() .describe("Start date (YYYY-MM-DD). Defaults to current week's Monday."), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }, _meta: { ui: { resourceUri: "ui://airmcp/calendar-week" } }, }, async ({ startDate }) => { const weekStart = getWeekMonday(startDate); const weekEnd = new Date(weekStart); weekEnd.setDate(weekEnd.getDate() + 7); const endStr = weekEnd.toISOString().slice(0, 10); const raw = await runJxa(listEventsScript(weekStart, endStr, 50, 0)); const parsed = typeof raw === "string" ? JSON.parse(raw) : raw; return { content: [ { type: "text" as const, text: JSON.stringify({ weekStart, events: parsed.events ?? [] }), }, ], }; }, ); - src/apps/tools.ts:186-196 (helper)Helper function getWeekMonday computes the Monday of the week for a given date string (or current date). It handles Sunday edge-case (Sunday -> Monday of previous week) and returns YYYY-MM-DD using local date parts to avoid UTC timezone shifts.
function getWeekMonday(dateStr?: string): string { const d = dateStr ? new Date(dateStr + "T00:00:00") : new Date(); const day = d.getDay(); const diff = d.getDate() - day + (day === 0 ? -6 : 1); d.setDate(diff); // Use local date parts — toISOString() returns UTC which shifts dates in UTC+ timezones const yyyy = d.getFullYear(); const mm = String(d.getMonth() + 1).padStart(2, "0"); const dd = String(d.getDate()).padStart(2, "0"); return `${yyyy}-${mm}-${dd}`; } - src/calendar/scripts.ts:25-95 (helper)The listEventsScript function generates JXA (JavaScript for Automation) code to query Apple Calendar events within a date range. It's called by the handler with weekStart, endStr, limit=50, offset=0, and no specific calendar filter. Returns a script string that when executed returns JSON with events array.
export function listEventsScript( startDate: string, endDate: string, limit: number, offset: number, calendar?: string, ): string { if (calendar) { return ` const Calendar = Application('Calendar'); const cals = Calendar.calendars.whose({name: '${esc(calendar)}'})(); if (cals.length === 0) throw new Error('Calendar not found: ${esc(calendar)}'); const cal = cals[0]; const start = new Date('${esc(startDate)}'); const end = new Date('${esc(endDate)}'); const events = cal.events.whose({ _and: [{startDate: {_greaterThanEquals: start}}, {startDate: {_lessThanEquals: end}}] })(); const total = events.length; const s = Math.min(${offset}, total); const e = Math.min(s + ${limit}, total); const result = []; for (let i = s; i < e; i++) { const ev = events[i]; result.push({ id: ev.uid(), summary: ev.summary(), startDate: ev.startDate().toISOString(), endDate: ev.endDate().toISOString(), allDay: ev.alldayEvent(), calendar: '${esc(calendar)}' }); } JSON.stringify({total: total, offset: s, returned: result.length, events: result}); `; } return ` const Calendar = Application('Calendar'); const cals = Calendar.calendars(); const start = new Date('${esc(startDate)}'); const end = new Date('${esc(endDate)}'); const all = []; for (const cal of cals) { const filtered = cal.events.whose({ _and: [{startDate: {_greaterThanEquals: start}}, {startDate: {_lessThanEquals: end}}] }); const count = filtered.length; if (count === 0) continue; const eUids = filtered.uid(); const eSummaries = filtered.summary(); const eStarts = filtered.startDate(); const eEnds = filtered.endDate(); const eAllDay = filtered.alldayEvent(); const calName = cal.name(); const safe = Math.min(count, eUids.length, eSummaries.length, eStarts.length, eEnds.length, eAllDay.length); for (let i = 0; i < safe; i++) { if (eUids[i] == null || eStarts[i] == null || eEnds[i] == null) continue; all.push({ id: eUids[i], summary: eSummaries[i] || '', startDate: eStarts[i].toISOString(), endDate: eEnds[i].toISOString(), allDay: eAllDay[i] ?? false, calendar: calName }); } } all.sort((a, b) => new Date(a.startDate) - new Date(b.startDate)); const total = all.length; const s = Math.min(${offset}, total); const e = Math.min(s + ${limit}, total); JSON.stringify({total: total, offset: s, returned: e - s, events: all.slice(s, e)}); `; }