# bookie [![npm](https://img.shields.io/npm/v/bookie-mcp)](https://www.npmjs.com/package/bookie-mcp) [![Publish to npm](https://github.com/yuens1002/bookie/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/yuens1002/bookie/actions/workflows/npm-publish.yml) **An MCP server that keeps books for freelancers and landlords — driven from Claude or GPT instead of QuickBooks.** Ask your LLM to import a bank statement, categorize spending, reconcile a month, or generate a Schedule C. Bookie provides the correct double-entry ledger underneath — so the model reasons over real numbers, not a spreadsheet it's improvising on the fly. **This is for you if:** you're a solopreneur, freelancer, or rental property owner already living in Claude or GPT, you're comfortable with a 5-minute setup, and you want books that are actually correct. **Not for you if:** you want a dashboard UI, you need multi-user access, or you're satisfied with QuickBooks / a spreadsheet. ## What you need before starting - **Node ≥ 24** - **[neonctl](https://neon.com/docs/reference/neon-cli)** — `npm install -g neonctl` (free [Neon](https://neon.tech) account; needed for the DB) - **An MCP-capable host:** Claude Desktop, Claude.ai, Cursor, VS Code, or any host supporting the MCP stdio or HTTP transport ## Quick start (local, stdio) **Recommended — from source, fully automated:** ```bash git clone https://github.com/yuens1002/bookie cd bookie npm install npm run setup # creates Neon DB, generates secrets, writes .env, runs db:push npm run build ``` `npm run setup` opens a browser to log into Neon; new to Neon? Use the "Sign up for an account" link and pick GitHub/Google/Microsoft rather than email+password — it completes in the same browser round-trip, no email-verification detour that could interrupt the CLI mid-wait. `npm run setup` prints a ready-to-paste Claude Desktop config block at the end: ```json { "mcpServers": { "bookie": { "command": "node", "args": ["/absolute/path/to/bookie/dist/index.js"], "env": { "BOOKIE_DB_URL": "", "BOOKIE_DB_DIRECT_URL": "", "BOOKIE_API_KEY": "" } } } } ``` **Adding another machine to the same ledger — no clone needed:** stdio is a *local* process — every machine running a stdio MCP client spawns its own copy of the server, so each one otherwise needs its own checkout. Once the Neon DB is provisioned (via `npm run setup` above, on any one machine), every *other* machine just needs the same connection strings — no `git clone`, no `npm install`, no `npm run build` to keep in sync. Point that machine's MCP host at the [published package](https://www.npmjs.com/package/bookie-mcp) instead: ```json { "mcpServers": { "bookie": { "command": "npx", "args": ["-y", "bookie-mcp"], "env": { "BOOKIE_DB_URL": "", "BOOKIE_DB_DIRECT_URL": "", "BOOKIE_API_KEY": "" } } } } ``` `npx` fetches and runs the published version on demand — every machine pointed at the same `BOOKIE_DB_URL` shares one ledger, without any of them (besides the original) needing a checkout. **Bootstrapping a DB without cloning at all:** if you don't have connection strings yet from any machine (e.g. you created the Neon project manually instead of via `npm run setup`), push bookie's bundled schema directly: ```bash mkdir bookie-mcp && cd bookie-mcp npm install bookie-mcp BOOKIE_DB_URL= BOOKIE_DB_DIRECT_URL= npx prisma db push --schema=node_modules/bookie-mcp/prisma/schema.prisma ``` Then use the same `npx -y bookie-mcp` config above. ## Quick start (remote, HTTP — for Claude.ai mobile) Deploy to Railway with one click: [![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/X2T0sN?referralCode=X2mmSS) Railway pulls the pre-built image from GHCR — no source build needed. Set the required env vars when prompted. See [docs/DEPLOYING.md](docs/DEPLOYING.md) for the full walkthrough (env var reference, Neon + Resend setup, Claude.ai OAuth connector). ## Why no UI? The host LLM already reads CSVs, sees receipt images, and writes prose. Bookie owns the things an LLM *shouldn't* improvise: a correct double-entry ledger, integer-cent money math, deterministic categorization rules, and reproducible reports. The model handles language and vision; the server handles the books. ## Tools The full, always-current tool reference lives in [`docs/TOOLS.md`](docs/TOOLS.md) (regenerate with `npm run docs:tools`). Today: | Tool | What it does | |------|--------------| | `manage_accounts` | Create/list/archive accounts (segment-scoped categories carry a tax line) | | `add_transaction` | Record one balanced double-entry (money flows from → to) | | `split_transaction` | One payment leg + N category legs (a receipt split across categories) | | `import_transactions` | Import a bank/card CSV as balanced entries — preview → confirm, with dedup | | `manage_rules` | Create/list/delete/test/suggest auto-categorization rules (categorize → account/property, or exclude) that power import-preview suggestions; `action=suggest` scans past categorizations and returns candidate rules for descriptions with 2+ occurrences | | `categorize_transaction` | Re-categorize the income/expense leg of an existing entry — explicit account or apply a stored rule | | `reconcile` | Match a bank/card statement CSV against the ledger and mark postings cleared — preview then commit | | `manage_receipts` | Attach, list, delete, or get a signed download URL for receipt data; optionally upload the original file (JPEG, PNG, WEBP, HEIC, or PDF) to Railway Bucket storage | | `generate_report` | Monthly reconciliation summary, or fiscal-year Schedule C / Schedule E tax P&L | | `export_report` | Render any report as markdown or CSV | | `send_report` | Run a report and email it via Resend | | `query_transactions` | List entries + postings by date range / account | | `account_balances` | Current balance per account | ## Resources Bookie exposes two MCP resources that an LLM can read without calling a tool: | Resource URI | MIME type | What it contains | |-------------|-----------|-----------------| | `bookie://accounts` | `application/json` | All active accounts with their current balances | | `bookie://reports/{year}` | `text/markdown` | Annual fiscal snapshot: Schedule C, Schedule E, and a one-row-per-month summary (opening balance, net income, cleared postings count) | ## Prompts Three canned workflow prompts guide the LLM through common bookkeeping tasks: | Prompt | Parameters | Purpose | |--------|-----------|---------| | `monthly-close` | `year`, `month` | Step-by-step month-end close: import CSV → categorize → reconcile → report → (optional) email | | `categorize-uncategorized` | _(none)_ | Find journal entries with no income/expense leg and walk through categorizing each | | `prepare-tax-summary` | `year` | Generate Schedule C + E, export as markdown and CSV, optionally email | ## Configuration See [`.env.example`](.env.example) for the full reference. Key variables: | Variable | Purpose | |----------|---------| | `BOOKIE_TRANSPORT` | `stdio` (default) or `http` | | `BOOKIE_DB_URL` | Neon pooled connection string | | `BOOKIE_DB_DIRECT_URL` | Neon direct connection string (for `db push`) | | `BOOKIE_API_KEY` | Static Bearer token (Claude Desktop / direct API) | | `PUBLIC_URL` | Public HTTPS base URL of the deployed server (Claude.ai connector) | | `JWT_SECRET` | HS256 signing secret for OAuth JWT access tokens | | `OAUTH_CLIENT_ID` | OAuth client ID (default: `claude-ai-connector`) | | `OAUTH_CLIENT_SECRET` | Required when using OAuth: `/authorize` refuses all requests when unset (prevents any visitor from authorizing); `/token` also validates it. Enter this value in the Claude.ai connector settings. | | `RESEND_API_KEY` | Resend API key for `send_report` | | `RESEND_FROM` | Verified sender address for `send_report` (e.g. `Bookie `) | | `AWS_ENDPOINT_URL` / `AWS_S3_BUCKET_NAME` / `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_DEFAULT_REGION` | Railway Bucket credentials — auto-injected when you connect a bucket to the service (use AWS SDK Generic style); enables receipt file upload in `manage_receipts` | ## Docs - [Architecture](docs/ARCHITECTURE.md) — data model, transports, layering - [Deploying](docs/DEPLOYING.md) — Railway + Neon + Resend setup - [Roadmap](docs/ROADMAP.md) — phased plan - [Changelog](CHANGELOG.md) — what shipped - [Releasing](docs/RELEASING.md) — versioning + release process - [Tools](docs/TOOLS.md) — generated manual - [Contributing](CONTRIBUTING.md) — setup, conventions, tests ## Safety Bookie stores financial data in your Neon Postgres database; connection strings live in `.env` (gitignored) and Railway env vars — never commit them. The HTTP transport requires auth on every `/mcp` request: either a static Bearer token (`BOOKIE_API_KEY`) or an OAuth JWT issued by the `/token` endpoint. Always set at least one before exposing the server beyond localhost. See [docs/DEPLOYING.md](docs/DEPLOYING.md) for the full Claude.ai connector OAuth setup. ## License MIT