Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

## 2026-05-28

### Fix broken `uvx` install (0.3.2)

- fixed the published console-script entry point: it pointed at the async `main()`, so `uvx monarch-mcp-jamiew` launched a coroutine that was never awaited and the server never started. Added a synchronous `run()` wrapper. (0.3.0/0.3.1 on PyPI were unusable via `uvx`.)
- floored `monarchmoneycommunity>=1.3.2` since the dev-only git pin isn't carried in the published wheel.
- rewrote the README install section to be `uvx`-first with per-client steps (Claude Desktop, Claude Code, Codex, others, from-source).

### MCP 2025 protocol features: structured output, titles, resource templates, completions, progress

- every tool now returns a typed Pydantic model, so FastMCP advertises an `outputSchema` and emits machine-readable structured content alongside a text fallback for older clients.
- added human-friendly `title`s to all tools, resources, and prompts.
- added parameterized resource templates: `accounts://{account_id}/holdings` and `accounts://{account_id}/history`.
- added argument completions for the prompt `category` and resource-template `account_id`, backed by live Monarch data.
- the batch tools (complete overview, spending patterns) now report progress via an injected Context.
- fixed `get_account_holdings` to pass the required `account_id` — the no-arg version was a latent bug.
- unwrap dict-shaped API responses for `get_accounts`, `get_transaction_categories`, and the autocompletion helpers: the real client returns `{"accounts": [...]}` / `{"categories": [...]}`, so the new structured tools were reporting empty lists on otherwise-successful calls. `get_institutions` now passes its full `{credentials, accounts, subscription}` payload through.

### Dependencies refreshed and mypy 2.x adopted

- bumped the lockfile to latest compatible across the board (pydantic 2.13, cryptography 48, starlette 1.2, rich 15, mcp 1.27, monarchmoneycommunity 1.3.2).
Expand Down
52 changes: 26 additions & 26 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,23 @@ refactor: split server.py into modular components (auth, tools, models)
- Structured logging with `structlog` for debugging
- Environment variables: `MONARCH_EMAIL`, `MONARCH_PASSWORD`, `MONARCH_MFA_SECRET`

**Complete Monarch Money API Coverage (22 Tools)**
**Complete Monarch Money API Coverage (19 Tools)**
- **Core**: `get_accounts`, `get_transactions`, `get_budgets`, `get_cashflow`
- **Categories**: `get_transaction_categories`
- **Transactions**: `create_transaction`, `update_transaction`, `update_transactions_bulk`, `search_transactions`
- **Investments**: `get_account_holdings`, `get_account_history`
- **Investments**: `get_account_holdings` (requires `account_id`), `get_account_history`
- **Banking**: `get_institutions`, `refresh_accounts`
- **Planning**: `get_recurring_transactions`, `set_budget_amount`
- **Manual**: `create_manual_account`
- **Batch Operations**: `get_transactions_batch`, `get_spending_summary`, `update_transactions_bulk`
- **Batch Operations**: `get_spending_summary`, `update_transactions_bulk`
- **Intelligent Analysis**: `get_complete_financial_overview`, `analyze_spending_patterns`
- **Analytics**: `get_usage_analytics`

**Type-Safe Data Processing**
- Pydantic models for validation (still available for reference)
- `convert_dates_to_strings()` ensures JSON compatibility
- Strict typing throughout (only 8 mypy warnings remain - untyped decorators)
Also exposes 5 MCP resources (3 static lists + 2 parameterized templates: `accounts://{account_id}/holdings|history`) and 4 prompt templates.

**Type-Safe Structured Output**
- Every tool returns a typed Pydantic model, so FastMCP advertises an `outputSchema` and emits structured content (plus a text fallback for older clients). See the "Structured output models" block in `server.py`.
- Monarch's GraphQL responses are dicts (e.g. `{"accounts": [...]}`), not bare lists. Use `extract_list(response, key)` (next to `extract_transactions_list`) to unwrap the inner list before counting it — passing the dict straight into a `list[...]` model field silently yields an empty list.
- `convert_dates_to_strings()` ensures JSON compatibility.

### Monarch Money API Integration

Expand Down Expand Up @@ -230,6 +231,10 @@ Server runs as MCP server configured in `.mcp.json` with:
- Absolute paths required for proper MCP integration
- Implements MCP capability negotiation for feature discovery

### Releasing & Publishing

Published to PyPI as `monarch-mcp-jamiew` and to the MCP Registry as `io.github.jamiew/monarch-mcp`. Users install via `uvx monarch-mcp-jamiew` (no clone) — so the `[project.scripts]` `monarch-mcp-jamiew = "server:run"` entry point must stay a *synchronous* wrapper (`run()`), never the async `main()` directly, or `uvx` launches a coroutine that's never awaited. Release flow: `/release` bumps `pyproject.toml`, tags `vX.Y.Z`, and `gh release create`s; the `release: published` event triggers `.github/workflows/publish.yml`, which publishes to both PyPI and the registry via **OIDC trusted publishing — no tokens stored**. The workflow sets `server.json`'s version from the tag, so `pyproject.toml` is the only manual version bump. Note: `[tool.uv.sources]`'s git pin of `monarchmoneycommunity` is dev-only and is *not* in the published wheel — PyPI installs resolve the `>=1.3.2` floor from `pyproject.toml` dependencies.

### Session Management

- Session files stored in `.mm/` directory (created automatically)
Expand All @@ -248,9 +253,10 @@ Server runs as MCP server configured in `.mcp.json` with:
- **✅ Structured Logging**: Context-rich logs with `structlog`
- **✅ Complete API Coverage**: All 14 Monarch Money API methods as tools

#### Quality Metrics (Updated October 2025)
- **70 passing tests** with comprehensive coverage including analytics, search, and bulk operations
- **MyPy errors reduced**: 111 → 84 (mainly untyped external decorators, ongoing improvement)
#### Quality Metrics (Updated May 2026)
- **202 passing tests** with comprehensive coverage including analytics, search, bulk operations, structured output, completions, resource templates, and progress
- **19 tools** (all returning typed Pydantic models / structured output), 3 static resources + 2 resource templates, 4 prompts
- **MyPy clean** under the repo's strict config (no `Any` at non-boundaries, no `as`)
- **Security**: Proper session handling and MFA support
- **Modern stack**: FastMCP 1.12.2, Pydantic, structlog, pytest
- **Usage analytics**: Real-time performance tracking and optimization suggestions
Expand All @@ -259,8 +265,7 @@ Server runs as MCP server configured in `.mcp.json` with:
### ✅ ADVANCED FEATURES (Recently Completed)

#### Smart Tool Design & UX
- **✅ Batch operations**: `get_transactions_batch()` for efficient multi-queries with parallel execution
- **✅ Bulk updates** (NEW October 2025): `update_transactions_bulk()` for updating multiple transactions in one call
- **✅ Bulk updates**: `update_transactions_bulk()` for updating multiple transactions in one call
- Parallel execution for maximum performance
- Individual error handling per transaction
- Summary statistics (succeeded/failed counts)
Expand All @@ -273,10 +278,9 @@ Server runs as MCP server configured in `.mcp.json` with:
- **✅ Smart aggregations**: `get_spending_summary()` with category/account/month grouping
- **✅ AsyncIO Runtime Fix**: Server now uses `mcp.run_stdio()` for proper MCP protocol compliance

#### Usage Analytics & Optimization (NEW)
- **✅ Usage tracking**: `@track_usage` decorator on all 20 tools for comprehensive analytics
#### Usage Analytics & Optimization
- **✅ Usage tracking**: `@track_usage` decorator on every tool for comprehensive analytics (logs tool calls, timing, and result sizes to stderr — there is no `get_usage_analytics` tool; analytics are observed via Claude's MCP log)
- **✅ Performance monitoring**: Execution time, error rates, and pattern detection
- **✅ Intelligent batching**: Real-time analysis of usage patterns to suggest optimizations
- **✅ Analytics logging**: Special markers in Claude's MCP log for easy filtering and optimization insights
- **✅ Session-based tracking**: UUID-based session tracking with in-memory pattern analysis

Expand All @@ -292,12 +296,7 @@ Server runs as MCP server configured in `.mcp.json` with:
- Predictive forecasting based on 3-month rolling averages
- Smart aggregations with confidence indicators
- Account usage patterns and category performance metrics

- **✅ Optimization Insights**: `get_usage_analytics()` - Real-time optimization:
- Tool usage frequency analysis and performance metrics
- Automatic detection of common usage sequences (30-second windows)
- Intelligent suggestions for batch operations
- Performance bottleneck identification
- Reports progress through an injected `Context` (`ctx.report_progress`)

#### Production Stability & Reliability Fixes (NEW)
- **✅ JSON-RPC Protocol Compliance**: All logging redirected to stderr to prevent stdout contamination
Expand Down Expand Up @@ -354,7 +353,7 @@ Server runs as MCP server configured in `.mcp.json` with:
- Add investment performance tracking and portfolio analysis

#### 6. Advanced Tool Features
**Current State**: All 20 core tools implemented
**Current State**: 19 core tools implemented
**Remaining Work:**
- Add bulk transaction operations (import/export)
- Implement transaction search with fuzzy matching
Expand All @@ -364,7 +363,7 @@ Server runs as MCP server configured in `.mcp.json` with:
### 🔄 REMAINING LOW PRIORITY TASKS

#### 7. Code Architecture & Organization
**Current State**: Single file with 20 tools, comprehensive tests
**Current State**: Single file with 19 tools, comprehensive tests
**Remaining Work:**
- Split into modules: `auth.py`, `tools.py`, `models.py`, `config.py` (optional - current structure works well)
- Implement Pydantic Settings for configuration management
Expand Down Expand Up @@ -400,7 +399,7 @@ Server runs as MCP server configured in `.mcp.json` with:
5. **Phase 5 (Intelligence)**: ML features, advanced analytics, financial insights
6. **Phase 6 (Ecosystem)**: MCP extensions, developer tools, architectural improvements

**Current Status** (Updated October 2025): Production-ready with 70 passing tests, 22 intelligent tools, comprehensive analytics, robust error handling, and enhanced reliability. Recent features: `update_transactions_bulk()` for parallel batch updates, `search_transactions` tool for efficient context-aware search, detailed tool call debugging with result size tracking. Recent critical fixes completed: authentication retry bug (stale client after re-auth), date serialization, broken pipe handling, dependency updates, and enhanced date parsing. Server is stable and ready for real-world usage with excellent user experience for date filtering, bulk operations, and error recovery.
**Current Status** (Updated May 2026): Production-ready with 202 passing tests, 19 intelligent tools, comprehensive analytics, robust error handling, and enhanced reliability. Recent MCP modernization: every tool returns structured output (outputSchema + structured content with a text fallback), tools/resources/prompts carry human-friendly `title`s, parameterized resource templates (`accounts://{account_id}/holdings|history`), argument completions for prompts/templates, and Context-based progress reporting on the batch tools. Earlier features: `update_transactions_bulk()` for parallel batch updates, `search_transactions`, result-size tracking; fixes for the auth retry bug, date serialization, broken pipes, and date parsing. Note: `get_account_holdings` now requires an `account_id` (the underlying library always did).

## Upstream Library & Fork Landscape

Expand Down Expand Up @@ -436,5 +435,6 @@ Re-run this analysis periodically (e.g. quarterly, or when something breaks):
- **MCP Python SDK**: https://github.com/modelcontextprotocol/python-sdk
- **Monarch Money API**: https://github.com/hammem/monarchmoney
- **MCP Server Examples**: https://github.com/modelcontextprotocol/servers
- Current MCP Protocol Version: "2025-06-18"
- Current stable MCP Protocol Version: "2025-11-25" (a newer draft exists that goes stateless and deprecates Sampling/Roots/MCP-logging — this server already logs to stderr, so it's well-positioned)
- This server uses structured tool output (outputSchema), tool/resource/prompt titles, resource templates, completions, and Context progress reporting (all 2025-06-18 features)
- Re-read all resources regularly to ensure compliance with any API or protocol changes
126 changes: 105 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,116 @@ Built on the [`monarchmoneycommunity`](https://github.com/bradleyseanf/monarchmo
## Features

- **19 tools** covering accounts, transactions, budgets, cashflow, investments, categories, goals, net worth, recurring transactions, and more
- **MCP resources** for quick access to categories, accounts, and institutions
- **MCP prompts** for guided financial analysis workflows
- **Structured output** — every tool returns a typed schema (`outputSchema` + machine-readable structured content) with a text fallback for older clients
- **MCP resources** for quick access to categories, accounts, and institutions, plus parameterized templates for per-account holdings and history (`accounts://{account_id}/holdings|history`)
- **MCP prompts** for guided financial analysis workflows, with live argument autocompletion
- **Smart output formatting** — compact transaction format reduces token usage by ~80%
- **Natural language dates** — "last month", "30 days ago", "this year" all work
- **Batch operations** — parallel multi-account queries, bulk transaction updates
- **Batch operations** — parallel multi-account queries, bulk transaction updates, with progress reporting
- **Spending analysis** — multi-month trend analysis with category/account breakdowns
- **Tool annotations** — proper read/write metadata for MCP clients
- **Tool annotations & titles** — read/write metadata and human-friendly titles for MCP clients

## Setup

### 1. Install dependencies
The server is published to [PyPI](https://pypi.org/project/monarch-mcp-jamiew/), so there's nothing to clone — [`uv`](https://docs.astral.sh/uv/) runs it on demand with `uvx`. You'll need `uv` installed and your Monarch credentials (see [Getting your MFA secret](#getting-your-mfa-secret) below).

### Standard config

Every MCP client uses the same shape — command `uvx`, package `monarch-mcp-jamiew`, and your three credentials as env vars:

```json
{
"mcpServers": {
"monarch-money": {
"command": "uvx",
"args": ["monarch-mcp-jamiew"],
"env": {
"MONARCH_EMAIL": "your-email@example.com",
"MONARCH_PASSWORD": "your-password",
"MONARCH_MFA_SECRET": "your-mfa-secret-key"
}
}
}
}
```

Pick your client below for the exact steps.

<details>
<summary><b>Claude Desktop</b></summary>

Edit your config file (create it if it doesn't exist) and add the [standard config](#standard-config) above under `mcpServers`:

- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

Then fully quit and reopen Claude Desktop.

</details>

<details>
<summary><b>Claude Code</b></summary>

```bash
cd /path/to/monarch-mcp
uv sync
claude mcp add monarch-money \
-e MONARCH_EMAIL=your-email@example.com \
-e MONARCH_PASSWORD=your-password \
-e MONARCH_MFA_SECRET=your-mfa-secret-key \
-- uvx monarch-mcp-jamiew
```

### 2. Configure your MCP client
Add `-s user` to make it available across all your projects. Verify with `claude mcp list`.

</details>

<details>
<summary><b>Codex CLI</b></summary>

```bash
codex mcp add monarch-money \
--env MONARCH_EMAIL=your-email@example.com \
--env MONARCH_PASSWORD=your-password \
--env MONARCH_MFA_SECRET=your-mfa-secret-key \
-- uvx monarch-mcp-jamiew
```

Or add the equivalent block to `~/.codex/config.toml`:

```toml
[mcp_servers.monarch-money]
command = "uvx"
args = ["monarch-mcp-jamiew"]
env = { MONARCH_EMAIL = "your-email@example.com", MONARCH_PASSWORD = "your-password", MONARCH_MFA_SECRET = "your-mfa-secret-key" }
```

</details>

<details>
<summary><b>Other clients (Cursor, VS Code, Windsurf, Cline, Zed, …)</b></summary>

Add to your `.mcp.json` (Claude Desktop, Claude Code, etc.):
These all accept the same [standard config](#standard-config) — drop it into the client's MCP config (e.g. Cursor's `~/.cursor/mcp.json`, or VS Code via `code --add-mcp`). Anything that speaks MCP over stdio works.

</details>

<details>
<summary><b>From source (development)</b></summary>

To run against a local checkout (and the git-pinned `monarchmoneycommunity` lib):

```bash
git clone https://github.com/jamiew/monarch-mcp
cd monarch-mcp
uv sync
```

Then point your client at the local copy with absolute paths (find them with `which uv` and `pwd`):

```json
{
"mcpServers": {
"monarch-money": {
"command": "/path/to/uv",
"args": [
"--directory",
"/path/to/monarch-mcp",
"run",
"python",
"server.py"
],
"command": "/abs/path/to/uv",
"args": ["--directory", "/abs/path/to/monarch-mcp", "run", "python", "server.py"],
"env": {
"MONARCH_EMAIL": "your-email@example.com",
"MONARCH_PASSWORD": "your-password",
Expand All @@ -53,9 +130,12 @@ Add to your `.mcp.json` (Claude Desktop, Claude Code, etc.):
}
```

Use absolute paths — find yours with `which uv` and `pwd`.
</details>

> [!NOTE]
> The `claude mcp add` / `codex mcp add` one-liners put your credentials in shell history. If that bothers you, edit the client's config file directly (as shown for Claude Desktop / Codex above) instead.

### 3. Get your MFA secret
### Getting your MFA secret

1. Go to Monarch Money settings and enable 2FA
2. When shown the QR code, look for "Can't scan?" or "Enter manually"
Expand All @@ -75,16 +155,16 @@ Use absolute paths — find yours with `which uv` and `pwd`.
| `update_transactions_bulk` | Update multiple transactions in parallel |
| `get_budgets` | Budget data and spending analysis |
| `get_cashflow` | Income and expense analysis |
| `get_account_holdings` | Investment holdings |
| `get_account_holdings` | Investment holdings for an account (requires `account_id`) |
| `get_account_history` | Account balance history |
| `get_institutions` | Linked financial institutions |
| `get_recurring_transactions` | Recurring transaction detection |
| `set_budget_amount` | Set a budget category amount |
| `create_manual_account` | Create a manually-tracked account |
| `refresh_accounts` | Trigger account data refresh |
| `get_spending_summary` | Spending aggregated by category, account, or month |
| `get_complete_financial_overview` | Combined 5-API call in parallel |
| `analyze_spending_patterns` | Multi-month trend analysis |
| `get_usage_analytics` | Tool usage stats and optimization tips |

### Transaction format

Expand Down Expand Up @@ -142,6 +222,10 @@ Run all checks locally (same as GitHub Actions CI):
uv run python scripts/ci.py
```

### Releasing

Cut a release with the `/release` flow (bump version in `pyproject.toml` → commit → tag `vX.Y.Z` → push → `gh release create`). Publishing the GitHub release triggers [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which builds and pushes to **PyPI** and the **MCP Registry** via OIDC trusted publishing — no API tokens are stored anywhere. The workflow injects the tag version into `server.json` automatically, so `pyproject.toml` is the only version field you bump by hand.

### Log analysis

Tools for measuring and optimizing token usage across MCP sessions:
Expand Down
Loading
Loading