Skip to main content
Glama
Xerrion

firefly-iii-mcp-server

by Xerrion

firefly-iii-mcp-server

An MCP (Model Context Protocol) server that exposes a curated, task-shaped surface of 41 tools over the Firefly III personal-finance API. Designed for an AI agent doing personal accounting on behalf of a human: record, review, budget, save, summarise.

Rather than mirroring Firefly's ~230 REST operations 1:1, this server is a facade with a thin anti-corruption layer that:

  • strips the JSON:API envelope (data: { type, id, attributes: {...} }) on every response,

  • flattens Firefly's currency-keyed maps into { currency_code, ... } arrays,

  • collapses per-account/per-bill/per-budget/per-category transaction list variants into a single list_transactions with filters,

  • normalises errors into one envelope with stable codes,

  • keeps amounts, IDs, and dates as strings (no float drift, no silent coercion).

The 41-tool catalogue and the capability groups deliberately not exposed in v1 are documented below.

Install

Requires Bun ≥ 1.3.

bun install

No build step — Bun runs TypeScript directly from src/index.ts.

Configuration

Two environment variables, both required. The server fails fast at startup if either is missing.

Variable

Description

FIREFLY_III_URL

Base URL of your Firefly III instance, no trailing slash. Example: https://demo.firefly-iii.org.

FIREFLY_III_TOKEN

Personal Access Token. Get one in Firefly III: Options → Profile → OAuth → Personal Access Tokens → Create New Token.

A .env.example is provided. Copy it to .env for local development (never commit .env).

Run

# stdio transport (the only supported transport in v1)
FIREFLY_III_URL=https://demo.firefly-iii.org \
FIREFLY_III_TOKEN=your-pat-here \
bun start

On success the server logs firefly-iii-mcp-server: ready on stdio to stderr (stdout is reserved for the MCP protocol).

MCP client configuration

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "firefly-iii": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/firefly-iii-mcp/src/index.ts"],
      "env": {
        "FIREFLY_III_URL": "https://demo.firefly-iii.org",
        "FIREFLY_III_TOKEN": "your-pat-here"
      }
    }
  }
}

opencode

Add to ~/.config/opencode/opencode.json (or your project-local opencode.json):

{
  "mcp": {
    "firefly-iii": {
      "type": "local",
      "command": ["bun", "run", "/absolute/path/to/firefly-iii-mcp/src/index.ts"],
      "environment": {
        "FIREFLY_III_URL": "https://demo.firefly-iii.org",
        "FIREFLY_III_TOKEN": "your-pat-here"
      },
      "enabled": true
    }
  }
}

Tools

All 41 tools are listed below. Their schemas are exposed to MCP clients through the server's tool catalogue.

Transactions (6)

  • list_transactions — browse recent transactions, filter by date / type / account

  • get_transaction — fetch one transaction with all its splits

  • search_transactions — free-text and operator search (amount_min:, category:, tag:, …)

  • create_transaction — record a withdrawal, deposit, or transfer (single or multi-split)

  • update_transaction — edit fields on an existing transaction

  • delete_transaction — delete a transaction by ID

create_transaction and update_transaction may return an overridden_fields envelope alongside the projected transaction. It lists fields the agent sent that Firefly's rule engine then overwrote (e.g. you sent category: "Food" and a rule rewrote it to "Groceries"). The envelope is absent when no diff is detected. v1.1 limitation: only the first split is diffed.

Accounts (5)

  • list_accounts — list accounts, filter by type or active

  • get_account — single account with current balance (historic balance via date)

  • create_account — create asset / expense / revenue / liability / cash account

  • update_account — update account metadata

  • delete_account — delete an account by ID

Categories (3)

  • list_categories — list categories

  • upsert_category — create or update a category

  • delete_category — delete a category

Tags (3)

  • list_tags — list tags

  • upsert_tag — create or update a tag

  • delete_tag — delete a tag by ID

Budgets (3)

  • list_budgets — list budgets enriched with limit / spent / remaining for a period

  • upsert_budget — create or update a budget; optionally set its limit in the same call

  • delete_budget — delete a budget by ID (Firefly clears its budget-limit rows; transactions are not deleted)

Bills (3)

  • list_bills — recurring expected expenses with next_expected_match and paid_dates

  • upsert_bill — create or update a bill (subscription, etc.)

  • delete_bill — delete a bill by ID (matched transactions are detached, not deleted)

Piggy banks (5)

The piggy-bank cluster uses an explicit create_* + update_* rather than a single upsert_* because Firefly's create-side schema requires four fields (name, accounts, target_amount, start_date) while the update-side schema requires none — the same asymmetric-required-fields pattern as rules CRUD.

  • list_piggy_banks — savings goals with progress (current_amount, target_amount, percentage)

  • create_piggy_bank — define a new savings goal

  • update_piggy_bank — rename, retarget, or re-attach accounts; partial update. Does NOT accept current_amount — balance changes go through contribute_piggy_bank, which is the single auditable path for moving money into or out of a piggy bank.

  • delete_piggy_bank — delete a savings goal by ID (linked accounts and transactions are untouched)

  • contribute_piggy_bank — add to (positive) or withdraw from (negative) a piggy bank

Rules (5)

  • list_rules — list rules; pass rule_group_id to scope to one group, else lists all rules

  • get_rule — fetch one rule with its triggers and actions

  • create_rule — create a rule in a group; triggers and actions are flat arrays (order derived from array index)

  • update_rule — update a rule; passing triggers: [] or actions: [] clears the list

  • delete_rule — delete a rule by ID

Rule groups (5)

  • list_rule_groups — list rule groups

  • get_rule_group — fetch one rule group

  • create_rule_group — create a rule group

  • update_rule_group — update a rule group's metadata

  • delete_rule_group — delete a rule group (cascades: all rules in the group are deleted)

Summary & insights (2)

  • get_financial_summary — net worth, income, expense, balance for a period; flattened across currencies

  • get_spending_insights — breakdown by category / budget / tag × expense / income

System (1)

  • get_system_info — Firefly version, primary currency, authenticated user

Shared conventions

  • Pagination on every list_* / search_* tool: { items, page, total_pages, total_items, has_more }. page is 1-indexed. limit defaults to 25 and is capped at 100 (over-limit requests are clamped, not rejected; the response includes limit_clamped_to: 100).

  • Amounts, IDs, dates are strings. Amounts are decimal strings ("-1012.12"). IDs are numeric strings ("42"). Dates are YYYY-MM-DD.

  • Currency by code, not ID. currency_code: "EUR", never currency_id: 1.

  • Errors are returned as a uniform envelope (see below); the tool result is marked isError: true so clients can detect failure.

Error envelope

{
  "ok": false,
  "error": {
    "code": "validation_error",
    "message": "The amount is required.",
    "field_errors": { "transactions.0.amount": ["The amount is required."] },
    "http_status": 422,
    "trace_id": "f54f1c80-7d9b-4a3e-9b71-1c0c7b3d3a1b"
  }
}

code is one of: validation_error, not_found, unauthenticated, forbidden, rate_limited, upstream_error, network_error, internal_error. HTML error pages from upstream are never leaked — they are converted into a safe synthetic upstream_error.

Example tool calls

List recent withdrawals in March 2026

Input to list_transactions:

{ "start": "2026-03-01", "end": "2026-03-31", "type": "withdrawal", "limit": 3 }

Output (structuredContent):

{
  "items": [
    {
      "id": "1042",
      "type": "withdrawal",
      "date": "2026-03-15",
      "amount": "42.50",
      "currency_code": "EUR",
      "description": "Groceries",
      "category": "Food",
      "source_name": "Checking",
      "destination_name": "Supermarket"
    }
  ],
  "page": 1,
  "total_pages": 4,
  "total_items": 12,
  "has_more": true
}

Record a withdrawal

Input to create_transaction:

{
  "type": "withdrawal",
  "date": "2026-03-20",
  "amount": "12.99",
  "description": "Coffee",
  "source": "Checking",
  "destination": "Daily Cafe",
  "category": "Food",
  "tags": ["weekly"]
}

source / destination accept either a numeric account ID ("7") or a free-form name; the server routes to Firefly's *_id vs *_name automatically.

Set a monthly budget for groceries with a limit

Input to upsert_budget:

{
  "name": "Groceries",
  "active": true,
  "limit": {
    "start": "2026-03-01",
    "end": "2026-03-31",
    "amount": "400.00",
    "currency_code": "EUR"
  }
}

Output (structuredContent):

{
  "id": "5",
  "name": "Groceries",
  "active": true,
  "limit": {
    "start": "2026-03-01",
    "end": "2026-03-31",
    "amount": "400.00",
    "currency_code": "EUR"
  }
}

Not exposed in v1

The following capability groups are deliberately omitted from v1 to keep the tool catalogue small and the agent's planning surface tractable: user / group admin, server configuration, currency admin, destructive admin (destroyData/purgeData), chart endpoints, autocomplete (*AC), webhooks, attachments (binary I/O over MCP is a separate design problem), per-currency / per-parent transaction list duplicates, exports, bulk update, currency exchange rates, recurrences, transaction links, object groups, available budgets, preferences, per-resource event/attachment sub-lists, and narrow insight slices.

Development

bun install           # install dependencies
bun run typecheck     # tsc --noEmit (TypeScript kept as a dev dep purely for typechecking)
bun test              # bun's built-in test runner (shape helpers, error mapping, tool catalogue, decimal, integration)
bun run dev           # bun --watch run src/index.ts

The catalogue test (tests/tool-catalogue.test.ts) asserts that exactly the 41 tools named in EXPECTED_TOOL_NAMES in src/tools.ts are registered. Update the catalogue, its expected names, and this README together when adding or removing a tool.

License

MIT