update-event
Modify existing calendar events by updating subject, body, time, location, or attendees. Use event ID to ensure accurate changes to scheduled meetings in Outlook.
Instructions
Update an existing calendar event
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| attendees | No | List of attendees to add or update for the event | |
| body | No | New content/body for the calendar event | |
| end | No | New end time in ISO format (e.g. 2025-04-20T13:00:00) | |
| eventId | Yes | ID of the event to update | |
| location | No | New location for the event | |
| start | No | New start time in ISO format (e.g. 2025-04-20T12:00:00) | |
| subject | No | New subject for the calendar event | |
| timeZone | No | New time zone for the event |
Implementation Reference
- src/tools/event-update.ts:33-166 (handler)The main handler function for the 'update-event' tool, which updates calendar event details including subject, body, dates, location, and attendees using the Microsoft Graph API.async ({ eventId, subject, body, start, end, timeZone, location, attendees }) => { const { graph, userEmail, authError } = await getGraphConfig(); if (authError) { return { content: [{ type: "text", text: `🔐 Authentication Required\n\n${authError}\n\nPlease complete the authentication and try again.` }] }; } // Create the event update object with only properties that should be updated const eventUpdates: Partial<Event> = {}; if (subject) { eventUpdates.subject = subject; } if (body) { eventUpdates.body = { contentType: "html", content: `${body}<br/>Updated around ${format(new Date(), 'dd-MMM-yyyy HH:mm')}` }; } if (start) { eventUpdates.start = { dateTime: start, timeZone: timeZone || undefined }; } if (end) { eventUpdates.end = { dateTime: end, timeZone: timeZone || undefined }; } if (location) { eventUpdates.location = { displayName: location }; } // Handle attendees if provided if (attendees && attendees.length > 0) { // First get the current event to merge with existing attendees const currentEvent = await graph.getEvent(eventId, userEmail); if (!currentEvent || !currentEvent.attendees) { // If no current attendees, just use the new ones const formattedAttendees: Attendee[] = attendees.map((attendee: any) => ({ emailAddress: { address: attendee.email, name: attendee.name || attendee.email }, type: attendee.type || "required" })); eventUpdates.attendees = formattedAttendees; } else { // Merge with existing attendees, avoiding duplicates const existingAttendees = currentEvent.attendees || []; const existingEmails = new Set( existingAttendees .filter((a: Attendee) => a.emailAddress?.address) .map((a: Attendee) => a.emailAddress!.address!.toLowerCase()) ); // Format new attendees const newAttendees: Attendee[] = attendees .filter((a: any) => !existingEmails.has(a.email.toLowerCase())) .map((attendee: any) => ({ emailAddress: { address: attendee.email, name: attendee.name || attendee.email }, type: attendee.type || "required" })); // Combine existing and new attendees eventUpdates.attendees = [...existingAttendees, ...newAttendees]; } } // First get the current event to show what's being updated const currentEvent = await graph.getEvent(eventId, userEmail); if (!currentEvent) { return { content: [ { type: "text", text: "Could not find the event to update. Please check the event ID.", }, ], }; } // Call the Graph API to update the event const result = await graph.updateEvent(eventId, eventUpdates, userEmail); if (!result) { return { content: [ { type: "text", text: "Failed to update calendar event. Check the logs for details.", }, ], }; } // Format the result for response const eventUrl = result.webLink || "No event URL available"; const successMessage = ` Calendar event updated successfully! Event ID: ${eventId} ${subject ? `New Subject: ${subject}\nPrevious: ${currentEvent.subject || "No subject"}` : ''} ${start ? `New Start: ${start}\nPrevious: ${currentEvent.start?.dateTime || "No start time"}` : ''} ${end ? `New End: ${end}\nPrevious: ${currentEvent.end?.dateTime || "No end time"}` : ''} ${location ? `New Location: ${location}\nPrevious: ${currentEvent.location?.displayName || "No location"}` : ''} Event URL: ${eventUrl} `; return { content: [ { type: "text", text: successMessage, }, ], }; }
- src/tools/event-update.ts:17-32 (schema)Zod schema defining the input parameters for the 'update-event' tool.{ eventId: z.string().describe("ID of the event to update"), subject: z.string().optional().describe("New subject for the calendar event"), body: z.string().optional().describe("New content/body for the calendar event"), start: z.string().optional().describe("New start time in ISO format (e.g. 2025-04-20T12:00:00)"), end: z.string().optional().describe("New end time in ISO format (e.g. 2025-04-20T13:00:00)"), timeZone: z.string().optional().describe("New time zone for the event"), location: z.string().optional().describe("New location for the event"), attendees: z.array( z.object({ email: z.string().describe("Email address of the attendee"), name: z.string().optional().describe("Name of the attendee"), type: z.enum(["required", "optional"]).optional().describe("Type of attendee: required or optional") }) ).optional().describe("List of attendees to add or update for the event"), },
- src/tools/event-update.ts:13-167 (registration)The registerTool call that registers the 'update-event' tool with the MCP server, including name, description, schema, and handler.registerTool( server, "update-event", "Update an existing calendar event", { eventId: z.string().describe("ID of the event to update"), subject: z.string().optional().describe("New subject for the calendar event"), body: z.string().optional().describe("New content/body for the calendar event"), start: z.string().optional().describe("New start time in ISO format (e.g. 2025-04-20T12:00:00)"), end: z.string().optional().describe("New end time in ISO format (e.g. 2025-04-20T13:00:00)"), timeZone: z.string().optional().describe("New time zone for the event"), location: z.string().optional().describe("New location for the event"), attendees: z.array( z.object({ email: z.string().describe("Email address of the attendee"), name: z.string().optional().describe("Name of the attendee"), type: z.enum(["required", "optional"]).optional().describe("Type of attendee: required or optional") }) ).optional().describe("List of attendees to add or update for the event"), }, async ({ eventId, subject, body, start, end, timeZone, location, attendees }) => { const { graph, userEmail, authError } = await getGraphConfig(); if (authError) { return { content: [{ type: "text", text: `🔐 Authentication Required\n\n${authError}\n\nPlease complete the authentication and try again.` }] }; } // Create the event update object with only properties that should be updated const eventUpdates: Partial<Event> = {}; if (subject) { eventUpdates.subject = subject; } if (body) { eventUpdates.body = { contentType: "html", content: `${body}<br/>Updated around ${format(new Date(), 'dd-MMM-yyyy HH:mm')}` }; } if (start) { eventUpdates.start = { dateTime: start, timeZone: timeZone || undefined }; } if (end) { eventUpdates.end = { dateTime: end, timeZone: timeZone || undefined }; } if (location) { eventUpdates.location = { displayName: location }; } // Handle attendees if provided if (attendees && attendees.length > 0) { // First get the current event to merge with existing attendees const currentEvent = await graph.getEvent(eventId, userEmail); if (!currentEvent || !currentEvent.attendees) { // If no current attendees, just use the new ones const formattedAttendees: Attendee[] = attendees.map((attendee: any) => ({ emailAddress: { address: attendee.email, name: attendee.name || attendee.email }, type: attendee.type || "required" })); eventUpdates.attendees = formattedAttendees; } else { // Merge with existing attendees, avoiding duplicates const existingAttendees = currentEvent.attendees || []; const existingEmails = new Set( existingAttendees .filter((a: Attendee) => a.emailAddress?.address) .map((a: Attendee) => a.emailAddress!.address!.toLowerCase()) ); // Format new attendees const newAttendees: Attendee[] = attendees .filter((a: any) => !existingEmails.has(a.email.toLowerCase())) .map((attendee: any) => ({ emailAddress: { address: attendee.email, name: attendee.name || attendee.email }, type: attendee.type || "required" })); // Combine existing and new attendees eventUpdates.attendees = [...existingAttendees, ...newAttendees]; } } // First get the current event to show what's being updated const currentEvent = await graph.getEvent(eventId, userEmail); if (!currentEvent) { return { content: [ { type: "text", text: "Could not find the event to update. Please check the event ID.", }, ], }; } // Call the Graph API to update the event const result = await graph.updateEvent(eventId, eventUpdates, userEmail); if (!result) { return { content: [ { type: "text", text: "Failed to update calendar event. Check the logs for details.", }, ], }; } // Format the result for response const eventUrl = result.webLink || "No event URL available"; const successMessage = ` Calendar event updated successfully! Event ID: ${eventId} ${subject ? `New Subject: ${subject}\nPrevious: ${currentEvent.subject || "No subject"}` : ''} ${start ? `New Start: ${start}\nPrevious: ${currentEvent.start?.dateTime || "No start time"}` : ''} ${end ? `New End: ${end}\nPrevious: ${currentEvent.end?.dateTime || "No end time"}` : ''} ${location ? `New Location: ${location}\nPrevious: ${currentEvent.location?.displayName || "No location"}` : ''} Event URL: ${eventUrl} `; return { content: [ { type: "text", text: successMessage, }, ], }; } );
- src/index.ts:35-35 (registration)Top-level registration call in the main server file that invokes registerEventUpdateTools to add the 'update-event' tool to the MCP server.registerEventUpdateTools(server);