Skip to main content
Glama
bhonick

lunchmoney-readonly-mcp

by bhonick

Read-only Lunch Money MCP for ChatGPT

A single-user remote MCP server for Lunch Money, designed for ChatGPT Business and deployed on Cloudflare Workers. It uses Google OAuth only to identify an allowlisted user; the Lunch Money API token is stored as a Cloudflare encrypted secret and is never returned to ChatGPT or an MCP tool.

This project was originally based on the bm1549/lunchmoney-mcp-cloudflare project and has been adapted into a read-only Lunch Money MCP template for Cloudflare Workers and ChatGPT. The bundled upstream implementation is retained under vendor-lunchmoney-mcp, including its original MIT license and attribution. Thanks to Brian Marks for the original work.

This repository is a template. It contains no live deployment URL, API token, Google OAuth secret, email address, or Cloudflare resource ID.

Default security model

The default Worker remains strictly read-only and enforces that boundary in two independent layers:

  1. createReadonlyServer() exposes a positive allowlist of 25 retrieval tools. Create, update, delete, upload, sync, refresh, split, grouping, and budget mutation tools are not registered.

  2. runWithReadonlyConfig() rejects any non-GET request to the Lunch Money API before a network request is made.

All retrieval tools declare readOnlyHint: true, destructiveHint: false, and openWorldHint: false.

The optional categorization mode described below does not replace or weaken the default deployment. If ACCESS_MODE is absent, the Worker is read-only.

Related MCP server: Monarch Money MCP Server

Optional category-only sibling Worker

For workflows where an assistant should help categorize transactions without receiving general write access, the same code can be deployed as a second Worker with:

ACCESS_MODE=categorize

That mode adds exactly one mutation tool:

categorize_transaction(transaction_id, category_id)

The category-only server has two independent safety layers:

  1. Its MCP surface is a positive allowlist containing the same 25 retrieval tools plus only categorize_transaction.

  2. Its API policy permits GET, plus a PUT to /transactions/{numeric-id} only when the JSON body contains exactly one key: category_id. All other POST, PUT, DELETE, and upload requests are rejected before fetch.

category_id may be a positive integer or null to remove a category. The categorization tool cannot change amount, date, payee, notes, tags, account, status, recurring linkage, metadata, splits, groups, or attachments.

Why use a sibling Worker?

Keeping two endpoints makes the trust boundary obvious:

  • your existing endpoint stays strictly read-only;

  • the second endpoint is connected only when you intentionally want categorization assistance;

  • a configuration mistake in the categorization deployment does not silently convert the read-only endpoint into a writer.

Requirements

  • A Lunch Money API token

  • A Cloudflare account with Workers and KV available

  • A Google Cloud OAuth 2.0 web client

  • A ChatGPT workspace that supports custom MCP apps

Install and verify

This repository tracks pnpm-lock.yaml, so use pnpm:

corepack enable
corepack prepare pnpm@10.15.0 --activate
pnpm install --frozen-lockfile
pnpm run typecheck
pnpm run lint
pnpm test

Focused access-boundary tests are also available:

pnpm run test:readonly
pnpm run test:categorize

Deploy the read-only Worker

  1. In wrangler.jsonc, choose a unique Worker name and create the OAuth KV namespace:

    pnpm exec wrangler kv namespace create OAUTH_KV

    Copy the returned namespace ID into REPLACE_WITH_OAUTH_KV_NAMESPACE_ID in wrangler.jsonc.

  2. Deploy once to obtain your Worker URL:

    pnpm exec wrangler deploy
  3. Create a Google OAuth 2.0 Web application. Add this redirect URI, replacing the host with your Worker URL:

    https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev/authorize/callback
  4. Set the production secrets interactively. Never put their values in Git:

    pnpm exec wrangler secret put GOOGLE_CLIENT_ID
    pnpm exec wrangler secret put GOOGLE_CLIENT_SECRET
    pnpm exec wrangler secret put ALLOWED_EMAILS
    pnpm exec wrangler secret put STATE_SECRET
    pnpm exec wrangler secret put LUNCHMONEY_API_TOKEN
  5. Deploy again. Your MCP endpoint is:

    https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev/mcp

Deploy the category-only sibling

Do not put personal Worker names, account IDs, KV IDs, or deployment URLs in the public repository. Keep the sibling configuration in the gitignored wrangler.categorize.personal.jsonc.

A practical setup is:

  1. Copy your private read-only deployment configuration to wrangler.categorize.personal.jsonc.

  2. Give it a different Worker name.

  3. Add:

    "vars": {
        "ACCESS_MODE": "categorize"
    }
  4. Prefer a separate OAuth KV namespace for the sibling so its OAuth grants are isolated from the read-only Worker.

  5. Add the sibling Worker's /authorize/callback URL to the Google OAuth web client, or create a separate OAuth client if you want stronger separation.

  6. Set the same required secrets against the sibling configuration:

    pnpm exec wrangler secret put GOOGLE_CLIENT_ID --config wrangler.categorize.personal.jsonc
    pnpm exec wrangler secret put GOOGLE_CLIENT_SECRET --config wrangler.categorize.personal.jsonc
    pnpm exec wrangler secret put ALLOWED_EMAILS --config wrangler.categorize.personal.jsonc
    pnpm exec wrangler secret put STATE_SECRET --config wrangler.categorize.personal.jsonc
    pnpm exec wrangler secret put LUNCHMONEY_API_TOKEN --config wrangler.categorize.personal.jsonc
  7. Deploy it:

    pnpm exec wrangler deploy --config wrangler.categorize.personal.jsonc

Connect the read-only and category-only endpoints as separate ChatGPT apps so you can tell which capability is active.

Connect ChatGPT

  1. In ChatGPT, create a custom app using the Worker's /mcp endpoint and choose OAuth authentication.

  2. Review the custom-app warning, create the draft, then publish and enable it.

  3. Connect with an allowlisted Google account.

  4. Start a fresh chat with the app enabled and verify the tool list before asking it to inspect or categorize Lunch Money data.

Before making the repository public

Run:

pnpm run check:public-release

Also review git status, confirm .dev.vars and both personal Wrangler config files are untracked, and ensure the Worker name, endpoint, Cloudflare resource IDs, and example documentation do not identify your personal deployment.

Verification

The access tests verify:

  • the exact strict read-only tool allowlist;

  • the exact category-only tool allowlist;

  • annotations for read and category-write tools;

  • absence of representative broader mutation tools;

  • rejection of arbitrary writes before network access; and

  • successful passage of only the exact category-only transaction PUT.

See THIRD_PARTY_NOTICES.md for attribution details.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    An MCP server providing full integration with the Lunch Money API to manage financial data including transactions, budgets, assets, and categories. It enables AI assistants to perform CRUD operations on financial records through a standardized HTTP interface.
    26
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Read-only MCP and HTTP proxy server for accessing Monarch Money financial data, enabling transaction analysis, budget tracking, and cashflow insights through natural language.
    6
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    MCP server for programmatic read-only access to RiseUp cashflow data, allowing AI assistants to retrieve budget information via natural language.
    2
    154
    22
    MIT
  • F
    license
    B
    quality
    B
    maintenance
    A read-only MCP server for the Dough personal finance app, enabling assistants to query financial data like balances, transactions, and budgets through natural language.
    8
    -