loading…
Search for a command to run...
loading…
Enables querying personal finance data including accounts, transactions, spending, holdings, net worth, and budgets from your self-hosted OpenCoffer instance. S
Enables querying personal finance data including accounts, transactions, spending, holdings, net worth, and budgets from your self-hosted OpenCoffer instance. Supports natural language queries through any MCP-compatible client.

Self-hosted personal finance with bank sync, dashboards, and a BYO-LLM chat that actually reads your numbers.
License: MIT Next.js Postgres Docker MCP
Quick start · Features · MCP · Configuration · Security
OpenCoffer is read-only against your financial accounts. It syncs through SimpleFIN, stores everything in a Postgres database you own, encrypts sensitive tokens and model keys at rest, and lets you ask finance questions through the in-app chat or any MCP-compatible client. Bring any model you want — OpenAI, Anthropic, OpenRouter, Groq, Together, Ollama, Hermes, ChatGPT subscription auth, or any OpenAI-compatible endpoint.
/api/mcp exposing the same finance tools used by chat, so any MCP client (Claude Desktop, Hermes, custom agents) can query your data with a bearer token.![]() Overview — net worth, cash flow, intelligence |
![]() Charts — deterministic, regenerated on sync |
![]() Chat — BYO model, persistent history |
The fastest path — Postgres, web, and worker running in three commands.
# 1. Generate secrets
cp .env.example .env
echo "NEXTAUTH_SECRET=$(openssl rand -base64 32)" >> .env
echo "APP_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> .env
# 2. Start Postgres, run migrations, then bring up the full stack
docker compose up -d postgres
docker compose run --rm web pnpm db:migrate
docker compose up -d --build
Open http://localhost:3000, create an account, then add a SimpleFIN setup token in Settings → Connections.
[!IMPORTANT]
APP_ENCRYPTION_KEYencrypts your SimpleFIN access URLs and LLM API keys at rest. Back it up. Rotating it makes existing encrypted secrets unreadable.
Requirements: Node.js 22, pnpm (via Corepack), Postgres 16+.
corepack enable
pnpm install
cp .env.example .env.local
# Point DATABASE_URL at your local Postgres, then:
pnpm db:migrate
pnpm dev # web on :3000
pnpm worker # background sync + categorization (second terminal)
For production-mode testing (recommended for mobile / LAN testing — next dev compiles on demand and is slow over the network):
pnpm build
pnpm start
pnpm worker
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Next.js │ │ Postgres 16 │ │ Worker │
│ (web) │◄───►│ (drizzle) │◄───►│ (cron) │
│ │ │ │ │ │
│ /dashboard │ │ accounts │ │ • sync │
│ /chat │ │ txns │ │ • categorize│
│ /settings │ │ insights │ │ • insights │
│ /api/mcp ───┼──┐ │ snapshots │ │ • snapshots │
└──────────────┘ │ │ budgets │ └──────┬───────┘
│ │ chat_msgs │ │
│ │ llm_creds* │ │
│ │ mcp_tokens* │ ▼
│ └──────────────┘ ┌──────────────┐
│ │ SimpleFIN │
▼ │ bridge │
┌─────────────────┐ └──────────────┘
│ MCP client │
│ (Claude / │ * encrypted with
│ Hermes / etc) │ APP_ENCRYPTION_KEY
└─────────────────┘
The worker is part of the release runtime, not optional dev tooling. It syncs SimpleFIN connections, categorizes new transactions with your chosen analysis model, refreshes AI insights, writes net-worth snapshots, and purges disconnected connections after their retention window.
All configuration lives in .env (Docker) or .env.local (dev). See .env.example for the full list.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | Postgres connection string |
NEXTAUTH_SECRET |
Yes | Auth.js session secret — openssl rand -base64 32 |
NEXTAUTH_URL |
Yes | Public URL of the web app |
APP_ENCRYPTION_KEY |
Yes | 32-byte base64 key for at-rest encryption of secrets |
APP_URL |
Yes | Used in MCP setup snippets shown in the UI |
OPENCOFFER_SYNC_CRON |
No | Worker sync cadence (default */30 * * * *) |
OLLAMA_BASE_URL |
No | Pre-seeded base URL when using the bundled Ollama profile |
To run Ollama inside the compose network:
docker compose --profile ollama up -d ollama
Then point the app at http://ollama:11434/v1 (inside Docker) or http://host.docker.internal:11434/v1 (host Ollama from a container).
OpenCoffer can talk to the same backend the official codex CLI uses, so a ChatGPT Plus/Pro/Business subscription works as a model credential — no extra OpenAI API spend.
Install the official Codex CLI and sign in with your ChatGPT account:
npm install -g @openai/codex
codex login
This opens a browser, completes the OAuth flow, and writes a token bundle to ~/.codex/auth.json.
In OpenCoffer, go to Settings → Models → Add credential and pick ChatGPT Plus/Pro subscription as the provider.
Paste the entire contents of ~/.codex/auth.json into the credential field and pick a model (e.g. one of the GPT-5.x options exposed via the codex backend). Leave the base URL blank — OpenCoffer defaults to https://chatgpt.com/backend-api/codex.
Save. OpenCoffer encrypts the token bundle with APP_ENCRYPTION_KEY and automatically refreshes the access token against auth.openai.com when it's within 60 seconds of expiry. If a refresh ever fails (you signed out elsewhere, the refresh token rotated, etc.), re-run codex login and paste the new auth.json.
This works for both the in-app chat and the background analysis model (categorization, insights, snapshots). Same auth, same provider config.
OpenCoffer uses SimpleFIN for read-only bank and brokerage data. There are no app-wide credentials — each user pastes their own setup token in Settings → Connections. The token is claimed once; the resulting access URL is encrypted with APP_ENCRYPTION_KEY.
Disconnecting a connection marks it for purge after 30 days. Hard-delete removes it immediately.
OpenCoffer exposes its finance tools to MCP-compatible clients at /api/mcp.
# 1. Create a token in Settings → MCP
# 2. Wire it into your MCP client (Hermes example):
hermes mcp add opencoffer \
--transport http \
--url http://localhost:3000/api/mcp \
--header "Authorization: Bearer oc_<your-token>"
Tool families available over MCP:
accounts recent_transactions transaction_search
spending_by_category holdings recurring_streams
upcoming_payments net_worth budgets
alerts chart_data category_fixes
The LLM writes the commentary; finance totals come from deterministic database-backed tools. No hallucinated balances.
APP_ENCRYPTION_KEY./api/mcp uses bearer auth instead of session cookies.NEXTAUTH_SECRET, APP_ENCRYPTION_KEY, .env, database backups, and SimpleFIN setup/access URLs private.See SECURITY.md for the full policy and disclosure channel.
docker compose logs -f web
docker compose logs -f worker
docker compose run --rm web pnpm db:migrate # apply new migrations
docker compose pull && docker compose up --build -d
Back up Postgres before upgrades:
docker compose exec postgres pg_dump -U opencoffer opencoffer > opencoffer.sql
docker compose exec -T postgres psql -U opencoffer opencoffer < opencoffer.sql
The hero GIF lives at public/demo.gif. It's rendered from real app screenshots captured with fake demo data — never real account data.
# Remotion source (preferred — produces the higher-res GIF)
cd demo/remotion
pnpm install
pnpm run render:gif # writes ../../public/demo.gif
# Deterministic Python fallback (no Remotion / Chromium required)
python3 scripts/generate-demo-gif.py
PRs welcome. See CONTRIBUTING.md for the local setup and the checks that should pass before opening a PR:
npx --no-install tsc --noEmit
pnpm lint
pnpm build
MIT © OpenCoffer contributors.
Run in your terminal:
claude mcp add opencoffer -- npx