diff --git a/package-lock.json b/package-lock.json index 698e4fc..d558220 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.25.3", "decimal.js": "^10.4.3", - "ynab": "^1.35.0", + "ynab": "^2.10.0", "zod": "^3.23.8" }, "bin": { @@ -5212,15 +5212,15 @@ "license": "ISC" }, "node_modules/ynab": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/ynab/-/ynab-1.55.0.tgz", - "integrity": "sha512-i5MEPWpMILUiqQ9JXFBa//ljGEAtVziyx2C1s09THWoPu8b1R7k/NjDQRsM3YpYUDFTDyKRTmKOA+vxzkkK9dQ==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/ynab/-/ynab-2.10.0.tgz", + "integrity": "sha512-zDH++4mbFpVDbDW1qIYS3pG3sPVtdth7c45aEfU7pVNqIcK6aVzK8eSksyOarrzaPKSq4OA9AXq1ixC7WGdpow==", "license": "Apache-2.0", "dependencies": { "fetch-ponyfill": "^7.1.0" }, "engines": { - "node": "<=18" + "node": ">=14" } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index 0104257..6a17aaf 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.25.3", "decimal.js": "^10.4.3", - "ynab": "^1.35.0", + "ynab": "^2.10.0", "zod": "^3.23.8" }, "devDependencies": { diff --git a/src/tools/budgets/get-budget-settings.ts b/src/tools/budgets/get-budget-settings.ts index 61411f7..a53e1e1 100644 --- a/src/tools/budgets/get-budget-settings.ts +++ b/src/tools/budgets/get-budget-settings.ts @@ -43,6 +43,14 @@ Returns currency format, date format, and currency ISO code.`, // Handler function /** * Handler for the ynab_get_budget_settings tool. + * + * @param args - Tool arguments containing optional budget_id + * @param client - YNAB client instance for API calls + * @returns JSON string with budget settings including date_format and currency_format + * + * @remarks + * SDK v2 made date_format and currency_format nullable. This handler returns null + * for missing formats rather than empty strings to preserve semantic meaning. */ export async function handleGetBudgetSettings( args: Record, @@ -54,21 +62,26 @@ export async function handleGetBudgetSettings( const response = await client.getBudgetSettingsById(budgetId); const settings = response.data.settings; + const dateFormat = settings.date_format; + const currencyFormat = settings.currency_format; + return JSON.stringify( { budget_id: sanitizeString(budgetId) ?? '', settings: { - date_format: sanitizeString(settings.date_format.format) ?? '', - currency_format: { - iso_code: sanitizeString(settings.currency_format.iso_code) ?? '', - example_format: sanitizeString(settings.currency_format.example_format) ?? '', - decimal_digits: settings.currency_format.decimal_digits, - decimal_separator: sanitizeString(settings.currency_format.decimal_separator) ?? '', - symbol_first: settings.currency_format.symbol_first, - group_separator: sanitizeString(settings.currency_format.group_separator) ?? '', - currency_symbol: sanitizeString(settings.currency_format.currency_symbol) ?? '', - display_symbol: settings.currency_format.display_symbol, - }, + date_format: dateFormat?.format ? sanitizeString(dateFormat.format) : null, + currency_format: currencyFormat + ? { + iso_code: sanitizeString(currencyFormat.iso_code) ?? '', + example_format: sanitizeString(currencyFormat.example_format) ?? '', + decimal_digits: currencyFormat.decimal_digits, + decimal_separator: sanitizeString(currencyFormat.decimal_separator) ?? '', + symbol_first: currencyFormat.symbol_first, + group_separator: sanitizeString(currencyFormat.group_separator) ?? '', + currency_symbol: sanitizeString(currencyFormat.currency_symbol) ?? '', + display_symbol: currencyFormat.display_symbol, + } + : null, }, }, null, diff --git a/src/tools/transactions/create-transaction.ts b/src/tools/transactions/create-transaction.ts index 4e46007..b92a8a3 100644 --- a/src/tools/transactions/create-transaction.ts +++ b/src/tools/transactions/create-transaction.ts @@ -122,6 +122,16 @@ Amount should be negative for expenses/outflows and positive for income/inflows. // Handler function /** * Handler for the ynab_create_transaction tool. + * + * @param args - Tool arguments including account_id, date, amount, and optional fields + * @param client - YNAB client instance for API calls + * @returns JSON string with created transaction details + * @throws Error if transaction creation fails + * + * @remarks + * Uses ynab.NewTransaction type (SDK v2) for creating transactions. + * Enum types are cast to ynab.TransactionClearedStatus and ynab.TransactionFlagColor. + * Security checks (rate limiting, write permission, audit logging) are handled by YnabClient. */ export async function handleCreateTransaction( args: Record, @@ -131,7 +141,7 @@ export async function handleCreateTransaction( const budgetId = client.resolveBudgetId(validated.budget_id); // Build transaction data, only including defined fields - const transactionData: ynab.SaveTransaction = { + const transactionData: ynab.NewTransaction = { account_id: validated.account_id, date: validated.date, amount: toMilliunits(validated.amount), @@ -142,10 +152,10 @@ export async function handleCreateTransaction( if (validated.category_id !== undefined) transactionData.category_id = validated.category_id; if (validated.memo !== undefined) transactionData.memo = validated.memo; if (validated.cleared !== undefined) - transactionData.cleared = validated.cleared as unknown as ynab.SaveTransaction.ClearedEnum; + transactionData.cleared = validated.cleared as ynab.TransactionClearedStatus; if (validated.approved !== undefined) transactionData.approved = validated.approved; if (validated.flag_color !== undefined) - transactionData.flag_color = validated.flag_color as unknown as ynab.SaveTransaction.FlagColorEnum; + transactionData.flag_color = validated.flag_color as ynab.TransactionFlagColor; const response = await client.createTransaction(budgetId, { transaction: transactionData, diff --git a/src/tools/transactions/create-transactions.ts b/src/tools/transactions/create-transactions.ts index 8f9ee7e..e9c756f 100644 --- a/src/tools/transactions/create-transactions.ts +++ b/src/tools/transactions/create-transactions.ts @@ -96,6 +96,15 @@ Use import_id to prevent duplicate imports.`, // Handler function /** * Handler for the ynab_create_transactions tool. + * + * @param args - Tool arguments including transactions array (max 100) + * @param client - YNAB client instance for API calls + * @returns JSON string with created transactions and duplicate info + * + * @remarks + * Uses ynab.NewTransaction type (SDK v2) for bulk transaction creation. + * Enum types are cast to ynab.TransactionClearedStatus and ynab.TransactionFlagColor. + * Security checks (rate limiting, write permission, audit logging) are handled by YnabClient. */ export async function handleCreateTransactions( args: Record, @@ -105,8 +114,8 @@ export async function handleCreateTransactions( const budgetId = client.resolveBudgetId(validated.budget_id); // Convert transactions to YNAB format - const ynabTransactions: ynab.SaveTransaction[] = validated.transactions.map((t) => { - const txn: ynab.SaveTransaction = { + const ynabTransactions: ynab.NewTransaction[] = validated.transactions.map((t) => { + const txn: ynab.NewTransaction = { account_id: t.account_id, date: t.date, amount: toMilliunits(t.amount), @@ -116,10 +125,10 @@ export async function handleCreateTransactions( if (t.payee_name !== undefined) txn.payee_name = t.payee_name; if (t.category_id !== undefined) txn.category_id = t.category_id; if (t.memo !== undefined) txn.memo = t.memo; - if (t.cleared !== undefined) txn.cleared = t.cleared as unknown as ynab.SaveTransaction.ClearedEnum; + if (t.cleared !== undefined) txn.cleared = t.cleared as ynab.TransactionClearedStatus; if (t.approved !== undefined) txn.approved = t.approved; if (t.flag_color !== undefined) - txn.flag_color = t.flag_color as unknown as ynab.SaveTransaction.FlagColorEnum; + txn.flag_color = t.flag_color as ynab.TransactionFlagColor; if (t.import_id !== undefined) txn.import_id = t.import_id; return txn; diff --git a/src/tools/transactions/update-transaction.ts b/src/tools/transactions/update-transaction.ts index 76ff4b3..d1e61a4 100644 --- a/src/tools/transactions/update-transaction.ts +++ b/src/tools/transactions/update-transaction.ts @@ -136,6 +136,15 @@ Only provide the fields you want to change.`, // Handler function /** * Handler for the ynab_update_transaction tool. + * + * @param args - Tool arguments including transaction_id and fields to update + * @param client - YNAB client instance for API calls + * @returns JSON string with updated transaction details + * + * @remarks + * Uses ynab.SaveTransactionWithOptionalFields type (SDK v2) for partial updates. + * Enum types are cast to ynab.TransactionClearedStatus and ynab.TransactionFlagColor. + * Security checks (rate limiting, write permission, audit logging) are handled by YnabClient. */ export async function handleUpdateTransaction( args: Record, @@ -155,12 +164,10 @@ export async function handleUpdateTransaction( if (validated.category_id !== undefined) updateData.category_id = validated.category_id; if (validated.memo !== undefined) updateData.memo = validated.memo; if (validated.cleared !== undefined) - updateData.cleared = - validated.cleared as unknown as ynab.SaveTransactionWithOptionalFields.ClearedEnum; + updateData.cleared = validated.cleared as ynab.TransactionClearedStatus; if (validated.approved !== undefined) updateData.approved = validated.approved; if (validated.flag_color !== undefined) - updateData.flag_color = - validated.flag_color as unknown as ynab.SaveTransactionWithOptionalFields.FlagColorEnum | null; + updateData.flag_color = validated.flag_color as ynab.TransactionFlagColor | null; const response = await client.updateTransaction(budgetId, validated.transaction_id, { transaction: updateData,