monarch-mcp
An agentic budgeting companion. A local-first Model Context Protocol server that turns Claude (or any MCP client) into a financial advisor over your Monarch Money data — it knows where your household stands, keeps the books honest, measures progress against your goals, and looks ahead.
[!IMPORTANT] Unofficial. Monarch Money has no public API. This server talks to Monarch's private GraphQL API and is not affiliated with, endorsed by, or supported by Monarch Money. Use at your own risk. See DISCLAIMER.md.
Why this exists
Monarch has no official API, so every Claude↔Monarch integration is a community-built wrapper. Rather than hand a third-party server full access to a live banking session, this is a purpose-built server you can read end to end, with one defining property:
It cannot move money — by construction. There is no transfer, payment, withdrawal, create, or delete code anywhere in it. The only write path can change a transaction's category, tags, or notes — nothing else. Capability denial is enforced by the code's absence of those tools, not by configuration you can misset.
It's read-and-categorize only, your session token never leaves your machine, and the whole thing is validated against real Monarch by a proper test pyramid.
The tools
Compound, task-oriented tools — each does a job, combining several API calls + computation
into one decision-ready result (not 1:1 API wrappers you could replace with curl):
| Tool | What it answers |
|---|---|
financial_overview |
"Where do we stand?" — net worth, this-month cash flow, month-over-month change |
spending_report |
Spending by category vs budget, over-budget flags, likely duplicates, vs prior period |
progress_vs_goals |
Actuals vs your stored goals — on track / drifting / off |
cashflow_forecast |
Upcoming bills + income → projected month-end position + shortfall warnings |
net_worth_trend |
Net worth over time, deltas by account type, biggest movers |
recurring_scan |
New / changed / "creeping" subscriptions and upcoming renewals |
triage_uncategorized + apply_changeset |
Propose categories from your own history, then commit only what you approve |
Quick start
1. Install
# One-line shell installer (macOS / Linux)
|
# PowerShell (Windows)
|
# Cargo, prebuilt binary — no compile (fetches the release artifacts)
# Cargo (from crates.io) — compiles from source
# Or build from source
2. Authenticate (one time)
Prompts for your Monarch email, password, and MFA code. The session token is written to
~/.config/monarch-mcp/session.json (mode 0600) and reused for months — your password and
MFA secret are never stored.
Sign in with Apple/Google? Monarch's API needs email+password. Add a password in Monarch → Settings → Security; your SSO login keeps working alongside it.
3. Register with your MCP client
Claude Code (works today, local stdio):
…or copy .mcp.json.example to .mcp.json in your project.
[!NOTE] Claude Cowork runs MCP servers in an isolated VM and currently can't reach a local stdio server (known issue). Use it from Claude Code on your machine; for Cowork you'd need to expose it as a remote HTTP MCP. See docs for the trade-offs.
4. Use it
"Give me a financial overview." · "How's our spending vs budget this month?" · "Any creeping subscriptions?" · "Are we on track for our goals?"
Goals (optional)
progress_vs_goals measures against a TOML file you point to with MONARCH_GOALS_FILE.
See goals.example.toml:
[]
= 20.0
[]
= 6.0
Security model
- No money movement exists in the binary. The mutating path is an allowlist of
category/tags/notes; any other field in a change request is rejected and reported. - Your token stays local. Auth happens on your machine; the session lives in
~/.config/monarch-mcp/session.json(0600). Credentials are never logged. - Human-in-the-loop writes.
triage_uncategorizedonly proposes; nothing is written until you approve a changeset andapply_changesetcommits exactly that.
Reporting a vulnerability: see SECURITY.md.
How it's built
Production Rust (rmcp + reqwest + tokio), built TDD/BDD-first, with a deliberate
Google test-size pyramid — because
testing only against mocks ships false confidence (it did, twice — see the ADRs):
| Tier | What | Count |
|---|---|---|
| Small | Hermetic, in-process unit tests (the aggregation/classification math) | ~270 |
| Medium | Behave BDD against a mock Monarch GraphQL server over loopback | ~57 |
| Large | Gated (MONARCH_LIVE=1) integration tests against real Monarch |
8 |
&& MONARCH_LIVE=1
The real GraphQL schema and the design decisions are documented in
docs/decisions/ (ADRs 0001–0003).
Project layout
src/ Rust MCP server — client, tools, goals, server, error
bdd/ Python + behave acceptance suite + mock Monarch GraphQL server
tests/ Large/live integration tests (gated)
docs/decisions/ ADRs (auth flow, real schema, tier-2 schema)
docs/specs/ Design spec
Contributing
Contributions welcome — see CONTRIBUTING.md for the dev setup
(mise / lefthook / clippy / rustfmt), the test-pyramid expectations, and the
TDD/BDD workflow. Also read CODE_OF_CONDUCT.md.
For the release process (secrets, merge→publish flow), see docs/RELEASING.md.
License
Dual-licensed under either of MIT or Apache-2.0 at your option. Unless you explicitly state otherwise, any contribution you submit shall be dual-licensed as above, without additional terms.