[4.0.0] - 2026-11-08
Breaking change. Spec parity pass against the LunchMoney v2 OpenAPI spec (2.11.1). Every tool now exposes the request fields the spec defines, accepts null where the spec marks a field nullable and null has meaning, enforces the spec's pairing, exclusivity and min-one-field rules before any request is sent, and validates currencies, amounts, IDs and dates with shared validators (src/schemas.ts). Tool count grows from 59 to 65.
Breaking
Inputs that previously reached the API and failed (or were silently coerced) are now rejected by the tool with a clear message. Valid calls are unchanged unless listed below.
- Amounts are no longer coerced.
null,""and non-numeric strings are rejected for transaction, budget, balance and manual-account amounts. Strings may have at most 4 decimal places. Numbers and strings are forwarded as supplied. - Currencies are validated against the spec's 167-code enum. Input is lowercased first, so
USDis accepted and sent asusd. Unknown codes are rejected. Previously any three-character string passed through. - Date ranges must be paired.
get_transactions,get_recurring_items,get_single_recurring_itemandtrigger_plaid_fetchrejectstart_datewithoutend_date(or the reverse).get_balance_history,get_account_balance_historyandget_crypto_synced_balance_historyreject a lonestart_monthorend_month, and rejectend_monthearlier thanstart_month. - Min-one-field PUT bodies return an error instead of an empty request.
update_tag,update_category,update_transaction,update_transactions_bulkandupdate_manual_accountnow refuse calls with no writable field.update_manual_cryptokeeps refusing an empty body: the spec allows{}, but the live API rejects it. - Mutually exclusive fields are rejected.
create_transactionsrejectsmanual_account_idandplaid_account_idtogether. Transaction updates rejecttag_idstogether withadditional_tag_ids.create_manual_accountandupdate_manual_accountrejectclosed_onunless the status isclosed. - Shape-level changes:
get_transactions,get_recurring_itemsandget_single_recurring_itemdate params, and thetrigger_plaid_fetchdate params, accept onlyYYYY-MM-DD.closed_onaccepts onlyYYYY-MM-DD, not the spec's date-time alternative.- IDs must be integers within int32. Transaction, group and attachment IDs must be positive integers. Fractional and out-of-range IDs are rejected.
split_transactioncategory_id: nullnow sends an uncategorized child. Previouslynullwas coerced to0.create_categoryandupdate_categorychildrenno longer treat numeric-looking strings such as"315174"as IDs. Pass IDs as JSON numbers.
delete_categoryanddelete_tagreturnisError: trueon a 422. The dependents payload is still included, with a hint to setforce=true. Previously this was a success-shaped result.- The 140-character payee cap on transaction writes was removed. The spec defines no limit, and the live API accepts longer payees. The 350-character notes cap stays: the spec is silent on it, but the live API rejects notes of 350+ characters.
Added
- Six settings tools for the spec's
/me/*settings endpoints:get_account_settingsandupdate_account_settings: account-wide currencies, locale, display name and rule automation.get_user_settingsandupdate_user_settings: user-wide date and time display preferences.get_user_account_settingsandupdate_user_account_settings: transaction review behaviour and the default manual account.- The update tools need at least one field. Note that the spec marks all three PUT request schemas and the format enums as
x-internal, so public support for the writes is uncertain.
searchonget_supported_cryptocurrencies. The endpoint returns well over a thousand coins and takes no filters, so the tool now filters by symbol, name or CoinGecko id whensearchis given, with exact symbol matches first.- Shared validators in
src/schemas.ts:currency,locale,amount,cryptoBalance,id,isoDate, and the user-settings format enums. - Missing request fields from the spec:
create_manual_accountandupdate_manual_account:status,external_id,custom_metadata.create_category:order,collapsed.update_category:archived_at,collapsed.update_tag:archived_at.upsert_account_balance_historyandupsert_crypto_synced_balance_historybalances: optionalidandto_base, which the server ignores.create_transactions:custom_metadatagained a 4096-character limit, enforced on the stringified value.
- Nullable fields where the spec allows
null:display_nameandinstitution_nameon manual accounts,subtypeon manual account updates,closed_onon create and update,descriptionon categories,noteson budgets (sendingnullclears it),display_nameandinstitution_nameon create-manual-crypto,symbolon balance-history entries,category_idandnoteson split children, anddefault_manual_account_id. - Budget summary and settings descriptions now state the spec's rules: occurrences are returned only for aligned responses,
aligned=falseranges may havenullbudgeted and available values, and currency and locale come from the account settings endpoint. - Plaid fetch 425 handling.
trigger_plaid_fetchreturns a clear error for425 Too Early, saying the account'slast_fetchmust be over a minute old. Its 202 message tells the model to verify the fetch againstlast_fetchand the other timestamps. - Test suite coverage for the shared validators (
test/schemas.test.mjs) and for the pre-request constraint rejections (test/constraints.tool.test.mjs).
Fixed
- Budget
upsert_budgetandremove_budgetcategory_idand dates are validated against the spec's int32 andYYYY-MM-DDrules. Previously fractional IDs and unpadded dates were forwarded. - The flat
budgetInvalidPeriodErrorObject400 response from the budgets API is now formatted with itsrequested_start_date,previous_valid_start_dateandnext_valid_start_datevalues, instead of falling through to a generic message. - Balance-history
balancevalues are forwarded as the caller supplied them. Numbers are no longer stringified, and string forms are validated instead of coerced. get_single_manual_crypto,update_manual_cryptoand the other crypto ID params now use the shared int32 ID validator.- Response types in
src/types.tsnow match the spec:Category.collapsedis a required boolean, child categories are alwayscollapsed: false, and the per-categoryrollover_poolwas removed because the spec defines it only at the top level of the summary response. AddedAccountSettings,UserSettingsandUserAccountSettings.