Skip to main content
Glama
timer-start.ts4.6 kB
/** * Timer Start Tool * * Starts a new timer by creating a TimeEntry with active=true and duration=0. * Note: FreshBooks typically allows only one active timer per user at a time. */ import { z } from "zod"; import { TimerStartInputSchema, TimerStartOutputSchema } from "./schemas.js"; import { ErrorHandler } from "../../errors/error-handler.js"; import { ToolContext } from "../../errors/types.js"; import { FreshBooksClientWrapper } from "../../client/freshbooks-client.js"; /** * Tool definition for timer_start */ export const timerStartTool = { name: "timer_start", description: `Start a new timer for time tracking in FreshBooks. WHEN TO USE: - User says "start timer", "begin tracking time", "clock in" - User wants to track time on a task or project - Starting work on billable hours HOW IT WORKS: Creates a new time entry with: - active=true (timer is running) - duration=0 (will auto-calculate when stopped) - startedAt=now (start time) - isLogged=false (not yet logged as completed time) IMPORTANT NOTES: - FreshBooks typically allows only ONE active timer per user - If a timer is already running, you may need to stop it first - The timer will continue running until explicitly stopped - Duration is auto-calculated from startedAt when stopped REQUIRED: - accountId: FreshBooks account ID (get from auth_status if not specified) OPTIONAL BUT HELPFUL: - projectId: Associate timer with a specific project (recommended for billing) - clientId: Associate timer with a client - serviceId: Type of service/work being performed - taskId: Specific task within a project - note: Description of work being performed (can be updated when stopping) - billable: Whether time is billable (default: true) - internal: Whether this is internal work (default: false) EXAMPLE USAGE: - "Start a timer for Project Alpha" - "Begin tracking time on bug fixes" - "Clock in for client meeting" RETURNS: Created time entry with: - id: Use this ID to stop or discard the timer later - active: true (timer is running) - duration: 0 (will be calculated when stopped) - startedAt: When timer started - timer: Active timer object with isRunning=true`, inputSchema: TimerStartInputSchema, outputSchema: TimerStartOutputSchema, async execute( input: z.infer<typeof TimerStartInputSchema>, client: FreshBooksClientWrapper ): Promise<z.infer<typeof TimerStartOutputSchema>> { const handler = ErrorHandler.wrapHandler( 'timer_start', async (input: z.infer<typeof TimerStartInputSchema>, _context: ToolContext) => { const { accountId, projectId, clientId, serviceId, taskId, note, billable, internal } = input; // Build the time entry data for creating an active timer const timeEntryData: Record<string, unknown> = { // Timer-specific fields active: true, // This makes it an active timer duration: 0, // Timer starts with 0 duration isLogged: false, // Not yet logged as completed time startedAt: new Date().toISOString(), // Start time is now // Optional associations ...(projectId !== undefined && { projectId }), ...(clientId !== undefined && { clientId }), ...(serviceId !== undefined && { serviceId }), ...(taskId !== undefined && { taskId }), ...(note !== undefined && { note }), // Optional flags ...(billable !== undefined && { billable }), ...(internal !== undefined && { internal }), }; // Use the FreshBooks client to create the time entry const result = await client.executeWithRetry( "timer_start", async (fbClient) => { const response = await fbClient.timeEntries.create(timeEntryData as any, parseInt(accountId)); if (!response.ok) { throw response.error; } return response.data; } ); // Extract the time entry from the response // FreshBooks returns: { time_entry: { ... } } const timeEntry = (result as { time_entry?: unknown }).time_entry ?? result; return timeEntry as z.infer<typeof TimerStartOutputSchema>; } ); return handler(input, { accountId: input.accountId }); }, }; /** * Wrapped handler for backward compatibility with tests */ export async function timerStartHandler( input: z.infer<typeof TimerStartInputSchema>, context: ToolContext & { client: FreshBooksClientWrapper } ): Promise<z.infer<typeof TimerStartOutputSchema>> { return timerStartTool.execute(input, context.client); }

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