Monarch Money MCP
FastMCP Python MCP server + REST API for Monarch Money β Docker-based, stateless, dual-protocol (any MCP client + any REST client)
Ask AI about Monarch Money MCP
Powered by Claude Β· Grounded in docs
I know everything about Monarch Money MCP. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
Monarch Money MCP Server
A portable Docker-based server that exposes Monarch Money personal finance data via two protocols simultaneously:
/mcpβ FastMCP streamable-HTTP for AI assistants that support the MCP protocol (Claude Desktop, etc.)/api/*β Plain REST endpoints for automation tools like n8n, Zapier, or custom scripts/healthβ Unauthenticated health check
Getting Started
Step 1 β Prerequisites
- Docker and Docker Compose installed
- A Monarch Money account
Step 2 β Generate your API key
This is the key that protects all endpoints. Generate one now and keep it handy:
python -c "import secrets; print(secrets.token_hex(32))"
Copy the output β you'll use it as MCP_API_KEY in the next step.
Step 3 β Create your .env file
cp .env.example .env
Open .env and fill it in. There are two ways to authenticate with Monarch:
Option A β Email + Password (easiest to start)
If you don't have a Monarch token yet, just use your login credentials:
MCP_API_KEY=your-generated-key-here
MONARCH_EMAIL=you@example.com
MONARCH_PASSWORD=your-monarch-password
If your account has 2FA enabled, you also need to add MONARCH_MFA_SECRET β see the 2FA setup section below before continuing.
Start the server:
docker compose up -d
Then grab your token so you can switch to Option B (recommended for long-term use):
curl -H "Authorization: Bearer your-generated-key-here" http://localhost:8000/api/token
You'll get back:
{ "token": "5de1575d9833c4eb..." }
Copy that token value and set it as MONARCH_TOKEN in your .env β then you can remove MONARCH_EMAIL and MONARCH_PASSWORD.
Option B β Token only (recommended for long-term / production)
Once you have your Monarch token (from Option A above, or extracted from your browser), set it directly:
MCP_API_KEY=your-generated-key-here
MONARCH_TOKEN=5de1575d9833c4eb...
The server uses the token directly and never makes a login call β this is stateless and works perfectly across container restarts.
Where to find your token in a browser: Open Monarch Money β DevTools (F12) β Application tab β Local Storage β look for a key containing
token. Or: Network tab β any API request β copy theAuthorization: Token ...header value.
Step 4 β Start the server
docker compose up -d
Step 5 β Verify it's working
# Health check (no auth needed)
curl http://localhost:8000/health
# Fetch your accounts (replace with your MCP_API_KEY)
curl -H "Authorization: Bearer your-generated-key-here" http://localhost:8000/api/accounts
You should see {"status": "ok"} and a JSON list of your accounts. If you do, you're good to go.
Environment Variables
| Variable | Required | Description |
|---|---|---|
MCP_API_KEY | β Yes | Protects all endpoints β generate with secrets.token_hex(32) |
MONARCH_TOKEN | Either/Or | Monarch bearer token (stateless, preferred) |
MONARCH_EMAIL | Either/Or | Email for login fallback |
MONARCH_PASSWORD | Either/Or | Password for login fallback |
MONARCH_MFA_SECRET | If 2FA enabled | TOTP Base32 secret key (see below) |
PORT | No | Port to listen on (default: 8000) |
You need either MONARCH_TOKEN or both MONARCH_EMAIL + MONARCH_PASSWORD. Token is preferred β it's faster and stateless.
2FA / TOTP Setup
If your Monarch account has two-factor authentication enabled, you must provide the raw Base32 secret key β NOT the 6-digit rotating code you type when logging in.
Finding your TOTP secret
From a password manager (e.g. 1Password, Bitwarden):
- Open your Monarch Money login entry
- Click Edit
- Find the OTP / Authenticator field β Copy Secret Key
- It looks like:
JBSWY3DPEHPK3PXP(uppercase letters and numbers, ~20β32 characters)
From Monarch directly (requires disabling and re-enabling 2FA):
- Go to Settings β Security β Two-factor authentication
- Click Disable, then re-enable it
- On the setup screen, Monarch shows a "two-factor text code" β that's the raw seed
Add it to .env:
MONARCH_MFA_SECRET=JBSWY3DPEHPK3PXP
The server uses the monarchmoney library to auto-compute the 6-digit TOTP code from the secret β you never need to type the 6-digit code manually.
Important:
MONARCH_MFA_SECRETis only needed when using email/password login (Option A). If you're usingMONARCH_TOKENdirectly, 2FA is already baked into the token and this variable is not needed.
REST API Endpoints
All endpoints require: Authorization: Bearer {MCP_API_KEY} except /health.
GET /health
Unauthenticated health check.
{ "status": "ok" }
GET /api/accounts
All accounts with current balances, types, and metadata.
No query parameters.
GET /api/transactions
Transactions with optional filtering.
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 100 | Max transactions to return (max 500) |
start_date | YYYY-MM-DD | β | Filter from this date inclusive |
end_date | YYYY-MM-DD | β | Filter to this date inclusive |
search | string | β | Free-text search across merchant/description |
category_ids | string (comma-separated IDs) | β | Restrict to these category IDs |
account_ids | string (comma-separated IDs) | β | Restrict to these account IDs |
tag_ids | string (comma-separated IDs) | β | Restrict to these tag IDs |
has_attachments | boolean | β | Filter by attachment presence |
has_notes | boolean | β | Filter by note presence |
is_split | boolean | β | Filter split transactions |
is_recurring | boolean | β | Filter recurring transactions |
Example:
GET /api/transactions?limit=50&start_date=2026-03-01&end_date=2026-03-31&search=Netflix
GET /api/cashflow
Detailed cashflow breakdown by category for a period.
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | Period start |
end_date | YYYY-MM-DD | Period end |
GET /api/budgets
Budget categories with planned amounts and actual spending.
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | Budget period start |
end_date | YYYY-MM-DD | Budget period end |
GET /api/recurring
Recurring transactions and subscriptions.
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | Period start |
end_date | YYYY-MM-DD | Period end |
GET /api/networth
Historical net worth snapshots (wraps get_aggregate_snapshots).
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | History start date |
end_date | YYYY-MM-DD | History end date |
POST /api/transaction/{id}
Update a transaction's category, notes, or flags.
Path parameter: id β the Monarch transaction ID
JSON body (all fields optional):
{
"category_id": "string",
"notes": "string",
"hide_from_reports": false,
"needs_review": true
}
GET /api/token
Return the current Monarch session token. Useful for bootstrapping MONARCH_TOKEN after an initial email/password login.
Requires auth. Returns:
{ "token": "5de1575d..." }
MCP Tools
get_accounts
Return all Monarch Money accounts with current balances, types, and metadata.
No parameters.
get_transactions
Return transactions with optional filtering.
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 100 | Max transactions (max 500) |
start_date | YYYY-MM-DD | β | Filter from this date inclusive |
end_date | YYYY-MM-DD | β | Filter to this date inclusive |
search | string | β | Free-text search across merchant/description |
category_ids | list[string] | β | Restrict to these category IDs |
account_ids | list[string] | β | Restrict to these account IDs |
tag_ids | list[string] | β | Restrict to these tag IDs |
has_attachments | boolean | β | Filter by attachment presence |
has_notes | boolean | β | Filter by note presence |
is_split | boolean | β | Filter split transactions only |
is_recurring | boolean | β | Filter recurring transactions only |
get_cashflow_summary
Return cashflow totals β income, expenses, and savings rate β for a period.
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | YYYY-MM-DD | First of current month | Period start |
end_date | YYYY-MM-DD | Today | Period end |
get_cashflow
Return detailed cashflow breakdown by category.
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | Period start |
end_date | YYYY-MM-DD | Period end |
get_budgets
Return budget categories with planned amounts and actual spending.
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | Budget period start |
end_date | YYYY-MM-DD | Budget period end |
get_recurring_transactions
Return recurring transactions and subscriptions.
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | Period start |
end_date | YYYY-MM-DD | Period end |
get_account_holdings
Return current holdings for an investment account.
| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | string | β | Monarch account ID β get from get_accounts first |
get_net_worth_history
Return historical net worth snapshots.
| Parameter | Type | Description |
|---|---|---|
start_date | YYYY-MM-DD | History start date |
end_date | YYYY-MM-DD | History end date |
get_transaction_categories
Return all transaction categories with IDs. Use IDs with get_transactions filters or set_budget_amount.
No parameters.
update_transaction
Update a transaction's category, notes, or flags. All fields except transaction_id are optional.
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction_id | string | β | The transaction ID to update |
category_id | string | β | New category ID (from get_transaction_categories) |
notes | string | β | Free-text notes / memo |
hide_from_reports | boolean | β | Exclude from spending reports |
needs_review | boolean | β | Flag as needing review |
set_budget_amount
Set the monthly budget amount for a category.
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | float | β | Budget amount in USD |
category_id | string | β | Category ID (from get_transaction_categories) |
start_date | YYYY-MM-01 | β | First day of the target month |
Claude Desktop Config
Add this to your claude_desktop_config.json. Since Claude Desktop requires stdio-based MCP entries, use mcp-proxy as a bridge:
{
"mcpServers": {
"monarch-money": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"http://localhost:8000/mcp"
],
"env": {
"API_ACCESS_TOKEN": "YOUR_MCP_API_KEY"
}
}
}
}
uvxis bundled with uv. Install it withpip install uvorbrew install uv.
n8n HTTP Request Config
- Method: GET (or POST for updates)
- URL:
http://your-host:8000/api/accounts - Headers:
Authorization: Bearer YOUR_MCP_API_KEY - Response format: JSON
Generate a Secure API Key
python -c "import secrets; print(secrets.token_hex(32))"
Coolify Deployment
This server is Coolify-ready. The docker-compose.yml uses an environment: block with ${VAR} substitution β Coolify detects these and surfaces them in its Environment Variables UI. No .env file needed on the server.
- Create a new Coolify resource β Docker Compose
- Point it at this repository
- Set your environment variables in the Coolify UI (
MCP_API_KEYis required; others are optional with sensible defaults) - Deploy β Coolify's Traefik proxy handles HTTPS automatically
Acknowledgments
This project is built on top of monarchmoney by @hammem β the Python client library that handles all Monarch Money API communication. None of this would be possible without that work.
