github akutishevsky/lunchmoney-mcp mcpb-2.2.0
MCPB-2.2.0

4 hours ago

[2.2.0] - 2026-08-01

Security

  • attach_file_to_transaction no longer reads arbitrary files (#16). The tool passed the caller-supplied file_path straight to readFile with no confinement, and its MIME allow-list checked a caller-supplied content_type rather than the file, so any readable path — ~/.ssh/id_rsa, a .env, /etc/passwd — could be uploaded to the LunchMoney attachments endpoint and retrieved again via get_transaction_attachment_url. Four changes:
    • The attachment type is now determined by sniffing the file's leading bytes, and the header is checked before the rest of the file is read. Non-media files are rejected without ever being buffered.
    • New optional LUNCHMONEY_ATTACHMENTS_DIR confines reads to one directory, enforced after realpath so .. traversal and symlink escapes are both caught. Unset leaves reads unconfined, which preserves existing desktop behaviour; remote/HTTP deployments should always set it.
    • Size is now checked via stat before any bytes are buffered, and non-regular files are rejected — previously readFile("/dev/zero") would grow unbounded and exhaust memory. The file is opened with O_NONBLOCK, because a read-only open(2) on a FIFO blocks until a writer appears; without it a caller could hang a request indefinitely, pin a libuv threadpool thread, and prevent clean shutdown.
    • Filesystem errors are logged to stderr but reported to the caller generically, so failed reads no longer distinguish ENOENT from EACCES and leak filesystem structure.

Added

  • Balance history tools — Get and manage monthly balance snapshots across all accounts (used by the Net Worth views). Nine new tools: get_balance_history, get_account_balance_history, upsert_account_balance_history, delete_account_balance_history, get_crypto_synced_balance_history, upsert_crypto_synced_balance_history, delete_crypto_synced_balance_history, delete_balance_history_entry, update_deleted_account_details. Tool count grows from 41 to 50.
  • Test suite (npm test), the project's first. Runs on Node's built-in test runner over the compiled output, so it typechecks as well. 78 tests covering src/attachments.ts — content sniffing, path confinement, resource limits — plus the attach_file_to_transaction tool boundary driven through a real MCP client over an in-memory transport. Every regression described in this release has a test pinning it. Wired into CI via .github/workflows/test.yml.
  • Automated publishing — pushes to main publish to npm and the MCP Registry when package.json carries a version that is not yet published, so non-release commits are a no-op (.github/workflows/publish-mcp.yml).

Changed

  • Attachment reading moved out of src/tools/transactions.ts into src/attachments.ts, so it can be unit-tested without standing up an McpServer. No behaviour change.
  • attach_file_to_transaction's content_type parameter is now an optional enum of the allowed types and is treated as an assertion: the file's real type always wins, and a mismatch is rejected rather than silently corrected. Previously it selected the declared type outright. HEIC and HEIF are exempt from the mismatch check, since the ISO-BMFF major brand does not reliably distinguish them (many .HEIC files, iOS ones included, carry mif1).
  • Updated to TypeScript 7 and refreshed dependencies.

Fixed

  • %PDF- is no longer required at byte 0. The PDF spec tolerates leading bytes and conforming readers scan for the marker, so PDFs from scanners that emit a preamble were being rejected.
  • An unset optional user_config field in a .mcpb install arrives as the literal ${user_config.LUNCHMONEY_ATTACHMENTS_DIR} template rather than being omitted. That string is truthy, so it was treated as a configured directory and made attach_file_to_transaction fail for every Claude Desktop user who left the field blank. Unsubstituted templates are now treated as unset.

Don't miss a new lunchmoney-mcp release

NewReleases is sending notifications on new releases.