Skip to main content
Glama
niondigital

MoCo MCP Server

by niondigital

get_activities

Retrieve and summarize time tracking activities by date, project, and task within a specified date range. Filter results by project ID to focus on specific work data.

Instructions

Get all activities within a date range with automatic summation by date, project, and task. Optionally filter by project ID.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
startDateYesStart date in ISO 8601 format (YYYY-MM-DD)
endDateYesEnd date in ISO 8601 format (YYYY-MM-DD)
projectIdNoOptional project ID to filter activities for a specific project

Implementation Reference

  • The main handler for the get_activities tool. Validates input dates, fetches activities from Moco API, aggregates them by date/project/task, formats the summary, and returns a formatted string response.
    export const getActivitiesTool = {
      name: 'get_activities',
      description: 'Get all activities within a date range with automatic summation by date, project, and task. Optionally filter by project ID.',
      inputSchema: zodToJsonSchema(GetActivitiesSchema),
      handler: async (params: z.infer<typeof GetActivitiesSchema>): Promise<string> => {
        const { startDate, endDate, projectId } = params;
    
        // Validate date format and range
        if (!validateDateRange(startDate, endDate)) {
          return createValidationErrorMessage({
            field: 'dateRange',
            value: `${startDate} to ${endDate}`,
            reason: 'invalid_date_range'
          });
        }
    
        try {
          const apiService = new MocoApiService();
          const activities = await apiService.getActivities(startDate, endDate, projectId);
    
          if (activities.length === 0) {
            return createEmptyResultMessage({
              type: 'activities',
              startDate,
              endDate,
              projectId
            });
          }
    
          const summary = aggregateActivities(activities, startDate, endDate);
          return formatActivitiesSummary(summary, projectId);
    
        } catch (error) {
          return `Error retrieving activities: ${error instanceof Error ? error.message : 'Unknown error'}`;
        }
      }
    };
  • Zod schema defining the input parameters for the get_activities tool: required startDate and endDate strings, optional positive projectId number.
    const GetActivitiesSchema = z.object({
      startDate: z.string().describe('Start date in ISO 8601 format (YYYY-MM-DD)'),
      endDate: z.string().describe('End date in ISO 8601 format (YYYY-MM-DD)'),
      projectId: z.number().positive().optional().describe('Optional project ID to filter activities for a specific project')
    });
  • src/index.ts:34-42 (registration)
    The getActivitiesTool is imported and included in the AVAILABLE_TOOLS array, which is used by the MCP server to list and dispatch tool calls.
    const AVAILABLE_TOOLS = [
      getActivitiesTool,
      getUserProjectsTool,
      getUserProjectTasksTool,
      getUserHolidaysTool,
      getUserPresencesTool,
      getUserSickDaysTool,
      getPublicHolidaysTool
    ];
  • MocoApiService method that fetches activities from the MoCo API endpoint '/activities' with date range and optional project filter, handling pagination automatically.
    async getActivities(startDate: string, endDate: string, projectId?: number): Promise<Activity[]> {
      const params: Record<string, string | number> = {
        from: startDate,
        to: endDate
      };
      
      if (projectId) {
        params.project_id = projectId;
      }
      
      return this.fetchAllPages<Activity>('/activities', params);
    }
  • Helper function that aggregates raw activities into structured summaries: daily breakdowns, project totals across days, task breakdowns, and grand total.
    function aggregateActivities(activities: Activity[], startDate: string, endDate: string): ActivityRangeSummary {
      // Group activities by date
      const activitiesByDate = new Map<string, Activity[]>();
      
      activities.forEach(activity => {
        if (!activitiesByDate.has(activity.date)) {
          activitiesByDate.set(activity.date, []);
        }
        activitiesByDate.get(activity.date)!.push(activity);
      });
    
      // Create daily summaries
      const dailySummaries: DailyActivitySummary[] = [];
      const projectTotalsMap = new Map<number, {
        projectName: string;
        totalHours: number;
        tasks: Map<number, { taskName: string; totalHours: number }>;
      }>();
    
      // Sort dates for consistent output
      const sortedDates = Array.from(activitiesByDate.keys()).sort();
      
      sortedDates.forEach(date => {
        const dayActivities = activitiesByDate.get(date)!;
        const dailySummary = createDailySummary(date, dayActivities);
        dailySummaries.push(dailySummary);
    
        // Accumulate project totals across all days
        dailySummary.projects.forEach(project => {
          if (!projectTotalsMap.has(project.projectId)) {
            projectTotalsMap.set(project.projectId, {
              projectName: project.projectName,
              totalHours: 0,
              tasks: new Map()
            });
          }
    
          const projectTotal = projectTotalsMap.get(project.projectId)!;
          projectTotal.totalHours += project.projectTotal.hours;
    
          project.tasks.forEach(task => {
            if (!projectTotal.tasks.has(task.taskId)) {
              projectTotal.tasks.set(task.taskId, {
                taskName: task.taskName,
                totalHours: 0
              });
            }
            projectTotal.tasks.get(task.taskId)!.totalHours += task.hours;
          });
        });
      });
    
      // Convert project totals map to array format
      const projectTotals = Array.from(projectTotalsMap.entries()).map(([projectId, data]) => ({
        projectId,
        projectName: data.projectName,
        total: createTimeFormat(data.totalHours),
        tasks: Array.from(data.tasks.entries()).map(([taskId, taskData]) => ({
          taskId,
          taskName: taskData.taskName,
          total: createTimeFormat(taskData.totalHours)
        }))
      }));
    
      // Calculate grand total
      const grandTotalHours = sumHours(dailySummaries.map(day => day.dailyTotal.hours));
    
      return {
        startDate,
        endDate,
        dailySummaries,
        projectTotals,
        grandTotal: createTimeFormat(grandTotalHours)
      };
    }

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