import { z } from "zod";
import { GraphClient } from "../graph-client.js";
export const updateEventSchema = z.object({
eventId: z.string().describe("The ID of the event to update"),
calendarId: z.string().optional().describe("Calendar ID. If omitted, uses the default calendar."),
subject: z.string().optional().describe("New event subject/title"),
body: z.string().optional().describe("New event body content (HTML supported)"),
startDateTime: z.string().optional().describe("New start date/time in ISO 8601 format"),
startTimeZone: z.string().optional().describe("Time zone for start time"),
endDateTime: z.string().optional().describe("New end date/time in ISO 8601 format"),
endTimeZone: z.string().optional().describe("Time zone for end time"),
location: z.string().optional().describe("New event location display name"),
attendees: z
.array(
z.object({
email: z.string().describe("Attendee email address"),
name: z.string().optional().describe("Attendee display name"),
type: z
.enum(["required", "optional", "resource"])
.optional()
.default("required")
.describe("Attendee type"),
})
)
.optional()
.describe("Updated list of attendees (replaces existing)"),
isAllDay: z.boolean().optional().describe("Whether this is an all-day event"),
isOnlineMeeting: z.boolean().optional().describe("Whether to enable online meeting (Teams)"),
showAs: z
.enum(["free", "tentative", "busy", "oof", "workingElsewhere", "unknown"])
.optional()
.describe("How to show the time on the calendar"),
importance: z.enum(["low", "normal", "high"]).optional().describe("Event importance level"),
sensitivity: z
.enum(["normal", "personal", "private", "confidential"])
.optional()
.describe("Event sensitivity level"),
categories: z.array(z.string()).optional().describe("Event categories/labels"),
reminderMinutesBeforeStart: z.number().optional().describe("Reminder in minutes before start"),
});
export const updateEventTool = {
name: "update-event",
description:
"Update an existing calendar event. Only the provided fields will be modified; other fields remain unchanged.",
inputSchema: {
type: "object" as const,
properties: {
eventId: { type: "string", description: "The ID of the event to update" },
calendarId: {
type: "string",
description: "Calendar ID. If omitted, uses the default calendar.",
},
subject: { type: "string", description: "New event subject/title" },
body: { type: "string", description: "New event body content (HTML supported)" },
startDateTime: {
type: "string",
description: "New start date/time in ISO 8601 format",
},
startTimeZone: { type: "string", description: "Time zone for start time" },
endDateTime: {
type: "string",
description: "New end date/time in ISO 8601 format",
},
endTimeZone: { type: "string", description: "Time zone for end time" },
location: { type: "string", description: "New event location display name" },
attendees: {
type: "array",
description: "Updated list of attendees (replaces existing)",
items: {
type: "object",
properties: {
email: { type: "string", description: "Attendee email address" },
name: { type: "string", description: "Attendee display name" },
type: {
type: "string",
enum: ["required", "optional", "resource"],
description: "Attendee type",
},
},
required: ["email"],
},
},
isAllDay: { type: "boolean", description: "Whether this is an all-day event" },
isOnlineMeeting: {
type: "boolean",
description: "Whether to enable online meeting (Teams)",
},
showAs: {
type: "string",
enum: ["free", "tentative", "busy", "oof", "workingElsewhere", "unknown"],
description: "How to show the time on the calendar",
},
importance: {
type: "string",
enum: ["low", "normal", "high"],
description: "Event importance level",
},
sensitivity: {
type: "string",
enum: ["normal", "personal", "private", "confidential"],
description: "Event sensitivity level",
},
categories: {
type: "array",
items: { type: "string" },
description: "Event categories/labels",
},
reminderMinutesBeforeStart: {
type: "number",
description: "Reminder in minutes before start",
},
},
required: ["eventId"],
},
};
export async function handleUpdateEvent(
graph: GraphClient,
args: z.infer<typeof updateEventSchema>
): Promise<string> {
const basePath = args.calendarId
? `/me/calendars/${args.calendarId}/events/${args.eventId}`
: `/me/events/${args.eventId}`;
const eventBody: Record<string, unknown> = {};
if (args.subject !== undefined) {
eventBody.subject = args.subject;
}
if (args.body !== undefined) {
eventBody.body = {
contentType: "HTML",
content: args.body,
};
}
if (args.startDateTime !== undefined) {
eventBody.start = {
dateTime: args.startDateTime,
timeZone: args.startTimeZone || "UTC",
};
}
if (args.endDateTime !== undefined) {
eventBody.end = {
dateTime: args.endDateTime,
timeZone: args.endTimeZone || "UTC",
};
}
if (args.location !== undefined) {
eventBody.location = {
displayName: args.location,
};
}
if (args.attendees !== undefined) {
eventBody.attendees = args.attendees.map((a) => ({
emailAddress: {
address: a.email,
name: a.name || a.email,
},
type: a.type || "required",
}));
}
if (args.isAllDay !== undefined) {
eventBody.isAllDay = args.isAllDay;
}
if (args.isOnlineMeeting !== undefined) {
eventBody.isOnlineMeeting = args.isOnlineMeeting;
if (args.isOnlineMeeting) {
eventBody.onlineMeetingProvider = "teamsForBusiness";
}
}
if (args.showAs !== undefined) {
eventBody.showAs = args.showAs;
}
if (args.importance !== undefined) {
eventBody.importance = args.importance;
}
if (args.sensitivity !== undefined) {
eventBody.sensitivity = args.sensitivity;
}
if (args.categories !== undefined) {
eventBody.categories = args.categories;
}
if (args.reminderMinutesBeforeStart !== undefined) {
eventBody.isReminderOn = true;
eventBody.reminderMinutesBeforeStart = args.reminderMinutesBeforeStart;
}
const event = await graph.patch<Record<string, unknown>>(basePath, eventBody);
return JSON.stringify(event, null, 2);
}