get_user_holidays
Retrieve annual holiday data with utilization calculations and remaining vacation days for workforce planning and time management.
Instructions
Get all user holidays for a specific year with utilization calculations and remaining vacation days
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| year | Yes | Year to retrieve holidays for (e.g., 2024) |
Implementation Reference
- src/tools/userHolidaysTools.ts:27-78 (handler)Main handler function executing the tool logic: validates input year, fetches holiday entitlements and taken holidays from API service, processes data into summary (total taken, entitlement, utilization, remaining), formats readable output.handler: async (params: z.infer<typeof GetUserHolidaysSchema>): Promise<string> => { const { year } = params; // Validate year if (!validateYear(year)) { return createValidationErrorMessage({ field: 'year', value: year, reason: 'invalid_year' }); } try { const apiService = new MocoApiService(); // Get both entitlements and actual taken holidays let entitlements: any[] = []; let takenHolidays: any[] = []; try { entitlements = await apiService.getUserHolidays(year); } catch (error) { console.error('DEBUG: Failed to get entitlements:', error); } try { console.error('DEBUG: About to call getTakenHolidays...'); takenHolidays = await apiService.getTakenHolidays(year); console.error('DEBUG: getTakenHolidays returned:', takenHolidays.length, 'items'); } catch (error) { console.error('DEBUG: Failed to get taken holidays:', error); console.error('DEBUG: Error details:', error instanceof Error ? error.message : 'Unknown error'); } // Debug logging console.error(`DEBUG: Got ${entitlements.length} entitlements and ${takenHolidays.length} taken holidays for year ${year}`); console.error('DEBUG: Entitlements:', JSON.stringify(entitlements, null, 2)); console.error('DEBUG: Taken holidays:', JSON.stringify(takenHolidays, null, 2)); if (takenHolidays.length === 0) { // Show entitlement info if available, otherwise just empty return formatHolidaysWithNoData(year, entitlements); } const summary = createHolidaySummary(takenHolidays, entitlements, year); console.error('DEBUG: Summary created:', JSON.stringify(summary, null, 2)); return formatHolidaysSummary(summary); } catch (error) { return `Error retrieving holidays for ${year}: ${error instanceof Error ? error.message : 'Unknown error'}`; } }
- src/tools/userHolidaysTools.ts:15-17 (schema)Zod schema defining input validation for the tool: requires integer 'year' parameter.const GetUserHolidaysSchema = z.object({ year: z.number().int().describe('Year to retrieve holidays for (e.g., 2024)') });
- src/index.ts:34-42 (registration)Tool registration: imported from './tools/userHolidaysTools.js' (line 23) and added to AVAILABLE_TOOLS array used by MCP server for tool listing and execution dispatching.const AVAILABLE_TOOLS = [ getActivitiesTool, getUserProjectsTool, getUserProjectTasksTool, getUserHolidaysTool, getUserPresencesTool, getUserSickDaysTool, getPublicHolidaysTool ];
- src/services/mocoApi.ts:216-230 (helper)Supporting API service method that fetches user holiday entitlements for the specified year from MoCo /users/holidays endpoint, handling 404 gracefully.async getUserHolidays(year: number): Promise<UserHoliday[]> { try { return await this.makeRequest<UserHoliday[]>('/users/holidays', { year: year }); } catch (error) { // If 404 error (Resource not found), return empty array instead of throwing error // This happens when no holiday data exists for the year yet if (error instanceof Error && error.message.includes('Resource not found')) { return []; } // Re-throw other errors throw error; } }
- src/services/mocoApi.ts:237-283 (helper)Supporting API service method fetching actual taken vacation days from MoCo /schedules endpoint by filtering for absence code '4' (Urlaub/vacation).async getTakenHolidays(year: number): Promise<any[]> { // Calculate year date range const startDate = `${year}-01-01`; const endDate = `${year}-12-31`; console.error(`DEBUG API: Trying to fetch schedules for ${startDate} to ${endDate}`); try { // Schedules endpoint has different response structure, use direct request // Based on previous success with makeRequest showing 63 schedules const allSchedules = await this.makeRequest<any[]>('/schedules', { from: startDate, to: endDate }); console.error(`DEBUG API: Found ${allSchedules.length} total schedules for ${year}`); if (allSchedules.length > 0) { console.error('DEBUG API: First few schedules:', JSON.stringify(allSchedules.slice(0, 3), null, 2)); } // Filter for absences (schedules with assignment type "Absence") const absences = allSchedules.filter(schedule => schedule.assignment && schedule.assignment.type === 'Absence' ); console.error(`DEBUG API: Found ${absences.length} absences with assignment codes:`, absences.map(a => a.assignment?.code + ' (' + a.assignment?.name + ')')); // Look specifically for vacation/holiday codes (we need to figure out which code is for vacation) const vacationCodes = ['3', '4', '5']; // Common vacation codes to try const holidays = absences.filter(schedule => vacationCodes.includes(schedule.assignment?.code) ); console.error(`DEBUG API: Found ${holidays.length} potential holidays with codes:`, holidays.map(a => a.assignment?.code + ' (' + a.assignment?.name + ')')); // Filter for only vacation days (assignment code "4") const vacationDays = absences.filter(schedule => schedule.assignment?.code === '4' && schedule.assignment?.name === 'Urlaub' ); console.error(`DEBUG API: Found ${vacationDays.length} actual vacation days (code 4)`); return vacationDays; } catch (error) { console.error('DEBUG API: Error fetching schedules:', error); console.error('DEBUG API: Error details:', error instanceof Error ? error.message : 'Unknown error'); return []; } }