Skip to main content
Glama
project-update.ts4.45 kB
/** * Project Update Tool * * Update an existing project in FreshBooks. */ import { z } from "zod"; import { ProjectUpdateInputSchema, ProjectSingleOutputSchema } 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 project_update */ export const projectUpdateTool = { name: "project_update", description: `Update an existing project in FreshBooks. WHEN TO USE: - User wants to modify project details - User says "update project", "change project", "mark project complete" - Adjusting billing rates, due dates, or status REQUIRED INFO: - projectId: Which project to update (numeric) - accountId: FreshBooks account (get from context) UPDATABLE FIELDS: - title: Change project name - description: Update project description - dueDate: Change completion deadline (ISO 8601) - clientId: Reassign to different client - billingMethod: Change how project is billed - rate: Update hourly rate - fixedPrice: Change fixed price amount - budget: Adjust project budget - active: Activate or deactivate project - complete: Mark project as complete/incomplete - internal: Change billable status STATUS CHANGES: - Set active=false to pause project (stops appearing in active lists) - Set complete=true to mark project done - Both can be combined for archival EXAMPLE PROMPTS: - "Mark project 12345 as complete" - "Update project Website Redesign to increase rate to $150/hr" - "Change project 98765 due date to next Friday" - "Deactivate project Mobile App" RETURNS: Updated project with all current settings. Changes take effect immediately for new time entries.`, inputSchema: ProjectUpdateInputSchema, outputSchema: ProjectSingleOutputSchema, async execute( input: z.infer<typeof ProjectUpdateInputSchema>, client: FreshBooksClientWrapper ): Promise<z.infer<typeof ProjectSingleOutputSchema>> { const handler = ErrorHandler.wrapHandler( "project_update", async (input: z.infer<typeof ProjectUpdateInputSchema>, _context: ToolContext) => { const { accountId, projectId, ...updates } = input; // Build update object for API (convert camelCase to snake_case) const project: Record<string, unknown> = {}; if (updates.title !== undefined) project.title = updates.title; if (updates.clientId !== undefined) project.client_id = updates.clientId; if (updates.description !== undefined) project.description = updates.description; if (updates.dueDate !== undefined) project.due_date = updates.dueDate; if (updates.budget !== undefined) project.budget = updates.budget; if (updates.fixedPrice !== undefined) project.fixed_price = updates.fixedPrice; if (updates.rate !== undefined) project.rate = updates.rate; if (updates.billingMethod !== undefined) project.billing_method = updates.billingMethod; if (updates.projectType !== undefined) project.project_type = updates.projectType; if (updates.internal !== undefined) project.internal = updates.internal; if (updates.projectManagerId !== undefined) project.project_manager_id = updates.projectManagerId; if (updates.active !== undefined) project.active = updates.active; if (updates.complete !== undefined) project.complete = updates.complete; // Execute the API call const result = await client.executeWithRetry( "project_update", async (fbClient) => { const response = await fbClient.projects.update(project, parseInt(accountId), projectId); if (!response.ok) { throw response.error; } return response.data; } ); // FreshBooks returns: { project: { ... } } const updatedProject = (result as { project?: unknown }).project ?? result; return updatedProject as z.infer<typeof ProjectSingleOutputSchema>; } ); return handler(input, { accountId: input.accountId }); }, }; /** * Wrapped handler for backward compatibility with tests */ export async function handleProjectUpdate( input: z.infer<typeof ProjectUpdateInputSchema>, context: { client: FreshBooksClientWrapper } ): Promise<z.infer<typeof ProjectSingleOutputSchema>> { return projectUpdateTool.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