actual-mcp-server 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +663 -0
- package/bin/actual-mcp-server.js +3 -0
- package/dist/generated/actual-client/types.js +5 -0
- package/dist/package.json +88 -0
- package/dist/src/actualConnection.js +157 -0
- package/dist/src/actualToolsManager.js +211 -0
- package/dist/src/auth/budget-acl.js +143 -0
- package/dist/src/auth/setup.js +58 -0
- package/dist/src/config.js +41 -0
- package/dist/src/index.js +313 -0
- package/dist/src/lib/ActualConnectionPool.js +343 -0
- package/dist/src/lib/ActualMCPConnection.js +125 -0
- package/dist/src/lib/actual-adapter.js +1228 -0
- package/dist/src/lib/actual-schema.js +222 -0
- package/dist/src/lib/budget-registry.js +64 -0
- package/dist/src/lib/constants.js +121 -0
- package/dist/src/lib/errors.js +19 -0
- package/dist/src/lib/loggerFactory.js +72 -0
- package/dist/src/lib/node-polyfills.js +20 -0
- package/dist/src/lib/query-validator.js +221 -0
- package/dist/src/lib/retry.js +26 -0
- package/dist/src/lib/schemas/common.js +203 -0
- package/dist/src/lib/toolFactory.js +109 -0
- package/dist/src/logger.js +127 -0
- package/dist/src/observability.js +58 -0
- package/dist/src/prompts/showLargeTransactions.js +6 -0
- package/dist/src/resources/accountsSummary.js +13 -0
- package/dist/src/server/httpServer.js +540 -0
- package/dist/src/server/httpServer_testing.js +401 -0
- package/dist/src/server/stdioServer.js +52 -0
- package/dist/src/server/streamable-http.js +148 -0
- package/dist/src/tests/actualToolsTests.js +70 -0
- package/dist/src/tests/observability.smoke.test.js +18 -0
- package/dist/src/tests/testMcpClient.js +170 -0
- package/dist/src/tests_adapter_runner.js +86 -0
- package/dist/src/tools/accounts_close.js +16 -0
- package/dist/src/tools/accounts_create.js +27 -0
- package/dist/src/tools/accounts_delete.js +16 -0
- package/dist/src/tools/accounts_get_balance.js +40 -0
- package/dist/src/tools/accounts_list.js +16 -0
- package/dist/src/tools/accounts_reopen.js +16 -0
- package/dist/src/tools/accounts_update.js +52 -0
- package/dist/src/tools/bank_sync.js +22 -0
- package/dist/src/tools/budget_updates_batch.js +77 -0
- package/dist/src/tools/budgets_getMonth.js +14 -0
- package/dist/src/tools/budgets_getMonths.js +14 -0
- package/dist/src/tools/budgets_get_all.js +13 -0
- package/dist/src/tools/budgets_holdForNextMonth.js +19 -0
- package/dist/src/tools/budgets_list_available.js +20 -0
- package/dist/src/tools/budgets_resetHold.js +16 -0
- package/dist/src/tools/budgets_setAmount.js +26 -0
- package/dist/src/tools/budgets_setCarryover.js +18 -0
- package/dist/src/tools/budgets_switch.js +27 -0
- package/dist/src/tools/budgets_transfer.js +64 -0
- package/dist/src/tools/categories_create.js +65 -0
- package/dist/src/tools/categories_delete.js +16 -0
- package/dist/src/tools/categories_get.js +14 -0
- package/dist/src/tools/categories_update.js +22 -0
- package/dist/src/tools/category_groups_create.js +18 -0
- package/dist/src/tools/category_groups_delete.js +26 -0
- package/dist/src/tools/category_groups_get.js +13 -0
- package/dist/src/tools/category_groups_update.js +21 -0
- package/dist/src/tools/get_id_by_name.js +36 -0
- package/dist/src/tools/index.js +63 -0
- package/dist/src/tools/payee_rules_get.js +27 -0
- package/dist/src/tools/payees_create.js +25 -0
- package/dist/src/tools/payees_delete.js +16 -0
- package/dist/src/tools/payees_get.js +14 -0
- package/dist/src/tools/payees_merge.js +17 -0
- package/dist/src/tools/payees_update.js +59 -0
- package/dist/src/tools/query_run.js +78 -0
- package/dist/src/tools/rules_create.js +129 -0
- package/dist/src/tools/rules_create_or_update.js +191 -0
- package/dist/src/tools/rules_delete.js +26 -0
- package/dist/src/tools/rules_get.js +13 -0
- package/dist/src/tools/rules_update.js +120 -0
- package/dist/src/tools/schedules_create.js +54 -0
- package/dist/src/tools/schedules_delete.js +41 -0
- package/dist/src/tools/schedules_get.js +13 -0
- package/dist/src/tools/schedules_update.js +40 -0
- package/dist/src/tools/server_get_version.js +22 -0
- package/dist/src/tools/server_info.js +86 -0
- package/dist/src/tools/session_close.js +100 -0
- package/dist/src/tools/session_list.js +24 -0
- package/dist/src/tools/transactions_create.js +50 -0
- package/dist/src/tools/transactions_delete.js +20 -0
- package/dist/src/tools/transactions_filter.js +73 -0
- package/dist/src/tools/transactions_get.js +23 -0
- package/dist/src/tools/transactions_import.js +21 -0
- package/dist/src/tools/transactions_search_by_amount.js +126 -0
- package/dist/src/tools/transactions_search_by_category.js +137 -0
- package/dist/src/tools/transactions_search_by_month.js +142 -0
- package/dist/src/tools/transactions_search_by_payee.js +142 -0
- package/dist/src/tools/transactions_summary_by_category.js +80 -0
- package/dist/src/tools/transactions_summary_by_payee.js +72 -0
- package/dist/src/tools/transactions_uncategorized.js +66 -0
- package/dist/src/tools/transactions_update.js +34 -0
- package/dist/src/tools/transactions_update_batch.js +60 -0
- package/dist/src/utils.js +63 -0
- package/package.json +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
# Actual MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://nodejs.org/)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://modelcontextprotocol.io/)
|
|
7
|
+
[](https://hub.docker.com/r/agigante80/actual-mcp-server)
|
|
8
|
+
[](https://hub.docker.com/r/agigante80/actual-mcp-server)
|
|
9
|
+
[](https://github.com/agigante80/actual-mcp-server/actions)
|
|
10
|
+
[](https://github.com/agigante80/actual-mcp-server)
|
|
11
|
+
|
|
12
|
+
**Talk to your budget. Run it anywhere. Trust it in production.**
|
|
13
|
+
|
|
14
|
+
Actual MCP Server is a [Model Context Protocol](https://modelcontextprotocol.io/) server that connects any MCP-compatible AI assistant — [LibreChat](https://www.librechat.ai/), [LobeChat](https://lobehub.com/home), [Claude Desktop](https://claude.ai/download), and more — directly to your self-hosted [Actual Budget](https://actualbudget.org/) instance. Ask natural language questions, create transactions, analyse spending, and manage your entire budget without ever opening the Actual Budget UI.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
┌─────────────┐ MCP/HTTP ┌──────────────────┐ Actual API ┌──────────────┐
|
|
18
|
+
│ LibreChat │ ◄───────────► │ Actual MCP │ ◄───────────► │ Actual │
|
|
19
|
+
│ LobeChat │ │ Server │ │ Budget │
|
|
20
|
+
│ (remote) │ │ (62 tools) │ │ Server │
|
|
21
|
+
└─────────────┘ └──────────────────┘ └──────────────┘
|
|
22
|
+
|
|
23
|
+
┌─────────────┐ MCP/stdio ┌──────────────────┐ Actual API ┌──────────────┐
|
|
24
|
+
│ Claude │ ◄───────────► │ Actual MCP │ ◄───────────► │ Actual │
|
|
25
|
+
│ Desktop │ │ Server │ │ Budget │
|
|
26
|
+
│ (local) │ │ (62 tools) │ │ Server │
|
|
27
|
+
└─────────────┘ └──────────────────┘ └──────────────┘
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Why this project?
|
|
31
|
+
|
|
32
|
+
Most Actual Budget MCP implementations are simple stdio bridges designed for single-user, local use with Claude Desktop. This project goes further:
|
|
33
|
+
|
|
34
|
+
- **62 tools — the most comprehensive coverage available.** Accounts, transactions, categories, payees, rules, budgets, batch operations, bank sync, and more. Covers 84% of the Actual Budget API.
|
|
35
|
+
- **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 needed for local use.
|
|
36
|
+
- **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.
|
|
37
|
+
- **Multi-budget switching at runtime.** Configure multiple budget files and let the AI switch between them mid-conversation with `actual_budgets_switch`.
|
|
38
|
+
- **Multi-user ready with OIDC.** Secure every session with JWKS-validated JWTs and per-user budget ACLs — no shared tokens required.
|
|
39
|
+
- **Production-grade reliability.** Connection pooling (up to 15 concurrent sessions), automatic retry with exponential backoff, and a full test suite (unit + E2E + integration).
|
|
40
|
+
|
|
41
|
+
> **Verified working** with [LibreChat](https://www.librechat.ai/), [LobeChat](https://lobehub.com/home), and [Claude Desktop](https://claude.ai/download). All 62 tools tested end-to-end. Any MCP-compatible client should work.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Table of Contents
|
|
46
|
+
|
|
47
|
+
- [Quick Start](#quick-start)
|
|
48
|
+
- [Available Tools](#available-tools)
|
|
49
|
+
- [Configuration](#configuration)
|
|
50
|
+
- [Multi-Budget Switching](#multi-budget-switching)
|
|
51
|
+
- [Transport & Authentication](#transport--authentication)
|
|
52
|
+
- [Testing](#testing)
|
|
53
|
+
- [Documentation](#documentation)
|
|
54
|
+
- [Comparison with Similar Projects](#comparison-with-similar-projects)
|
|
55
|
+
- [Contributing](#contributing)
|
|
56
|
+
- [License](#license)
|
|
57
|
+
- [Disclaimer](#disclaimer)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### Prerequisites
|
|
64
|
+
|
|
65
|
+
- [Actual Budget](https://actualbudget.org/) server running (local or remote)
|
|
66
|
+
- Your **Budget Sync ID**: Actual → Settings → Show Advanced Settings → Sync ID
|
|
67
|
+
- **Node.js 20+** (npm method) or **Docker**
|
|
68
|
+
|
|
69
|
+
### Option A — Docker (recommended)
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
docker run -d \
|
|
73
|
+
--name actual-mcp-server-backend \
|
|
74
|
+
-p 3600:3600 \
|
|
75
|
+
# Use the same URL you type in your browser to open Actual Budget:
|
|
76
|
+
# http://localhost:5006 — if Actual Budget runs on the same machine
|
|
77
|
+
# http://192.168.1.50:5006 — if it runs on another machine on your network
|
|
78
|
+
# https://actual.yourdomain.com — if you use a domain name
|
|
79
|
+
# http://actual:5006 — if both containers share a Docker network (use container name)
|
|
80
|
+
-e ACTUAL_SERVER_URL=http://localhost:5006 \
|
|
81
|
+
-e ACTUAL_PASSWORD=your_password \
|
|
82
|
+
-e ACTUAL_BUDGET_SYNC_ID=your_sync_id \
|
|
83
|
+
-e MCP_SSE_AUTHORIZATION=your_secret_token \
|
|
84
|
+
-v actual-mcp-data:/data \ # required — see note below
|
|
85
|
+
-v actual-mcp-logs:/app/logs \
|
|
86
|
+
ghcr.io/agigante80/actual-mcp-server:latest
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
> **Why the `/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 `/data` volume gives the container a persistent, writable place to store that local copy. Without it the container has nowhere to write and will fail on startup. See the [Actual API docs](https://actualbudget.org/docs/api/) for details.
|
|
90
|
+
>
|
|
91
|
+
> **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.
|
|
92
|
+
|
|
93
|
+
**Verify it's running:**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Quick health check
|
|
97
|
+
curl http://localhost:3600/health
|
|
98
|
+
# Expected: {"status":"ok","transport":"http","version":"..."}
|
|
99
|
+
|
|
100
|
+
# Full MCP handshake (also verifies your token)
|
|
101
|
+
curl -s -X POST http://localhost:3600/http \
|
|
102
|
+
-H "Authorization: Bearer your_secret_token" \
|
|
103
|
+
-H "Content-Type: application/json" \
|
|
104
|
+
-H "Accept: application/json, text/event-stream" \
|
|
105
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli-test","version":"1.0"}}}' \
|
|
106
|
+
| python3 -m json.tool
|
|
107
|
+
# Success: JSON response with "protocolVersion" and "serverInfo"
|
|
108
|
+
# Wrong token: {"error": "Unauthorized"}
|
|
109
|
+
# Server not running: curl: (7) Failed to connect
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Also available on Docker Hub: `agigante80/actual-mcp-server:latest`
|
|
113
|
+
|
|
114
|
+
### Option B — Docker Compose
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
git clone https://github.com/agigante80/actual-mcp-server.git
|
|
118
|
+
cd actual-mcp-server
|
|
119
|
+
cp .env.example .env # fill in ACTUAL_SERVER_URL, ACTUAL_PASSWORD, ACTUAL_BUDGET_SYNC_ID
|
|
120
|
+
|
|
121
|
+
docker compose --profile production up -d # Nginx proxy on :3600
|
|
122
|
+
# or
|
|
123
|
+
docker compose --profile dev up -d # dev mode with hot-reload
|
|
124
|
+
# or
|
|
125
|
+
docker compose --profile fullstack up -d # includes Actual Budget server on :5006
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Option C — npm (HTTP server)
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
git clone https://github.com/agigante80/actual-mcp-server.git
|
|
132
|
+
cd actual-mcp-server
|
|
133
|
+
npm install
|
|
134
|
+
cp .env.example .env # fill in required values
|
|
135
|
+
npm run build
|
|
136
|
+
npm run dev -- --http
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Server starts at `http://localhost:3000/http` (dev) or `http://localhost:3600/http` (Docker).
|
|
140
|
+
|
|
141
|
+
### Option D — stdio (Claude Desktop native, no Docker or HTTP server needed)
|
|
142
|
+
|
|
143
|
+
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.
|
|
144
|
+
|
|
145
|
+
Add to `claude_desktop_config.json` (see [docs/guides/MCP_CLIENTS_SETUP.md](docs/guides/MCP_CLIENTS_SETUP.md) for config file location and all client options):
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"mcpServers": {
|
|
150
|
+
"actual-budget": {
|
|
151
|
+
"command": "npx",
|
|
152
|
+
"args": ["-y", "actual-mcp-server", "--stdio"],
|
|
153
|
+
"env": {
|
|
154
|
+
"ACTUAL_SERVER_URL": "http://localhost:5006",
|
|
155
|
+
"ACTUAL_PASSWORD": "your_actual_password",
|
|
156
|
+
"ACTUAL_BUDGET_SYNC_ID": "your-sync-id-here",
|
|
157
|
+
"MCP_BRIDGE_DATA_DIR": "/absolute/path/to/data-dir"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
> **No token needed.** stdio runs as a local process owned by your user — the transport itself is the security boundary. All 62 tools are available.
|
|
165
|
+
>
|
|
166
|
+
> **`MCP_BRIDGE_DATA_DIR` should be an absolute path** — without it, the data directory resolves relative to wherever the client spawns the process, which can be unpredictable. The directory is created automatically on first run.
|
|
167
|
+
|
|
168
|
+
### Connect an AI client
|
|
169
|
+
|
|
170
|
+
**LibreChat / LobeChat** — add to `librechat.yaml` (or LobeChat MCP plugin settings):
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
mcpServers:
|
|
174
|
+
actual-mcp:
|
|
175
|
+
type: "streamable-http"
|
|
176
|
+
url: "http://actual-mcp-server-backend:3600/http"
|
|
177
|
+
headers:
|
|
178
|
+
Authorization: "Bearer YOUR_TOKEN_HERE"
|
|
179
|
+
serverInstructions: true
|
|
180
|
+
timeout: 600000
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
See [docs/guides/AI_CLIENT_SETUP.md](docs/guides/AI_CLIENT_SETUP.md) for full LibreChat, LobeChat, network, and HTTPS/TLS proxy setup.
|
|
184
|
+
|
|
185
|
+
**Claude Desktop via HTTP** (when the server is already running as a Docker container):
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"mcpServers": {
|
|
190
|
+
"actual-budget": {
|
|
191
|
+
"command": "npx",
|
|
192
|
+
"args": [
|
|
193
|
+
"-y",
|
|
194
|
+
"mcp-remote",
|
|
195
|
+
"http://localhost:3600/http",
|
|
196
|
+
"--header",
|
|
197
|
+
"Authorization: Bearer YOUR_TOKEN_HERE"
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Claude Desktop via stdio** (native, no HTTP server needed — see Option D above):
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"mcpServers": {
|
|
209
|
+
"actual-budget": {
|
|
210
|
+
"command": "node",
|
|
211
|
+
"args": ["/absolute/path/to/actual-mcp-server/dist/src/index.js", "--stdio"],
|
|
212
|
+
"env": {
|
|
213
|
+
"ACTUAL_SERVER_URL": "http://localhost:5006",
|
|
214
|
+
"ACTUAL_PASSWORD": "your_password",
|
|
215
|
+
"ACTUAL_BUDGET_SYNC_ID": "your-sync-id",
|
|
216
|
+
"MCP_BRIDGE_DATA_DIR": "/absolute/path/to/actual-mcp-server/actual-data"
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
See [docs/guides/MCP_CLIENTS_SETUP.md](docs/guides/MCP_CLIENTS_SETUP.md) for all options (including Cursor, VS Code, Gemini CLI), Linux/NVM path fixes, and troubleshooting.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Available Tools
|
|
228
|
+
|
|
229
|
+
**62 tools** across 12 categories. All tools use the `actual_<category>_<action>` naming convention.
|
|
230
|
+
|
|
231
|
+
### Accounts (7)
|
|
232
|
+
|
|
233
|
+
| Tool | Description |
|
|
234
|
+
|------|-------------|
|
|
235
|
+
| `actual_accounts_list` | List all accounts |
|
|
236
|
+
| `actual_accounts_create` | Create new account |
|
|
237
|
+
| `actual_accounts_update` | Update account details |
|
|
238
|
+
| `actual_accounts_delete` | Permanently delete account |
|
|
239
|
+
| `actual_accounts_close` | Close account (soft delete) |
|
|
240
|
+
| `actual_accounts_reopen` | Reopen closed account |
|
|
241
|
+
| `actual_accounts_get_balance` | Get account balance at a date |
|
|
242
|
+
|
|
243
|
+
### Transactions (12)
|
|
244
|
+
|
|
245
|
+
**Standard (6)**
|
|
246
|
+
|
|
247
|
+
| Tool | Description |
|
|
248
|
+
|------|-------------|
|
|
249
|
+
| `actual_transactions_get` | Get transactions for an account |
|
|
250
|
+
| `actual_transactions_filter` | Filter with advanced criteria |
|
|
251
|
+
| `actual_transactions_create` | Create new transaction(s) |
|
|
252
|
+
| `actual_transactions_import` | Import and reconcile transactions |
|
|
253
|
+
| `actual_transactions_update` | Update a transaction |
|
|
254
|
+
| `actual_transactions_delete` | Delete a transaction |
|
|
255
|
+
|
|
256
|
+
**Exclusive ActualQL-powered (6)** — unique to this MCP server
|
|
257
|
+
|
|
258
|
+
| Tool | Description |
|
|
259
|
+
|------|-------------|
|
|
260
|
+
| `actual_transactions_search_by_month` | Search by month using `$month` transform |
|
|
261
|
+
| `actual_transactions_search_by_amount` | Find by amount range |
|
|
262
|
+
| `actual_transactions_search_by_category` | Search by category name |
|
|
263
|
+
| `actual_transactions_search_by_payee` | Find by payee/vendor |
|
|
264
|
+
| `actual_transactions_summary_by_category` | Spending summary grouped by category |
|
|
265
|
+
| `actual_transactions_summary_by_payee` | Top vendors with totals and counts |
|
|
266
|
+
|
|
267
|
+
### Categories (4)
|
|
268
|
+
|
|
269
|
+
`actual_categories_get` · `actual_categories_create` · `actual_categories_update` · `actual_categories_delete`
|
|
270
|
+
|
|
271
|
+
### Category Groups (4)
|
|
272
|
+
|
|
273
|
+
`actual_category_groups_get` · `actual_category_groups_create` · `actual_category_groups_update` · `actual_category_groups_delete`
|
|
274
|
+
|
|
275
|
+
### Payees (6)
|
|
276
|
+
|
|
277
|
+
`actual_payees_get` · `actual_payees_create` · `actual_payees_update` · `actual_payees_delete` · `actual_payees_merge` · `actual_payee_rules_get`
|
|
278
|
+
|
|
279
|
+
### Budgets (10)
|
|
280
|
+
|
|
281
|
+
| Tool | Description |
|
|
282
|
+
|------|-------------|
|
|
283
|
+
| `actual_budgets_list_available` | List all configured budget files |
|
|
284
|
+
| `actual_budgets_switch` | Switch active budget (multi-budget) |
|
|
285
|
+
| `actual_budgets_get_all` | List available budget files |
|
|
286
|
+
| `actual_budgets_getMonths` | List budget months |
|
|
287
|
+
| `actual_budgets_getMonth` | Get budget for a specific month |
|
|
288
|
+
| `actual_budgets_setAmount` | Set category budget amount |
|
|
289
|
+
| `actual_budgets_transfer` | Transfer amount between categories |
|
|
290
|
+
| `actual_budgets_setCarryover` | Enable/disable carryover |
|
|
291
|
+
| `actual_budgets_holdForNextMonth` | Hold funds for next month |
|
|
292
|
+
| `actual_budgets_resetHold` | Reset hold status |
|
|
293
|
+
|
|
294
|
+
### Rules (4)
|
|
295
|
+
|
|
296
|
+
`actual_rules_get` · `actual_rules_create` · `actual_rules_update` · `actual_rules_delete`
|
|
297
|
+
|
|
298
|
+
### Advanced Query & Sync (2)
|
|
299
|
+
|
|
300
|
+
| Tool | Description |
|
|
301
|
+
|------|-------------|
|
|
302
|
+
| `actual_query_run` | Execute custom ActualQL query |
|
|
303
|
+
| `actual_bank_sync` | Trigger bank sync (GoCardless/SimpleFIN) |
|
|
304
|
+
|
|
305
|
+
### Batch Operations (1)
|
|
306
|
+
|
|
307
|
+
`actual_budget_updates_batch` — batch multiple budget updates in one call
|
|
308
|
+
|
|
309
|
+
### Server Information & Lookup (3)
|
|
310
|
+
|
|
311
|
+
| Tool | Description |
|
|
312
|
+
|------|-------------|
|
|
313
|
+
| `actual_server_info` | Server status, version, build info |
|
|
314
|
+
| `actual_server_get_version` | Actual Budget server version |
|
|
315
|
+
| `actual_get_id_by_name` | Resolve name → UUID for accounts, categories, payees |
|
|
316
|
+
|
|
317
|
+
### Session Management (2)
|
|
318
|
+
|
|
319
|
+
`actual_session_list` · `actual_session_close`
|
|
320
|
+
|
|
321
|
+
### Not Yet Implemented
|
|
322
|
+
|
|
323
|
+
- Scheduled/recurring transactions (`getSchedules`, `createSchedule`, `updateSchedule`, `deleteSchedule`)
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Configuration
|
|
328
|
+
|
|
329
|
+
All configuration is via environment variables. Copy `.env.example` to `.env` to get started.
|
|
330
|
+
|
|
331
|
+
### Complete Environment Variables Reference
|
|
332
|
+
|
|
333
|
+
| Variable | Default | Required | Description |
|
|
334
|
+
|----------|---------|----------|-------------|
|
|
335
|
+
| **Actual Budget Connection** ||||
|
|
336
|
+
| `ACTUAL_SERVER_URL` | `http://localhost:5006` | Yes | URL of your Actual Budget server. Use the same URL you type in your browser: `http://localhost:5006` (local), `http://192.168.1.x:5006` (network), `https://actual.yourdomain.com` (domain), or `http://actual:5006` (container name if on the same Docker network) |
|
|
337
|
+
| `ACTUAL_PASSWORD` | — | Yes | Password for Actual Budget server |
|
|
338
|
+
| `ACTUAL_BUDGET_SYNC_ID` | — | Yes | Budget Sync ID from Actual (Settings → Sync ID) |
|
|
339
|
+
| `ACTUAL_BUDGET_PASSWORD` | — | No | Optional encryption password for encrypted budgets |
|
|
340
|
+
| **MCP Server Settings** ||||
|
|
341
|
+
| `MCP_BRIDGE_PORT` | `3000` (dev) / `3600` (Docker) | No | Port for MCP server to listen on |
|
|
342
|
+
| `MCP_BRIDGE_BIND_HOST` | `0.0.0.0` | No | Host address to bind server to (`0.0.0.0` = all interfaces) |
|
|
343
|
+
| `MCP_BRIDGE_DATA_DIR` | `./actual-data` | No | Directory to store Actual Budget local data (SQLite). **Required to be a persistent path.** The `@actual-app/api` library downloads a local copy of your budget here to run queries — use a volume mount in Docker to persist it across restarts |
|
|
344
|
+
| `MCP_BRIDGE_PUBLIC_HOST` | auto-detected | No | Public hostname/IP for server (shown in logs) |
|
|
345
|
+
| `MCP_BRIDGE_PUBLIC_SCHEME` | auto-detected | No | Public scheme (`http` or `https`) |
|
|
346
|
+
| `MCP_BRIDGE_USE_TLS` | `false` | No | Set to `true` to advertise `https://` in the server URL (for reverse-proxy setups where TLS is terminated upstream) |
|
|
347
|
+
| **Transport Configuration** ||||
|
|
348
|
+
| `MCP_TRANSPORT_MODE` | `--http` | No | Transport mode: `--http` or `--stdio` |
|
|
349
|
+
| `MCP_HTTP_PATH` | `/http` | No | HTTP endpoint routing path |
|
|
350
|
+
| `MCP_BRIDGE_HTTP_PATH` | same as `MCP_HTTP_PATH` | No | Advertised HTTP path shown to clients (set when a reverse proxy rewrites the path) |
|
|
351
|
+
| **Session Management** ||||
|
|
352
|
+
| `USE_CONNECTION_POOL` | `true` | No | Enable session-based connection pooling |
|
|
353
|
+
| `MAX_CONCURRENT_SESSIONS` | `15` | No | Maximum concurrent MCP sessions allowed |
|
|
354
|
+
| `SESSION_IDLE_TIMEOUT_MINUTES` | `5` (pool) / `2` (HTTP) | No | Minutes before idle session cleanup |
|
|
355
|
+
| **Security & Authentication** ||||
|
|
356
|
+
| `AUTH_PROVIDER` | `none` | No | Auth mode: `none` (static Bearer) or `oidc` (JWKS-validated JWT) |
|
|
357
|
+
| `MCP_SSE_AUTHORIZATION` | — | No | Static Bearer token (`AUTH_PROVIDER=none`; highly recommended in production) |
|
|
358
|
+
| `OIDC_ISSUER` | — | If OIDC | OIDC issuer URL (e.g., `https://sso.example.com`) |
|
|
359
|
+
| `OIDC_RESOURCE` | — | No | Expected `aud` claim in JWT (your client ID) |
|
|
360
|
+
| `OIDC_SCOPES` | — | No | Comma-separated required scopes; leave empty for Casdoor |
|
|
361
|
+
| `AUTH_BUDGET_ACL` | — | No | Per-user budget ACL — see [AI Client Setup](docs/guides/AI_CLIENT_SETUP.md#oidc-authentication-multi-user) |
|
|
362
|
+
| `MCP_ENABLE_HTTPS` | `false` | No | Enable native TLS. Requires `MCP_HTTPS_CERT` and `MCP_HTTPS_KEY` |
|
|
363
|
+
| `MCP_HTTPS_CERT` | — | No | Path to PEM certificate file (required when `MCP_ENABLE_HTTPS=true`) |
|
|
364
|
+
| `MCP_HTTPS_KEY` | — | No | Path to PEM private key file (required when `MCP_ENABLE_HTTPS=true`) |
|
|
365
|
+
| **Logging Configuration** ||||
|
|
366
|
+
| `MCP_BRIDGE_STORE_LOGS` | `false` | No | Enable file logging (vs console only) |
|
|
367
|
+
| `MCP_BRIDGE_LOG_DIR` | `./logs` | No | Directory for log files (if `STORE_LOGS=true`) |
|
|
368
|
+
| `MCP_BRIDGE_LOG_LEVEL` | `debug` | No | Log level: `error`, `warn`, `info`, `debug` |
|
|
369
|
+
| **Log Rotation** (when `MCP_BRIDGE_STORE_LOGS=true`) ||||
|
|
370
|
+
| `MCP_BRIDGE_MAX_FILES` | `14d` | No | Keep rotated logs for N days (e.g., `14d`, `30d`) |
|
|
371
|
+
| `MCP_BRIDGE_MAX_LOG_SIZE` | `20m` | No | Rotate when file reaches size (e.g., `20m`, `100m`) |
|
|
372
|
+
| `MCP_BRIDGE_ROTATE_DATEPATTERN` | `YYYY-MM-DD` | No | Date pattern for rotated log filenames |
|
|
373
|
+
| **Development & Debugging** ||||
|
|
374
|
+
| `DEBUG` | `false` | No | Enable debug mode (verbose logging) |
|
|
375
|
+
| `LOG_LEVEL` | `info` | No | Log level override: `error`, `warn`, `info`, `debug` |
|
|
376
|
+
| `MCP_BRIDGE_DEBUG_TRANSPORT` | `false` | No | Enable transport-level debug logging |
|
|
377
|
+
| **Advanced/Internal** ||||
|
|
378
|
+
| `ACTUAL_API_CONCURRENCY` | `5` | No | Max concurrent Actual API operations |
|
|
379
|
+
| `NODE_ENV` | `production` | No | Node environment; `production` hides stack traces in error responses |
|
|
380
|
+
| `VERSION` | auto-detected | No | Server version (auto-set by build/Docker) |
|
|
381
|
+
| `TZ` | `UTC` | No | Timezone for timestamps (e.g., `America/New_York`) |
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Multi-Budget Switching
|
|
386
|
+
|
|
387
|
+
Configure multiple Actual Budget files so the AI can switch between them at runtime using `actual_budgets_list_available` and `actual_budgets_switch`.
|
|
388
|
+
|
|
389
|
+
`BUDGET_N_SERVER_URL` and `BUDGET_N_PASSWORD` fall back to `ACTUAL_SERVER_URL` / `ACTUAL_PASSWORD` when omitted.
|
|
390
|
+
|
|
391
|
+
| Variable | Required | Fallback |
|
|
392
|
+
|----------|----------|---------|
|
|
393
|
+
| `BUDGET_DEFAULT_NAME` | No | `"Default"` |
|
|
394
|
+
| `BUDGET_N_NAME` | Yes (enables group) | — |
|
|
395
|
+
| `BUDGET_N_SYNC_ID` | Yes | — |
|
|
396
|
+
| `BUDGET_N_SERVER_URL` | No | `ACTUAL_SERVER_URL` |
|
|
397
|
+
| `BUDGET_N_PASSWORD` | No | `ACTUAL_PASSWORD` |
|
|
398
|
+
| `BUDGET_N_ENCRYPTION_PASSWORD` | No | — |
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
# Default budget
|
|
402
|
+
ACTUAL_SERVER_URL=http://actual:5006
|
|
403
|
+
ACTUAL_PASSWORD=my-password
|
|
404
|
+
ACTUAL_BUDGET_SYNC_ID=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
|
|
405
|
+
BUDGET_DEFAULT_NAME=Personal
|
|
406
|
+
|
|
407
|
+
# Budget 1 — same server, same password
|
|
408
|
+
BUDGET_1_NAME=Family
|
|
409
|
+
BUDGET_1_SYNC_ID=bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb
|
|
410
|
+
|
|
411
|
+
# Budget 2 — different server
|
|
412
|
+
BUDGET_2_NAME=Business
|
|
413
|
+
BUDGET_2_SERVER_URL=https://actual-office.example.com
|
|
414
|
+
BUDGET_2_PASSWORD=office-password
|
|
415
|
+
BUDGET_2_SYNC_ID=cccccccc-cccc-cccc-cccc-cccccccccccc
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Transport & Authentication
|
|
421
|
+
|
|
422
|
+
The server supports two transport modes:
|
|
423
|
+
|
|
424
|
+
| Mode | Flag | Use case | Auth |
|
|
425
|
+
|------|------|----------|------|
|
|
426
|
+
| HTTP | `--http` | LibreChat, LobeChat, Docker, multi-user deployments | Bearer token or OIDC |
|
|
427
|
+
| stdio | `--stdio` | Claude Desktop, Cursor, local single-user use | None (OS process isolation) |
|
|
428
|
+
|
|
429
|
+
The two modes are mutually exclusive — pass exactly one flag when starting the server.
|
|
430
|
+
|
|
431
|
+
### stdio transport
|
|
432
|
+
|
|
433
|
+
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.
|
|
434
|
+
|
|
435
|
+
**Key properties of stdio mode:**
|
|
436
|
+
|
|
437
|
+
- No network port — the transport is a pipe, not a socket
|
|
438
|
+
- No auth token — process ownership is the security boundary
|
|
439
|
+
- All logs go to stderr so they never corrupt the JSON-RPC framing on stdout
|
|
440
|
+
- The process exits when stdin closes (Claude Desktop shutting down)
|
|
441
|
+
- All 62 tools are available, identical to HTTP mode
|
|
442
|
+
|
|
443
|
+
**Start manually to verify:**
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
cd /path/to/actual-mcp-server
|
|
447
|
+
ACTUAL_SERVER_URL=http://localhost:5006 \
|
|
448
|
+
ACTUAL_PASSWORD=your_password \
|
|
449
|
+
ACTUAL_BUDGET_SYNC_ID=your-sync-id \
|
|
450
|
+
node dist/src/index.js --stdio
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Send a test request (keep stdin open with `sleep`):
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
{ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'; sleep 5; } \
|
|
457
|
+
| ACTUAL_SERVER_URL=http://localhost:5006 ACTUAL_PASSWORD=your_password ACTUAL_BUDGET_SYNC_ID=your-sync-id \
|
|
458
|
+
node dist/src/index.js --stdio 2>/dev/null
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**Claude Desktop config** (`claude_desktop_config.json`):
|
|
462
|
+
|
|
463
|
+
```json
|
|
464
|
+
{
|
|
465
|
+
"mcpServers": {
|
|
466
|
+
"actual-budget": {
|
|
467
|
+
"command": "node",
|
|
468
|
+
"args": ["/absolute/path/to/actual-mcp-server/dist/src/index.js", "--stdio"],
|
|
469
|
+
"env": {
|
|
470
|
+
"ACTUAL_SERVER_URL": "http://localhost:5006",
|
|
471
|
+
"ACTUAL_PASSWORD": "your_actual_password",
|
|
472
|
+
"ACTUAL_BUDGET_SYNC_ID": "your-sync-id-here",
|
|
473
|
+
"MCP_BRIDGE_DATA_DIR": "/absolute/path/to/actual-mcp-server/actual-data"
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
> **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`.
|
|
481
|
+
|
|
482
|
+
See [docs/guides/MCP_CLIENTS_SETUP.md](docs/guides/MCP_CLIENTS_SETUP.md) for all connection options (stdio native, mcp-remote via HTTP/HTTPS), other clients (Cursor, VS Code, Gemini CLI, Claude Code), Linux path fixes, and troubleshooting.
|
|
483
|
+
|
|
484
|
+
### HTTP transport
|
|
485
|
+
|
|
486
|
+
**HTTP transport** uses the `/http` endpoint (StreamableHTTP) with optional Bearer token or OIDC authentication.
|
|
487
|
+
|
|
488
|
+
#### Static Bearer token (single-user)
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
# Generate a token
|
|
492
|
+
openssl rand -hex 32
|
|
493
|
+
|
|
494
|
+
# Add to .env
|
|
495
|
+
MCP_SSE_AUTHORIZATION=your_token_here
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Clients send: `Authorization: Bearer your_token_here`
|
|
499
|
+
|
|
500
|
+
#### OIDC (multi-user)
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
AUTH_PROVIDER=oidc
|
|
504
|
+
OIDC_ISSUER=https://sso.yourdomain.com
|
|
505
|
+
OIDC_RESOURCE=your-client-id # must match 'aud' JWT claim
|
|
506
|
+
OIDC_SCOPES= # leave empty for Casdoor
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
See [AI Client Setup — OIDC](docs/guides/AI_CLIENT_SETUP.md#oidc-authentication-multi-user) for `AUTH_BUDGET_ACL` format and Casdoor notes.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Testing
|
|
514
|
+
|
|
515
|
+
| Command | What It Tests | Requires Live Server |
|
|
516
|
+
|---------|---------------|---------------------|
|
|
517
|
+
| `npm run build` | TypeScript compilation | No |
|
|
518
|
+
| `npm run test:unit-js` | 62-tool smoke, schema validation, auth ACL | No |
|
|
519
|
+
| `npm run test:adapter` | Adapter, retry logic, concurrency | No |
|
|
520
|
+
| `npm run test:e2e` | MCP protocol compliance (Playwright) | No |
|
|
521
|
+
| `npm run test:e2e:docker:full` | Full stack integration | Yes (Docker) |
|
|
522
|
+
| `npm run test:integration` | Live server sanity checks | Yes |
|
|
523
|
+
| `npm run test:integration:full` | Full live integration suite | Yes |
|
|
524
|
+
|
|
525
|
+
**Integration test levels** (`tests/manual/`): `sanity` → `smoke` → `normal` → `extended` → `full` → `cleanup`
|
|
526
|
+
|
|
527
|
+
See [`tests/manual/README.md`](tests/manual/README.md) and [`tests/e2e/README.md`](tests/e2e/README.md) for details.
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Documentation
|
|
532
|
+
|
|
533
|
+
| Document | Contents |
|
|
534
|
+
|---|---|
|
|
535
|
+
| [docs/guides/MCP_CLIENTS_SETUP.md](docs/guides/MCP_CLIENTS_SETUP.md) | **Start here** — connect Claude Desktop, Cursor, VS Code (Copilot), Gemini CLI, or Claude Code |
|
|
536
|
+
| [docs/guides/AI_CLIENT_SETUP.md](docs/guides/AI_CLIENT_SETUP.md) | LibreChat & LobeChat setup, Docker networking, HTTPS/TLS proxy, OIDC |
|
|
537
|
+
| [docs/guides/DEPLOYMENT.md](docs/guides/DEPLOYMENT.md) | Docker, Docker Compose profiles, production config, Kubernetes |
|
|
538
|
+
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Component layers, data flow, transport protocols |
|
|
539
|
+
| [docs/SECURITY_AND_PRIVACY.md](docs/SECURITY_AND_PRIVACY.md) | Auth models, threat model, hardening |
|
|
540
|
+
| [docs/TESTING_AND_RELIABILITY.md](docs/TESTING_AND_RELIABILITY.md) | Test strategy, coverage, reliability patterns |
|
|
541
|
+
| [docs/NEW_TOOL_CHECKLIST.md](docs/NEW_TOOL_CHECKLIST.md) | Step-by-step guide for adding a new MCP tool |
|
|
542
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Development setup, code standards, PR process |
|
|
543
|
+
| [.env.example](.env.example) | Fully annotated environment variable reference |
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Comparison with Similar Projects
|
|
548
|
+
|
|
549
|
+
Several MCP servers exist for personal finance management. Here's how this project compares with the closest alternatives.
|
|
550
|
+
|
|
551
|
+
> **Snapshot date**: 2026-03-20. Versions and features reflect each project's latest release at that date.
|
|
552
|
+
|
|
553
|
+
### Feature Comparison
|
|
554
|
+
|
|
555
|
+
| Feature | **agigante80/actual-mcp-server** | [s-stefanov/actual-mcp](https://github.com/s-stefanov/actual-mcp) | [henfrydls/actual-budget-mcp](https://github.com/henfrydls/actual-budget-mcp) | [WGDevelopment/ynab-mcp-server](https://github.com/WGDevelopment/ynab-mcp-server) |
|
|
556
|
+
|---|---|---|---|---|
|
|
557
|
+
| **Version** | v0.4.26 | v1.11.1 | v0.2.0 | v0.1.0 |
|
|
558
|
+
| **Budget App** | Actual Budget (self-hosted) | Actual Budget (self-hosted) | Actual Budget (self-hosted) | YNAB (cloud, subscription) |
|
|
559
|
+
| **Language** | TypeScript / Node.js | TypeScript / Node.js | TypeScript / Node.js | Python |
|
|
560
|
+
| **Tool Count** | **62** | ~22 | 18 | 9 |
|
|
561
|
+
| **— Setup & Distribution —** |||||
|
|
562
|
+
| **Transport** | HTTP + stdio | STDIO + SSE option | STDIO | STDIO |
|
|
563
|
+
| **Docker support** | ✅ Full (image + Compose) | ✅ Image only | ❌ | ❌ |
|
|
564
|
+
| **Published package (npx/pip)** | ✅ `npx actual-mcp-server` | ✅ `npx actual-mcp` | ✅ `npx actual-budget-mcp` | ✅ `pip install ynab-mcp` |
|
|
565
|
+
| **— Security & Access —** |||||
|
|
566
|
+
| **Authentication** | ✅ Bearer token + OIDC (JWKS) | ⚠️ Optional Bearer token | ❌ None (local only) | ✅ OS keyring / env var |
|
|
567
|
+
| **Read-only mode** | ❌ All tools always available | ✅ Write requires `--enable-write` flag | ❌ | ✅ Most tools are read-only |
|
|
568
|
+
| **Multi-budget switching** | ✅ Runtime switch via tool | ❌ | ❌ | ✅ (YNAB natively multi-budget) |
|
|
569
|
+
| **— Production & Reliability —** |||||
|
|
570
|
+
| **Connection pooling** | ✅ Up to 15 concurrent sessions | ❌ | ❌ | ❌ |
|
|
571
|
+
| **Retry / backoff** | ✅ 3 attempts, exponential backoff | ❌ | ❌ | ❌ |
|
|
572
|
+
| **Automated test suite** | ✅ Unit + E2E + integration | ❌ | ❌ | ❌ |
|
|
573
|
+
| **— Transactions —** |||||
|
|
574
|
+
| **Create / update / delete** | ✅ | ✅ | ✅ | ✅ |
|
|
575
|
+
| **Import & reconcile** | ✅ `actual_transactions_import` | ❌ | ❌ | ❌ |
|
|
576
|
+
| **Scheduled / recurring** | ❌ (planned) | ❌ | ❌ | ❌ |
|
|
577
|
+
| **— Analysis & Reporting —** |||||
|
|
578
|
+
| **ActualQL custom queries** | ✅ 6 exclusive tools + `actual_query_run` | ❌ | ❌ | N/A |
|
|
579
|
+
| **Summary by category / payee** | ✅ | ✅ spending-by-category | ✅ | ❌ |
|
|
580
|
+
| **Spending projections / forecast** | ❌ | ❌ | ✅ end-of-month forecast | ❌ |
|
|
581
|
+
| **Budget vs actual comparison** | ✅ via `actual_budgets_getMonth` | ❌ | ✅ dedicated tool | ✅ month summary |
|
|
582
|
+
| **Bank sync** | ✅ GoCardless / SimpleFIN | ❌ | ✅ | ❌ (YNAB handles sync natively) |
|
|
583
|
+
| **— Budget Management —** |||||
|
|
584
|
+
| **Set / transfer / carryover / hold** | ✅ Full (10 tools) | ❌ | ✅ Partial | ✅ Partial |
|
|
585
|
+
| **Batch budget updates** | ✅ `actual_budget_updates_batch` | ❌ | ❌ | ❌ |
|
|
586
|
+
| **— Accounts, Payees & Rules —** |||||
|
|
587
|
+
| **Account lifecycle (close/reopen)** | ✅ | ❌ | ❌ | N/A |
|
|
588
|
+
| **Payee merging** | ✅ `actual_payees_merge` | ❌ | ❌ | N/A |
|
|
589
|
+
| **Payee rules management** | ✅ Full CRUD | ✅ Full CRUD | ❌ | N/A |
|
|
590
|
+
| **— UX & Usability —** |||||
|
|
591
|
+
| **Natural language date parsing** | ❌ YYYY-MM-DD required | ❌ | ✅ "last month", "yesterday" | ❌ |
|
|
592
|
+
| **Bilingual support** | ❌ | ❌ | ✅ English + Spanish | ❌ |
|
|
593
|
+
| **Auto name → UUID resolution** | ⚠️ Explicit tool (`actual_get_id_by_name`) | ❌ | ✅ Automatic in all tools | ❌ |
|
|
594
|
+
| **AI prompt templates** | ❌ | ✅ financial-insights, budget-review | ❌ | ❌ |
|
|
595
|
+
| **Tested AI clients** | LibreChat, LobeChat | Claude Desktop, Codex | Claude Desktop, Cursor, VS Code | Claude Code |
|
|
596
|
+
| **License** | MIT | MIT | MIT | MIT |
|
|
597
|
+
|
|
598
|
+
### When to choose which project
|
|
599
|
+
|
|
600
|
+
- **This project** — best for production deployments, multi-user environments (OIDC), LibreChat/LobeChat, Docker-native setup, or for Claude Desktop users who want a native stdio connection without any HTTP server overhead.
|
|
601
|
+
- **s-stefanov/actual-mcp** — the original implementation; good for Claude Desktop with STDIO transport, AI-generated prompt templates, and built-in read-only mode.
|
|
602
|
+
- **henfrydls/actual-budget-mcp** — best for Spanish-speaking users, Cursor/VS Code integration, or when you want natural-language dates, automatic name resolution, and spending forecasts without any server setup.
|
|
603
|
+
- **WGDevelopment/ynab-mcp-server** — only option if you're a YNAB user; privacy-first design with OS keyring token storage and local-LLM focus.
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Contributing
|
|
608
|
+
|
|
609
|
+
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code standards, and the PR process.
|
|
610
|
+
|
|
611
|
+
Quick flow:
|
|
612
|
+
1. Fork → `git checkout -b feature/my-feature`
|
|
613
|
+
2. Make changes + add tests
|
|
614
|
+
3. `npm run build && npm run test:unit-js` must pass
|
|
615
|
+
4. Open a Pull Request
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## Architecture
|
|
620
|
+
|
|
621
|
+
- **Runtime**: Node.js 22 (Alpine Linux in Docker)
|
|
622
|
+
- **Language**: TypeScript 5.9 (ESM, NodeNext module resolution)
|
|
623
|
+
- **MCP SDK**: `@modelcontextprotocol/sdk` ^1.25.2
|
|
624
|
+
- **Actual API**: `@actual-app/api` ^26.3.0
|
|
625
|
+
- **Validation**: Zod (runtime types + JSON Schema for tool inputs)
|
|
626
|
+
- **Transports**: Express + StreamableHTTP (`--http`) · `StdioServerTransport` (`--stdio`)
|
|
627
|
+
- **Logging**: Winston with daily rotation (all output routed to stderr in stdio mode)
|
|
628
|
+
|
|
629
|
+
Every Actual API call goes through the `withActualApi()` wrapper in `src/lib/actual-adapter.ts`, which handles init/shutdown lifecycle, retry (3 attempts, exponential backoff), and concurrency limiting. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for full design documentation.
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## License
|
|
634
|
+
|
|
635
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## Acknowledgments
|
|
640
|
+
|
|
641
|
+
- **[Actual Budget](https://actualbudget.org/)** — open-source budgeting software
|
|
642
|
+
- **[Model Context Protocol](https://modelcontextprotocol.io/)** — standardised AI-app integration
|
|
643
|
+
- **[LibreChat](https://github.com/danny-avila/LibreChat)** — open-source ChatGPT alternative
|
|
644
|
+
- **[s-stefanov/actual-mcp](https://github.com/s-stefanov/actual-mcp)** — original adapter pattern
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## Disclaimer
|
|
649
|
+
|
|
650
|
+
This project started as a **personal learning exercise** to explore the [Model Context Protocol](https://modelcontextprotocol.io/) technology. It is an independent open-source project, not affiliated with, endorsed by, or supported by [Actual Budget](https://actualbudget.org/) or any other organisation.
|
|
651
|
+
|
|
652
|
+
The software is provided **as-is**, without warranty of any kind. The author accepts no responsibility for how it is used, for any data loss, financial errors, or other consequences arising from its use. If you connect it to real financial data, you do so entirely at your own risk.
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## Support
|
|
657
|
+
|
|
658
|
+
- **[GitHub Issues](https://github.com/agigante80/actual-mcp-server/issues)** — bug reports and feature requests
|
|
659
|
+
- **[GitHub Discussions](https://github.com/agigante80/actual-mcp-server/discussions)** — questions and ideas
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
**Version:** 0.5.0 | **Tool Count:** 62 (verified LibreChat-compatible)
|