Skip to main content
Glama
timeentry-list.ts6.26 kB
/** * timeentry_list Tool * * List time entries from FreshBooks with filtering and pagination. */ import { z } from 'zod'; import { TimeEntryListInputSchema, TimeEntryListOutputSchema } from './schemas.js'; import { FreshBooksClientWrapper } from '../../client/index.js'; import { ErrorHandler } from '../../errors/error-handler.js'; import { ToolContext } from '../../errors/types.js'; import { logger } from '../../utils/logger.js'; /** * Tool definition for timeentry_list */ export const timeentryListTool = { name: 'timeentry_list', description: `List time entries from FreshBooks. WHEN TO USE: - User asks to see their time entries, logged hours, or time tracking history - User wants to review time for a specific project or client - User needs to find entries within a date range - User wants to see active/running timers - User asks "show my time entries", "what time did I log today", "time on project X" REQUIRED: - accountId: FreshBooks account ID (get from auth_status if not specified) OPTIONAL FILTERS: - projectId: Filter by specific project - clientId: Filter by specific client - taskId: Filter by specific task - serviceId: Filter by specific service - active: Filter by active status (true = running timers only) - billable: Filter by billable status - billed: Filter by whether already billed - startedAfter: Show entries after this date (ISO 8601) - startedBefore: Show entries before this date (ISO 8601) PAGINATION: - page: Page number (default: 1) - perPage: Results per page (default: 30, max: 100) RETURNS: Array of time entries with: - duration: Time in seconds - note: Description of work - startedAt: When the entry began - projectId, clientId, taskId, serviceId: Associated entities - billable, billed: Billing status - active: Whether timer is currently running Plus pagination metadata (page, pages, total) EXAMPLES: - "Show my time entries for today" - "List time logged on project 123" - "Show billable time entries from last week" - "Find active timers"`, inputSchema: TimeEntryListInputSchema, outputSchema: TimeEntryListOutputSchema, /** * Execute the tool */ async execute( input: z.infer<typeof TimeEntryListInputSchema>, client: FreshBooksClientWrapper ): Promise<z.infer<typeof TimeEntryListOutputSchema>> { const handler = ErrorHandler.wrapHandler( 'timeentry_list', async ( input: z.infer<typeof TimeEntryListInputSchema>, _context: ToolContext ) => { logger.debug('Listing time entries', { accountId: input.accountId, filters: { projectId: input.projectId, clientId: input.clientId, active: input.active, }, }); const result = await client.executeWithRetry( 'timeentry_list', async (fbClient) => { // Import query builders from SDK const { SearchQueryBuilder, PaginationQueryBuilder } = await import( '@freshbooks/api/dist/models/builders/index.js' ); // Build query builders const queryBuilders: any[] = []; // Add pagination if (input.page || input.perPage) { const pagination = new PaginationQueryBuilder() .page(input.page || 1) .perPage(input.perPage || 30); queryBuilders.push(pagination); } // Add search filters const hasFilters = input.projectId || input.clientId || input.taskId || input.serviceId || input.active !== undefined || input.billable !== undefined || input.billed !== undefined || input.startedAfter || input.startedBefore; if (hasFilters) { const search = new SearchQueryBuilder(); if (input.projectId) { search.equals('project_id', input.projectId); } if (input.clientId) { search.equals('client_id', input.clientId); } if (input.taskId) { search.equals('task_id', input.taskId); } if (input.serviceId) { search.equals('service_id', input.serviceId); } if (input.active !== undefined) { search.boolean('active', input.active); } if (input.billable !== undefined) { search.boolean('billable', input.billable); } if (input.billed !== undefined) { search.boolean('billed', input.billed); } if (input.startedAfter) { search.between('started_at', { min: input.startedAfter, max: input.startedBefore || new Date().toISOString(), }); } else if (input.startedBefore) { search.between('started_at', { min: '1970-01-01T00:00:00Z', max: input.startedBefore, }); } queryBuilders.push(search); } // Call FreshBooks API const response = await fbClient.timeEntries.list( parseInt(input.accountId), queryBuilders ); if (!response.ok) { throw response.error; } const responseData = response.data as any; const paginationData = responseData?.pages || {}; return { timeEntries: responseData?.timeEntries || [], pagination: { page: paginationData.page || 1, pages: paginationData.pages || 1, perPage: paginationData.per_page || paginationData.perPage || 30, total: paginationData.total || 0, }, }; } ); logger.info('Time entries listed successfully', { count: result.timeEntries.length, total: result.pagination.total, }); return result as any; } ); return handler(input, { accountId: input.accountId }) as any; }, };

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/Good-Samaritan-Software-LLC/freshbooks-mcp'

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