Actual Budget MCP

by agigante80

Not rated
GitHub

About

Docker MCP server connecting Claude Desktop/LibreChat/LobeChat to Actual Budget for natural-language budgeting, transaction management, and financial insights.

Details

Author
agigante80
Categories
Other, Finance, Database

Complete Environment Variables Reference

Configure multiple Actual Budget files so the AI can switch between them at runtime usingactual_budgets_list_availableandactual_budgets_switch.

BUDGET_N_SERVER_URLandBUDGET_N_PASSWORDfall back toACTUAL_SERVER_URL/ACTUAL_PASSWORDwhen omitted.

# Default budget ACTUAL_SERVER_URL=http://actual:5006 ACTUAL_PASSWORD=my-password ACTUAL_BUDGET_SYNC_ID=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa BUDGET_DEFAULT_NAME=Personal # Budget 1 (same server, same password) BUDGET_1_NAME=Family BUDGET_1_SYNC_ID=bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb # Budget 2 (different server) BUDGET_2_NAME=Business BUDGET_2_SERVER_URL=https://actual-office.example.com BUDGET_2_PASSWORD=office-password BUDGET_2_SYNC_ID=cccccccc-cccc-cccc-cccc-cccccccccccc

The server supports two transport modes:

The two modes are mutually exclusive. Pass exactly one flag when starting the server.

stdio is the simplest way to connect Claude Desktop directly to Actual Budget. The MCP server runs as a child process; Claude Desktop spawns it, communicates over stdin/stdout using NDJSON (the MCP wire format), and the process exits cleanly when Claude Desktop closes.

- No network port. The transport is a pipe, not a socket.
- No auth token. Process ownership is the security boundary.
- All logs go to stderr so they never corrupt the JSON-RPC framing on stdout
- The process exits when stdin closes (Claude Desktop shutting down)
- All 74 tools are available, identical to HTTP mode

cd /path/to/actual-mcp-server ACTUAL_SERVER_URL=http://localhost:5006 \ ACTUAL_PASSWORD=your_password \ ACTUAL_BUDGET_SYNC_ID=your-sync-id \ node dist/src/index.js --stdio

Send a test request (keep stdin open withsleep):

{ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'; sleep 5; } \ | ACTUAL_SERVER_URL=http://localhost:5006 ACTUAL_PASSWORD=your_password ACTUAL_BUDGET_SYNC_ID=your-sync-id \ node dist/src/index.js --stdio 2>/dev/null

Claude Desktop config(claude_desktop_config.json):

{ "mcpServers": { "actual-budget": { "command": "node", "args": ](https://github.com/agigante80/actual-mcp-server/blob/HEAD/docs/guides/MCP_CLIENTS_SETUP.md)["/absolute/path/to/actual-mcp-server/dist/src/index.js", "--stdio"], "env": { "ACTUAL_SERVER_URL": "http://localhost:5006", "ACTUAL_PASSWORD": "your_actual_password", "ACTUAL_BUDGET_SYNC_ID": "your-sync-id-here", "MCP_BRIDGE_DATA_DIR": "/absolute/path/to/actual-mcp-server/actual-data" } } } }

Path must be absolute.Claude Desktop does not inherit shellPATH, sonodemust also be absolute if you use NVM or a non-standard install:/home/youruser/.nvm/versions/node/v22.x.x/bin/node.

Seedocs/guides/MCP_CLIENTS_SETUP.mdfor all connection options (stdio native, mcp-remote via HTTP/HTTPS), other clients (Cursor, VS Code, Gemini CLI, Claude Code), Linux path fixes, and troubleshooting.

HTTP transportuses the/httpendpoint (StreamableHTTP) with optional Bearer token or OIDC authentication.

# Generate a token openssl rand -hex 32 # Add to .env MCP_SSE_AUTHORIZATION=your_token_here

Clients send:Authorization: Bearer your_token_here

AUTH_PROVIDER=oidc OIDC_ISSUER=https://sso.yourdomain.com OIDC_RESOURCE=your-client-id # must match 'aud' JWT claim OIDC_SCOPES= # leave empty for Casdoor

OAuth discovery endpoints (automatic in OIDC mode).WhenAUTH_PROVIDER=oidc, the server publishes the two metadata documents an OAuth client needs to bootstrap a login, somcp-remoteand Claude.ai's native connector can discover the flow without manual endpoint configuration:

- GET /.well-known/oauth-protected-resource(RFC 9728): identifies this server as a protected resource and points at yourOIDC_ISSUERas the authorization server.
- GET /.well-known/oauth-authorization-server(RFC 8414, #285): the authorization server metadata (itsauthorization_endpoint/token_endpoint/registration_endpoint), re-served from your IdP's own OpenID discovery document. This is here because several clients look for it on the resource-server origin, and some IdPs (e.g. Authentik) do not expose it where those clients look. It is fetched once at startup and served verbatim, exposes only endpoints your IdP already publishes publicly, and requires no authentication (a client reads it before it has a token). No extra configuration is needed; it is absent whenAUTH_PROVIDERis notoidc.

Where the per-user budget ACL comes from.By default the ACL is theAUTH_BUDGET_ACLmap you maintain by hand. Since v0.10.x it can instead be derived from the Actual server's own per-file access list, so granting or revoking someone in Actual takes effect here without a config edit and a restart:

**Talk to your budget. Run it anywhere. Trust it in production.** Actual MCP Server is a[Model Context Protocolserver that connects any MCP-compatible AI assistant (such as](https://modelcontextprotocol.io/)[LibreChat,](https://www.librechat.ai/)[LobeChat,](https://lobehub.com/home)[Claude Desktop, and more) directly to your self-hosted](https://claude.ai/download)[Actual Budgetinstance. Ask natural language questions, create transactions, analyse spending, and manage your entire budget without ever opening the Actual Budget UI. ``` `┌─────────────┐ MCP/HTTP ┌──────────────────┐ Actual API ┌──────────────┐ │ LibreChat │ ◄───────────► │ Actual MCP │ ◄───────────► │ Actual │ │ LobeChat │ │ Server │ │ Budget │ │ (remote) │ │ (74 tools) │ │ Server │ └─────────────┘ └──────────────────┘ └──────────────┘ ┌─────────────┐ MCP/stdio ┌──────────────────┐ Actual API ┌──────────────┐ │ Claude │ ◄───────────► │ Actual MCP │ ◄───────────► │ Actual │ │ Desktop │ │ Server │ │ Budget │ │ (local) │ │ (74 tools) │ │ Server │ └─────────────┘ └──────────────────┘ └──────────────┘` ``` Most Actual Budget MCP implementations are simple stdio bridges designed for single-user, local use with Claude Desktop. This project goes further: - **74 tools, the most comprehensive coverage available.**Accounts, transactions, categories, payees, tags, notes, rules, budgets, batch operations, bank sync, and more. Covers the reachable Actual Budget API with no genuine gaps. - **HTTP and stdio transport.**Runs as a real remote server for LibreChat/LobeChat (`--http`), or as a direct local process for Claude Desktop (`--stdio`). No Docker or HTTP server is needed for local use. - **6 exclusive ActualQL-powered tools.**Search and summarise transactions by month, amount, category, or payee using Actual Budget's native query engine. Aggregated results, no raw data dumped into the AI context window. - **Multi-budget switching at runtime.**Configure multiple budget files and let the AI switch between them mid-conversation with`actual_budgets_switch`. Works on both transports: HTTP keys the active budget to the MCP session, and stdio (Claude Desktop, Claude Code, Cursor) gets a synthetic per-process session so a switch is scoped to that process rather than shared globally (#348). - **Multi-user ready with OIDC.**Secure every session with JWKS-validated JWTs and per-user budget ACLs. No shared tokens required. - **Production-grade reliability.**Connection pooling (up to 15 concurrent sessions), automatic retry with exponential backoff, and a full test suite (unit + E2E + integration). **Verified working**with](https://actualbudget.org/)[LibreChat,](https://www.librechat.ai/)[LobeChat, and](https://lobehub.com/home)[Claude Desktop. All 74 tools tested end-to-end. Any MCP-compatible client should work. - ](https://claude.ai/download)[Quick Start - ](#quick-start)[Upgrading - ](#upgrading)[Available Tools - ](#available-tools)[Configuration - ](#configuration)[Multi-Budget Switching - ](#multi-budget-switching)[Transport & Authentication - ](#transport--authentication)[Testing - ](#testing)[Documentation - ](#documentation)[Contributing - ](#contributing)[License - ](#license)[Disclaimer - ](#disclaimer)[Actual Budgetserver running (local or remote) - Your**Budget Sync ID**: Actual → Settings → Show Advanced Settings → Sync ID - **Node.js 22+**(npm method) or**Docker** ``` `docker run -d \ --name actual-mcp-server-backend \ -p 3600:3600 \ # Use the same URL you type in your browser to open Actual Budget: # http://localhost:5006 (if Actual Budget runs on the same machine) # http://192.168.1.50:5006 (if it runs on another machine on your network) # https://actual.yourdomain.com (if you use a domain name) # http://actual:5006 (if both containers share a Docker network; use container name) -e ACTUAL_SERVER_URL=http://localhost:5006 \ -e ACTUAL_PASSWORD=your_password \ -e ACTUAL_BUDGET_SYNC_ID=your_sync_id \ -e MCP_SSE_AUTHORIZATION=your_secret_token \ -v actual-mcp-data:/app/data \ # required, see note below -v actual-mcp-logs:/app/logs \ ghcr.io/agigante80/actual-mcp-server:latest` ``` **Why the`/app/data`volume is required:**Actual Budget does not expose a REST API. The official`@actual-app/api`library (used internally by this server) works by downloading a local copy of your budget data, running all queries on that local copy, then syncing changes back. The`/app/data`volume gives the container a persistent, writable place to store that local copy (it is the directory the image creates and owns as the runtime user). Without it the container has nowhere to write and will fail on startup. See the](https://actualbudget.org/)[Actual API docsfor details. **actual-mcp does not need to run on the same machine as Actual Budget.**You can have Actual Budget on one server and actual-mcp on another - as long as`ACTUAL_SERVER_URL`points to your Actual Budget instance, everything works. ``` `# Quick health check curl http://localhost:3600/health # Expected: {"status":"ok","transport":"http","version":"..."} # Full MCP handshake (also verifies your token) curl -s -X POST http://localhost:3600/http \ -H "Authorization: Bearer your_secret_token" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli-test","version":"1.0"}}}' \ | python3 -m json.tool # Success: JSON response with "protocolVersion" and "serverInfo" # Wrong token: {"error": "Unauthorized"} # Server not running: curl: (7) Failed to connect` ``` Also available on Docker Hub:`agigante80/actual-mcp-server:latest` ``` `git clone https://github.com/agigante80/actual-mcp-server.git cd actual-mcp-server cp .env.example .env # fill in ACTUAL_SERVER_URL, ACTUAL_PASSWORD, ACTUAL_BUDGET_SYNC_ID docker compose --profile production up -d # production: MCP server listens on :3600 # or docker compose --profile dev up -d # dev mode with hot-reload` ``` The compose file defines only the`dev`and`production`profiles. The MCP server listens on`:3600`directly: there is no bundled reverse proxy and no bundled Actual Budget server, so point`ACTUAL_SERVER_URL`at your own Actual instance. For TLS, enable native HTTPS with`MCP_ENABLE_HTTPS=true`(plus`MCP_HTTPS_CERT`and`MCP_HTTPS_KEY`), or front the server with your own reverse proxy. **Requires Node.js 22+.**npm and npx do not enforce this, so check with`node --version`first. On an older Node the server refuses to start and tells you so. Note that`npx`runs whichever`node`is first on your`PATH`, which is not always the one you installed most recently. ``` `# Quick start via npx (no clone needed): ACTUAL_SERVER_URL=http://localhost:5006 \ ACTUAL_PASSWORD=your_password \ ACTUAL_BUDGET_SYNC_ID=your-sync-id \ MCP_SSE_AUTHORIZATION=your_token \ npx actual-mcp-server --http # Or clone for development / custom config: git clone https://github.com/agigante80/actual-mcp-server.git cd actual-mcp-server npm install cp .env.example .env # fill in required values npm run build npm run dev -- --http` ``` Server starts at`http://localhost:3600/http`by default (the listen port is`MCP_BRIDGE_PORT`, default`3600`). ### Option D: stdio (Claude Desktop native, no Docker or HTTP server needed) The stdio transport runs the MCP server as a child process. Claude Desktop spawns it directly and communicates over stdin/stdout. No network port, no auth token, no Docker required. No cloning needed:`npx`downloads and caches the package automatically. Add to`claude_desktop_config.json`(see](https://actualbudget.org/docs/api/)[docs/guides/MCP_CLIENTS_SETUP.mdfor config file location and all client options): ``` `{ "mcpServers": { "actual-budget": { "command": "npx", "args": ](https://github.com/agigante80/actual-mcp-server/blob/HEAD/docs/guides/MCP_CLIENTS_SETUP.md)["-y", "actual-mcp-server", "--stdio"], "env": { "ACTUAL_SERVER_URL": "http://localhost:5006", "ACTUAL_PASSWORD": "your_actual_password", "ACTUAL_BUDGET_SYNC_ID": "your-sync-id-here", "MCP_BRIDGE_DATA_DIR": "/absolute/path/to/data-dir" } } } }` ``` **No token needed.**stdio runs as a local process owned by your user. The transport itself is the security boundary. All 74 tools are available. **`MCP_BRIDGE_DATA_DIR`should be an absolute path.**Without one, the data directory resolves relative to wherever the client spawns the process, which can be unpredictable. The directory is created automatically on first run. ### Option E: Unraid (Community Applications) Actual MCP Server is published in the Unraid**Community Applications**store:**[ca.unraid.net/apps/actual-mcp-server**. This runs the HTTP transport, the right choice for LibreChat, LobeChat, and other remote MCP clients. Install it from the**Apps**tab (Community Applications): - Open the**Apps**tab and search for**`actual-mcp-server`**, then click**Install**. - Fill in**Actual server URL**,**Actual server password**, and**Actual server Sync ID**(the Sync ID is in Actual Budget: open the budget,**Settings, Show advanced settings, Sync ID**). - **Set a strong MCP auth token.**Generate one with`openssl rand -hex 32`. A blank token disables all HTTP authentication and exposes your financial data unauthenticated on the LAN, so this is required (see](https://ca.unraid.net/apps/actual-mcp-server-0bghkvs0c7c8bg)[Transport & Authentication). - Leave**PUID=99**and**PGID=100**(`nobody:users`) so the container can write the appdata Data and Logs directories, then start it. - Reach the health endpoint via the container's**WebUI**link (port`3600`); point your MCP client at`http://](#transport--authentication)[server-ip]:3600/http`with the Bearer token. The Unraid template lives in[`unraid/actual-mcp-server.xml`. For the publishing workflow see](https://github.com/agigante80/actual-mcp-server/blob/HEAD/unraid/actual-mcp-server.xml)[docs/UNRAID_CA_PUBLISHING.md. **LibreChat / LobeChat**: add to`librechat.yaml`(or LobeChat MCP plugin settings): ``` `mcpServers: actual-mcp: type: "streamable-http" url: "http://actual-mcp-server-backend:3600/http" headers: Authorization: "Bearer YOUR_TOKEN_HERE" serverInstructions: true timeout: 600000` ``` See](https://github.com/agigante80/actual-mcp-server/blob/HEAD/docs/UNRAID_CA_PUBLISHING.md)[docs/guides/AI_CLIENT_SETUP.mdfor full LibreChat, LobeChat, network, and HTTPS/TLS proxy setup. **Claude Desktop via HTTP**(when the server is already running as a Docker container): ``` `{ "mcpServers": { "actual-budget": { "command": "npx", "args": ](https://github.com/agigante80/actual-mcp-server/blob/HEAD/docs/guides/AI_CLIENT_SETUP.md)[ "-y", "mcp-remote", "http://localhost:3600/http", "--header", "Authorization: Bearer YOUR_TOKEN_HERE" ] } } }` ``` **Claude Desktop via stdio**(native, no HTTP server needed; see Option D above): ``` `{ "mcpServers": { "actual-budget": { "command": "node", "args": ["/absolute/path/to/actual-mcp-server/dist/src/index.js", "--stdio"], "env": { "ACTUAL_SERVER_URL": "http://localhost:5006", "ACTUAL_PASSWORD": "your_password", "ACTUAL_BUDGET_SYNC_ID": "your-sync-id", "MCP_BRIDGE_DATA_DIR": "/absolute/path/to/actual-mcp-server/actual-data" } } } }` ``` See[docs/guides/MCP_CLIENTS_SETUP.mdfor all options (including Cursor, VS Code, Gemini CLI), Linux/NVM path fixes, and troubleshooting. ``` `docker pull ghcr.io/agigante80/actual-mcp-server:latest docker stop actual-mcp-server-backend docker rm actual-mcp-server-backend # Re-run the original docker run command with the same flags and volumes` ``` Also available on Docker Hub:`docker pull agigante80/actual-mcp-server:latest` ``` `docker compose pull docker compose --profile production up -d` ``` ``` `git pull npm install npm run build # Then restart the server` ``` If you run`npx actual-mcp-server`without a globally installed version, npx fetches the latest from the registry automatically. But if you previously installed it globally (`npm install -g actual-mcp-server`), the global install takes precedence, so you must upgrade it explicitly: ``` `# Upgrade the global install npm install -g actual-mcp-server # Or force the registry version without touching your global install npx actual-mcp-server@latest --http` ``` For Claude Desktop (stdio), restart Claude after upgrading. **74 tools**across all categories. All tools use the`actual_<category>_<action>`naming convention. **Split transactions:**pass a`subtransactions`array (each child needs an`amount`in integer cents;`category`and`notes`are optional). The child amounts must sum to the parent`amount`(the server does not enforce this, so the tool does). A split parent carries no category of its own: put categories on the children.`actual_transactions_update`can edit the children of a transaction that is ALREADY a split; converting a plain transaction into a split via update is not supported (create it as a split instead). Note:`actual_transactions_import`forwards a`subtransactions`array to the API but does NOT apply the sum check, so use`actual_transactions_create`for guaranteed-balanced splits. **Exclusive ActualQL-powered (6)**, unique to this MCP server **Note:**Use`actual_transfers_create`for any account-to-account movement, not`actual_transactions_create`. The dedicated tool creates both sides (debit and credit) atomically so the books stay balanced. Limitations: both accounts must exist and be open, and`from_account`must differ from`to_account`. `actual_categories_get`·`actual_categories_create`·`actual_categories_update`·`actual_categories_delete` `actual_category_groups_get`·`actual_category_groups_create`·`actual_category_groups_update`·`actual_category_groups_delete` `actual_payees_get`·`actual_payees_common_list`·`actual_payees_create`·`actual_payees_update`·`actual_payees_delete`·`actual_payees_merge`·`actual_payee_rules_get` `actual_tags_list`·`actual_tags_create`·`actual_tags_update`·`actual_tags_delete` `actual_rules_get`·`actual_rules_create`·`actual_rules_update`·`actual_rules_delete` `actual_budget_updates_batch`: batch multiple budget updates in one call `actual_session_list`·`actual_session_close` - Scheduled/recurring transactions (`getSchedules`,`createSchedule`,`updateSchedule`,`deleteSchedule`) All configuration is via environment variables. Copy`.env.example`to`.env`to get started. ### Complete Environment Variables Reference Configure multiple Actual Budget files so the AI can switch between them at runtime using`actual_budgets_list_available`and`actual_budgets_switch`. `BUDGET_N_SERVER_URL`and`BUDGET_N_PASSWORD`fall back to`ACTUAL_SERVER_URL`/`ACTUAL_PASSWORD`when omitted. ``` `# Default budget ACTUAL_SERVER_URL=http://actual:5006 ACTUAL_PASSWORD=my-password ACTUAL_BUDGET_SYNC_ID=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa BUDGET_DEFAULT_NAME=Personal # Budget 1 (same server, same password) BUDGET_1_NAME=Family BUDGET_1_SYNC_ID=bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb # Budget 2 (different server) BUDGET_2_NAME=Business BUDGET_2_SERVER_URL=https://actual-office.example.com BUDGET_2_PASSWORD=office-password BUDGET_2_SYNC_ID=cccccccc-cccc-cccc-cccc-cccccccccccc` ``` The server supports two transport modes: The two modes are mutually exclusive. Pass exactly one flag when starting the server. stdio is the simplest way to connect Claude Desktop directly to Actual Budget. The MCP server runs as a child process; Claude Desktop spawns it, communicates over stdin/stdout using NDJSON (the MCP wire format), and the process exits cleanly when Claude Desktop closes. - No network port. The transport is a pipe, not a socket. - No auth token. Process ownership is the security boundary. - All logs go to stderr so they never corrupt the JSON-RPC framing on stdout - The process exits when stdin closes (Claude Desktop shutting down) - All 74 tools are available, identical to HTTP mode ``` `cd /path/to/actual-mcp-server ACTUAL_SERVER_URL=http://localhost:5006 \ ACTUAL_PASSWORD=your_password \ ACTUAL_BUDGET_SYNC_ID=your-sync-id \ node dist/src/index.js --stdio` ``` Send a test request (keep stdin open with`sleep`): ``` `{ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'; sleep 5; } \ | ACTUAL_SERVER_URL=http://localhost:5006 ACTUAL_PASSWORD=your_password ACTUAL_BUDGET_SYNC_ID=your-sync-id \ node dist/src/index.js --stdio 2>/dev/null` ``` **Claude Desktop config**(`claude_desktop_config.json`): ``` `{ "mcpServers": { "actual-budget": { "command": "node", "args": ](https://github.com/agigante80/actual-mcp-server/blob/HEAD/docs/guides/MCP_CLIENTS_SETUP.md)["/absolute/path/to/actual-mcp-server/dist/src/index.js", "--stdio"], "env": { "ACTUAL_SERVER_URL": "http://localhost:5006", "ACTUAL_PASSWORD": "your_actual_password", "ACTUAL_BUDGET_SYNC_ID": "your-sync-id-here", "MCP_BRIDGE_DATA_DIR": "/absolute/path/to/actual-mcp-server/actual-data" } } } }` ``` **Path must be absolute.**Claude Desktop does not inherit shell`PATH`, so`node`must also be absolute if you use NVM or a non-standard install:`/home/youruser/.nvm/versions/node/v22.x.x/bin/node`. See[docs/guides/MCP_CLIENTS_SETUP.mdfor all connection options (stdio native, mcp-remote via HTTP/HTTPS), other clients (Cursor, VS Code, Gemini CLI, Claude Code), Linux path fixes, and troubleshooting. **HTTP transport**uses the`/http`endpoint (StreamableHTTP) with optional Bearer token or OIDC authentication. ``` `# Generate a token openssl rand -hex 32 # Add to .env MCP_SSE_AUTHORIZATION=your_token_here` ``` Clients send:`Authorization: Bearer your_token_here` ``` `AUTH_PROVIDER=oidc OIDC_ISSUER=https://sso.yourdomain.com OIDC_RESOURCE=your-client-id # must match 'aud' JWT claim OIDC_SCOPES= # leave empty for Casdoor` ``` **OAuth discovery endpoints (automatic in OIDC mode).**When`AUTH_PROVIDER=oidc`, the server publishes the two metadata documents an OAuth client needs to bootstrap a login, so`mcp-remote`and Claude.ai's native connector can discover the flow without manual endpoint configuration: - `GET /.well-known/oauth-protected-resource`(RFC 9728): identifies this server as a protected resource and points at your`OIDC_ISSUER`as the authorization server. - `GET /.well-known/oauth-authorization-server`(RFC 8414, #285): the authorization server metadata (its`authorization_endpoint`/`token_endpoint`/`registration_endpoint`), re-served from your IdP's own OpenID discovery document. This is here because several clients look for it on the resource-server origin, and some IdPs (e.g. Authentik) do not expose it where those clients look. It is fetched once at startup and served verbatim, exposes only endpoints your IdP already publishes publicly, and requires no authentication (a client reads it before it has a token). No extra configuration is needed; it is absent when`AUTH_PROVIDER`is not`oidc`. **Where the per-user budget ACL comes from.**By default the ACL is the`AUTH_BUDGET_ACL`map you maintain by hand. Since v0.10.x it can instead be derived from the Actual server's own per-file access list, so granting or revoking someone in Actual takes effect here without a config edit and a restart:](https://github.com/agigante80/actual-mcp-server/blob/HEAD/docs/guides/MCP_CLIENTS_SETUP.md)
No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.