@notsuhas/moneylover-kit

中文文档
0.5.4发布于 2026/11/02MITTypeScriptES Module构建来源已验证

Unofficial Money Lover client, CLI and MCP server. Full transaction CRUD.

原始使用文档
文档目录15 节
  1. Why this exists
  2. Install
  3. CLI
  4. Lending
  5. MCP server
  6. Library
  7. One mobile session
  8. The one thing to know before you start
  9. Environment
  10. Docs
  11. Contributing
  12. Licence
  13. Transaction times
  14. npm trusted publishing setup
  15. Persistent MCP reads

moneylover-kit

npm

Unofficial Money Lover client, CLI and MCP server. Full transaction CRUD, lending, and a documented API — from your email and password, with nothing else to set up.

Not affiliated with Money Lover or Finsify. Money Lover has no public API; this talks to the same endpoints its own apps use.

Why this exists

Other Money Lover clients can create and read transactions. None of them can update or delete one, because the wire format is a full replace — a naive edit silently wipes the people, the event, the exclude-from-report flag and the reminder attached to the row. This rebuilds every write from the live row, so an edit changes only what you asked it to.

It also documents the parts that cost real time to work out: why a wrong category id hangs for two minutes instead of erroring, why an empty result isn't an empty account, and why logging in twice can sign you out of your own phone. See docs/traps.md.

Install

npm install -g @notsuhas/moneylover-kit    # or npx @notsuhas/moneylover-kit

To run it from source instead, clone and build — npm install -g github:notsuhas/moneylover-kit does not work, because npm skips devDependencies when preparing a git dependency and leaves no compiler to build with:

git clone https://github.com/notsuhas/moneylover-kit && cd moneylover-kit
npm ci && npm run build && npm install -g .

Then set your credentials:

export MONEYLOVER_EMAIL="[email protected]"
export MONEYLOVER_PASSWORD="…"

CLI

moneylover login                 # once — mints and caches a token
moneylover wallets               # names and balances
moneylover categories            # what you can write to
moneylover list --note coffee --from 2026-01-01 --limit 10

moneylover add  --wallet Cash --category Groceries --amount -480 --note "DMart"
moneylover edit <id> --note "DMart, cleaning supplies"
moneylover rm   <id>

Wallets and categories too:

moneylover add-wallet   --name Travel --currency 11
moneylover add-category --name Supplements --all-wallets --parent "Health"
moneylover edit-category --category Supplements --name Vitamins
moneylover rm-category  --category Vitamins

--all-wallets and --parent need --backend mobile: a category that spans every wallet, or nests under another, lives in a layer the web API doesn't model.

Amounts are signed: -480 is spent, 4500 is earned. Money Lover stores the direction in the category rather than the amount, so a sign that disagrees with the category is rejected instead of quietly corrected.

--json on any command gives machine-readable output.

Lending

Money Lover tracks money between people in four of its own system categories. This wraps them, so the app's debt view sees what you record:

moneylover lend    --person Sam --amount 5000 --wallet Savings
moneylover collect --person Sam --amount 3000 --wallet Current --parent-id ORIGINAL_LOAN_ID
moneylover lending
person                          lent   collected   outstanding     you owe
Sam                          5000.00     3000.00       2000.00        0.00
Jordan                        800.00      800.00          0.00      450.00

The wallet is per leg, so lending from one account and being paid back into a different one is normal — the balance is tracked against the person, not the account. borrow and repay are the mirror for money you owe. Collections and repayments require --parent-id pointing to the original loan or debt. Split a payment across originals when necessary; standalone offsets are rejected because they leave the app’s original records open.

MCP server

Two transports. Both expose the same tools: list_wallets, list_categories, list_events, search_transactions, add_transaction, edit_transaction, delete_transaction, record_lending, lending_summary.

Managing wallets, categories and events is opt-in, behind two flags: MONEYLOVER_MCP_ALLOW_STRUCTURE=1 for creating and editing them, and MONEYLOVER_MCP_ALLOW_DELETE=1 for delete_wallet and delete_category. A rename can be typed back; deleting a wallet takes every transaction in it and neither API has an undo, which is why it is its own switch.

Local, for Claude Desktop / Cursor — add to your MCP config:

{
  "mcpServers": {
    "moneylover": {
      "command": "npx",
      "args": ["-y", "-p", "@notsuhas/moneylover-kit", "moneylover-mcp"],
      "env": {
        "MONEYLOVER_EMAIL": "[email protected]",
        "MONEYLOVER_PASSWORD": "…"
      }
    }
  }
}

Remote, over HTTP — for running it somewhere and pointing a client at it:

MCP_TOKEN=$(openssl rand -hex 32) moneylover-mcp-http   # POST /mcp, GET /health

It refuses to start without MCP_TOKEN. This endpoint can create and delete transactions in a real account; an unauthenticated port is never the right default.

In Docker — a Dockerfile and compose.yaml are in the repo:

cp .env.example .env      # email, password, and an MCP_TOKEN
docker compose up -d      # POST localhost:8790/mcp

Mount something persistent at /config, as the compose file does. That is where the token cache lives, and without it every restart spends one of the account's device slots.

Full setup notes, including how to keep an agent from doing something irreversible: docs/mcp.md.

Library

import { createClient } from "@notsuhas/moneylover-kit";

const ml = createClient();

await ml.wallets();
await ml.transactions({ note: "coffee", from: "2026-01-01" });
await ml.addTransaction({
  wallet: "Cash",
  category: "Groceries",
  amount: -480,
});
await ml.lending("Sam");

The CLI and the MCP server are both thin layers over this, so they cannot do anything the library can't.

One mobile session

When the Android OAuth client is configured, every normal read and transaction or category write uses the mobile API. Wallet balances are derived exactly as the app derives them: sum the synced rows in integer minor units and exclude future-dated transactions. The result matched the web API for every wallet on a live 11,239-row account.

Wallet-filtered fresh searches and ordinary receipt duplicate checks/readback fetch a fresh complete snapshot of only the affected wallets, using the Android app's account_id request filter. Receipt balances reuse the verified wallet snapshot. No cross-call TTL or incremental cursor is used for this fast path, so external edits and deletions remain visible on the next operation.

Whole-account audits and linked loan/debt validation retain a full reconciliation. Interrupted pulls restart from the beginning; partial pages never become a complete snapshot. Wallet-scoped reads do not replace other wallets.

To enable mobile:

export MONEYLOVER_MOBILE_CLIENT="…"
export MONEYLOVER_MOBILE_SECRET="…"

Those are the Android app's own credentials, hardcoded in every copy of it. They aren't a secret of yours, but they're not published here — a searchable public copy is what gets them rotated, which would break every unofficial client at once. docs/api.md explains how to get them.

Without those two values the client fails clearly; it never falls back to a web login. --backend web remains an explicit diagnostic escape hatch. Wallet creation, rename and deletion use the mobile sync protocol too.

Use MONEYLOVER_MOBILE_TOKEN if you supply a token directly. Normally the cached rotating refresh token is safer because it self-renews.

The one thing to know before you start

A Money Lover account allows only a handful of devices to hold a token at once — five, currently — and every login registers another one. Nothing gets kicked off when you reach the limit; instead the next login is refused, with "Maximum device limit reached. Please log out to continue." So you don't lose data — you lose the ability to sign in at all, including on a replacement phone, until you log out from a device you still have.

So this caches your token under ~/.config/moneylover-kit/ and renews it without registering another device, so a service maintains itself with no further logins. The mobile route is non-standard: the Android app sends an empty body to oauth.moneylover.me/refresh-token with the refresh token as Bearer auth.

Set MONEYLOVER_ACCESS_TOKEN to supply a token directly and never log in.

Environment

MONEYLOVER_EMAIL · MONEYLOVER_PASSWORDcredentials
MONEYLOVER_ACCESS_TOKENuse this token, never log in
MONEYLOVER_BACKENDforce web or mobile
MONEYLOVER_MOBILE_CLIENT · MONEYLOVER_MOBILE_SECRETrequired by the mobile backend
MONEYLOVER_CONFIG_DIRwhere the token cache lives
MCP_TOKEN · MCP_PORT · MCP_HOSTHTTP MCP transport
MONEYLOVER_MCP_ALLOW_STRUCTUREMCP: wallet/category/event writes
MONEYLOVER_MCP_ALLOW_DELETEMCP: wallet/category deletes

Docs

  • docs/api.md — both APIs: auth, endpoints, item shapes
  • docs/traps.md — everything that cost a day to work out
  • docs/mcp.md — wiring the MCP server into a client
  • spec/ — OpenAPI spec for the web API, plus observed schemas

Contributing

See CONTRIBUTING.md. npm run verify runs typecheck, lint, formatting and the codebase-health gate.

Licence

MIT. Use it against your own account.

Transaction times

Write tools accept optional dateTime instead of date, for example "2026-10-19T11:10:00+09:00" for a receipt printed at 11:10 in Japan. Use a full ISO timestamp with seconds and either Z or an explicit UTC offset. Do not send both fields. Date-only calls keep their existing behavior; omitted fields on edits preserve the saved time. The CLI equivalent is --date-time '2026-10-19T11:10:00+09:00'. MCP transaction results include dateTime when a timestamp is available.

npm trusted publishing setup

The release workflow uses GitHub OIDC rather than NPM_TOKEN. Configure a trusted publisher on the npm package for this exact GitHub repository and release.yml, with direct publishing allowed and no environment restriction. Keep repository.url aligned with the repository. A newly configured publisher must complete a successful publish within two days or npm expires it.

If publishing returns E404 while package reads work, check the package's trusted publisher configuration and repository metadata before replacing tokens. Passing CI does not verify npm publish authorization; verify the release job itself.

Persistent MCP reads

MCP read tools now return local SQLite snapshots with explicit sync metadata. Pass fresh: true for an audit or latest upstream state. A stale read starts background reconciliation; receipt writes and verification always use fresh API reads. This reduces repeated provider calls without promising network latency. Node 22.13+ is required. See MCP caching for migration, response shape changes, recovery and private-volume requirements.

版本与发布记录

@notsuhas/moneylover-kit 共发布 22 个版本,首次发布于 2026/09/11;过去 12 个月发布了 22 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.5.4latest2026/11/021 天前
0.5.32026/11/021 天前
0.5.22026/11/021 天前
0.5.12026/10/295 天前
0.5.02026/10/295 天前
0.4.22026/10/295 天前

关于 @notsuhas/moneylover-kit 的常见问题

@notsuhas/moneylover-kit 是什么?

非官方的钱情人客户端,CLI和MCP服务器。完整事务CRUD。

如何安装 @notsuhas/moneylover-kit?

在项目目录运行 npm install @notsuhas/moneylover-kit,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 moneylover、moneylover-mcp、moneylover-mcp-http,可以用 npx moneylover 直接运行。

@notsuhas/moneylover-kit 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@notsuhas/moneylover-kit 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@notsuhas/moneylover-kit 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.13。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@notsuhas/moneylover-kit 可以商用吗?

@notsuhas/moneylover-kit 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@notsuhas/moneylover-kit 还在维护吗?

最新版本 0.5.4 发布于 2026/11/02(1 天前);至今共发布 22 个版本,其中过去 12 个月发布了 22 个;首次发布于 2026/09/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。