Skip to main content
Glama

mcp-nextcloud-calendar

calendars.ts6.78 kB
import express from 'express'; type Request = express.Request; type Response = express.Response; type NextFunction = express.NextFunction; import { Calendar } from '../models/index.js'; import { CalendarService } from '../services/index.js'; /** * Sanitizes error messages to avoid exposing implementation details * @param error The original error * @returns A sanitized error object with message and status code */ export function sanitizeError(error: unknown): { message: string; status: number } { // Default error response const defaultError = { message: 'An unexpected error occurred. Please try again later.', status: 500, }; // If no error provided, return default if (!error) { return defaultError; } // Cast to Error if possible const err = error as Error; const errorMsg = err.message || ''; // Authorization errors if ( errorMsg.toLowerCase().includes('unauthorized') || errorMsg.toLowerCase().includes('permission') ) { return { message: 'You do not have permission to perform this action.', status: 403, }; } // Not found errors if (errorMsg.toLowerCase().includes('not found')) { return { message: 'The requested calendar was not found.', status: 404, }; } // Lock errors if (errorMsg.toLowerCase().includes('locked')) { return { message: 'The calendar is currently locked. Please try again later.', status: 423, }; } // Validation errors if (errorMsg.toLowerCase().includes('invalid') || errorMsg.toLowerCase().includes('required')) { return { message: 'Invalid request data. Please check your input and try again.', status: 400, }; } // Default to generic server error return defaultError; } export function getCalendarsHandler(calendarService: CalendarService | null) { return (req: Request, res: Response, _next: NextFunction): void => { if (!calendarService) { res.status(503).json({ error: 'Calendar service not available' }); return; } calendarService .getCalendars() .then((calendars) => { res.status(200).json({ calendars }); }) .catch((error) => { console.error('Error getting calendars:', error); const { message, status } = sanitizeError(error); res.status(status).json({ error: message }); }); }; } export function createCalendarHandler(calendarService: CalendarService | null) { return (req: Request, res: Response, _next: NextFunction): void => { if (!calendarService) { res.status(503).json({ error: 'Calendar service not available' }); return; } const calendarData = req.body; if (!calendarData || typeof calendarData !== 'object') { res.status(400).json({ error: 'Invalid calendar data' }); return; } // Validate required fields if (!calendarData.displayName) { res.status(400).json({ error: 'Calendar display name is required' }); return; } try { // Create new calendar object, omitting id and url which will be assigned by the service const newCalendar: Omit<Calendar, 'id' | 'url'> = { displayName: calendarData.displayName, color: calendarData.color || '#0082c9', owner: '', // Will be assigned by service isDefault: false, isShared: false, isReadOnly: false, permissions: { canRead: true, canWrite: true, canShare: true, canDelete: true, }, category: calendarData.category, focusPriority: calendarData.focusPriority, metadata: calendarData.metadata, }; calendarService .createCalendar(newCalendar) .then((calendar) => { res.status(201).json({ calendar }); }) .catch((error) => { console.error('Error creating calendar:', error); const { message, status } = sanitizeError(error); res.status(status).json({ error: message }); }); } catch (error) { console.error('Error processing create calendar request:', error); const { message, status } = sanitizeError(error); res.status(status).json({ error: message }); } }; } export function updateCalendarHandler(calendarService: CalendarService | null) { return (req: Request, res: Response, _next: NextFunction): void => { if (!calendarService) { res.status(503).json({ error: 'Calendar service not available' }); return; } const calendarId = req.params.id; if (!calendarId) { res.status(400).json({ error: 'Calendar ID is required' }); return; } const updates = req.body; if (!updates || typeof updates !== 'object') { res.status(400).json({ error: 'Invalid update data' }); return; } // Remove fields that cannot be updated by the client const safeUpdates: Partial<Calendar> = { displayName: updates.displayName, color: updates.color, category: updates.category, focusPriority: updates.focusPriority, metadata: updates.metadata, }; // Clean undefined values Object.keys(safeUpdates).forEach((key) => { if (safeUpdates[key as keyof typeof safeUpdates] === undefined) { delete safeUpdates[key as keyof typeof safeUpdates]; } }); if (Object.keys(safeUpdates).length === 0) { res.status(400).json({ error: 'No valid fields to update' }); return; } calendarService .updateCalendar(calendarId, safeUpdates) .then((calendar) => { res.status(200).json({ calendar }); }) .catch((error) => { console.error('Error updating calendar:', error); const { message, status } = sanitizeError(error); res.status(status).json({ error: message }); }); }; } export function deleteCalendarHandler(calendarService: CalendarService | null) { return (req: Request, res: Response, _next: NextFunction): void => { if (!calendarService) { res.status(503).json({ error: 'Calendar service not available' }); return; } const calendarId = req.params.id; if (!calendarId) { res.status(400).json({ error: 'Calendar ID is required' }); return; } calendarService .deleteCalendar(calendarId) .then((success) => { if (success) { res.status(204).send(); // 204 No Content is appropriate for successful DELETE } else { res.status(500).json({ error: 'Failed to delete calendar' }); } }) .catch((error) => { console.error('Error deleting calendar:', error); const { message, status } = sanitizeError(error); res.status(status).json({ error: message }); }); }; }

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/Cheffromspace/mcp-nextcloud-calendar'

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