Skip to main content
Glama
niondigital

MoCo MCP Server

by niondigital

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
NameRequiredDescriptionDefault
yearYesYear to retrieve holidays for (e.g., 2024)

Implementation Reference

  • 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'}`;
      }
    }
  • 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
    ];
  • 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;
      }
    }
  • 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 [];
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions 'utilization calculations and remaining vacation days' which adds some context about what the tool returns, but doesn't cover important aspects like whether this requires authentication, rate limits, pagination behavior, or error conditions. For a tool that presumably accesses user data, this is a significant gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that communicates the core purpose without any wasted words. It's appropriately sized for a simple single-parameter tool and front-loads the essential information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read operation with 100% schema coverage but no annotations and no output schema, the description is adequate but incomplete. It explains what the tool returns ('utilization calculations and remaining vacation days') which partially compensates for the missing output schema, but doesn't provide enough behavioral context for a tool that likely requires authentication and returns potentially sensitive user data.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with the single parameter 'year' well-documented in the schema. The description doesn't add any parameter-specific information beyond what's already in the schema. This meets the baseline of 3 when schema coverage is high and no additional parameter context is provided.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Get all user holidays'), resource ('user holidays'), and scope ('for a specific year with utilization calculations and remaining vacation days'). It distinguishes from siblings like get_public_holidays (which likely lacks user-specific calculations) and get_user_sick_days (different type of time off).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, when not to use it, or how it differs from sibling tools beyond implicit scope differences. The agent must infer usage from tool names alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/niondigital/moco-mcp'

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