Skip to main content
Glama
client-update.ts5.98 kB
/** * client_update Tool * * Update an existing client's information. */ import { z } from 'zod'; import { ClientUpdateInputSchema, ClientSingleOutputSchema } 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 client_update */ export const clientUpdateTool = { name: 'client_update', description: `Update an existing client's information in FreshBooks. WHEN TO USE: - User wants to modify client details - User says "update client", "change client info", "edit customer" - Correcting client contact information - Updating billing address or preferences - Changing client status (archive/activate) REQUIRED: - accountId: FreshBooks account ID (get from auth_status if not specified) - clientId: The client ID to update (numeric) - At least one field to update UPDATABLE FIELDS: Contact: fName, lName, organization, email Phones: busPhone, homePhone, mobPhone, fax Primary address: pStreet, pStreet2, pCity, pProvince, pCode, pCountry Secondary address: sStreet, sStreet2, sCity, sProvince, sCode, sCountry Financial: currencyCode, language, vatNumber, vatName Preferences: allowLateFees, allowLateNotifications Status: visState (0=active, 1=deleted, 2=archived) Notes: note PARTIAL UPDATES: Only include fields you want to change. Omitted fields remain unchanged. RETURNS: Updated client record with all current information. EXAMPLES: - "Update client 123's email to newemail@example.com" - "Change client 456's address to 789 Oak Street, Boston, MA" - "Archive client 789 (set visState to 2)" - "Enable late fees for client 234"`, inputSchema: ClientUpdateInputSchema, outputSchema: ClientSingleOutputSchema, /** * Execute the tool */ async execute( input: z.infer<typeof ClientUpdateInputSchema>, client: FreshBooksClientWrapper ): Promise<z.infer<typeof ClientSingleOutputSchema>> { const handler = ErrorHandler.wrapHandler( 'client_update', async ( input: z.infer<typeof ClientUpdateInputSchema>, _context: ToolContext ) => { const { accountId, clientId, ...updateData } = input; logger.debug('Updating client', { accountId, clientId, fields: Object.keys(updateData), }); // Build update object for API (convert camelCase to snake_case) const updates: Record<string, unknown> = {}; // Contact information if (updateData.fName !== undefined) updates.fname = updateData.fName; if (updateData.lName !== undefined) updates.lname = updateData.lName; if (updateData.organization !== undefined) updates.organization = updateData.organization; if (updateData.email !== undefined) updates.email = updateData.email; // Phone numbers if (updateData.busPhone !== undefined) updates.bus_phone = updateData.busPhone; if (updateData.homePhone !== undefined) updates.home_phone = updateData.homePhone; if (updateData.mobPhone !== undefined) updates.mob_phone = updateData.mobPhone; if (updateData.fax !== undefined) updates.fax = updateData.fax; // Note if (updateData.note !== undefined) updates.note = updateData.note; // Primary address if (updateData.pStreet !== undefined) updates.p_street = updateData.pStreet; if (updateData.pStreet2 !== undefined) updates.p_street2 = updateData.pStreet2; if (updateData.pCity !== undefined) updates.p_city = updateData.pCity; if (updateData.pProvince !== undefined) updates.p_province = updateData.pProvince; if (updateData.pCode !== undefined) updates.p_code = updateData.pCode; if (updateData.pCountry !== undefined) updates.p_country = updateData.pCountry; // Secondary address if (updateData.sStreet !== undefined) updates.s_street = updateData.sStreet; if (updateData.sStreet2 !== undefined) updates.s_street2 = updateData.sStreet2; if (updateData.sCity !== undefined) updates.s_city = updateData.sCity; if (updateData.sProvince !== undefined) updates.s_province = updateData.sProvince; if (updateData.sCode !== undefined) updates.s_code = updateData.sCode; if (updateData.sCountry !== undefined) updates.s_country = updateData.sCountry; // Financial settings if (updateData.currencyCode !== undefined) updates.currency_code = updateData.currencyCode; if (updateData.language !== undefined) updates.language = updateData.language; if (updateData.vatNumber !== undefined) updates.vat_number = updateData.vatNumber; if (updateData.vatName !== undefined) updates.vat_name = updateData.vatName; // Billing preferences if (updateData.allowLateFees !== undefined) updates.allow_late_fees = updateData.allowLateFees; if (updateData.allowLateNotifications !== undefined) { updates.allow_late_notifications = updateData.allowLateNotifications; } // Status if (updateData.visState !== undefined) updates.vis_state = updateData.visState; const result = await client.executeWithRetry( 'client_update', async (fbClient) => { const response = await fbClient.clients.update(updates, accountId, String(clientId)); if (!response.ok) { throw response.error; } return response.data; } ); // FreshBooks returns: { client: { ... } } const updatedClient = (result as { client?: unknown }).client ?? result; logger.info('Client updated successfully', { clientId, }); return updatedClient as z.infer<typeof ClientSingleOutputSchema>; } ); return handler(input, { accountId: input.accountId }); }, };

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