Actual MCP Server
Talk to your self-hosted Actual Budget from any MCP client: a remote HTTP server for LibreChat/LobeChat or a local stdio process for Claude Desktop, with 84 tools for transactions, budgets, rules, and bank sync. No Docker needed for local use.
Actual MCP Server is an open-source mcp server by agigante80, written mainly in JavaScript, with 74 GitHub stars and the MIT license. Its code was last updated Oct 31, 2026.
Talk to your Actual Budget in plain language: ask where the money went, and let your AI assistant make the changes you approve.
What it lets you do:
- Find where your money went, by payee, category or month.
- Compare what you spent with what you planned, and see if you are on track.
- Add, fix and categorise transactions, after you approve them.
- Tidy up accounts, payees, categories and rules, and plan the month ahead.
Ask: "How much did I spend on groceries last month, by payee?", "Am I on track this month?", "Which payees cost me the most this year?"
Ask it to change things (it confirms first): "Which uncategorised transactions look like my usual groceries? Categorise them after I confirm.", "Add a $47.50 grocery transaction at Whole Foods to my checking account.", "Move $200 from Dining Out to Emergency Fund for this month."
Works with: Claude Desktop, Claude Code, Cursor, VS Code with Copilot, Gemini CLI and Codex CLI on your own machine, and chat UIs such as LibreChat and LobeChat against a server you run in Docker (also on Unraid and in the official MCP Registry as io.github.agigante80/actual-mcp-server). It needs a client with MCP support: a hosted assistant that cannot reach your machine or private network cannot use it, and neither can a client that supports neither stdio nor HTTP MCP. Every client page: docs/guides/clients/.
Quick start
For Claude Code on your own machine, one command registers the server over stdio. It needs Node.js 22 or later and your Actual password in the ACTUAL_PASSWORD environment variable. The single quotes matter: your shell must not expand the reference, so the password never appears in the process list or in Claude Code's config.
claude mcp add --scope user actual-budget \
--env ACTUAL_SERVER_URL=http://localhost:5006 \
--env 'ACTUAL_PASSWORD=${ACTUAL_PASSWORD}' \
--env ACTUAL_BUDGET_SYNC_ID=your-sync-id-here \
--env MCP_BRIDGE_DATA_DIR=/absolute/path/to/data-dir \
-- npx -y actual-mcp-server --stdio
Replace the URL, the Sync ID (Actual: Settings, Show advanced settings, Sync ID) and the data directory, which should be a folder only you can read. Then check it under Verify your setup.
Or let Claude do it. Paste this into a Claude Code session:
Install and configure the Actual Budget MCP server for me over stdio, using
`npx -y actual-mcp-server --stdio`. Ask me for my Actual server URL and my
Sync ID. Take the password from the ACTUAL_PASSWORD environment variable that I
have already set: never ask me to type it into this chat, never echo or log it,
and never write it into a file in a repository. Create a data directory that
only my user can read, register the server for my user with `claude mcp add
--scope user`, passing the password as the literal reference
'ACTUAL_PASSWORD=${ACTUAL_PASSWORD}' in single quotes, then run the checks
under "Verify your setup" in the README.
Other clients: one page each in the client guides. Chat UIs (LibreChat, LobeChat) and several users need the HTTP path below.
Run it over HTTP (Docker)
You need an Actual Budget server and Docker. 1. Create .env with a generated token. In an empty directory:
[ -f .env ] || install -m 600 /dev/null .env
[ -z "$(tail -c 1 .env)" ] || printf '\n' >> .env
for key in ACTUAL_SERVER_URL=http://YOUR-ACTUAL-HOST:5006 ACTUAL_PASSWORD= ACTUAL_BUDGET_SYNC_ID=; do
grep -q "^${key%%=*}=" .env || printf '%s\n' "$key" >> .env
done
chmod 600 .env
if [ "$(grep -c '^MCP_SSE_AUTHORIZATION=' .env)" != 1 ] || ! grep -Eq '^MCP_SSE_AUTHORIZATION=[^[:space:]]{32,}$' .env; then
( umask 077; install -m 600 /dev/null .env.new; { grep -v '^MCP_SSE_AUTHORIZATION=' .env; printf 'MCP_SSE_AUTHORIZATION=%s\n' "$(openssl rand -hex 32)"; } > .env.new ) && mv .env.new .env
fi
grep '^MCP_SSE_AUTHORIZATION=' .env
The last line prints the Bearer token your client sends. It never overwrites a value you set, except a token that is missing, duplicated or shorter than 32 characters, so it is safe to run again.
2. Fill in .env: ACTUAL_PASSWORD, ACTUAL_BUDGET_SYNC_ID (Actual: Settings, Show advanced settings, Sync ID) and ACTUAL_SERVER_URL. The URL is read inside the container, where localhost is the container itself: use your Actual server's LAN address or domain, or http://host.docker.internal:5006 when Actual runs on the Docker host.
3. Start the server from the same directory:
<!-- runnable: docker-run -->docker run -d \
--name actual-mcp-server-backend \
-p 3600:3600 \
--add-host=host.docker.internal:host-gateway \
--env-file .env \
-v actual-mcp-data:/app/data \
-v actual-mcp-logs:/app/logs \
ghcr.io/agigante80/actual-mcp-server:latest
Check it with curl http://localhost:3600/health. The image is also on Docker Hub as agigante80/actual-mcp-server. Production flags, TLS, reverse proxies and the reason for the /app/data volume are in the deployment guide.
Docker Compose (Compose 2.24.0 or later), from a clone of this repository:
<!-- runnable: compose-production -->[ -f .env ] || install -m 600 .env.example .env
chmod 600 .env
if [ "$(grep -c '^MCP_SSE_AUTHORIZATION=' .env)" != 1 ] || ! grep -Eq '^MCP_SSE_AUTHORIZATION=[^[:space:]]{32,}$' .env; then
( umask 077; install -m 600 /dev/null .env.new; { grep -v '^MCP_SSE_AUTHORIZATION=' .env; printf 'MCP_SSE_AUTHORIZATION=%s\n' "$(openssl rand -hex 32)"; } > .env.new ) && mv .env.new .env
fi
grep '^MCP_SSE_AUTHORIZATION=' .env
docker compose --profile production up -d
On a fresh .env, fill in the three Actual settings, then run the last line again.
npx (Node.js 22 or later, no container), in a directory holding a filled-in .env from step 1, where http://localhost:5006 is right for Actual on the same machine:
npx actual-mcp-server --http
Verify your setup
- In a new conversation in your client, ask: "List my Actual Budget accounts and their balances." You should get your accounts back.
- Over HTTP,
tools/listshould return 15 tools over 85 operations (the default compact surface; 85 is the legacy surface underMCP_TOOL_SURFACE=legacy). The count comes from that HTTP check: the stdioinitializeprobe lists no tools. - For a stdio client, check the server by hand before blaming the client: send one
initializerequest and look forserverInfoin the reply. The command is in verify your setup in the client guide.
Under the hood
15 tools over 85 operations covering accounts, transactions, budgets, rules, schedules and more, over stdio or HTTP, with Bearer token or OIDC auth, per-user budget access, up to 15 concurrent sessions, and automatic retry of transient Actual errors (3 attempts, exponential backoff; deletes and merges are never retried).
Privacy
Budget data the tools return goes to whichever model provider your AI client uses. The server itself contacts only the configured Actual server and, when OIDC auth is configured, your identity provider (discovery and JWKS). Logs stay on the host you run it on. Details: security and privacy.
Compatibility
Node.js 22 or later, Actual Budget server 25.0.0 or later, and the bundled @actual-app/api (its version is in package.json and reported by get_context with topic: "version"). Requirements and upgrade steps: upgrading.
Tools
Amounts are integer cents and dates are YYYY-MM-DD strings. Each tool takes an action or report selector; the fields of every action and its caveats are in the tools reference.
Context and lookup
get_context: Read the budget structure (accounts, categories, payees) or the Actual server details in one call. Example prompt: "What accounts and categories do I have?"list_entities: List or look up accounts, categories, payees, rules, schedules, tags, notes or budget files, and resolve a name to an id. Example prompt: "List my payees whose name contains Market."
Reading transactions
search_transactions: Find transactions by date, account, category, payee or amount. Example prompt: "Show my Costco purchases over $100 this year."
Reports
summarize_transactions: Total spending and income by category, payee, account or month, find recurring expenses and read account balances. Example prompt: "How much did I spend on groceries each month this year?"
Budget months
list_budget_months: Read the list of budget months, or one month with budgeted, spent and balance per category. Example prompt: "Which categories are overspent in October 2026?"manage_budget_months: Set a month budget amount, carryover or hold, move money between categories and write the month note. Example prompt: "Move $50 from Dining Out to Groceries for this month."
Querying
run_query: Run a read-only SQL query against the budget data when no other read tool fits. Example prompt: "Run a query for my uncleared transactions over $500 since January."
Changing data
manage_transactions: Create, change, delete, import, merge or transfer transactions. Example prompt: "Add a $12.50 coffee purchase to my checking account for today."manage_accounts: Create, change, close, reopen, delete, bank-sync or annotate accounts and account groups. Example prompt: "Close my old savings account."manage_categories: Create, change, delete or annotate budget categories and category groups. Example prompt: "Create a Pets category in the Everyday group."manage_payees: Create, change, delete, merge or annotate payees. Example prompt: "Merge the payees Costco and Costco Wholesale."manage_tags: Create, change or delete tags. Example prompt: "Create a tag called vacation with a blue color."manage_rules: Create, upsert, change or delete the rules that categorize imported transactions. Example prompt: "Make a rule that files every Spotify transaction under Subscriptions."manage_schedules: Create, change or delete one-off and recurring scheduled transactions. Example prompt: "Schedule my $900 rent on the first of every month."manage_budget_files: Switch the active budget, import a budget file or export the active budget. Example prompt: "Export my budget to a file."
Reducing the tool surface
By default the server serves 15 tools over 85 operations (the compact surface, MCP_TOOL_SURFACE=compact). Set MCP_TOOL_SURFACE=legacy to publish the 85 actual_* tools instead; the toolset names and counts in the table below are operations, and a compact tool is listed when at least one operation behind it is selected. A call to an operation a toolset leaves out is refused naming MCP_TOOLSETS. Chat clients with a small tool budget (Gemini, LibreChat) do better with fewer. A tool that is not published is also refused if a client calls it by name.
| Toolset | Operations | Contents |
|---|---|---|
context | 14 | Orientation, lookups and server information |
transactions | 14 | Transaction reads, create, update, delete, import and transfers |
analysis | 7 | Summaries, aggregates and balances |
budget | 10 | Budget months, amounts, carryover, holds, transfers, batch updates and notes |
rules | 7 | Rules and payee rules, including actual_rules_create_batch |
schedules | 5 | Scheduled transactions |
structure | 21 | Accounts, account groups, categories, category groups, payees and tags |
query | 1 | actual_query_run (SELECT only) |
admin | 6 | Budget switching, import, export, bank sync and session management |
On the default compact surface the chat preset publishes 6 tools: get_context, list_budget_months, run_query, manage_transactions, manage_rules and manage_budget_months.
With MCP_TOOL_SURFACE=legacy the chat preset publishes 12 tools: actual_get_context, actual_query_run, actual_transactions_update_batch, actual_budget_updates_batch, actual_rules_create_batch, actual_transactions_create, actual_transactions_update, actual_transactions_delete, actual_rules_create, actual_budgets_transfer, actual_budgets_set_amount and actual_budgets_get_month.
MCP_READ_ONLY=true publishes 6 compact tools (get_context, list_entities, search_transactions, summarize_transactions, list_budget_months and run_query); every tool that can write is hidden whole. With MCP_TOOL_SURFACE=legacy it hides and refuses 48 write-capable tools and leaves 37 published.
How large the tools/list response is for each choice, so you can pick for a small tool budget:
| Configuration | Tools | tools/list bytes | KiB |
|---|---|---|---|
| Compact surface (default) | 15 | 41000 | 40.0 |
Compact, MCP_TOOLSETS=chat | 6 | 16658 | 16.3 |
Compact, MCP_READ_ONLY=true | 6 | 16935 | 16.5 |
MCP_TOOL_SURFACE=legacy | 85 | 120457 | 117.6 |
Legacy, MCP_TOOLSETS=chat | 12 | 24744 | 24.2 |
Legacy, MCP_READ_ONLY=true | 37 | 44582 | 43.5 |
Measured offline, as the server builds the list (the bytes of the tools/list result, not an estimate); reproduce with node scripts/measure-tools-list-size.mjs.
Example: a chat assistant with two extra tools.
MCP_TOOLSETS=chat
MCP_TOOLS=list_entities,search_transactions
A configuration that resolves to zero tools refuses to start. See Security and Privacy.
Prompts
Prompts are ready-made workflows a client can offer as templates or slash commands. Those that can change data ask before they write.
<!-- BEGIN GENERATED: capabilities-prompts --> <!-- Generated from dist/src/prompts/index.js by `npm run docs:gen`. Do not edit. -->| Prompt | Parameters | Description |
|---|---|---|
monthly_review | month (optional) | Review a month: budget versus actual per category, overspent and unused categories, income versus expenses, and suggestions. |
spending_check | date (optional) | Quick check on a month so far: on track or overspending, categories to watch, and what is left to spend. |
spending_patterns | months (optional), end_month (optional) | Spending trends over the last N full months: direction, biggest category changes, savings rate trend, unusual items. |
budget_cleanup | date (optional) | Read-only review of payees, rules, categories and accounts for duplicates and unused items; proposes changes and asks before writing. |
categorize_uncategorized | since (optional) | Find uncategorised transactions, propose categories from payee history, confirm, apply in one batch, and offer rules for repeat payees. |
A prompt appears only when every tool it names is offered. With MCP_READ_ONLY=true, categorize_uncategorized is hidden, because it names a tool that can write.
Resources
None yet: the server offers tools and prompts only.
Configuration
<!-- env-summary:start -->| Variable | Required | Description |
|---|---|---|
ACTUAL_SERVER_URL | Yes | URL of your Actual Budget server, as seen from where the MCP server runs. Inside a container localhost is the container itself: use the host's address, the container name on a shared Docker network, or http://host.docker.internal:5006 |
ACTUAL_PASSWORD | Yes | Login password for your Actual Budget server (not the budget encryption password) |
ACTUAL_BUDGET_SYNC_ID | Yes | Budget Sync ID from Actual (Settings then Sync ID) |
ACTUAL_BUDGET_PASSWORD | No | Encryption password for an end-to-end encrypted budget |
MCP_BRIDGE_PORT | No | Port the MCP server listens on |
MCP_SSE_AUTHORIZATION | No | Static Bearer token clients must send (the raw token, not Bearer ...); highly recommended in production |
AUTH_PROVIDER | No | none (static Bearer) or oidc (JWKS-validated JWT) |
MCP_TOOLSETS | No | Toolset groups and presets to publish; see Reducing the tool surface |
Every variable, with its type and default: configuration reference. Several budgets: multiple budgets. Auth modes, per-client tokens and OIDC: authentication.
Documentation
- Documentation index: every page.
- Connect a client, deployment, authentication, upgrading, troubleshooting.
- Architecture, testing and reliability.
Contributing
Contributions are welcome. See CONTRIBUTING.md for setup, the checks every change must pass and the PR process. Questions and bug reports: SUPPORT.md.
Security
Report a vulnerability privately as described in SECURITY.md, not in a public issue.
Sponsor
I build and maintain this in my own time. It is free, it stays free, and it gets maintained either way. If it saved you some time, you can say thanks at github.com/sponsors/agigante80. Entirely optional.
License
MIT, see LICENSE. Built on Actual Budget and the Model Context Protocol, with thanks to s-stefanov/actual-mcp for the original adapter pattern. An independent project, not affiliated with Actual Budget, provided as-is without warranty: if you connect it to real financial data, you do so at your own risk.
Version: 0.30.0 | Tool Count: 85 (verified LibreChat-compatible)
Actual MCP Server alternatives
View more →Similar mcp servers in Deployment & DevOps, ranked by GitHub stars. Compare licence, recent activity and scan status before you choose.
| Name | Stars | Licence | Last updated | Scan |
|---|---|---|---|---|
| Actual MCP Server (this page) agigante80 | 74 | MIT | Oct 31, 2026 | Scanned, no flagged issues |
| OpenMetadata open-metadata | 16k | Apache-2.0 | Nov 1, 2026 | Scanned, see report |
| Drawio Skill Agents365-ai | 10k | MIT | Nov 1, 2026 | Scanned, no flagged issues |
| Openstatus openstatusHQ | 9.2k | AGPL-3.0 | Nov 1, 2026 | Scanned, no flagged issues |
| Ghidra MCP bethington | 6k | Apache-2.0 | Oct 31, 2026 | Scanned, no flagged issues |
| Kubefwd txn2 | 4.2k | Apache-2.0 | Oct 27, 2026 | Scanned, no flagged issues |