@goodsamsoftware/freshbooks-mcp 1.0.18 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"journalentry-create.d.ts","sourceRoot":"","sources":["../../../src/tools/journal-entry/journalentry-create.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAG7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAyDxB,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,UAC5C,uBAAuB,GAC9B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;CAsD3D,CAAC"}
1
+ {"version":3,"file":"journalentry-create.d.ts","sourceRoot":"","sources":["../../../src/tools/journal-entry/journalentry-create.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAG7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAyDxB,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,UAC5C,uBAAuB,GAC9B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;CAsF3D,CAAC"}
@@ -64,11 +64,11 @@ NOTE: This is a create-only operation. Journal entries cannot be updated or dele
64
64
  outputSchema: JournalEntryCreateOutputSchema,
65
65
  async execute(input, client) {
66
66
  const handler = ErrorHandler.wrapHandler('journalentry_create', async (input, _context) => {
67
- const { accountId, ...entryData } = input;
67
+ const { accountId, name, date, description, currencyCode, details } = input;
68
68
  // Validate that debits equal credits
69
69
  let totalDebits = 0;
70
70
  let totalCredits = 0;
71
- for (const detail of entryData.details) {
71
+ for (const detail of details) {
72
72
  if (detail.debit) {
73
73
  totalDebits += parseFloat(detail.debit);
74
74
  }
@@ -81,20 +81,50 @@ NOTE: This is a create-only operation. Journal entries cannot be updated or dele
81
81
  if (difference > 0.01) {
82
82
  throw ErrorHandler.createValidationError(`Journal entry must balance. Debits: ${totalDebits.toFixed(2)}, Credits: ${totalCredits.toFixed(2)}, Difference: ${difference.toFixed(2)}`, { tool: 'journalentry_create', accountId });
83
83
  }
84
- // The SDK transform reads `userEnteredDate` (→ wire `user_entered_date`);
85
- // the input field is `date`, which the SDK ignores. Map it so the
86
- // required date is actually sent.
87
- entryData.userEnteredDate = entryData.date;
88
- // Execute the API call
89
- const result = await client.executeWithRetry("journalentry_create", async (fbClient) => {
90
- const response = await fbClient.journalEntries.create(entryData, accountId);
91
- if (!response.ok) {
92
- throw response.error;
93
- }
94
- return response.data;
95
- });
96
- // Extract journal entry data
97
- return result.journalEntry || result;
84
+ // POST the wire payload directly instead of via the SDK. The SDK's
85
+ // transformJournalEntryRequest has two defects (both live-confirmed):
86
+ // 1. It omits currency_code unless the caller's currencyCode survived
87
+ // schema parsing — and a journal entry WITHOUT currency_code makes the
88
+ // accounting API 500 with the opaque "There was an error accessing your
89
+ // account data." So default it here, in the handler, not the schema.
90
+ // 2. transformDateRequest parses "YYYY-MM-DD" as UTC midnight then reads
91
+ // local Y/M/D, shifting the stored date back a day in negative-UTC
92
+ // timezones. Sending the raw "YYYY-MM-DD" string avoids the shift.
93
+ // (Per-line `description` is intentionally not sent: the API ignores it.)
94
+ const body = {
95
+ journal_entry: {
96
+ name,
97
+ user_entered_date: date,
98
+ currency_code: currencyCode || 'USD',
99
+ details: details.map((d) => ({
100
+ sub_accountid: d.subAccountId,
101
+ ...(d.debit !== undefined ? { debit: d.debit } : {}),
102
+ ...(d.credit !== undefined ? { credit: d.credit } : {}),
103
+ })),
104
+ },
105
+ };
106
+ const result = await client.executeRawWithRetry('POST', `/accounting/account/${accountId}/journal_entries/journal_entries`, body, 'journalentry_create');
107
+ if (!result.ok) {
108
+ throw result.error ?? new Error('Journal entry creation failed');
109
+ }
110
+ // Accounting API returns { response: { result: { journal_entry: {...} } } }
111
+ // in snake_case; map it to the camelCase output contract.
112
+ const je = result.data?.response?.result?.journal_entry ?? result.data;
113
+ return {
114
+ id: je.id ?? je.entryid,
115
+ name: je.name,
116
+ description: je.description ?? description,
117
+ date: je.user_entered_date ?? date,
118
+ currencyCode: je.currency_code,
119
+ details: Array.isArray(je.details)
120
+ ? je.details.map((d) => ({
121
+ subAccountId: d.sub_accountid,
122
+ debit: d.debit ?? undefined,
123
+ credit: d.credit ?? undefined,
124
+ description: d.description ?? undefined,
125
+ }))
126
+ : [],
127
+ };
98
128
  });
99
129
  return handler(input, { accountId: input.accountId });
100
130
  },
@@ -1 +1 @@
1
- {"version":3,"file":"journalentry-create.js","sourceRoot":"","sources":["../../../src/tools/journal-entry/journalentry-create.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAI7D;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kGAiDmF;IAEhG,WAAW,EAAE,6BAA6B;IAC1C,YAAY,EAAE,8BAA8B;IAE5C,KAAK,CAAC,OAAO,CACX,KAAoD,EACpD,MAA+B;QAE/B,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CACtC,qBAAqB,EACrB,KAAK,EAAE,KAAoD,EAAE,QAAqB,EAAE,EAAE;YACpF,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,GAAG,KAAK,CAAC;YAE1C,qCAAqC;YACrC,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,IAAI,YAAY,GAAG,CAAC,CAAC;YAErB,KAAK,MAAM,MAAM,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACvC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBACjB,WAAW,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC1C,CAAC;gBACD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,YAAY,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;YAED,8DAA8D;YAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,CAAC;YACxD,IAAI,UAAU,GAAG,IAAI,EAAE,CAAC;gBACtB,MAAM,YAAY,CAAC,qBAAqB,CACtC,uCAAuC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAC1I,EAAE,IAAI,EAAE,qBAAqB,EAAE,SAAS,EAAE,CAC3C,CAAC;YACJ,CAAC;YAED,0EAA0E;YAC1E,kEAAkE;YAClE,kCAAkC;YACjC,SAAiB,CAAC,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC;YAEpD,uBAAuB;YACvB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAC1C,qBAAqB,EACrB,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACjB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,SAAgB,EAAE,SAAS,CAAC,CAAC;gBAEnF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBACjB,MAAM,QAAQ,CAAC,KAAK,CAAC;gBACvB,CAAC;gBAED,OAAO,QAAQ,CAAC,IAAI,CAAC;YACvB,CAAC,CACF,CAAC;YAEF,6BAA6B;YAC7B,OAAQ,MAAc,CAAC,YAAY,IAAK,MAAc,CAAC;QACzD,CAAC,CACF,CAAC;QAEF,OAAO,OAAO,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"journalentry-create.js","sourceRoot":"","sources":["../../../src/tools/journal-entry/journalentry-create.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAI7D;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kGAiDmF;IAEhG,WAAW,EAAE,6BAA6B;IAC1C,YAAY,EAAE,8BAA8B;IAE5C,KAAK,CAAC,OAAO,CACX,KAAoD,EACpD,MAA+B;QAE/B,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CACtC,qBAAqB,EACrB,KAAK,EAAE,KAAoD,EAAE,QAAqB,EAAE,EAAE;YACpF,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;YAE5E,qCAAqC;YACrC,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,IAAI,YAAY,GAAG,CAAC,CAAC;YAErB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBACjB,WAAW,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC1C,CAAC;gBACD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,YAAY,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;YAED,8DAA8D;YAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,CAAC;YACxD,IAAI,UAAU,GAAG,IAAI,EAAE,CAAC;gBACtB,MAAM,YAAY,CAAC,qBAAqB,CACtC,uCAAuC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAC1I,EAAE,IAAI,EAAE,qBAAqB,EAAE,SAAS,EAAE,CAC3C,CAAC;YACJ,CAAC;YAED,mEAAmE;YACnE,sEAAsE;YACtE,uEAAuE;YACvE,2EAA2E;YAC3E,4EAA4E;YAC5E,yEAAyE;YACzE,0EAA0E;YAC1E,uEAAuE;YACvE,uEAAuE;YACvE,0EAA0E;YAC1E,MAAM,IAAI,GAAG;gBACX,aAAa,EAAE;oBACb,IAAI;oBACJ,iBAAiB,EAAE,IAAI;oBACvB,aAAa,EAAE,YAAY,IAAI,KAAK;oBACpC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC3B,aAAa,EAAE,CAAC,CAAC,YAAY;wBAC7B,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACpD,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBACxD,CAAC,CAAC;iBACJ;aACF,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAC7C,MAAM,EACN,uBAAuB,SAAS,kCAAkC,EAClE,IAAI,EACJ,qBAAqB,CACtB,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,MAAM,MAAM,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnE,CAAC;YAED,4EAA4E;YAC5E,0DAA0D;YAC1D,MAAM,EAAE,GAAI,MAAM,CAAC,IAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,IAAI,MAAM,CAAC,IAAI,CAAC;YAEhF,OAAO;gBACL,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,OAAO;gBACvB,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,WAAW,EAAE,EAAE,CAAC,WAAW,IAAI,WAAW;gBAC1C,IAAI,EAAE,EAAE,CAAC,iBAAiB,IAAI,IAAI;gBAClC,YAAY,EAAE,EAAE,CAAC,aAAa;gBAC9B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;oBAChC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;wBAC1B,YAAY,EAAE,CAAC,CAAC,aAAa;wBAC7B,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,SAAS;wBAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,SAAS;wBAC7B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS;qBACxC,CAAC,CAAC;oBACL,CAAC,CAAC,EAAE;aAC2C,CAAC;QACtD,CAAC,CACF,CAAC;QAEF,OAAO,OAAO,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"project-update.d.ts","sourceRoot":"","sources":["../../../src/tools/project/project-update.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGnF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA6CnB,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,UACvC,uBAAuB,GAC9B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;CA+CtD,CAAC;AAEF;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,EAC/C,OAAO,EAAE;IAAE,MAAM,EAAE,uBAAuB,CAAA;CAAE,GAC3C,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAEpD"}
1
+ {"version":3,"file":"project-update.d.ts","sourceRoot":"","sources":["../../../src/tools/project/project-update.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGnF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA6CnB,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,UACvC,uBAAuB,GAC9B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;CA2FtD,CAAC;AAqBF;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,EAC/C,OAAO,EAAE;IAAE,MAAM,EAAE,uBAAuB,CAAA;CAAE,GAC3C,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAEpD"}
@@ -53,37 +53,72 @@ for new time entries.`,
53
53
  async execute(input, client) {
54
54
  const handler = ErrorHandler.wrapHandler("project_update", async (input, _context) => {
55
55
  const { businessId, projectId, ...updates } = input;
56
- // Build update object using camelCase properties
57
- // The FreshBooks SDK's transformProjectRequest() will convert to API format
58
- const project = {};
59
- if (updates.title !== undefined)
60
- project.title = updates.title;
61
- if (updates.clientId !== undefined)
62
- project.clientId = updates.clientId;
63
- if (updates.description !== undefined)
64
- project.description = updates.description;
65
- if (updates.dueDate !== undefined)
66
- project.dueDate = updates.dueDate;
67
- if (updates.budget !== undefined)
68
- project.budget = updates.budget;
69
- if (updates.fixedPrice !== undefined)
70
- project.fixedPrice = updates.fixedPrice;
71
- if (updates.rate !== undefined)
72
- project.rate = updates.rate;
73
- if (updates.billingMethod !== undefined)
74
- project.billingMethod = updates.billingMethod;
75
- if (updates.projectType !== undefined)
76
- project.projectType = updates.projectType;
77
- if (updates.internal !== undefined)
78
- project.internal = updates.internal;
79
- if (updates.projectManagerId !== undefined)
80
- project.projectManagerId = updates.projectManagerId;
81
- if (updates.active !== undefined)
82
- project.active = updates.active;
83
- if (updates.complete !== undefined)
84
- project.complete = updates.complete;
56
+ // Require at least one field to change (otherwise the round-trip is wasted
57
+ // and the intent is ambiguous).
58
+ const changedFields = Object.keys(updates).filter((k) => updates[k] !== undefined);
59
+ if (changedFields.length === 0) {
60
+ throw ErrorHandler.createValidationError("No fields provided to update. Please specify at least one field to change.", { tool: "project_update", businessId, projectId });
61
+ }
85
62
  // Execute the API call
86
63
  const result = await client.executeWithRetry("project_update", async (fbClient) => {
64
+ // Read-modify-write: the Projects API 500s ("An internal error has
65
+ // occurred", #70) on a partial PUT — it requires the full editable
66
+ // representation. Fetch the current project, overlay the user's
67
+ // changes, and send the complete object. (Mirrors expense_update.)
68
+ const existingResponse = await fbClient.projects.single(businessId, projectId);
69
+ if (!existingResponse.ok) {
70
+ throw existingResponse.error;
71
+ }
72
+ // projects.single returns the SDK-parsed project directly (not wrapped).
73
+ const existing = (existingResponse.data.project ??
74
+ existingResponse.data);
75
+ // Seed the payload from the existing EDITABLE fields only. Read-only /
76
+ // computed fields (sample, loggedDuration, billedAmount, billedStatus,
77
+ // retainerId, expenseMarkup, group, services, timestamps) are
78
+ // intentionally omitted — echoing them back is what triggers the 500.
79
+ const project = {
80
+ title: existing.title,
81
+ description: existing.description,
82
+ // The SDK parses due_date into a JS Date; the API wants "YYYY-MM-DD".
83
+ dueDate: toApiDate(existing.dueDate),
84
+ clientId: existing.clientId,
85
+ internal: existing.internal,
86
+ budget: existing.budget,
87
+ fixedPrice: existing.fixedPrice,
88
+ rate: existing.rate,
89
+ billingMethod: existing.billingMethod,
90
+ projectType: existing.projectType,
91
+ projectManagerId: existing.projectManagerId,
92
+ active: existing.active,
93
+ complete: existing.complete,
94
+ };
95
+ // Overlay only the fields the user provided.
96
+ if (updates.title !== undefined)
97
+ project.title = updates.title;
98
+ if (updates.clientId !== undefined)
99
+ project.clientId = updates.clientId;
100
+ if (updates.description !== undefined)
101
+ project.description = updates.description;
102
+ if (updates.dueDate !== undefined)
103
+ project.dueDate = updates.dueDate;
104
+ if (updates.budget !== undefined)
105
+ project.budget = updates.budget;
106
+ if (updates.fixedPrice !== undefined)
107
+ project.fixedPrice = updates.fixedPrice;
108
+ if (updates.rate !== undefined)
109
+ project.rate = updates.rate;
110
+ if (updates.billingMethod !== undefined)
111
+ project.billingMethod = updates.billingMethod;
112
+ if (updates.projectType !== undefined)
113
+ project.projectType = updates.projectType;
114
+ if (updates.internal !== undefined)
115
+ project.internal = updates.internal;
116
+ if (updates.projectManagerId !== undefined)
117
+ project.projectManagerId = updates.projectManagerId;
118
+ if (updates.active !== undefined)
119
+ project.active = updates.active;
120
+ if (updates.complete !== undefined)
121
+ project.complete = updates.complete;
87
122
  const response = await fbClient.projects.update(project, businessId, projectId);
88
123
  if (!response.ok) {
89
124
  throw response.error;
@@ -97,6 +132,24 @@ for new time entries.`,
97
132
  return handler(input, { businessId: input.businessId });
98
133
  },
99
134
  };
135
+ /**
136
+ * Coerce a project due_date (which the SDK parses into a JS Date) back to the
137
+ * "YYYY-MM-DD" string the Projects API expects. Passes through strings/null and
138
+ * never throws on an invalid value (returns null rather than crash the update).
139
+ */
140
+ function toApiDate(value) {
141
+ if (value === null || value === undefined) {
142
+ return null;
143
+ }
144
+ if (value instanceof Date) {
145
+ return Number.isNaN(value.getTime()) ? null : value.toISOString().slice(0, 10);
146
+ }
147
+ if (typeof value === "string") {
148
+ // Already "YYYY-MM-DD" — keep as-is; otherwise take the date portion.
149
+ return value.slice(0, 10);
150
+ }
151
+ return null;
152
+ }
100
153
  /**
101
154
  * Wrapped handler for backward compatibility with tests
102
155
  */
@@ -1 +1 @@
1
- {"version":3,"file":"project-update.js","sourceRoot":"","sources":["../../../src/tools/project/project-update.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project-update.js","sourceRoot":"","sources":["../../../src/tools/project/project-update.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodsamsoftware/freshbooks-mcp",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "FreshBooks MCP server providing 1:1 parity with the FreshBooks Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/server.js",