One server for the whole household
Run ynab-mcp on a server you control and everyone can use it from claude.ai, the Claude apps or any MCP client, each with their own YNAB account.
When to self-host
For one person using Claude Desktop or Claude Code on one computer, the local install is simpler and you can stop there. Self-host when you want any of these:
- to use your budget from claude.ai or the Claude mobile apps, which connect to remote servers;
- to share one instance with a partner, family or small team, with nobody seeing anyone else's budget;
- to keep tokens off individual laptops.
There is no central ynab-mcp service. You run the instance: it fetches each user's YNAB data from YNAB and sends tool results only to that user's MCP client, which passes them to Claude as part of the conversation. See Where your data goes.
How it works
In HTTP mode with OAuth configured, the server signs people in with YNAB itself. There are no separate accounts or passwords: a person's identity is their YNAB user.
- MCP clientclaude.ai, Claude Desktop, Claude Code
- Your ynab-mcp serverShows a consent screen, stores each user's YNAB grant encrypted
- YNABThe user approves access to their budget
- A person adds your server's
/mcpaddress to their client. - The client registers with your server and opens its consent page, which names the client and where it will send them back.
- They choose read-only or read-write and continue to YNAB to approve.
- Your server stores their YNAB grant, encrypted, and gives the client its own short-lived token. From then on, every request runs as that person, with their own cache, rate limit and audit log.
Setup at a glance
- Register a YNAB OAuth application in YNAB's Developer Settings, with the redirect URI
https://YOUR_PUBLIC_URL/oauth/ynab/callback. - Generate an encryption key with
openssl rand -base64 32and keep it somewhere safe. It must stay the same across restarts. - Set the environment:
MCP_TRANSPORT=http,PUBLIC_URL,YNAB_OAUTH_CLIENT_ID,YNAB_OAUTH_CLIENT_SECRET,ENCRYPTION_KEY, and a durableSTORAGE_DRIVER. OAuth mode turns on when the four OAuth settings are all present. - Put it behind TLS. OAuth needs HTTPS. A reverse proxy such as Caddy, Traefik or nginx in front of the container is the usual way. Set
TRUST_PROXY=1for a single proxy hop, but only when the server is reachable solely through the proxy (publish no ports). Otherwise clients can spoofX-Forwarded-Forand dodge the per-IP rate limits. - Connect a client to
https://YOUR_PUBLIC_URL/mcp.
A minimal Docker Compose service looks like this (the guide has the full version with Caddy):
services:
ynab-mcp:
image: ghcr.io/auzroz/ynab-mcp:latest
environment:
MCP_TRANSPORT: http
PUBLIC_URL: https://ynab-mcp.example.com
YNAB_OAUTH_CLIENT_ID: ${YNAB_OAUTH_CLIENT_ID}
YNAB_OAUTH_CLIENT_SECRET: ${YNAB_OAUTH_CLIENT_SECRET}
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
STORAGE_DRIVER: sqlite
SQLITE_PATH: /data/ynab-mcp.db
# Only with a proxy in front and no published ports.
TRUST_PROXY: "1"
volumes: [ "ynab-data:/data" ]
volumes: { ynab-data: {} }
Every setting is listed in the configuration reference.
Storage
| Driver | Good for |
|---|---|
memory | Trying it out. The default. Everything is lost on restart, so everyone has to reconnect. |
sqlite | A single instance: a household or a small team. Set SQLITE_PATH to a file on a persistent volume. |
postgres | When you already run Postgres, or want managed backups. Set DATABASE_URL. |
Stored YNAB tokens are encrypted with AES-256-GCM using your ENCRYPTION_KEY. Back the database up like anything else that matters.
Access levels
Read-only or read-write is chosen per connection at the consent screen. Someone can connect their phone read-only and their laptop read-write, and each keeps its own level; a token refresh never widens it.
As the operator you can narrow it further:
YNAB_OAUTH_ALLOW_WRITE=falseoffers only read-only at consent.YNAB_READ_ONLY=true(the default) keeps the whole server read-only, whatever people choose. Set it tofalseto allow read-write connections at all.
Connecting clients
- claude.ai: add a custom connector with the URL
https://YOUR_PUBLIC_URL/mcp. Claude discovers your server's OAuth settings and walks you through consent. - Claude Code:
claude mcp add --transport http ynab https://YOUR_PUBLIC_URL/mcp, then run/mcpin a session to sign in. - Claude Desktop and stdio-only clients: use the
mcp-remoteshim, which runs the same sign-in flow.
npx mcp-remote https://YOUR_PUBLIC_URL/mcp
Without the OAuth settings, HTTP mode takes a YNAB token per request in an X-YNAB-Token header. It is meant for a personal instance on a private network behind TLS. For anything shared or public, use OAuth mode.
Upgrading
Back up the database first. Copy the SQLite file while the server is stopped, or pg_dump the Postgres database. On startup the server updates its schema in place. Read the release notes before upgrading, as some releases ask users to reconnect once.
The full guide
The deployer guide on GitHub has every detail: registering the YNAB app, each setting, the TLS and Compose setup, host and origin checks behind proxies, sessions, token rotation, and upgrades.