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
JavaScript
/**
* 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
};