balance-history
Get account balance history over time
Ask your Actual Budget file where the money went — by category, by month, by payee — then write the correction back: reclassify a transaction, add a rule, import a statement, or pull the latest from the bank.
LABSCO SUMMARY
The analysis tools do the arithmetic for you — spending by category, monthly income against expenses, balance history — which is what makes this usable in conversation rather than as a table dump. The write side is opt-in and complete enough to deserve that: transactions, categories, payees and rules can all be deleted, and a deleted transaction does not come back. Start it without --enable-write while you are getting a feel for it, and reach for the import tool rather than create-transaction for anything arriving in bulk, since it reconciles on imported_id and will show you the result under a dry run first.
A server over an Actual Budget file, covering transactions, categories, payees, rules and bank sync, with the write half kept behind a launch flag.
Node 16 or newer and an Actual Budget you can reach: ACTUAL_SERVER_URL and ACTUAL_PASSWORD for a remote server, ACTUAL_BUDGET_SYNC_ID for the budget file to open, and ACTUAL_DATA_DIR for the local cache, which is optional when a server URL is set. An encrypted budget takes its unlock password separately in ACTUAL_BUDGET_ENCRYPTION_PASSWORD. Every write tool stays hidden until the server is started with --enable-write. Bank sync needs the account already linked in Actual. Amounts are in cents, positive for a deposit and negative for a payment. MIT.
One command — docker pull sstefanov/actual-mcp:latest
USE CASES
Break the range down by category, compare it against the months either side, then pull the transactions behind whichever category moved.
Pull the transactions that landed in the wrong place, read the category groups to find where they belong, and set the category on each one.
Check which account you are importing into, run the import as a dry run to see what it would do, then let it reconcile on imported_id — or trigger the bank sync and skip the file entirely.
Find how the payee is recorded, read the rules already in place so the new one does not contradict them, and add the rule with its conditions and actions.
Read the current groups, add the group the new structure needs, create categories inside it, and move the existing ones over by updating their group.
Counted once with only startup setup. Other versions, modes or optional credentials may expose a different list.
balance-historyGet account balance history over time
create-categoryCreate a new category
create-category-groupCreate a new category group
create-payeeCreate a new payee
create-ruleCreate a new rule
create-transactionCreate a new transaction. Use this to add transactions to accounts. Supports transfers between accounts by specifying transfer_account_id.
delete-categoryDelete a category
delete-category-groupDelete a category group
delete-payeeDelete a payee
delete-ruleDelete a rule
delete-transactionDelete a transaction by its ID. This action is permanent and cannot be undone.
get-accountsRetrieve a list of all accounts with their current balance and ID.
get-grouped-categoriesRetrieve a list of all category groups with their id, name, type and category list.
get-payeesRetrieve a list of all payees with their id, name, categoryId and transferAccountId.
get-rulesRetrieve a list of all rules. PS amount comes in cents: positive for deposit, negative for payment
get-transactionsGet transactions for an account with optional filtering
import-transactionsImport a list of transactions into an account using reconciliation logic. Deduplicates via imported_id to prevent duplicates on repeated imports. Supports dry-run mode to preview changes without persisting them.
monthly-summaryGet monthly income, expenses, and savings
run-bank-syncRun bank synchronization (GoCardless/SimpleFIN) to download latest transactions. Provide accountId for a specific account, use "onbudget"/"offbudget" for groups, or omit to sync all linked accounts.
spending-by-categoryGet spending breakdown by category for a specified date range
update-categoryUpdate a category
update-category-groupUpdate a category group
update-payeeUpdate a payee
update-ruleUpdate a rule
update-transactionUpdate an existing transaction. Can modify date, amount, payee, category, notes, cleared status, and subtransactions.
BEFORE YOU INSTALL
25 tools when we connected. That count assumes --enable-write; without it the write tools don't load. import-transactions, which loads a bank statement, plus delete-transaction and run-bank-sync are missing from the documented feature list.
npx on PATH
CONTEXT COST
Rated by the size of the 25 tool definitions that ride along on every turn, not by how many there are
INSTALLATION
docker pull sstefanov/actual-mcp:latest{
"mcpServers": {
"actualBudget": {
"command": "npx",
"args": [
"-y",
"actual-mcp",
"--enable-write"
],
"env": {
"ACTUAL_DATA_DIR": "<YOUR_ACTUAL_DATA_DIR>",
"ACTUAL_PASSWORD": "<YOUR_ACTUAL_PASSWORD>",
"ACTUAL_SERVER_URL": "<YOUR_ACTUAL_SERVER_URL>",
"ACTUAL_BUDGET_SYNC_ID": "<YOUR_ACTUAL_BUDGET_SYNC_ID>"
}
}
}
}{
"mcpServers": {
"actualBudget": {
"command": "node",
"args": [
"<YOUR_PATH_TO_CLONE>/build/index.js",
"--enable-write"
],
"env": {
"ACTUAL_DATA_DIR": "<YOUR_ACTUAL_DATA_DIR>",
"ACTUAL_PASSWORD": "<YOUR_ACTUAL_PASSWORD>",
"ACTUAL_SERVER_URL": "<YOUR_ACTUAL_SERVER_URL>",
"ACTUAL_BUDGET_SYNC_ID": "<YOUR_ACTUAL_BUDGET_SYNC_ID>"
}
}
}
}{
"mcpServers": {
"actualBudget": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"<YOUR_PATH_TO_DATA>:/data",
"-e",
"ACTUAL_PASSWORD=<YOUR_ACTUAL_PASSWORD>",
"-e",
"ACTUAL_SERVER_URL=<YOUR_ACTUAL_SERVER_URL>",
"-e",
"ACTUAL_BUDGET_SYNC_ID=<YOUR_ACTUAL_BUDGET_SYNC_ID>",
"sstefanov/actual-mcp:latest",
"--enable-write"
]
}
}
}git clone https://github.com/s-stefanov/actual-mcp.git
cd actual-mcp
npm install
npm run buildIn the same terminal, export ACTUAL_SERVER_URL, ACTUAL_PASSWORD and ACTUAL_BUDGET_SYNC_ID (or ACTUAL_DATA_DIR for a local budget), as in the README's environment step
npm start -- --sse --port 3000Keep that terminal open, then add this to ~/.codex/config.toml:
[mcp_servers.actual-budget]
url = "http://localhost:3000"The url must use the port you passed to npm start. Add --enable-write to the npm start line if you want the write tools.