
lunchmoney-mcp-server-oauth
by Squixx
lunchmoney-mcp-server-oauth
Self-hostable remote MCP server for Lunch Money with a built-in OAuth 2.1 authorization server — so it works as a claude.ai custom connector on Claude mobile, web, and desktop, as well as Claude Code and any other Streamable-HTTP MCP client.
Wraps @akutishevsky/lunchmoney-mcp (40+ tools covering transactions, budgets, categories, recurring items, assets, crypto, tags) and serves it over HTTP.
Why this exists
If you want Claude on your phone to see your Lunch Money data, your options were all bad:
| Option | Problem |
|---|---|
| stdio MCP servers (most community servers) | Local-only; Claude mobile can't use them |
| HTTP server + static bearer token | claude.ai custom connectors have no field for a static header — OAuth is the only supported auth (anthropics/claude-ai-mcp#112) |
| Hosted MCP platforms | You hand a third party your Lunch Money API token — full read/write access to your finances |
| No auth | Your finances, public |
This server closes the gap: it implements the minimal OAuth 2.1 surface Claude needs (RFC 8414 + RFC 9728 discovery, RFC 7591 dynamic client registration, authorization-code grant with mandatory S256 PKCE, rotating refresh tokens), with a single shared secret as the consent "login". Your API token never leaves your box.
How it works
- You add
https://lm.example.com/mcpas a custom connector in Claude. - Claude discovers the OAuth metadata, registers itself as a client, and opens a browser to the consent page.
- You paste your
MCP_AUTH_TOKEN(a secret you generated) once. - Claude receives access + refresh tokens and keeps them fresh on its own, across all your Claude surfaces.
Stateless by design: every artifact the server issues — client IDs,
authorization codes, access and refresh tokens — is an HMAC-signed blob
keyed off MCP_AUTH_TOKEN via HKDF. There is no database and no session
store, which means:
- container restarts don't log Claude out
- the container runs with a read-only filesystem
- rotating
MCP_AUTH_TOKENinstantly revokes every client and token — that's your kill switch
| Artifact | Lifetime |
|---|---|
| authorization code | 2 min, single-use |
| access token | 1 hour |
| refresh token | 90 days, rotated on every refresh |
Quick start
# 1. Secrets
cp docker-compose.example.yml docker-compose.yml
cat > .env <<EOF
LUNCHMONEY_API_TOKEN=<lunchmoney.app -> Settings -> Developers>
LUNCHMONEY_MCP_TOKEN=$(openssl rand -base64 48)
EOF
# 2. Set BASE_URL in docker-compose.yml to your public https URL, then:
docker compose up -d
# 3. Put a TLS reverse proxy in front (see below), then add the connector
# in Claude: Settings -> Connectors -> Add custom connector ->
# https://lm.example.com/mcp
The image is multi-arch (amd64/arm64), built on Google's distroless Node 22 (no shell, no package manager, runs as non-root uid 65532), published by CI from this repo: `ghcr.io/squixx/l
Related servers

n8n
by n8n-io
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

@modelcontextprotocol/server-everything
OfficialMCP server that exercises all the features of the MCP protocol

@modelcontextprotocol/server-filesystem
OfficialMCP server for filesystem access