Skip to main content
Glama
cubicecho

MCP Actual

by cubicecho

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
PORTNoHTTP port.3000
DATA_DIRNoWhere the downloaded budget is cached../data (/data in Docker)
ACTUAL_SYNC_IDNoThe budget's Sync ID: Actual → Settings → Advanced settings → "Sync ID". A UUID like a1b2c3d4-…. Required.
ACTUAL_PASSWORDNoThe sync server's login password. Required.
MCP_ACTUAL_TOKENNoBearer token clients must send to /mcp. Required unless SECURE_LOCAL_NET=true.
SECURE_LOCAL_NETNo`true` runs with no auth at all (trusted networks only). Alternative to MCP_ACTUAL_TOKEN.
ACTUAL_SERVER_URLNoBase URL of the Actual sync server, scheme included, no trailing path (e.g. https://budget.example.com or http://192.168.1.50:5006). Required.
ACTUAL_TIMEOUT_MSNoDeadline for one Actual operation; bank sync gets its own, longer one.120000
ACTUAL_ENABLE_WRITESNo`false` serves only read-only tools; write tools are not advertised at all.true
ACTUAL_ENCRYPTION_PASSWORDNoOnly if the budget has end-to-end encryption enabled.
HTTP_KEEP_ALIVE_TIMEOUT_MSNoHow long an idle client connection is kept open. Above the 60 s nginx and ALB hold theirs; raise it behind a proxy that holds longer. `0` never closes one.75000

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
prompts
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_accountsA

List every account in the Actual Budget file with its current balance. Returns each account’s id, name, balance (in cents as amount and as a decimal in amountDecimal), whether it is off-budget (a tracking account), and whether it is closed — plus onBudgetTotal (open on-budget accounts) and total (all open accounts). The budget is synced with the server before reading. Balances are as of TODAY: a future-dated transaction, such as a posted schedule, is not counted, so these figures can be lower than the ones Actual’s own account screen shows. Mention that if a balance looks off rather than assuming the budget is wrong.

resolve_name_to_idA

Look up the id of an account, category, payee, or schedule by its exact name. Returns { id: null } when nothing matches — that is a normal answer, not an error, so use it to check whether something exists before creating it. Most other tools take ids, so this saves listing everything just to find one.

list_categoriesA

List every budget category with its id, name, and containing group. Categories are addressed by id by the budgeting and rule tools, so this is usually the first call when working with either. Hidden categories are excluded unless includeHidden is true.

list_schedulesA

List Actual’s scheduled (recurring) transactions with their next due date and amount. Useful context when a budget or rule looks wrong: a category may be funded for a schedule that has not posted yet.

list_tagsA

List the tags defined in this budget. Rules can match tags in transaction notes (hasTags), so this is the vocabulary available to such a rule.

get_noteA

Read the note attached to an entity (transaction, account, category, …) by its id. Returns { note: null } when there is none.

sync_budgetA

Pull the latest changes from the Actual sync server. Read tools already sync where it matters, so reach for this after editing the budget in the Actual UI and wanting those edits reflected immediately.

update_noteA

Replace the note attached to an entity by its id. Notes are free text and overwrite wholesale — read the existing note first with get_note if you mean to append to it.

run_bank_syncA

Trigger Actual’s bank sync to pull new transactions from linked accounts, optionally for one account. Slow and rate-limited by the bank, so call it deliberately rather than before every read. Fails rather than reporting a hollow success when the account does not exist, is closed, or has no bank link. Returns the accounts it actually synced — Actual does not report how many transactions arrived, so follow up with search_transactions rather than claiming a count.

search_transactionsA

Search transactions across every account, filtered by any combination of date range, account, payee, category, note text, payee-name text, amount range, and cleared/reconciled state. Amounts are integer cents and negative means an outflow. Results are newest-first and capped by limit (default 100, max 1000); when truncated is true, more matched than were returned — page with offset or narrow the filters rather than assuming you have seen everything. This is the tool for payee cleanup: it can answer "where else does this payee appear?", which the per-account listing cannot.

get_transactionsA

List every transaction in one account between two dates, with no result cap. Use search_transactions for anything cross-account or filtered; this is the exhaustive per-account read, e.g. for reconciling. Split transactions are returned as the parent followed by each of its legs (isParent / isChild), so summing every row double-counts a split — total the legs, or the parents, not both.

update_transactionA

Change a transaction’s category, payee, notes, cleared flag, date, or amount. Only the fields you pass are touched; pass null to clear a category, payee, or note. Amounts are integer cents. Returns the transaction as stored afterwards — rules may rewrite a value on write, so trust the response over the request. The main tool for recategorizing during cleanup.

list_payeesA

List every payee. With withUsage (the default) each payee also carries transactionCount and lastTransactionDate, which is what makes cleanup decisions possible — the busiest payee in a group is normally the one to merge others into. Payees with a transferAccountId represent the other side of a transfer, not a merchant, and must never be merged.

find_duplicate_payeesA

Group payees whose names differ only by case, punctuation, or a trailing store/reference number — Trader Joe’s #123 and TRADER JOES 456, for example. Each group names a suggestedTarget (the most-used member) and the other candidates, plus the reason they were grouped. Matching is exact once normalized, so an abbreviation and its expansion do NOT group: AMZN Mktp US*2H4 and Amazon are reported separately. An empty result therefore means "no name-shaped duplicates", not "no duplicates" — to find those, scan list_payees yourself and propose them to the user. The conservative rule is deliberate: a false positive here feeds an irreversible merge. This only suggests; nothing is merged. Confirm a group really is one merchant before calling merge_payees. Transfer payees are never included.

create_payeeA

Create a payee by name and return it with its new id. Check resolve_name_to_id first — creating a payee that already exists under a slightly different name is how duplicates appear in the first place.

update_payeeA

Rename a payee. Renaming is the only edit Actual’s public API exposes for payees — favorite and category-learning flags are not reachable. Renaming does not merge: to combine two payees, use merge_payees.

merge_payeesA

Merge one or more payees into a target payee: their transactions move to the target and the merged payees are removed. THIS CANNOT BE UNDONE — confirm the payees really are the same merchant before calling, and never merge a payee that has a transferAccountId, which would corrupt transfers. Takes ids, not names, so a near-miss on a name cannot silently merge the wrong thing.

describe_rule_schemaA

Return the exact structure of an Actual rule: every condition field with the operators legal for it, the action operations, how values are typed, and worked examples. Call this BEFORE create_rule or update_rule — the condition format is a strict union and an invalid field/operator pairing is rejected.

list_rulesA

List the budget’s rules with their conditions and actions. Pass payeeId to list only the rules Actual associates with that payee, which is the quick way to see why transactions for one merchant keep getting a particular category.

create_ruleA

Create a rule from conditions and actions. Call describe_rule_schema first for the exact format. Conditions reference accounts, categories, and payees by id, not name. The rule applies to future imports and edits — it does not retroactively change existing transactions.

update_ruleA

Replace a rule’s conditions and actions. This overwrites the whole rule, so send the complete set — anything omitted is dropped, not preserved. Read the current rule with list_rules first.

preview_rule_effectsA

Run the budget’s rules over EXISTING transactions without saving anything, and report the field changes they would make. Actual applies rules on import and edit only, so transactions already in the budget are untouched until you act on them — this shows what a rule would have done to them. The usual flow is create_rule, then this to check it against real data, then apply_rule_actions to make the changes stick. IMPORTANT: this reports the net effect of the ENTIRE rule set, not one rule in isolation. Actual has no per-rule preview, and rules interact by rank, so a change shown here may come from a rule other than the one you just wrote. Verify against list_rules before assuming which rule caused it. Each change gives from/to as readable names plus fromId/toId for the fields that hold ids — pass toId as the action value to apply_rule_actions. Transactions the rules would not change are omitted, so an empty entries with a non-zero scanned means the rules are a no-op here.

apply_rule_actionsA

Apply rule actions to specific transactions and SAVE the result. This is the write half of preview_rule_effects: preview first, then pass the transaction ids it returned. The actions are applied UNCONDITIONALLY to every id you pass — rule conditions are NOT evaluated here, so a wrong id is silently changed rather than skipped. Pass only ids you have actually seen, from preview_rule_effects or search_transactions; never ids you assembled yourself. Edits real transactions in bulk, at most 500 per call, and cannot be undone through this server. Actions use the same format as create_rule (see describe_rule_schema), and values are ids, not names — preview_rule_effects reports these as toId. Returns the ids actually updated, plus any that did not exist under missing.

list_budget_monthsA

List every month the budget file covers, oldest first, as YYYY-MM. Use it to find the current or most recent month before reading or setting budget amounts.

get_budget_monthA

Read one month’s budget: totals (income, budgeted, spent, balance, and toBudget — what is still unassigned) plus every category with its budgeted, spent, and balance amounts and its carryover flag. All amounts are integer cents; spending is negative. This is the tool for "am I over budget?". Income categories (isIncome: true) are different: Actual tracks money coming in as received, and leaves their budgeted/spent/balance at 0 on a standard envelope budget. Read received for those, and never report an income category as "0 spent" — the figure simply lives elsewhere.

set_budget_amountA

Set the amount budgeted to one category for one month, in integer cents. This replaces the existing amount rather than adding to it. Returns the category’s resulting budgeted/spent/balance figures so the effect is visible immediately.

set_budget_carryoverA

Turn rollover on or off for a category. With carryover on, an unspent balance rolls into the next month instead of returning to "to budget"; an overspend carries forward as a negative. IMPORTANT: this is not scoped to the one month. Actual applies the flag from the given month FORWARD to the end of the budget range, overwriting it on every later month — including ones set deliberately. The result reports only the month you named, so say what you changed rather than implying it was one month.

hold_for_next_monthA

Hold some of this month’s leftover "to budget" money back for next month, in integer cents. This ADDS to whatever is already held for that month — it does not replace it, so calling twice with 1000 leaves 2000 held. To correct a hold, call reset_budget_hold first. The amount is clamped to what is actually available, so the hold can be smaller than you asked for. Read heldAmount (how much the buffer really grew) and forNextMonth (the resulting total) rather than assuming the request landed in full; held: false means there was no surplus to hold at all.

reset_budget_holdA

Release everything held back for next month, returning it to this month’s "to budget". Safe to call when nothing is held. Returns the resulting forNextMonth, which should be 0.

list_category_groupsA

List the groups categories are filed under, with their ids and how many categories each holds. Use this to find the groupId for create_category — list_categories only names groups that already have a visible category, so a new or empty group (categoryCount: 0) is only discoverable here.

create_category_groupA

Create an empty category group to file categories under, then fill it with create_category. Groups are spending groups: Actual’s API cannot create an income group, and every budget already has the one it needs.

update_category_groupA

Rename a category group or hide/unhide it. Only the fields you pass are changed. Hiding a group hides every category in it, so list_categories will report those categories as hidden — unhide the group here rather than trying to unhide them one by one.

create_categoryA

Create a budget category inside an existing category group. Get the group id from list_category_groups, or create the group first with create_category_group. Income categories behave differently from spending ones — set isIncome only for money coming in.

update_categoryA

Rename a category, move it to another group, or hide/unhide it. Only the fields you pass are changed. Hiding keeps history intact and is the safe alternative to deleting a category you no longer use.

Prompts

Interactive templates invoked by user choice

NameDescription
explore_budgetStart here. Orients you (and the agent) around what this Actual budget contains and which tools to reach for, with the conventions that make the rest of the tools behave — ids over names, integer cents, sync before reading, and where the write gate sits.
categorize_transactionsFind transactions with no category, group them by payee, and propose a category for each — then apply the ones I approve, and optionally write rules so they categorize themselves next time.
cleanup_payeesReview payees that look like the same merchant under different names (bank noise like "AMZN Mktp US*2H4" vs "Amazon") and merge them after confirmation. Groups the candidates, shows usage counts, and never merges without asking.
backfill_ruleSafely apply a categorization (or renaming) rule to transactions already in the budget: author the rule, preview what it would change, confirm, then apply. Use this instead of calling apply_rule_actions directly — it enforces the preview-then-confirm ordering those tools rely on.

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4/5.0

Scored across 34 tools

Disambiguation5/5

Each tool targets a distinct resource+action, and the descriptions actively police boundaries (e.g., search_transactions is cross-account/filtered vs get_transactions exhaustive per-account; preview_rule_effects is read-only vs apply_rule_actions saves). list_categories/list_category_groups and list_payees/find_duplicate_payees are clearly separated by purpose. No two tools appear to do the same thing.

Naming Consistency4/5

Strong, consistent verb_noun convention throughout (sync_budget, list_accounts, create_category, update_payee, merge_payees, create_rule, apply_rule_actions). A few deviate into noun/other phrasings (describe_rule_schema, find_duplicate_payees, hold_for_next_month, resolve_name_to_id), but they remain readable and predictable.

Tool Count3/5

34 tools is heavy by the usual 3-15 guideline, sitting well into the 'too many' range. However, the domain is genuinely broad (accounts, categories, groups, payees, rules, transactions, budget months, notes), and each tool covers a distinct operation with little redundancy, making it borderline rather than bloated.

Completeness4/5

Coverage is thorough across budgeting, categories/groups, payees, rules, transactions, and notes, including lifecycle operations like create/update/merge. Gaps remain: no create/delete transaction and no account create/update (partly API limits noted in descriptions), but core read/cleanup/budgeting workflows are complete.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive