Skip to main content
ClaudeWave

Forward a receipt to your inbox and it's filed automatically.

MCP ServersRegistry oficial1 estrellas0 forksTypeScriptActualizado today
Install in Claude Code / Claude Desktop
Method: Manual
Claude Code CLI
git clone https://github.com/assaf/expense
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "expense": {
      "command": "node",
      "args": ["/path/to/expense/dist/index.js"],
      "env": {
        "DATABASE_URL": "<database_url>",
        "RESEND_API_KEY": "<resend_api_key>",
        "INBOUND_EMAIL_WEBHOOK_SECRET": "<inbound_email_webhook_secret>",
        "DEEPSEEK_API_KEY": "<deepseek_api_key>"
      }
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Clone https://github.com/assaf/expense and follow its README for install instructions.
Detected environment variables
DATABASE_URLRESEND_API_KEYINBOUND_EMAIL_WEBHOOK_SECRETDEEPSEEK_API_KEY
Casos de uso

Resumen de MCP Servers

# Expense

> Expense is a receipt tracker with no friction: receipts arrive by email and file themselves, mileage prices itself from IRS rates, and an AI assistant does the data entry you'd rather skip — capture, log, and ask, all through MCP.

## Screenshots

![Expense list — reports, receipts, and a mileage route](public/screenshot-home.png)

![Receipt editor with the receipt image](public/screenshot-expense.png)

What it does:

- Log expenses two ways: receipt-based (upload/scan an image, add date, report,
  category, merchant, amount) and mileage (drive route on a map — Leaflet + OSRM
  — with configurable per-year mileage rates)
- **Receipts by email**: forward a receipt to your inbox address and it's
  parsed (merchant/amount/category) and added automatically — see below
- Organize into reports and categories; every receipt image is stored and
  auto-renamed to a convention (YYYY-MM-DD_Report_Name.jpg)
- Export: PDF per report (with embedded receipt images) and a ZIP of everything
- Settings: reports, categories, mileage rates, home location for mileage routes

Stack:

- React Router v8 (framework mode) + Tailwind v4, TypeScript
- Postgres via Prisma — accounts, users, expenses, reports, categories,
  settings, mileage, image blobs
- Images: Postgres BYTEA (prod and dev/test) — no external store
- Deployed on Vercel + Neon (git push to main auto-deploys)

Auth & accounts (the recent work):

- Email/password login (scrypt-hashed), sessions via signed cookies
- Multi-user accounts: each account has its own data, users in the same account
  share everything, other accounts fully isolated
- New users join an account via an 8-char invite code (shown in Settings,
  regenerable); anyone can self-signup into a fresh account
- Image keys are namespaced per account so two accounts can never collide

## Accounts & sharing

Login is email/password (scrypt-hashed) — the email is the login name, stored
lowercase and unique, format-validated at signup/join. Every expense, report,
category, and setting belongs to an **account**; everyone in an account shares
them, and accounts are fully isolated from each other.

- **Sign up** → creates a brand-new account (starts empty).
- **Join** → enter an account's invite code (Settings → Account) to share
  that account's data.
- The first account/user is bootstrapped from `APP_EMAIL`/`APP_PASSWORD`
  when the database is empty; pre-email accounts get their login backfilled
  from `APP_EMAIL` on first start (initStore).

## SEO & AI discovery

The public marketing pages double as the site's AI-search surface: when
someone asks an assistant for a free expense tracker, GPTBot / OAI-SearchBot /
ClaudeBot / PerplexityBot crawl and quote them. The copy is written as
standalone, quotable answers that name the app and its URL, and it lives in
ONE place — `app/lib/seo-content.ts` — which renders every surface:

| Page                                     | Purpose                                                        |
| ---------------------------------------- | -------------------------------------------------------------- |
| `/`                                      | Landing page (SoftwareApplication JSON-LD)                     |
| `/about`                                 | Full feature/benefit list (AboutPage JSON-LD)                  |
| `/faq`                                   | 13 Q&As matching real AI queries (FAQPage JSON-LD)             |
| `/alternatives`                          | Expense vs Expensify comparison (WebPage + FAQPage JSON-LD)    |
| `/llms.txt`                              | The llmstxt.org file — the curated overview AI assistants read |
| `/about.md` `/faq.md` `/alternatives.md` | Markdown mirrors per the llms.txt convention                   |

Supporting plumbing: `public/robots.txt` explicitly allows the AI crawlers
(GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot / Claude-SearchBot /
Claude-User, PerplexityBot / Perplexity-User, Google-Extended,
Applebot-Extended, meta-externalagent) while app routes stay blocked, and
`public/sitemap.xml` lists the public pages.

These routes are public (see the root loader in `app/root.tsx`); everything
else still requires a session.

## What it does

- Track **receipt** expenses (date, merchant, amount, image, category, report)
  and **mileage** expenses (date, 2+ addresses, distance, amount, report).
- Mileage routes run **Home → stops → Home**; distance is computed via OSRM and
  the amount from a per-year mileage rate. Maps use Leaflet + OpenStreetMap —
  **no API keys required**.
- Incomplete expenses are highlighted so they're easy to finish.
- Paste (⌘V) or upload an image anywhere to start a new receipt.
- **Export**: each report as a PDF (grouped by category, with all receipt
  images), or everything as a ZIP (CSV + images named `YYYY-MM-DD_REPORT_FILE.ext`).
- **AI assistants (MCP)**: any MCP client — Claude Code, Claude Desktop,
  Cursor — connects by signing in with your account (OAuth; no API keys).
  See [AI assistants](#ai-assistants-mcp) below.

## AI assistants (MCP)

The app speaks the Model Context Protocol at `https://expense.labnotes.org/mcp`
(auth: OAuth 2.1 authorization-code + PKCE — sign in with your account and
approve the connection; no API keys). An assistant connected to your account
can:

- **Capture a receipt** — a photo or PDF in the chat runs the same OCR +
  extraction pipeline as the web app and is categorized from your own
  merchant history.
- **Log a drive** — give it stops in plain English; it geocodes, routes, and
  prices the trip at the year's IRS rate.
- **Answer spending questions** — "how much did I spend on flights last
  quarter?" gets the exact total from your data.
- **Build reports** — create/close reports, move expenses into them, export
  a report PDF.
- **Reconcile** — paste a bank statement CSV; it finds every charge with no
  matching receipt (read-only).

Connect any MCP client:

```json
// Claude Code — .mcp.json (no headers needed: the client discovers OAuth)
{
  "mcpServers": {
    "expense": {
      "type": "http",
      "url": "https://expense.labnotes.org/mcp"
    }
  }
}
```

The client opens your browser; you sign in and click Allow. Manage
connections (per-token delete, full disconnect) in **Settings → Agents &
API (MCP)**. See [`docs/mcp.md`](docs/mcp.md) for the full reference and
[`docs/mcp-directories.md`](docs/mcp-directories.md) for the directory
listings.

## State

Storage is Postgres-only via **Prisma** (`prisma/schema.prisma` is the
single schema source of truth; the client is generated to
`prisma/generated` by `pnpm build:prisma`). `DATABASE_URL` is required at
startup (the app exits with a clear error otherwise). Receipt images live in
Postgres BYTEA (`image_blobs`) in prod and dev — no separate storage service.

| Data                        | Images                         |
| --------------------------- | ------------------------------ |
| `accounts` / `users` /      | Postgres BYTEA (`image_blobs`, |
| `expenses` / `reports` /    | prod and dev)                  |
| `categories` / `settings` / |                                |
| `mileage` / `image_blobs`   |                                |

All reads/writes go through `app/lib/store.server.ts` (→
`app/lib/database.ts`, Prisma queries scoped by `accountId`); image storage
is behind `app/lib/images.server.ts` (Prisma `imageBlob`).
Keys are `images/{accountId}/...` pathnames on every backend — namespaced
per account so two accounts can never collide on the same filename.
Schema changes: edit `prisma/schema.prisma`, then `prisma migrate dev --name …` locally and
`pnpm db:push` (or `pnpm db:migrate`) before deploying.

### `data/` — removed

The file-era migration source (`data/*.csv` + `data/images/*` and the
`pnpm migrate-data` one-off) was deleted in the Jul 2026 cleanup — data now
lives in the database, and importing from Expensify happens via
`scripts/import-expensify.ts`. Cloning prod uses `scripts/clone`
(`prisma/backup.sql`).

## Quick start

## Environment variables

Load order: real `process.env` (Vercel dashboard, or inline) wins; a local
`.env` file fills the gaps. `DATABASE_URL` is required; `.env` is gitignored. if
(!hasDatabase()) {

**dev / test — local `.env`:**

```bash
# .env (project root, gitignored)
DATABASE_URL=postgres://assaf@localhost/expense_dev   # include the local user
SESSION_SECRET=…         # signs the session cookie (random hex)
APP_EMAIL=…           # bootstrap: first account's email (empty DB only)
APP_PASSWORD=…           # bootstrap: first account's password (empty DB only)
# Receipts by email (all optional):
# RESEND_API_KEY=re_…            INBOUND_EMAIL_WEBHOOK_SECRET=whsec_…
# INBOUND_EMAIL_ADDRESS=receipts@example.com   # forwarding + reply sender
# DEEPSEEK_API_KEY=sk-…          RECEIPT_OCR_MODE=auto
```

On an empty database the first account + user are bootstrapped from
`APP_EMAIL`/`APP_PASSWORD` (fail-closed if missing); afterwards users are
created through the app's signup/join flow. `SESSION_SECRET` is always
required. `APP_EMAIL`/`APP_PASSWORD` can be removed from `.env` once you
have at least one user.

Accounts created before email login (username era) keep their old username
as the stored email until `APP_EMAIL` is set — `initStore` then backfills
that address onto the bootstrap (oldest) user, so the configured credentials
keep working.

Tests intentionally hardcode `expense_test` (Postgres incl. image blobs),
ignore the local database, and reset the schema from Prisma on each run
(`pnpm test:db:push` in the test setup).

**prod — Vercel:** set env vars in the project dashboard (Settings →
Environment Variables): `DATABASE_URL` (Vercel Postgres / Neon pooled URL),
`SESSION_SECRET`,
and (only until the first user exists) `APP_EMAIL` / `APP_PASSWORD`.
Vercel injects them at runtime; `.env` never exists there.

## Receipts by email

Forward a receipt email to your inbox address and it's parsed and added
automatically: the merchant, amount, and ca
expense-trackerexpensesmcp-servertaxeswebapp

Lo que la gente pregunta sobre expense

¿Qué es assaf/expense?

+

assaf/expense es mcp servers para el ecosistema de Claude AI. Forward a receipt to your inbox and it's filed automatically. Tiene 1 estrellas en GitHub y se actualizó por última vez today.

¿Cómo se instala expense?

+

Puedes instalar expense clonando el repositorio (https://github.com/assaf/expense) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.

¿Es seguro usar assaf/expense?

+

assaf/expense aún no ha sido auditado por nuestro agente de seguridad. Revisa el repositorio original en GitHub antes de usarlo en producción.

¿Quién mantiene assaf/expense?

+

assaf/expense es mantenido por assaf. La última actividad registrada en GitHub es de today, con 0 issues abiertos.

¿Hay alternativas a expense?

+

Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.

Despliega expense en tu cloud

Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.

¿Mantienes este repo? Añade un badge a tu README

Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.

Featured on ClaudeWave: assaf/expense
[![Featured on ClaudeWave](https://claudewave.com/api/badge/assaf-expense)](https://claudewave.com/repo/assaf-expense)
<a href="https://claudewave.com/repo/assaf-expense"><img src="https://claudewave.com/api/badge/assaf-expense" alt="Featured on ClaudeWave: assaf/expense" width="320" height="64" /></a>

Más MCP Servers

Alternativas a expense