UNPKG

outlook-mcp

Version:

Comprehensive MCP server for Claude to access Microsoft Outlook and Teams via Microsoft Graph API - including Email, Calendar, Contacts, Tasks, Teams, Chats, and Online Meetings

290 lines (244 loc) 7.34 kB
/** * Calendar management functionality */ const { callGraphAPI } = require('../utils/graph-api'); const { ensureAuthenticated } = require('../auth'); /** * List calendars handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleListCalendars(args) { try { // Ensure user is authenticated const accessToken = await ensureAuthenticated(); // Build the API path const apiPath = 'me/calendars'; // Build query parameters const queryParams = { '$select': 'id,name,color,isDefaultCalendar,canShare,canViewPrivateItems,canEdit,owner', '$orderby': 'name asc' }; console.error('Fetching calendars'); // Make API call const response = await callGraphAPI(accessToken, 'GET', apiPath, null, queryParams); const calendars = response.value || []; return { content: [ { type: "text", text: `Found ${calendars.length} calendars:\n\n${calendars.map(calendar => { const isDefault = calendar.isDefaultCalendar ? ' (Default)' : ''; const permissions = []; if (calendar.canEdit) permissions.push('Edit'); if (calendar.canShare) permissions.push('Share'); if (calendar.canViewPrivateItems) permissions.push('View Private'); const permissionsText = permissions.length > 0 ? permissions.join(', ') : 'Read-only'; return `📅 ${calendar.name}${isDefault} ID: ${calendar.id} Color: ${calendar.color} Permissions: ${permissionsText} Owner: ${calendar.owner ? calendar.owner.name : 'Unknown'}`; }).join('\n\n')}` } ] }; } catch (error) { console.error('Error in handleListCalendars:', error); return { error: { code: -32603, message: `Failed to list calendars: ${error.message}` } }; } } /** * Create calendar handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleCreateCalendar(args) { try { const { name, color } = args; if (!name) { return { error: { code: -32602, message: "Calendar name is required" } }; } // Ensure user is authenticated const accessToken = await ensureAuthenticated(); // Build the calendar object const calendarData = { name: name }; // Add color if provided if (color) { calendarData.color = color; } // Build the API path const apiPath = 'me/calendars'; console.error(`Creating calendar: ${name}`); // Make API call const newCalendar = await callGraphAPI(accessToken, 'POST', apiPath, calendarData); return { content: [ { type: "text", text: `✅ Calendar created successfully! **Name:** ${newCalendar.name} **Calendar ID:** ${newCalendar.id} **Color:** ${newCalendar.color} **Default:** ${newCalendar.isDefaultCalendar ? 'Yes' : 'No'} The calendar has been created and is ready to use.` } ] }; } catch (error) { console.error('Error in handleCreateCalendar:', error); return { error: { code: -32603, message: `Failed to create calendar: ${error.message}` } }; } } /** * Update calendar handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleUpdateCalendar(args) { try { const { calendarId, name, color } = args; if (!calendarId) { return { error: { code: -32602, message: "Calendar ID is required" } }; } // Ensure user is authenticated const accessToken = await ensureAuthenticated(); // Build the update object (only include provided fields) const updateData = {}; if (name !== undefined) updateData.name = name; if (color !== undefined) updateData.color = color; // Ensure we have at least one field to update if (Object.keys(updateData).length === 0) { return { error: { code: -32602, message: "At least one field (name or color) must be provided to update" } }; } // Build the API path const apiPath = `me/calendars/${calendarId}`; console.error(`Updating calendar: ${calendarId}`); // Make API call const updatedCalendar = await callGraphAPI(accessToken, 'PATCH', apiPath, updateData); return { content: [ { type: "text", text: `✅ Calendar updated successfully! **Name:** ${updatedCalendar.name} **Calendar ID:** ${updatedCalendar.id} **Color:** ${updatedCalendar.color} The calendar has been updated with the provided information.` } ] }; } catch (error) { console.error('Error in handleUpdateCalendar:', error); return { error: { code: -32603, message: `Failed to update calendar: ${error.message}` } }; } } /** * Delete calendar handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleDeleteCalendar(args) { try { const { calendarId } = args; if (!calendarId) { return { error: { code: -32602, message: "Calendar ID is required" } }; } // Ensure user is authenticated const accessToken = await ensureAuthenticated(); // First, get the calendar details for confirmation const calendarPath = `me/calendars/${calendarId}`; let calendarName = 'Unknown'; try { const calendar = await callGraphAPI(accessToken, 'GET', calendarPath, null, { '$select': 'name,isDefaultCalendar' }); calendarName = calendar.name || 'Unknown'; // Prevent deletion of default calendar if (calendar.isDefaultCalendar) { return { error: { code: -32603, message: "Cannot delete the default calendar" } }; } } catch (error) { console.error('Could not retrieve calendar for deletion:', error); } // Build the API path const apiPath = `me/calendars/${calendarId}`; console.error(`Deleting calendar: ${calendarId} (${calendarName})`); // Make API call to delete the calendar await callGraphAPI(accessToken, 'DELETE', apiPath); return { content: [ { type: "text", text: `✅ Calendar deleted successfully! **Calendar:** ${calendarName} **Calendar ID:** ${calendarId} The calendar and all its events have been permanently removed.` } ] }; } catch (error) { console.error('Error in handleDeleteCalendar:', error); // Handle specific error cases if (error.message.includes('404') || error.message.includes('Not Found')) { return { error: { code: -32603, message: `Calendar not found: ${calendarId}` } }; } return { error: { code: -32603, message: `Failed to delete calendar: ${error.message}` } }; } } module.exports = { handleListCalendars, handleCreateCalendar, handleUpdateCalendar, handleDeleteCalendar };