Skip to main content
Glama

๐Ÿ’ฐ Personal Budget MCP Server

License: MIT Python 3.11+

Track personal finances by talking to an LLM. An MCP server that gives any MCP-compatible client typed tools to log transactions, manage a category library, and analyse spending โ€” plus interactive dashboards rendered directly in the chat client.

Built with Python, FastMCP, SQLAlchemy, SQLite and PostgreSQL.


Why this exists

Chat is a good interface for expense logging. "Spent ยฃ42 at Tesco and ยฃ8 on coffee" is faster than opening an app and filling in two forms, and an LLM can categorise it for you.

The problem is that an LLM with no tools will happily tell you it logged your transaction. Getting this to work means the model must be unable to confuse "I recorded this" with "I described recording this" โ€” so the tools have to return unambiguous success or failure, reject bad input rather than coercing it, and expose enough query surface that the agent reads real state instead of reconstructing it from conversation history.

That design problem is the actual point of this repo. The budgeting is the excuse.


Related MCP server: Personal Finance Tracker

๐Ÿ“ธ Screenshots

Budget dashboard

Spending trends

Budget Dashboard

Spending Trends


๐Ÿง  Design notes: making agent calls trustworthy

Explicit failure over silent coercion. Tools validate input and return a structured error naming what was wrong, rather than guessing at intent. An invalid type, a malformed date, or a category_id that doesn't exist fails loudly, so the agent can correct itself and report accurately to the user instead of inventing a confirmation.

Batch-first write tools. add_transaction, update_transaction, delete_transaction and add_category all accept either a single item or an items list. Agents naturally handle several things at once ("log these five expenses"), and forcing them into one call per record multiplies both latency and the number of places a partial failure can hide.

Referential integrity at the tool boundary. delete_category takes an optional reassign_to_category_id, so removing a category can't silently orphan its transactions. The integrity decision is surfaced as a parameter the agent must reason about rather than a side effect it discovers later.

Read surface sized for multi-turn use. get_summary, get_transactions and get_uncategorized_transactions cover aggregate, detail and triage reads with consistent filter arguments across all three. get_uncategorized_transactions returns results sorted by description specifically so an agent can categorise bulk imports in coherent groups instead of one row at a time.

Idempotent schema bootstrap. Tables and 15 default categories are created on first startup, so a fresh clone or a new cloud deployment is immediately usable and there's no partially-initialised state for a tool call to land in.


โœจ Features

  • Local or cloud storage โ€” zero-setup SQLite (in-memory or data/budget.db), or PostgreSQL via any provider such as Neon.

  • Interactive dashboards in-client โ€” category pie charts and searchable transaction tables rendered via prefab-ui, returned as MCP UI apps rather than plain text.

  • Spending trends โ€” continuous category line chart with month/week/day granularity toggle, date-range slider and searchable table.

  • Batch operations โ€” single-item or bulk write across transactions and categories.

  • Reproducible environment โ€” uv for fast, locked dependency resolution.

  • Broad client support โ€” Claude Desktop, Claude Code, Cursor, Goose, Open WebUI, and any other MCP host.


๐Ÿš€ Quickstart

git clone https://github.com/PedroLiu1999/budget-mcp.git
cd budget-mcp
uv sync
uv run pytest          # confirm the install works
uv run server.py       # start the server (in-memory SQLite by default)

Then register it with your client โ€” Claude Code is the one-liner:

claude mcp add budget -- uv run --directory "/absolute/path/to/budget-mcp" server.py

To persist data, set DATABASE_URL in a .env file first (see Database configuration).


๐Ÿ›  Available tools

Tool

Description

Arguments

budget_dashboard

Interactive UI app: category breakdown chart and searchable transaction table.

search (str, opt)month (str YYYY-MM, opt)type (income|expense, opt)limit (int, default 100)

spending_trends

Interactive UI app: spending over time with category line chart, granularity toggle, date-range slider and searchable table.

granularity (month|week|day, default month)days_range (range list [start, end], opt)category_id (int, opt)type (expense|income, opt)start_date (str, opt)end_date (str, opt)limit (int, default 1000)

add_transaction

Logs one or many income/expense transactions.

items (list of dicts, opt โ€” batch)amount (float, opt)category_id (int, opt)description (str, opt)type (expense|income, opt)date (str YYYY-MM-DD, opt)

get_summary

Aggregated summary: income, expense, net balance, optional category breakdown.

month (str YYYY-MM, opt)start_date / end_date (str YYYY-MM-DD, opt)category_id (int, opt)type (income|expense, opt)by_category (bool, default False)

get_transactions

Detailed transaction records by filter.

category_id (int, opt)type (income|expense, opt)month (str, opt)start_date / end_date (str, opt)min_amount / max_amount (float, opt)search (str, opt)limit (int, default 50)

get_uncategorized_transactions

Uncategorised transactions sorted by description, for bulk categorisation.

type (income|expense, opt)search (str, opt)limit (int, default 100)

update_transaction

Updates one or many transactions.

items (list of update dicts, opt)transaction_id (int, opt)amount (float, opt)category_id (int, opt)description (str, opt)type (str, opt)date (str YYYY-MM-DD, opt)

delete_transaction

Removes one or many transactions by ID.

transaction_ids (int or list of int)

list_categories

Lists active categories.

type (expense|income, opt)

add_category

Adds one or many categories.

items (list of dicts, opt)name (str, opt)type (expense|income, opt)description (str, opt)

update_category

Updates a category's properties.

category_id_or_name (str)new_name (str, opt)type (str, opt)description (str, opt)

delete_category

Removes one or many categories, optionally reassigning their transactions.

category_ids_or_names (str, int or list)reassign_to_category_id (int, opt)


โš™๏ธ Database configuration

Set via the DATABASE_URL environment variable in a .env file. Keep .env out of version control.

Local SQLite โ€” in-memory (default if DATABASE_URL is unset):

DATABASE_URL=sqlite:///:memory:

Local SQLite file โ€” persists between restarts:

DATABASE_URL=sqlite:///data/budget.db

PostgreSQL / Neon:

DATABASE_URL=postgresql://<user>:<password>@<hostname>/<dbname>?sslmode=require

Tables and 15 default category seeds are created automatically on first startup.


๐Ÿ”Œ Client setup

Claude Code (CLI)

claude mcp add budget -- uv run --directory "/absolute/path/to/budget-mcp" server.py

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "personal-budget": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/budget-mcp", "server.py"]
    }
  }
}

Cursor IDE

Settings โ†’ Features โ†’ MCP โ†’ Add New MCP Server

  • Type: command

  • Name: budget-mcp

  • Command: uv run --directory "/absolute/path/to/budget-mcp" server.py

Open WebUI

Bridge the stdio server over HTTP with mcpo:

uvx mcpo --port 8000 -- uv run server.py

Then in Admin Panel โ†’ Settings โ†’ External Tools, add the OpenAPI connection URL http://localhost:8000 (or http://host.docker.internal:8000 from Docker).


โ˜๏ธ Cloud deployment

For remote hosts, Docker, or platforms such as Horizon:

  1. Set DATABASE_URL to a cloud PostgreSQL connection string in the deployment environment โ€” in-memory SQLite will not persist across restarts.

  2. Point the runner at the ASGI app:

    fastmcp run server.py:mcp

Schema tables and default categories initialise on import, so no migration step is needed on first boot.


๐Ÿงช Testing

uv run pytest

Inspect tools interactively with the FastMCP Inspector:

uv run fastmcp dev inspector server.py:mcp

Or preview interactive UI applications directly in the browser:

uv run fastmcp dev apps server.py:mcp

๐Ÿ“ License

MIT โ€” see LICENSE.

Available Tools

12 tools
add_categoryA

Create one or more categories in the category library.

Supports single category parameters OR a batch list/dict of items in items.

  • items: Optional list of dicts. Each dict can contain: {"name": str, "type": "expense"|"income", "description": str}.

  • name: Unique category name (used if items is omitted).

  • type: Category type ('expense' or 'income', defaults to 'expense').

  • description: Optional description explaining what belongs in this category.

Inputs: name, type, items, description. Returns: result

add_transactionA

Add one or more income or expense transactions to the budget.

Supports single transaction parameters OR a batch list/dict of items in items.

Bulk Import Workflow:

  • You can bulk import transactions without categories (category_id is optional).

  • After bulk logging, use get_uncategorized_transactions to review uncategorized transactions sorted by description.

  • Then use update_transaction to systematically assign category IDs to matching descriptions in bulk.

Arguments:

  • items: Optional list of dicts (or single dict) for batch insertion. Each dict can contain: {"amount": float, "category_id": int (optional), "description": str, "type": "expense"|"income", "date": "YYYY-MM-DD"}.

  • amount: Transaction monetary value (used if items is omitted).

  • category_id: Optional integer category ID from list_categories (omitting logs as 'Uncategorized').

  • description: Details or description of transaction (used if items is omitted).

  • type: Must be either 'expense' or 'income' (defaults to 'expense').

  • date: Optional transaction date formatted as YYYY-MM-DD or ISO string.

Inputs: date, type, items, amount, +2 more. Returns: result

budget_dashboardC

Browse the interactive budget dashboard with a category breakdown chart and transaction data table.

Inputs: type, limit, month.

delete_categoryA

Delete one or more categories from the library.

Supports a single category ID/name or a list of category IDs/names in category_ids_or_names.

  • category_ids_or_names: ID/name or list of IDs/names to delete.

  • category_id_or_name: Alias for single category deletion.

  • reassign_to_category_id: Target category ID to reassign linked transactions to.

Inputs: category_id_or_name, category_ids_or_names, reassign_to_category_id. Returns: result

delete_transactionB

Delete one or more transactions by ID.

Supports a single integer ID or a list of integer IDs in transaction_ids.

  • transaction_ids: Integer ID or list of integer IDs to delete.

  • transaction_id: Alias for single ID deletion.

Inputs: transaction_id, transaction_ids. Returns: result

get_summaryA

Get a summary of expenses, income, and net balance with flexible filtering and optional category breakdown.

  • month: Filter by month (YYYY-MM).

  • start_date: Filter starting from date (YYYY-MM-DD).

  • end_date: Filter ending at date (YYYY-MM-DD).

  • category_id: Optional integer category ID filter from list_categories.

  • type: Filter by transaction type ('expense' or 'income').

  • by_category: Set to True to include detailed category breakdown.

Inputs: type, month, end_date, start_date, +2 more. Returns: result

get_transactionsA

Get transactions based on specified filter criteria.

  • category_id: Optional integer filter by category ID.

  • type: Filter by type ('income' or 'expense').

  • month: Filter by month formatted as YYYY-MM.

  • start_date: Filter transactions on or after YYYY-MM-DD.

  • end_date: Filter transactions on or before YYYY-MM-DD.

  • min_amount: Filter transactions with amount >= min_amount.

  • max_amount: Filter transactions with amount <= max_amount.

  • search: Keyword search matching description or category.

  • limit: Maximum number of records to return (default 50).

Inputs: type, limit, month, search, +5 more. Returns: result

get_uncategorized_transactionsA

Get all uncategorized transactions sorted alphabetically by description.

Designed for systematic categorization after bulk import: Use this tool to retrieve transactions imported without categories. Because results are sorted by description, similar merchant/expense descriptions are grouped together, enabling fast and consistent bulk updates via update_transaction.

Arguments:

  • type: Optional filter by transaction type ('income' or 'expense').

  • search: Optional keyword search filter for description.

  • limit: Maximum number of records to return (default 100).

Inputs: type, limit, search. Returns: result

list_categoriesA

List established categories available for transactions.

  • type: Optional filter by 'expense' or 'income'. Use this tool to see standard existing categories before creating new ones.

Inputs: type. Returns: result

update_categoryA

Update an existing category's name, type, or description.

  • category_id_or_name: ID or current name of the category to update (required).

  • new_name: Optional new category name.

  • type: Optional new type ('expense' or 'income').

  • description: Optional new description string.

Inputs: category_id_or_name (required), type, new_name, description. Returns: result

update_transactionA

Update one or more existing transactions by ID.

Supports single transaction updates OR a batch list/dict of update items in items. Use this tool to assign category_id, amount, description, type, or date.

Systematic Categorization Workflow:

  • Pass a batch list in items containing {"transaction_id": id, "category_id": cat_id} to categorize multiple transactions at once.

Arguments:

  • items: Optional list of update dicts. Each dict must include "transaction_id" and optional update fields.

  • transaction_id: ID of transaction to update (used if items is omitted).

  • category_id: Integer category ID from list_categories to assign a category.

  • amount: Optional new monetary amount.

  • description: Optional new description.

  • type: Optional new type ('expense' or 'income').

  • date: Optional new date (YYYY-MM-DD).

Inputs: date, type, items, amount, +3 more. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelogโ€ฆ

    TDQS

    A3.6/5.0

    Scored across 12 tools

    Disambiguation4/5

    Most tools are clearly distinct in purpose - categories, transactions, summaries, trends, and dashboard each have a unique role. There's minor potential confusion between get_summary and spending_trends (both aggregate data), and list_categories vs add_category are distinct enough. Overall boundaries are clear.

    Naming Consistency4/5

    The naming mostly follows a consistent verb_noun pattern: list_categories, add_transaction, get_summary, update_transaction, delete_category. Minor deviations exist: 'budget_dashboard' and 'spending_trends' use noun-phrase naming instead of the verb-first convention, breaking the pattern slightly.

    Tool Count5/5

    12 tools is well-scoped for a budget management server covering full lifecycle operations on both transactions and categories, plus reporting/visualization tools. Each tool earns its place without redundancy or bloat.

    Completeness5/5

    The surface provides full CRUD for transactions (add, get, update, delete) and categories (add, update, delete, list), plus specialized workflows like bulk import/categorization (get_uncategorized_transactions), and reporting (get_summary, spending_trends, budget_dashboard). No significant gaps in the budget domain.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      D
      maintenance
      A lightweight server built with FastMCP and SQLite for managing personal finances. It allows users to add, list, and summarize expenses by category through MCP-compatible clients.
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      A lightweight MCP server that lets LLM clients track, query, and summarize personal expenses using a local SQLite database.
      -
    • F
      license
      B
      quality
      D
      maintenance
      A lightweight local MCP server that enables users to add, list, edit, and delete expenses via SQLite database through natural language in MCP-compatible clients.
      4
      1
      -