# com.pulsemcp/monarch-money (npm · monarch-money-mcp-server)

MCP server for Monarch Money — account, transaction, and budget management.

- Trust score: 65/100 (medium)
- Change this week: +25
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- npm · `monarch-money-mcp-server`: 65/100 (this document), [markdown](https://verifymcp.io/servers/com-pulsemcp-monarch-money/monarch-money-mcp-server.md), [page](https://verifymcp.io/servers/com-pulsemcp-monarch-money/monarch-money-mcp-server)

## Channel facts

- Registry: `npm`
- Package: `monarch-money-mcp-server`
- Version: `0.0.13`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Supply Chain Security**: 87/100
  - No malware found by supply-chain analysis.
  - Only part of the dependency tree could be resolved (95 of 99), so this covers what we could see, not the whole tree.
  - No install/post-install scripts declared.
  - Only part of the dependency tree could be resolved (95 of 99), so this covers what we could see, not the whole tree.
- **Provenance & Transparency**: 45/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 28 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 58/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 7274 tokens (~316/item across 23 items; 23 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 91/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 74% of tool parameters carry a description.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add com-pulsemcp-monarch-money -- npx -y monarch-money-mcp-server
```

### Codex

```bash
codex mcp add com-pulsemcp-monarch-money -- npx -y monarch-money-mcp-server
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "com-pulsemcp-monarch-money": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "monarch-money-mcp-server"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add com-pulsemcp-monarch-money --command npx --arg -y --arg monarch-money-mcp-server
```

### Hermes

```yaml
mcp_servers:
  com-pulsemcp-monarch-money:
    command: "npx"
    args: ["-y", "monarch-money-mcp-server"]
```

### Other

```json
{
  "mcpServers": {
    "com-pulsemcp-monarch-money": {
      "command": "npx",
      "args": [
        "-y",
        "monarch-money-mcp-server"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-03 (score 65, +1)

No change was recorded against any check on this day. Stability & Change Management went from 23 to 27. That category is still filling its 30-day observation window: 7 days of observed history at the previous scan, 8 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-08-02 (score 64, +48)

- [security regression] Provenance: unverified → fail
- [security improvement] Install scripts: unverified → pass
- [security improvement] Known CVEs: unverified → partial
- [security improvement] Malware scan: unverified → pass
- [functional improvement] Schema quality: unverified → excellent
- [functional improvement] License: unverified → pass
- [functional improvement] Dependency health: unverified → partial
- [functional improvement] Maintenance: unverified → pass
- [functional improvement] MCP protocol: unverified → pass
- [functional improvement] Stability: unverified → 0.23
- [functional] Licence: MIT

### 2026-07-31 (score 16, −24)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 40, +16)

- [functional improvement] Tool coverage: unverified → 100

### 2026-07-28 (score 24, −16)

- [functional regression] Tool coverage: 100 → unverified
- [functional] First check of Schema quality: unverified

### 2026-07-27 (score 40)

First indexed and scored.

## MCP tools (23)

### `check_authentication` (~389 tokens)

Check whether the Monarch Money MCP server has a valid session, and return setup instructions when it does not.

When authenticated, returns:
\```json
{
  "authenticated": true,
  "email": "you@example.com",
  "id": "user_123",
  "name": "Your Name",
  "sessionPath": "/home/you/.monarch-money-mcp/session.enc",
  "obtainedAt": "2026-01-15T12:34:56.000Z"
}
\```

When not authenticated, returns a multi-line string explaining the four ways to authenticate the server:

1\. **Env-var token (simplest, headless)** — Set `MONARCH_SESSION_TOKEN=<token>` in the server's environment. Useful for sandboxed or unattended deployments.
2\. **Env-var email + password** — Set `MONARCH_EMAIL` and `MONARCH_PASSWORD`. The server runs Monarch's REST login at startup. The first time from a new install Monarch sends an email OTP — read the code, set `MONARCH_EMAIL_OTP=<code>`, and restart. Set `MONARCH_TOTP=<code>` if your account has 2FA enabled.
3\. **Login script (interactive)** — Run `npm run login` from the server package directory.
4\. **Pass an existing token via tool** — Call `monarch_login_with_token` with a token you obtained another way.

Once authenticated, the session persists across restarts. The encryption key is derived from `MONARCH_SESSION_PASSPHRASE` when set, otherwise from the host + user — making the encrypted file machine-bound by default.

\**Use cases:**
\- Confirm the server is ready before running other tools
\- Diagnose auth errors from other tools
\- Discover where the encrypted session file lives on disk
\- Get setup instructions for a fresh install

### `monarch_login_with_token` (~224 tokens)

Save a pre-obtained Monarch Money session token to encrypted on-disk storage.

The token is written to `~/.monarch-money-mcp/session.enc` (or `MONARCH_STATE_DIR/session.enc` when set), encrypted with AES-256-GCM. Once saved, all other tools will pick it up automatically — no env var configuration needed.

This tool is for users who already have a valid session token. Most users should run the login script (`npm run login`) instead, which performs the email/password/TOTP exchange for you.

The tool will validate the token by calling Monarch's `me` endpoint before saving. An invalid token returns an error and is not persisted.

\**Use cases:**
\- Migrate a token captured from a browser session into the server
\- Restore access after a session expiry without re-running the login script
\- Rotate the on-disk token to a freshly issued one

Input parameters:

- `email` (string): Optional email address associated with the token.
- `token` (string, required): Monarch Money session token (a JWT-like string).

### `get_accounts` (~356 tokens)

List every account connected to the Monarch Money workspace, including assets and liabilities.

Returns balance, type/subtype, hidden/sync flags, last update time, and the linked institution. Use this as the starting point for nearly every read operation — most other tools take an account id you'll find here.

Set `includeHoldings: true` to attach investment holdings (ticker, quantity, value, cost basis) to each account that tracks them. Holdings are an extra GraphQL request per account, so omit the flag when you only need balances.

Example response (with `includeHoldings: true`):
\```json
[
  {
    "id": "acc_123",
    "displayName": "Vanguard Brokerage",
    "currentBalance": 84210.55,
    "displayBalance": 84210.55,
    "isAsset": true,
    "type": { "name": "brokerage", "display": "Brokerage" },
    "institution": { "id": "inst_42", "name": "Vanguard" },
    "holdings": [
      { "id": "h_1", "ticker": "VTI", "name": "Vanguard Total Stock Market", "quantity": 312.5, "costBasis": 65000, "value": 78912.5 }
    ]
  }
]
\```

\**Use cases:**
\- Discover account ids for use with other tools
\- Render a "connected accounts" overview
\- Compute total balance per institution
\- Pull holdings for portfolio analysis (with `includeHoldings: true`)

Input parameters:

- `includeHoldings` (boolean): When true, attach investment holdings to each account. Default: false.

### `get_account_balance_history` (~175 tokens)

Daily balance snapshots for a single account over a date range. Useful for charting a balance curve, computing average balance, or spotting a sudden drop.

Example response:
\```json
[
  { "date": "2026-01-01", "balance": 4321.55 },
  { "date": "2026-01-02", "balance": 4180.22 }
]
\```

\**Use cases:**
\- Plot a per-account balance chart
\- Compute month-over-month balance change for one account
\- Investigate a specific date when a balance dropped unexpectedly

Input parameters:

- `accountId` (string, required): Account UUID — fetch via get_accounts.
- `endDate` (string, required): Inclusive end date (YYYY-MM-DD).
- `startDate` (string, required): Inclusive start date (YYYY-MM-DD).

### `set_account_balance_history` (~493 tokens)

Set the recorded daily balance history for a (manual) account. This edits the balance chart / snapshots you see in Monarch — NOT a transaction, and NOT just the single "current balance".

\**How Monarch stores this:** balances are per-day snapshots. Monarch has no GraphQL mutation for dated balances; this tool drives Monarch's "Upload Balance History" importer under the hood (upload a date,balance CSV → parse → poll to completion). Writes are a **per-date UPSERT**: every date you specify is set/created; dates you don't specify are left unchanged. Only works on manual accounts (synced accounts get their history from the institution).

Provide the account plus **either** mode:
\- **Range mode** — `startDate` + `endDate` + `balance`: sets the SAME balance for every day from start to end (inclusive). Use this to backfill a flat value across a window.
\- **Explicit mode** — `snapshots`: an array of `{ date, balance }` to set specific days to specific values.

Balances are signed (negative for liabilities). Read the result back with `get_account_balance_history` to confirm.

Example (range):
\```json
{ "accountId": "acc_123", "startDate": "2026-05-28", "endDate": "2026-07-06", "balance": 237000 }
\```

Example response:
\```json
{ "accountId": "acc_123", "updatedCount": 40, "startDate": "2026-05-28", "endDate": "2026-07-06", "status": "completed" }
\```

\**Use cases:**
\- Backfill a manual account's balance to a fixed value across a date range
\- Correct specific days' recorded balances
\- Seed balance history for a newly created manual account

Input parameters:

- `accountId` (string, required): Account UUID — fetch via get_accounts. Must be manual.
- `balance` (number): Range mode: the balance to set for every day in the range (signed).
- `endDate` (string): Range mode: inclusive end date (YYYY-MM-DD).
- `snapshots` (array): Explicit mode: specific { date, balance } snapshots. Mutually exclusive with the range fields.
- `startDate` (string): Range mode: inclusive start date (YYYY-MM-DD).

### `refresh_accounts` (~130 tokens)

Force a sync against the upstream financial institutions for the given accounts (or all accounts when omitted). This is a long-running operation on Monarch's side — the tool returns immediately once the sync is enqueued.

Example response:
\```json
{ "enqueued": true, "accounts": "all", "errors": [] }
\```

\**Use cases:**
\- Pull the latest balances before generating a report
\- Recover from a stuck or stale account sync
\- Force a refresh after manually fixing institution credentials

Input parameters:

- `accountIds` (array): Optional list of account UUIDs. Omit to refresh all.

### `get_net_worth` (~441 tokens)

Net worth view, returned in two flavors:

\- Default (`view: "history"`): time series of net worth (and assets/liabilities) over a date range. Omit both dates to fetch the full history Monarch has on file.
\- `view: "by_type"`: current net worth grouped by account type (e.g., depository, brokerage, credit, loan), synthesized client-side from `get_accounts`. Use for "how is my net worth distributed?" style questions. Date params are ignored in this view.

Example response (`view: "history"`):
\```json
[
  { "date": "2026-01-01", "netWorth": 124300, "assets": 162400, "liabilities": -38100 },
  { "date": "2026-01-02", "netWorth": 124910, "assets": 163100, "liabilities": -38190 }
]
\```

Example response (`view: "by_type"`):
\```json
[
  { "type": "Brokerage",   "balance": 84210.55 },
  { "type": "Checking",    "balance": 4321.55 },
  { "type": "Credit Card", "balance": -1245.10 }
]
\```

\**View enum:**
\- `history` (default): time series across the full date range
\- `by_type`: grouped current snapshot by account type

\**Use cases:**
\- Plot a net worth chart over the last year
\- Show "what is my net worth made of?" using `view: "by_type"`
\- Pull a specific window (`startDate`/`endDate`) for a quarterly review
\- Compare assets vs. liabilities at the start and end of a period

Input parameters:

- `endDate` (string): Inclusive end date (YYYY-MM-DD). Only used by view: history.
- `startDate` (string): Inclusive start date (YYYY-MM-DD). Only used by view: history.
- `view` (string): Which net-worth view to return. Default: history (time series).

### `get_transactions` (~1009 tokens)

Query transactions in five different shapes — pick the one that matches what you actually want to know.

\**View enum:**
\- `list` (default) — paged list of transactions with filters. Returns `{ totalCount, results }`. Use this for "show me all transactions matching X."
\- `summary` — aggregate totals (count, total income, total expense, average) over a date range. Fast top-line view. Requires `startDate` + `endDate`.
\- `cashflow` — income / expense / savings / savings rate over a date range. Requires `startDate` + `endDate`.
\- `by_category` — total spend per category over a date range. One row per category with the total amount. Requires `startDate` + `endDate`.
\- `recurring` — forecast occurrences of recurring transactions Monarch has detected (subscriptions, payroll, rent). Each row carries the stream's name, frequency, expected date, and amount. Defaults to the next 90 days when `startDate`/`endDate` are omitted.

Filter parameters (`accountIds`, `categoryIds`, `tagIds`, `merchantIds`, `search`, `amountGte`, `amountLte`, `needsReview`, `hideFromReports`, `isSplit`, `limit`, `offset`) only apply when `view: "list"`. Other views ignore them.

Example response (`view: "list"`):
\```json
{
  "totalCount": 421,
  "results": [
    {
      "id": "tx_abc",
      "amount": -42.18,
      "date": "2026-01-15",
      "merchant": { "id": "m_1", "name": "Whole Foods" },
      "category": { "id": "cat_food", "name": "Groceries" },
      "account":  { "id": "acc_chk", "displayName": "Checking" },
      "needsReview": false
    }
  ]
}
\```

Example response (`view: "summary"`):
\```json
{ "count": 421, "totalIncome": 8420.00, "totalExpense": -5210.18, "averageTransaction": 7.62 }
\```

Example response (`view: "cashflow"`):
\```json
{
  "startDate": "2026-01-01", "endDate": "2026-01-31",
  "income": 8420.00, "expense": -5210.18, "savings": 3209.82, "savingsRate": 0.381
}
\```

Example response (`view: "by_category"`):
\```json
[
  { "categoryId": "cat_food", "categoryName": "Groceries",…

Input parameters:

- `accountIds` (array)
- `amountGte` (number)
- `amountLte` (number)
- `categoryIds` (array)
- `endDate` (string): Inclusive end date (YYYY-MM-DD).
- `hideFromReports` (boolean)
- `isSplit` (boolean)
- `limit` (integer)
- `merchantIds` (array)
- `needsReview` (boolean)
- `offset` (integer)
- `search` (string): Free-text search.
- `startDate` (string): Inclusive start date (YYYY-MM-DD).
- `tagIds` (array)
- `view` (string): Which view to return. Default: list.

### `get_transaction_details` (~259 tokens)

Fetch a single transaction by id, including its splits (if any). Use after get_transactions (`view: "list"`) to drill into a specific row.

Example response:
\```json
{
  "id": "tx_abc",
  "amount": -42.18,
  "date": "2026-01-15",
  "merchant": { "id": "m_1", "name": "Whole Foods" },
  "category": { "id": "cat_food", "name": "Groceries" },
  "splits": [
    { "id": "split_1", "amount": -32.18, "category": { "id": "cat_food",  "name": "Groceries" } },
    { "id": "split_2", "amount": -10.00, "category": { "id": "cat_house", "name": "Household" } }
  ]
}
\```

\**Use cases:**
\- Inspect splits of a parent transaction
\- Show notes / tags / review state for one specific transaction
\- Verify a transaction id before calling `update_transaction` or `delete_transaction`

Input parameters:

- `transactionId` (string, required): Transaction UUID.

### `create_transaction` (~228 tokens)

Create a manual transaction. Use this for cash spending or other transactions Monarch can't import automatically.

The amount sign matters: negative = expense (money out), positive = income (money in).

Example response:
\```json
{
  "id": "tx_new123",
  "amount": -12.50,
  "date": "2026-01-20",
  "account": { "id": "acc_chk", "displayName": "Checking" },
  "merchant": { "id": "m_new", "name": "Coffee Shop" }
}
\```

\**Use cases:**
\- Log cash spending Monarch can't see
\- Backfill a missing transaction
\- Add a one-off income event (gift, refund, side income)

Input parameters:

- `accountId` (string, required): Account UUID.
- `amount` (number, required): Amount; negative for expenses, positive for income.
- `categoryId` (string, required): Category UUID (required by Monarch).
- `date` (string, required): Transaction date (YYYY-MM-DD).
- `merchantName` (string, required)
- `notes` (string)

### `update_transaction` (~473 tokens)

Update fields on a transaction. Single tool that consolidates the per-field "setter" operations.

Provide `id` plus any subset of:
\- `amount`, `date`, `categoryId` — patch the core fields
\- `merchantName` — rename the merchant via free-form string (Monarch may auto-create a new merchant for unknown names; reassigning to an existing merchant by id is not supported)
\- `notes` — replace the notes (pass an empty string to clear)
\- `hideFromReports` — toggle the "hide from reports" flag
\- `reviewed` — true marks the transaction reviewed; false puts it back in the review queue
\- `tagIds` — full replace of the tag set (pass `[]` to remove all tags)

Omitted fields are left unchanged. The tool calls multiple Monarch endpoints under the hood (the GraphQL API has separate mutations for tags and review state) and rolls them up into one logical update.

Example response (the patched transaction, post-update):
\```json
{
  "id": "tx_abc",
  "amount": -42.18,
  "notes": "Reviewed and recategorized",
  "needsReview": false,
  "category": { "id": "cat_food", "name": "Groceries" },
  "tags": [{ "id": "tag_personal", "name": "Personal" }]
}
\```

\**Use cases:**
\- Recategorize a transaction
\- Replace the tag set on a transaction
\- Mark a transaction reviewed and update its notes in one call
\- Hide a transfer from reports
\- Bulk-recategorize: provide `bulkTransactionIds` + `categoryId` to apply one category to many transactions in one call

Input parameters:

- `amount` (number)
- `bulkTransactionIds` (array): Bulk mode: apply categoryId to every transaction in this list.
- `categoryId` (string)
- `date` (string): YYYY-MM-DD.
- `hideFromReports` (boolean)
- `id` (string): Transaction UUID.
- `merchantName` (string): Rename merchant via free-form string. Single-tx only.
- `notes` (string)
- `reviewed` (boolean)
- `tagIds` (array)

### `delete_transaction` (~68 tokens)

Permanently delete a transaction. This action cannot be undone.

Example response:
\```json
{ "deleted": true, "errors": [] }
\```

\**Use cases:**
\- Remove a duplicate manual entry
\- Delete a transaction created by mistake

Input parameters:

- `id` (string, required): Transaction UUID.

### `split_transaction` (~167 tokens)

Split a single transaction into multiple categorized parts. The split amounts must sum to the parent transaction's amount. Replaces any existing splits.

Returns the new child split transactions (id + amount). Use `get_transactions` with `isSplit: true` if you need richer details on the split children.

Example response:
\```json
[
  { "id": "split_1", "amount": -32.18 },
  { "id": "split_2", "amount": -10.00 }
]
\```

\**Use cases:**
\- Split a Costco run into "Groceries" and "Household"
\- Allocate a shared dinner across multiple categories
\- Break out the tip from a restaurant charge

Input parameters:

- `id` (string, required)
- `splits` (array, required)

### `get_categories` (~349 tokens)

List every category configured on the workspace, with its parent group and "system category" flag (system categories are predefined by Monarch and can't be renamed).

Set `includeGroups: true` to also return the top-level category groups (Income, Expense, Transfer, etc.) — useful for rendering a grouped picker. The shape becomes `{ categories, groups }` instead of a bare array.

Example response (default):
\```json
[
  { "id": "cat_food", "name": "Groceries",   "isSystemCategory": false, "group": { "id": "grp_exp", "name": "Expense" } },
  { "id": "cat_dine", "name": "Dining",      "isSystemCategory": false, "group": { "id": "grp_exp", "name": "Expense" } }
]
\```

Example response (`includeGroups: true`):
\```json
{
  "categories": [
    { "id": "cat_food", "name": "Groceries", "group": { "id": "grp_exp", "name": "Expense" } }
  ],
  "groups": [
    { "id": "grp_exp", "name": "Expense" },
    { "id": "grp_inc", "name": "Income" }
  ]
}
\```

\**Use cases:**
\- Discover category ids for use with `update_transaction` or `set_budget_amount`
\- Render a grouped category picker (with `includeGroups: true`)
\- Identify which categories are system-defined vs. user-defined

Input parameters:

- `includeGroups` (boolean): When true, return both categories and category groups. Default: false.

### `get_tags` (~151 tokens)

List all transaction tags configured on the workspace, with name, color, and display order.

Example response:
\```json
[
  { "id": "tag_personal", "name": "Personal", "color": "#ff8800", "order": 1 },
  { "id": "tag_work",     "name": "Work",     "color": "#0088ff", "order": 2 }
]
\```

\**Use cases:**
\- Discover tag ids for use with `update_transaction` (`tagIds`)
\- Render a tag picker
\- Look up an existing tag's id before deleting it with `delete_tag`, or its `color` format before calling `create_tag`

### `create_tag` (~236 tokens)

Create a new transaction tag. Returns the created tag ({ id, name, color, order }); Monarch assigns `order` server-side.

Both `name` and `color` are required. `color` is a hex string like the ones returned by `get_tags` (e.g. `#19d2a5`, `#ff8800`) — call `get_tags` first if you need to match an existing palette.

Example call:
\```json
{ "name": "Reimbursable", "color": "#19d2a5" }
\```

Example response:
\```json
{ "id": "tag_new", "name": "Reimbursable", "color": "#19d2a5", "order": 7 }
\```

\**Use cases:**
\- Add a tag you'll then assign to transactions via `update_transaction` (`tagIds`)
\- Set up a tagging scheme without leaving the assistant

Input parameters:

- `color` (string, required): Hex color like #19d2a5 (6-digit, matches get_tags).
- `name` (string, required): Display name for the new tag.

### `delete_tag` (~132 tokens)

Delete a transaction tag by id. Removes the tag from the workspace and unassigns it from any transactions that carried it.

Returns `{ deleted, errors }`. `deleted` is confirmed by re-reading the tag list after the mutation (Monarch's raw `deleted` flag is not trusted).

Example call:
\```json
{ "id": "tag_old" }
\```

\**Use cases:**
\- Remove a stale or accidentally-created tag
\- Clean up tags left behind by earlier automation

Use `get_tags` to look up the tag id first.

Input parameters:

- `id` (string, required): Tag id to delete.

### `get_transaction_rules` (~332 tokens)

List every transaction rule configured on the workspace. Rules auto-classify imported transactions based on merchant/amount/account criteria.

Example response:
\```json
[
  {
    "id": "rule_1",
    "order": 1,
    "merchantCriteria": [{ "operator": "contains", "value": "Whole Foods" }],
    "amountCriteria": { "operator": "gte", "value": 50, "isExpense": true },
    "categoryIds": ["cat_food"],
    "accountIds": ["acc_chk"],
    "setCategoryAction": { "id": "cat_groceries", "name": "Groceries" },
    "setHideFromReportsAction": false,
    "addTagsAction": [{ "id": "tag_food", "name": "Food" }],
    "lastAppliedAt": "2026-04-12T18:22:01Z"
  }
]
\```

The action fields are echoed back in read shape: `setCategoryAction` as the
assigned category object and `addTagsAction` as the added tag objects. When you
write a rule (create/update), those same fields take a bare category-id string
and an array of tag-id strings respectively.

\**Use cases:**
\- Audit existing auto-categorization rules
\- Inspect a rule's match criteria, actions, and last-run time
\- Read a rule's full state before editing it (`update_transaction_rule` replaces the whole rule)

To change rules, use `create_transaction_rule`, `update_transaction_rule`, and `delete_transaction_rule`.

### `create_transaction_rule` (~535 tokens)

Create a transaction rule that auto-classifies imported transactions.

A rule has **criteria** (what it matches) and **actions** (what it does to matches). Supply at least one criterion and at least one action.

Criteria:
\- `merchantCriteria` — array of { operator, value } matchers against the merchant name (e.g. operator `contains`).
\- `merchantCriteriaUseOriginalStatement` — match against the raw bank statement text instead of the cleaned merchant name.
\- `amountCriteria` — single { operator, value, isExpense } matcher (e.g. operator `gte`).
\- `categoryIds` / `accountIds` — only match transactions already in these categories / accounts (use `get_categories` / `get_accounts` for ids).

Actions:
\- `setCategoryAction` — category id to assign to matches (a bare id string, NOT an array; use `get_categories`).
\- `setHideFromReportsAction` — hide matching transactions from reports.
\- `addTagsAction` — tag ids to add to matches (use `get_tags`).

Set `applyToExistingTransactions: true` to retroactively run the rule against transactions you already have.

Monarch does not echo the created rule back, so this returns the **full refreshed rule list** — find the new rule (and its id, for later edits) there.

Example: "When the merchant contains 'Whole Foods', categorize as Groceries":
\```json
{
  "merchantCriteria": [{ "operator": "contains", "value": "Whole Foods" }],
  "setCategoryAction": "cat_groceries",
  "applyToExistingTransactions": true
}
\```

\**Use cases:**
\- Auto-categorize a recurring merchant
\- Auto-hide transfers from reports
\- Auto-tag a class of spending

Input parameters:

- `accountIds` (array): Only match transactions in these account ids.
- `addTagsAction` (array): Action: tag ids to add to matching transactions.
- `amountCriteria` (object): Single amount matcher (criteria).
- `applyToExistingTransactions` (boolean): Retroactively apply the rule to existing transactions.
- `categoryIds` (array): Only match transactions already in these category ids.
- `merchantCriteria` (array): Merchant-name matchers (criteria).
- `merchantCriteriaUseOriginalStatement` (boolean): Match the raw statement text instead of the cleaned merchant.
- `setCategoryAction` (string): Action: category id to assign to matches (single id string).
- `setHideFromReportsAction` (boolean): Action: hide matching transactions from reports.

### `update_transaction_rule` (~529 tokens)

Update an existing transaction rule. Provide the rule `id` (from `get_transaction_rules`) plus the rule's complete desired criteria and actions.

\**This is a FULL REPLACE, not a patch.** The fields you send define the rule's entire new state — any criterion or action you omit is REMOVED from the rule. You must re-supply at least one criterion (`merchantCriteria`, `amountCriteria`, `categoryIds`, or `accountIds`) AND at least one action (`setCategoryAction`, `setHideFromReportsAction`, or `addTagsAction`) on every call. Accepts the same criteria/action fields as `create_transaction_rule`.

\**Safe workflow:** call `get_transaction_rules` first, take the rule's current criteria and actions, apply your change to that full state, and send the whole thing back. Sending only the one field you want to change will wipe out everything else on the rule.

Returns the full refreshed rule list (Monarch does not echo the updated rule back). Only the rule named by `id` is affected — sibling rules are untouched.

Example (a rule that matched "Whole Foods" → Groceries, now repointed to Dining while keeping its merchant criterion):
\```json
{
  "id": "rule_1",
  "merchantCriteria": [{ "operator": "contains", "value": "Whole Foods" }],
  "setCategoryAction": "cat_dining"
}
\```

\**Use cases:**
\- Repoint a rule to a different category (re-supplying its criteria)
\- Tighten or loosen a rule's match criteria (re-supplying its actions)
\- Toggle a rule's hide-from-reports action (re-supplying its criteria)

Input parameters:

- `accountIds` (array): Only match transactions in these account ids.
- `addTagsAction` (array): Action: tag ids to add to matching transactions.
- `amountCriteria` (object): Single amount matcher (criteria).
- `applyToExistingTransactions` (boolean): Retroactively apply the rule to existing transactions.
- `categoryIds` (array): Only match transactions already in these category ids.
- `id` (string, required): Rule id to update (from get_transaction_rules).
- `merchantCriteria` (array): Merchant-name matchers (criteria).
- `merchantCriteriaUseOriginalStatement` (boolean): Match the raw statement text instead of the cleaned merchant.
- `setCategoryAction` (string): Action: category id to assign to matches (single id string).
- `setHideFromReportsAction` (boolean): Action: hide matching transactions from reports.

### `delete_transaction_rule` (~102 tokens)

Permanently delete a transaction rule by id (from `get_transaction_rules`). This action cannot be undone. Existing transactions the rule already classified are not reverted.

Example response:
\```json
{ "deleted": true, "errors": [] }
\```

\**Use cases:**
\- Remove a rule that mis-categorizes transactions
\- Clean up a rule that is no longer needed

Input parameters:

- `id` (string, required): Rule id to delete (from get_transaction_rules).

### `get_budgets` (~239 tokens)

List per-category planned budget amounts across one or more months. Each row pairs a category with its planned amount for a single month — multi-month windows return one row per (category, month).

Date arguments take the year-month portion of the YYYY-MM-DD value; the day is ignored. Omit both dates to get the current month's budgets.

Example response:
\```json
[
  {
    "categoryId": "cat_food",
    "categoryName": "Groceries",
    "amount": 600,
    "month": "2026-01-01"
  },
  {
    "categoryId": "cat_dine",
    "categoryName": "Dining",
    "amount": 250,
    "month": "2026-01-01"
  }
]
\```

\**Use cases:**
\- Show "what is my budget for X?" for each category
\- Audit current-period budget allocations before adjusting
\- Pull a historical period's budget for retrospective analysis

Input parameters:

- `endDate` (string): Inclusive end date (YYYY-MM-DD).
- `startDate` (string): Inclusive start date (YYYY-MM-DD).

### `set_budget_amount` (~257 tokens)

Set the planned budget amount for a category for a single month. Pass `applyToFuture: true` to roll the change forward to all subsequent months; otherwise the change applies only to the month containing `startDate` (or the current month if `startDate` is omitted).

Returns the request echoed back along with the new `budgetItemId` — Monarch's mutation is intentionally minimal and doesn't surface the post-update Budget shape.

Example response:
\```json
{
  "budgetItemId": "bi_abc123",
  "categoryId": "cat_food",
  "amount": 650,
  "startDate": "2026-01-01",
  "applyToFuture": false
}
\```

\**Use cases:**
\- Bump a category's budget after recategorizing transactions
\- Apply a new budget across all future months (`applyToFuture: true`)
\- Adjust a one-off month's budget without touching ongoing settings

Input parameters:

- `amount` (number, required): New budget amount.
- `applyToFuture` (boolean): When true, applies to all future periods. Default: false.
- `categoryId` (string, required): Category UUID.
- `startDate` (string): Optional period start (YYYY-MM-DD).

## Diagnostics

Captured diagnostic sections: Provenance, Dependencies. The full working is on the page: https://verifymcp.io/servers/com-pulsemcp-monarch-money/monarch-money-mcp-server#diagnostics

## Score history

- 2026-08-03: 65
- 2026-08-02: 64
- 2026-08-01: 16
- 2026-07-31: 16
- 2026-07-30: 40
- 2026-07-28: 24
- 2026-07-27: 40

## Links

- npm package: https://www.npmjs.com/package/monarch-money-mcp-server
- Socket report: https://socket.dev/npm/package/monarch-money-mcp-server
- Repository: https://github.com/pulsemcp/mcp-servers
- Changelog RSS feed: https://verifymcp.io/servers/com-pulsemcp-monarch-money/monarch-money-mcp-server/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/com-pulsemcp-monarch-money/monarch-money-mcp-server/changelog.json
- HTML version of this page: https://verifymcp.io/servers/com-pulsemcp-monarch-money/monarch-money-mcp-server
