Skip to main content
Glama

Outlook Meetings Scheduler MCP Server

event-update.ts10.9 kB
import { z } from "zod"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { Event, Attendee } from "@microsoft/microsoft-graph-types"; import { format } from 'date-fns'; import { registerTool } from "../utils/tool-registration.js"; import { getGraphConfig } from "../utils/graph-config.js"; /** * Register event update tools with the MCP server */ export function registerEventUpdateTools(server: McpServer): void { // Register update event tool 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 } = getGraphConfig(); // 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, }, ], }; } ); // Register update event attendees tool registerTool( server, "update-event-attendees", "Add or remove attendees from a calendar event", { eventId: z.string().describe("ID of the event to update"), addAttendees: z.array( z.object({ email: z.string().describe("Email address of the attendee to add"), 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 to the event"), removeAttendees: z.array( z.string().describe("Email addresses of attendees to remove from the event") ).optional().describe("List of email addresses to remove from the event"), }, async ({ eventId, addAttendees, removeAttendees }) => { const { graph, userEmail } = getGraphConfig(); // First get the current event to get existing attendees 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.", }, ], }; } // Get current attendees or initialize empty array const currentAttendees = currentEvent.attendees || []; // Process attendee removals if any let updatedAttendees = [...currentAttendees]; let removedAttendeesList: string[] = []; if (removeAttendees && removeAttendees.length > 0) { // Create a set of lowercase email addresses to remove for case-insensitive matching const emailsToRemove = new Set(removeAttendees.map((email: string) => email.toLowerCase())); // Filter out attendees that should be removed updatedAttendees = currentAttendees.filter((attendee: Attendee) => { const email = attendee.emailAddress?.address?.toLowerCase() || ''; const shouldRemove = emailsToRemove.has(email); if (shouldRemove) { removedAttendeesList.push(attendee.emailAddress?.address || email); } return !shouldRemove; }); } // Process attendee additions if any let addedAttendeesList: string[] = []; if (addAttendees && addAttendees.length > 0) { // Get existing email addresses to avoid duplicates const existingEmails = new Set( updatedAttendees .filter((a: Attendee) => a.emailAddress?.address) .map((a: Attendee) => a.emailAddress!.address!.toLowerCase()) ); // Create new attendee objects for those that don't already exist const newAttendees: Attendee[] = addAttendees .filter((a: any) => !existingEmails.has(a.email.toLowerCase())) .map((attendee: any) => { addedAttendeesList.push(attendee.email); return { emailAddress: { address: attendee.email, name: attendee.name || attendee.email }, type: attendee.type || "required" }; }); // Add new attendees to the list updatedAttendees = [...updatedAttendees, ...newAttendees]; } // Only update if there are changes if ((addAttendees && addAttendees.length > 0) || (removeAttendees && removeAttendees.length > 0)) { // Update the event with only the attendees property const eventUpdates: Partial<Event> = { attendees: updatedAttendees }; // 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 event attendees. Check the logs for details.", }, ], }; } // Format the result for response const eventUrl = result.webLink || "No event URL available"; let successMessage = `Calendar event attendees updated successfully!\n\n`; successMessage += `Event: ${currentEvent.subject || "No subject"}\n`; if (addedAttendeesList.length > 0) { successMessage += `\nAdded attendees:\n${addedAttendeesList.join('\n')}\n`; } if (removedAttendeesList.length > 0) { successMessage += `\nRemoved attendees:\n${removedAttendeesList.join('\n')}\n`; } successMessage += `\nEvent URL: ${eventUrl}`; return { content: [ { type: "text", text: successMessage, }, ], }; } else { return { content: [ { type: "text", text: "No changes to attendees were specified.", }, ], }; } } ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/anoopt/outlook-meetings-scheduler-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server