Actual MCP 1.15.0 connects to OpenID-only Actual servers and merges duplicate payees

3 hours ago

Version 1.15.0 of the Actual Budget MCP server lets it connect to Actual servers that require OpenID sign-in. It also adds a tool for merging duplicate payees, lets get-transactions search every account at once, and fixes monthly totals that left out ordinary transactions.

Ask about this presentation

Chapters

  1. 0:00Actual MCP 1.15.0
  2. 0:19Session token sign-in
  3. 0:41Finding the token
  4. 1:00merge-payees
  5. 1:21What merge-payees refuses
  6. 1:38get-transactions across accounts
  7. 1:57monthly-summary fix
  8. 2:19What looks different
  9. 2:42Upgrade
Show transcript
  1. Version 1.15.0 of the Actual Budget MCP server lets it connect to Actual servers that require OpenID sign-in. It also adds a tool for merging duplicate payees, lets get-transactions search every account at once, and fixes monthly totals that left out ordinary transactions.

    Slide text

    Actual MCP now connects to OpenID-only servers and merges duplicate payees

    actual-mcp 1.15.0 · 2026-10-15
    ADD Session token sign-in for OpenID-enforced servers NEW
    ADD merge-payees a new write tool NEW
    CHG get-transactions accountId is optional CHANGED
    FIX monthly-summary counts ordinary transactions FIXED
    actual-mcp · v1.15.0 github.com/s-stefanov/actual-mcp
  2. An Actual server can enforce OpenID login, through Google for example. Password login is then disabled, so the password the MCP server signs in with stops working. Version 1.15.0 adds a session token variable instead. You copy the token from a browser that's signed in to Actual, and if both are set, the token wins.

    Slide text

    A session token signs in where OpenID has turned off passwords

    ACTUAL_SERVER_URL=https://your-actual-server.com unchanged
    ACTUAL_PASSWORD=your-password password login disabled by ACTUAL_OPENID_ENFORCE=true
    ACTUAL_SESSION_TOKEN=your-session-token new in 1.15.0, wins over the password
    actual-mcp · v1.15.0 README · OpenID servers (session token auth)
  3. To find it, open DevTools in that browser. Under Application, then IndexedDB, the user-token key holds it. It grants full access to your budgets, so treat it like a password. When it expires, tool calls fail with this message. Sign in again, replace the token, and restart the server.

    Slide text

    Copy the token from your browser's DevTools

    Application › IndexedDB › actual › asyncStorage › user-token
    A UUID, not a long bearer token

    It grants full access to your budgets. Treat it like a password.

    When it expires, tool calls fail
    Authentication failed: invalid or expired session token

    Sign in again, replace the token, restart the server.

    actual-mcp · v1.15.0 lifetime set by the server's ACTUAL_TOKEN_EXPIRATION
  4. merge-payees takes the payee to keep and a list of duplicates. Transactions on the duplicates move to the payee you keep, and the duplicates are removed. Rules that named them keep working, because Actual maps the old IDs to the target when it loads rules. It's a write tool, so it appears only when the server runs with the enable write flag.

    Slide text

    merge-payees folds duplicates into the payee you keep

    Duplicatein mergeIds
    Duplicatein mergeIds
    →
    Payee to keeptargetId
    Their transactions move to the payee you keep
    The duplicates are removed
    Rules that named them keep working
    // merge-payees { "targetId": "<payee to keep>", "mergeIds": ["<id>", "<id>"] }
    A write tool: listed only when the server starts with --enable-write
    actual-mcp · v1.15.0 src/tools/payees/merge-payees · #253
  5. The tool checks every ID first. Transfer payees are rejected, because Actual's own merge skips them and would still report success. IDs that don't exist are rejected. And the payee you keep is dropped from the duplicate list, since merging a payee into itself would delete it.

    Slide text

    merge-payees checks every ID before it calls Actual

    A transfer payee, as the target or a duplicateActual's own merge skips these and would still report success "… is a transfer payee and cannot be merged" REJECTED
    An ID that doesn't exist "Payee … does not exist" REJECTED
    The kept payee listed as a duplicate merging a payee into itself would delete it removed from mergeIds, merge goes ahead DROPPED
    actual-mcp · v1.15.0 merge-payees/index.ts
  6. In 1.14.0, asking get-transactions for a month without naming an account stopped with an error. Now the account is optional, and leaving it out searches every account, on-budget and off-budget. Results are sorted newest first before the limit applies, so a limit keeps the most recent transactions.

    Slide text

    Leave out accountId and get-transactions searches every account

    1.14.0
    // get-transactions { "startDate": "2025-01-01", "endDate": "2025-01-31" }
    accountId is required and must be a string
    1.15.0
    // get-transactions { "startDate": "2025-01-01", "endDate": "2025-01-31" }
    Every account, on- and off-budget,
    sorted newest first before limit applies
    actual-mcp · v1.15.0 #242
  7. Actual returns ordinary, non-split transactions with an empty list of split parts. The old check read that as a split with nothing in it, so those transactions dropped out, and only the parts of real splits were counted. Now they all count. In the January test case, that's 100 dollars of income, 80 dollars of expenses, and four transactions.

    Slide text

    monthly-summary now counts ordinary transactions

    DATE CATEGORY AMOUNT BEFORE THE FIX
    2026-01-05 Salary +$100.00 SKIPPED
    2026-01-10 Groceries −$50.00 SKIPPED
    2026-01-15 SplitGroceries −$20.00 · Fuel −$10.00 −$30.00 COUNTED
    IN 1.15.0 INCOME $100.00 EXPENSES $80.00 TRANSACTIONS 4
    actual-mcp · v1.15.0 January 2026 test case · transaction-aggregator.test.ts · #252
  8. This release has zero breaking changes, but three things will look different. Monthly totals now include ordinary transactions, so they can differ from what 1.14.0 reported. With both a token and a password set, the token is used and a warning is logged. And Actual's API packages move from 26.9.0 to 26.10.0.

    Slide text

    No breaking changes, but three things look different

    FIX Monthly totals can change months with ordinary transactions won't match what 1.14.0 reported TOTALS
    ADD Token and password both set the token is used and a warning is logged TOKEN
    DEP @actual-app/api and core 26.10.0 up from 26.9.0 26.10.0
    actual-mcp · v1.15.0 #252 · #255 · #254
  9. To upgrade, pull the 1.15.0 Docker image, or run version 1.15.0 of the actual-mcp package from npm. If you switch to a session token, expect to replace it when your server's token expiration runs out. With 1.15.0, OpenID servers connect, duplicate payees merge, and monthly totals count every transaction.

    Slide text

    Upgrade to actual-mcp 1.15.0

    docker pull sstefanov/actual-mcp:v1.15.0
    or run the actual-mcp npm package at version 1.15.0
    OpenID servers connect duplicate payees merge every-account search monthly totals count every transaction
    github.com/s-stefanov/actual-mcp/releases/tag/v1.15.0
    actual-mcp · v1.15.0 github.com/s-stefanov/actual-mcp

What happened in AI today, in your inbox

One short email each evening. Read it and you’re caught up.

Built in New York with ❤️