Delete Event
delete_eventDelete a calendar event by providing its unique identifier. The event is removed from your calendar.
Instructions
Delete a calendar event by ID.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Event UID |
Implementation Reference
- src/calendar/tools.ts:314-340 (handler)The main handler for the delete_event tool. Registers the tool with the MCP server, defines input schema (id), and runs automation via Swift (delete-event command) or JXA (deleteEventScript). Returns a DeleteResult with deleted: true and the event summary.
server.registerTool( "delete_event", { title: "Delete Event", description: "Delete a calendar event by ID. This action is permanent.", inputSchema: { id: z.string().max(500).describe("Event UID"), }, annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false, }, }, async ({ id }) => { try { const result = await runAutomation<DeleteResult>({ swift: { command: "delete-event", input: { id } }, jxa: () => deleteEventScript(id), }); return ok(result); } catch (e) { return errJxaFor("delete event", e); } }, ); - src/calendar/scripts.ts:198-215 (helper)The JXA (JavaScript for Automation) helper script for delete_event. Generates a JXA script string that iterates all calendars, finds the event by UID, calls Calendar.delete() to remove it, and returns {deleted: true, summary}. Throws if event not found.
export function deleteEventScript(id: string): string { return ` const Calendar = Application('Calendar'); const cals = Calendar.calendars(); let result = null; for (const cal of cals) { const events = cal.events.whose({uid: '${esc(id)}'})(); if (events.length > 0) { const summary = events[0].summary(); Calendar.delete(events[0]); result = {deleted: true, summary: summary}; break; } } if (!result) throw new Error('Event not found: ${esc(id)}'); JSON.stringify(result); `; } - src/calendar/tools.ts:61-64 (schema)TypeScript interface DeleteResult defining the return type: { deleted: boolean; summary: string } for the delete_event response.
interface DeleteResult { deleted: boolean; summary: string; } - src/calendar/tools.ts:92-530 (registration)The registerCalendarTools function that is the entry point for registering all calendar tools, including delete_event, with the MCP server.
export function registerCalendarTools(server: McpServer, _config: AirMcpConfig): void { server.registerTool( "list_calendars", { title: "List Calendars", description: "List all calendars with name, color, and writable status.", inputSchema: {}, outputSchema: { calendars: z.array( z.object({ id: z.string(), name: z.string(), color: z.string().nullable(), writable: z.boolean(), }), ), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async () => { try { const result = await runAutomation<CalendarItem[]>({ swift: { command: "list-calendars" }, jxa: () => listCalendarsScript(), }); return okStructured({ calendars: result }); } catch (e) { return errJxaFor("list calendars", e); } }, ); server.registerTool( "list_events", { title: "List Events", description: "List events within a date range. Requires startDate and endDate (ISO 8601). Optionally filter by calendar name. Supports limit/offset pagination.", inputSchema: { startDate: z.string().max(64).describe("Start of range (ISO 8601, e.g. '2026-03-01T00:00:00Z')"), endDate: z.string().max(64).describe("End of range (ISO 8601, e.g. '2026-03-31T23:59:59Z')"), calendar: z.string().max(500).optional().describe("Filter by calendar name"), limit: z .number() .int() .min(1) .max(1000) .optional() .default(100) .describe("Max events to return (default: 100)"), offset: z.number().int().min(0).optional().default(0).describe("Number of events to skip (default: 0)"), }, outputSchema: { total: z.number(), offset: z.number(), returned: z.number(), events: z.array( z.object({ id: z.string(), summary: z.string(), startDate: z.string(), endDate: z.string(), allDay: z.boolean(), calendar: z.string(), }), ), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async ({ startDate, endDate, calendar, limit, offset }) => { try { const result = await runAutomation<EventListResult>({ swift: { command: "list-events", input: { startDate, endDate, calendar, limit, offset }, }, jxa: () => listEventsScript(startDate, endDate, limit, offset, calendar), }); return okUntrustedStructured(result); } catch (e) { return errJxaFor("list events", e); } }, ); server.registerTool( "read_event", { title: "Read Event", description: "Read full details of a calendar event by ID. Includes attendees (read-only), location, description, and recurrence info.", inputSchema: { id: z.string().max(500).describe("Event UID"), }, outputSchema: { id: z.string(), summary: z.string(), description: z.string().nullable(), location: z.string().nullable(), startDate: z.string(), endDate: z.string(), allDay: z.boolean(), recurrence: z.string().nullable(), url: z.string().nullable(), calendar: z.string(), attendees: z.array( z.object({ name: z.string().nullable(), email: z.string().nullable(), status: z.string().nullable(), }), ), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async ({ id }) => { try { const result = await runAutomation<EventDetail>({ swift: { command: "read-event", input: { id } }, jxa: () => readEventScript(id), }); return okUntrustedStructured(result); } catch (e) { return errJxaFor("read event", e); } }, ); server.registerTool( "create_event", { title: "Create Event", description: "Create a new calendar event. Recurring events cannot be created via automation. Attendees cannot be added programmatically.", inputSchema: { summary: z.string().min(1).max(500).describe("Event title"), startDate: z.string().max(64).describe("Start date/time (ISO 8601, e.g. '2026-03-15T09:00:00Z')"), endDate: z.string().max(64).describe("End date/time (ISO 8601, e.g. '2026-03-15T10:00:00Z')"), location: z.string().max(5000).optional().describe("Event location"), description: z.string().max(5000).optional().describe("Event notes/description"), calendar: z.string().max(500).optional().describe("Target calendar name. Defaults to first writable calendar."), allDay: z.boolean().optional().describe("Set as all-day event"), }, annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, async ({ summary, startDate, endDate, location, description, calendar, allDay }) => { try { const result = await runAutomation<MutationResult>({ swift: { command: "create-event", input: { title: summary, startDate, endDate, location, notes: description, calendar, allDay }, }, jxa: () => createEventScript(summary, startDate, endDate, { location, description, calendar, allDay }), }); return ok(result); } catch (e) { return errJxaFor("create event", e); } }, ); server.registerTool( "update_event", { title: "Update Event", description: "Update event properties. Only specified fields are changed. Attendees and recurrence rules cannot be modified via automation.", inputSchema: { id: z.string().max(500).describe("Event UID"), summary: z.string().max(500).optional().describe("New title"), startDate: z .string() .max(64) .optional() .describe("New start date/time (ISO 8601, e.g. '2026-03-15T09:00:00Z')"), endDate: z.string().max(64).optional().describe("New end date/time (ISO 8601, e.g. '2026-03-15T10:00:00Z')"), location: z.string().max(5000).optional().describe("New location"), description: z.string().max(5000).optional().describe("New notes/description"), }, annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false, }, }, async ({ id, summary, startDate, endDate, location, description }) => { try { const result = await runAutomation<MutationResult>({ swift: { command: "update-event", input: { id, title: summary, startDate, endDate, location, notes: description }, }, jxa: () => updateEventScript(id, { summary, startDate, endDate, location, description }), }); return ok(result); } catch (e) { return errJxaFor("update event", e); } }, ); server.registerTool( "delete_event", { title: "Delete Event", description: "Delete a calendar event by ID. This action is permanent.", inputSchema: { id: z.string().max(500).describe("Event UID"), }, annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false, }, }, async ({ id }) => { try { const result = await runAutomation<DeleteResult>({ swift: { command: "delete-event", input: { id } }, jxa: () => deleteEventScript(id), }); return ok(result); } catch (e) { return errJxaFor("delete event", e); } }, ); server.registerTool( "search_events", { title: "Search Events", description: "Search events by keyword in title or description within a date range.", inputSchema: { query: z.string().max(500).describe("Search keyword"), startDate: z.string().max(64).describe("Start of range (ISO 8601, e.g. '2026-03-01T00:00:00Z')"), endDate: z.string().max(64).describe("End of range (ISO 8601, e.g. '2026-03-31T23:59:59Z')"), limit: z.number().int().min(1).max(500).optional().default(50).describe("Max results (default: 50)"), }, outputSchema: { total: z.number(), events: z.array( z.object({ id: z.string(), summary: z.string(), startDate: z.string(), endDate: z.string(), allDay: z.boolean(), calendar: z.string(), }), ), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async ({ query, startDate, endDate, limit }) => { try { const result = await runAutomation<SearchResult>({ swift: { command: "search-events", input: { query, startDate, endDate, limit }, }, jxa: () => searchEventsScript(query, startDate, endDate, limit), }); return okUntrustedStructured(result); } catch (e) { return errJxaFor("search events", e); } }, ); server.registerTool( "get_upcoming_events", { title: "Get Upcoming Events", description: "Get the next N upcoming events from now (searches up to 30 days ahead). A convenience wrapper that doesn't require date range parameters.", inputSchema: { limit: z.number().int().min(1).max(500).optional().default(10).describe("Max events to return (default: 10)"), }, outputSchema: { total: z.number(), returned: z.number(), events: z.array( z.object({ id: z.string(), summary: z.string(), startDate: z.string(), endDate: z.string(), allDay: z.boolean(), calendar: z.string(), location: z.string(), }), ), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async ({ limit }) => { try { const result = await runAutomation<UpcomingEventsResult>({ swift: { command: "get-upcoming-events", input: { limit } }, jxa: () => getUpcomingEventsScript(limit), }); return okUntrustedStructured(result); } catch (e) { return errJxaFor("get upcoming events", e); } }, ); server.registerTool( "today_events", { title: "Today's Events", description: "Get all calendar events for today.", inputSchema: {}, outputSchema: { total: z.number(), events: z.array( z.object({ id: z.string(), summary: z.string(), startDate: z.string(), endDate: z.string(), allDay: z.boolean(), calendar: z.string(), location: z.string(), }), ), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async () => { try { const result = await runAutomation<TodayEventsResult>({ swift: { command: "today-events" }, jxa: () => todayEventsScript(), }); return okUntrustedLinkedStructured("today_events", result); } catch (e) { return errJxaFor("get today's events", e); } }, ); server.registerTool( "create_recurring_event", { title: "Create Recurring Event", description: "Create a recurring calendar event via EventKit. Supports daily, weekly, monthly, and yearly recurrence with configurable intervals. Requires macOS 26+ Swift bridge.", inputSchema: { summary: z.string().min(1).max(500).describe("Event title"), startDate: z.string().max(64).describe("Start date/time (ISO 8601, e.g. '2026-03-15T09:00:00Z')"), endDate: z.string().max(64).describe("End date/time (ISO 8601, e.g. '2026-03-15T10:00:00Z')"), location: z.string().max(5000).optional().describe("Event location"), description: z.string().max(5000).optional().describe("Event notes/description"), calendar: z.string().max(500).optional().describe("Target calendar name. Defaults to the default calendar."), recurrence: z .object({ frequency: z.enum(["daily", "weekly", "monthly", "yearly"]).describe("Recurrence frequency"), interval: z.number().int().min(1).describe("Repeat every N frequency units (e.g. 2 = every 2 weeks)"), endDate: z .string() .max(64) .optional() .describe("Recurrence end date (ISO 8601, e.g. '2026-12-31T23:59:59Z')"), count: z.number().int().min(1).optional().describe("Number of occurrences (alternative to endDate)"), daysOfWeek: z .array(z.number().int().min(1).max(7)) .optional() .describe("Days of week for weekly recurrence (1=Sun, 2=Mon, ..., 7=Sat)"), }) .describe("Recurrence rule"), }, annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, async ({ summary, startDate, endDate, location, description, calendar, recurrence }) => { try { const result = await runSwift<RecurringEventResult>( "create-recurring-event", JSON.stringify({ title: summary, startDate, endDate, location, notes: description, calendar, recurrence, }), ); return ok(result); } catch (e) { return errJxaFor("create recurring event", e); } }, ); } - src/calendar/tools.ts:13-13 (registration)Import of deleteEventScript from scripts.ts, linking the tool handler to its JXA helper script.
deleteEventScript,