Skip to main content
Glama
timesheets.tools.ts6.91 kB
import { Injectable } from '@nestjs/common'; import { Tool } from '@rekog/mcp-nest'; import { z } from 'zod'; import { AuthService } from '@/auth/auth.service'; import { TimesheetsService } from './timesheets.service'; import { ApiClientService } from '@/shared/http/api-client.service'; import { ResponseUtil } from '@/common/utils/response.util'; /** * MCP Tools for timesheet management * Provides descriptive tool names for LLM decision making: * - create_new_timesheet_entry: Create a new daily timesheet entry with work details * - list_user_timesheet_entries: Fetch and list user's timesheet entries with pagination * - fetch_available_work_activities: Get all available work activities/task types */ @Injectable() export class TimesheetsTools { constructor( private readonly authService: AuthService, private readonly timesheetsService: TimesheetsService, private readonly apiClient: ApiClientService, ) {} /** * Authenticate using environment credentials if no token exists * Used by all tools to ensure authentication */ private async ensureAuthenticated(): Promise<{ user: any; token: string } | null> { try { // Try to get existing token let user = this.authService.getCurrentUser(); let token = this.authService.getToken(); // Try to refresh token try { const refreshedToken = await this.authService.refreshToken(); if (refreshedToken) { token = refreshedToken; try { user = this.authService.getCurrentUser(); } catch (e) { // Continue with existing user } } } catch (error) { // Token refresh failed, try to login with env credentials return await this.authenticateWithEnvCredentials(); } return { user, token }; } catch (error) { // No token in config, try to login with env credentials return await this.authenticateWithEnvCredentials(); } } /** * Authenticate using environment variables */ private async authenticateWithEnvCredentials(): Promise<{ user: any; token: string } | null> { const username = process.env.TIMESHEET_USERNAME; const password = process.env.TIMESHEET_PASSWORD; if (!username || !password) { return null; } try { const loginResult = await this.authService.login(username, password); if (!loginResult.success || !loginResult.user) { return null; } try { const user = this.authService.getCurrentUser(); const token = this.authService.getToken(); return { user, token }; } catch (error) { return null; } } catch (error) { return null; } } @Tool({ name: 'create_new_timesheet_entry', description: 'Create a new daily timesheet entry. Records work done for a specific date, including start/end time, project, module, activity type, and work description. Minimum description length is 10 characters. Automatically handles authentication with fresh token. Calls: POST /api/timesheets/create', parameters: z.object({ project_id: z.number().describe('Project ID - which project the work belongs to'), module_id: z.number().describe('Module ID - which module/component within the project'), activity_id: z.number().describe('Activity ID - the type of work (e.g., Development, Code Review, Testing)'), start_time: z.string().describe('Start time in HH:MM:SS format (e.g., 09:00:00)'), end_time: z.string().describe('End time in HH:MM:SS format (e.g., 10:30:00)'), duration: z.number().describe('Duration in minutes (total work time for this entry)'), description: z .string() .min(10) .describe('Detailed work description (minimum 10 characters) - what was accomplished'), date: z.string().describe('Date in YYYY-MM-DD format (e.g., 2025-11-04)'), }), }) async createNewTimesheetEntry(params: { project_id: number; module_id: number; activity_id: number; start_time: string; end_time: string; duration: number; description: string; date: string; }) { try { const auth = await this.ensureAuthenticated(); if (!auth || !auth.user || !auth.token) { const username = process.env.TIMESHEET_USERNAME; const password = process.env.TIMESHEET_PASSWORD; if (!username || !password) { return ResponseUtil.error( 'User not authenticated. Please configure TIMESHEET_USERNAME and TIMESHEET_PASSWORD in your MCP client environment variables.', ); } return ResponseUtil.error( 'Authentication failed: Invalid username or password. Please verify your credentials in the MCP client configuration.', ); } const result = await this.timesheetsService.createTimesheetEntry(params); return ResponseUtil.success( '✓ Daily timesheet entry created successfully!', result, ); } catch (error) { return ResponseUtil.error( error.message || 'Failed to create daily timesheet entry', ); } } @Tool({ name: 'list_user_timesheet_entries', description: 'Fetch and display user\'s timesheet entries with pagination support. Shows previously recorded work entries. Default limit is 10 entries per page, maximum 100. Automatically handles authentication with fresh token. Calls: GET /api/timesheets/list/{userId}', parameters: z.object({ page: z .number() .optional() .default(1) .describe('Page number for pagination (default: 1)'), limit: z .number() .optional() .default(10) .describe('Number of entries per page (default: 10, max: 100)'), }), }) async listUserTimesheetEntries(params: { page?: number; limit?: number }) { try { const auth = await this.ensureAuthenticated(); if (!auth || !auth.user || !auth.token) { const username = process.env.TIMESHEET_USERNAME; const password = process.env.TIMESHEET_PASSWORD; if (!username || !password) { return ResponseUtil.error( 'User not authenticated. Please configure TIMESHEET_USERNAME and TIMESHEET_PASSWORD in your MCP client environment variables.', ); } return ResponseUtil.error( 'Authentication failed: Invalid username or password. Please verify your credentials in the MCP client configuration.', ); } const { data, pagination } = await this.timesheetsService.fetchTimesheetEntries(params); return ResponseUtil.success( '✓ Timesheet entries fetched successfully!', data, pagination, ); } catch (error) { return ResponseUtil.error( error.message || 'Failed to fetch timesheet entries', ); } } }

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/arshad-khan1/Timesheet-mcp'

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