Skip to main content
Glama
HamzaLatif02

budget-mcp

by HamzaLatif02

budget-mcp

MCP server for budget tooling, built on the official MCP Python SDK.

Project layout

budget-mcp/
├── pyproject.toml
├── budget.db              # SQLite db, created by init_db.py (gitignored)
├── src/
│   └── budget_mcp/
│       ├── __init__.py
│       ├── server.py      # MCPServer instance + tools
│       ├── db.py          # schema DDL + connection helper
│       ├── init_db.py     # resets budget.db and seeds example rows
│       ├── money.py       # dollars <-> integer-cents conversion
│       ├── dates.py       # date validation + period resolution
│       ├── categorizer.py # LLM-based transaction categorizer
│       └── eval_categorizer.py  # accuracy check against a labeled set
├── tests/
│   ├── conftest.py         # puts src/ on sys.path for test collection
│   └── test_tools.py       # end-to-end tool tests, see "Tests" below
└── .venv/                 # local virtualenv (gitignored)

Related MCP server: Hello World MCP Server

Requirements

  • Python 3.10+ (this project was set up with Python 3.12 via Homebrew: brew install python@3.12)

Setup

cd budget-mcp
/opt/homebrew/bin/python3.12 -m venv .venv
.venv/bin/pip install -e ".[dev]"
PYTHONPATH=src .venv/bin/python -m budget_mcp.init_db   # creates + seeds budget.db

macOS + iCloud Drive gotcha: if ~/Desktop is synced via iCloud Drive, the editable install's _editable_impl_budget_mcp.pth file in .venv/lib/python3.12/site-packages/ can end up with the macOS "hidden" file flag set, which makes Python 3.12 skip it — a bare import budget_mcp (e.g. in a REPL or test) will fail with ModuleNotFoundError even though the install "succeeded". If that happens, run:

chflags nohidden .venv/lib/python3.12/site-packages/_editable_impl_budget_mcp.pth

This doesn't affect running the server or the init script below — both are invoked with PYTHONPATH=src, which sidesteps the editable-install mechanism entirely.

categorize_transaction calls the Anthropic API, so it needs a key:

export ANTHROPIC_API_KEY=sk-ant-...

Add the same variable to the env block in the Claude Desktop config below so it's available when Claude Desktop launches the server.

Database

Three tables (see src/budget_mcp/db.py for the full DDL):

  • budgets(category PK, monthly_limit)

  • transactions(id, date, amount, category -> budgets.category, source, note)

  • savings_goals(id, name, target_amount, current_amount, account_type)

All money columns are integer cents (e.g. 50000 == $500.00) to avoid float rounding — SQLite has no real DECIMAL type. transactions.amount is signed: negative = expense, positive = income.

Re-run PYTHONPATH=src .venv/bin/python -m budget_mcp.init_db any time to wipe budget.db and reset it to the seed data.

Tools

  • ping() — placeholder, returns "pong".

  • add_transaction(date, amount, category, source, note=None) — inserts a transaction and returns it plus the category's running total for that transaction's calendar month. amount is dollars (e.g. -45.67); date must be YYYY-MM-DD; category must already exist in budgets. Rejects bad dates, zero/non-finite/sub-cent amounts, unknown categories, and empty source with a clear error message (no stack traces).

  • get_spending_summary(period, group_by, start_date=None, end_date=None) — sums expense transactions (amount < 0) over period ("this_month", "last_month", or "custom" with start_date/end_date), grouped by "category" or "source", and returns each group's total plus % of total spend. Rejects unknown period/group_by values and missing/invalid custom-range dates.

  • categorize_transaction(description) — classifies a raw statement line (e.g. "TESCO STORES 3421 LONDON") into one of rent, food, transport, savings, business_expense, entertainment, other, via a Claude Haiku 4.5 call with structured JSON output (category, confidence, reasoning). The returned category is checked against the fixed list before being returned — an invalid category from the model surfaces as an error rather than being trusted. Requires ANTHROPIC_API_KEY (see Setup above).

Tests

.venv/bin/pytest tests/ -v

Each test spawns a real server subprocess and drives it through the actual MCP protocol (same path Claude Desktop uses), against a fresh throwaway SQLite db (via BUDGET_MCP_DB_PATH) — your real budget.db is never touched. Covers both tools' happy paths (including that running totals and spend percentages come out exact, not float-drifted) and every validation rejection (bad dates, zero/non-finite/sub-cent amounts, unknown categories, empty source, bad period/group_by, missing custom-range dates).

categorize_transaction isn't in this suite — LLM output isn't deterministic, so it doesn't belong in a pass/fail unit test. Instead, check its accuracy against 15 hand-labeled realistic statement lines:

PYTHONPATH=src .venv/bin/python -m budget_mcp.eval_categorizer

This calls the live API (needs ANTHROPIC_API_KEY) and prints a pass/fail per example plus overall accuracy.

Running locally

Run the server directly (it speaks MCP over stdio):

PYTHONPATH=src .venv/bin/python -m budget_mcp.server

It will sit waiting for an MCP client to talk to it over stdin/stdout — that's expected, it's not meant to be run interactively.

To poke at it with the official inspector UI instead:

PYTHONPATH=src .venv/bin/mcp dev src/budget_mcp/server.py

Connecting to Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json and add an mcpServers entry:

{
  "mcpServers": {
    "budget-mcp": {
      "command": "/Users/hamza/Desktop/projects/budget-mcp/.venv/bin/python",
      "args": ["-m", "budget_mcp.server"],
      "env": {
        "PYTHONPATH": "/Users/hamza/Desktop/projects/budget-mcp/src",
        "ANTHROPIC_API_KEY": "sk-ant-..."
      }
    }
  }
}

Then fully quit and reopen Claude Desktop. In a new conversation, the tools should be available (look for the tools/hammer icon) — try asking Claude to call ping, then to add a transaction or get a spending summary.

Notes

  • Uses MCP Python SDK v2 (mcp.server.MCPServer, formerly FastMCP in v1.x). Requires mcp>=1.2.0 per pyproject.toml, but what's actually installed here is the current 2.x line.

  • Tool validation errors are raised as mcp.server.mcpserver.exceptions.ToolError, which the framework returns to the client as a plain error message — never a Python traceback.

Available Tools

4 tools
add_transactionA

Insert a transaction and return it plus the category's running total for its month.

date: ISO 8601 'YYYY-MM-DD'. amount: dollars, signed (negative = expense, positive = income), precise to the cent. category: must already exist in the budgets table.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYes
noteNo
amountYes
sourceYes
categoryYes

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the disclosure burden. It discloses the return value (transaction plus running total), amount sign convention, and the category existence requirement, which is meaningful behavioral context. It does not cover failure modes or side effects beyond insertion.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact: a one-sentence purpose followed by three terse parameter bullets. Every sentence adds information and it is easily scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although the core purpose is clear, the tool is incomplete for a 5-parameter no-annotation, no-output-schema case: 'source' is required but undefined, and there's no guidance on when to use add_transaction versus categorize_transaction. Error or rejection behavior for invalid categories is also unexplored.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description explains date, amount, and category, adding useful meaning beyond the bare schema. However, it omits the required 'source' parameter entirely and also does not explain 'note,' leaving 2 of 5 parameters undocumented despite 0% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Insert a transaction and return it plus the category's running total for its month,' clearly identifying a create operation with a specific return value. The verb 'Insert' and resource 'transaction' distinguish it from read-only siblings like get_spending_summary and from categorize_transaction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for creating new transactions but provides no explicit when-to-use guidance or exclusions of alternatives like categorize_transaction. It does state a prerequisite (category must already exist), but does not say when to choose this tool over a sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

categorize_transactionA

Suggest a budget category for a raw transaction description via an LLM classifier.

description: raw text as it might appear on a statement, e.g. "TESCO STORES 3421 LONDON".

Returns category (one of rent/food/transport/savings/business_expense/ entertainment/other), confidence (0-1), and reasoning. The category is checked against the allowed list before being returned - an invalid category from the model surfaces as an error rather than being passed through.

ParametersJSON Schema
NameRequiredDescriptionDefault
descriptionYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations available, the description fully carries the burden of behavioral disclosure. It explains that an LLM is used, that the category is validated against a fixed list, that invalid categories surface as errors, and it specifies the return fields (category, confidence, reasoning). This goes beyond basic expectations and provides meaningful transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded with the purpose. The only minor issue is the use of 'description:' on a separate line, which could be slightly confusing because it mirrors the tool's own description field. Otherwise, it is structured logically and contains no wasted content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of output schema and annotations, the description covers all essential context: input format with example, output structure with allowed categories and confidence range, and error behavior. Nothing critical is missing for the agent to invoke and interpret the result correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides no description for the single 'description' parameter, so the tool description compensates by defining it as 'raw text as it might appear on a statement' with a concrete example ('TESCO STORES 3421 LONDON'). This gives the agent clear semantic understanding that the schema lacks.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'Suggest a budget category for a raw transaction description via an LLM classifier.' This uses a specific verb and resource, and it is distinct from sibling tools like add_transaction or get_spending_summary, leaving no ambiguity about its purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The context strongly implies when to use this tool: whenever a raw transaction description needs a budget category. It includes an example of the expected input and explains the return structure, making the use case clear. However, it does not explicitly mention when not to use it or point to alternatives, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_spending_summaryA

Summarize expense transactions (amount < 0) over a period, grouped by category or source.

period: 'this_month', 'last_month', or 'custom' (requires start_date and end_date). group_by: 'category' or 'source'. start_date/end_date: ISO 8601 'YYYY-MM-DD', inclusive, only used when period='custom'.

ParametersJSON Schema
NameRequiredDescriptionDefault
periodYes
end_dateNo
group_byYes
start_dateNo

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the transparency burden. It discloses that only transactions with amount < 0 are considered, dates are inclusive, and custom periods require start/end dates. However, it does not state that the operation is read-only, nor does it describe the output structure or any side effects, leaving room for ambiguity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: a one-sentence purpose followed by parameter details. Every sentence contributes value, and the format makes the information easily scannable for an agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 4 parameters, no output schema, and no annotations. The description documents parameters well but does not explain what the summary output looks like (e.g., totals, counts, breakdown structure). An agent may not know how to interpret the returned data, which is a notable gap given the lack of an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description fully explains all parameters: allowed values for period and group_by, the requirement for start_date/end_date when period='custom', and the ISO 8601 format with inclusive behavior. This adds essential meaning beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the tool as summarizing expense transactions (amount < 0) over a period, grouped by category or source. It distinguishes itself from sibling tools (ping, add_transaction, categorize_transaction) by focusing on aggregate read-only analysis rather than mutations or health checks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use the tool (summarizing expenses) and explains the period and grouping options. It does not explicitly name alternatives or state when not to use it, but the sibling context and the explanatory parameter notes make the intended usage clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pingA

Placeholder tool to verify the server is wired up correctly.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of disclosure. It indicates a non-destructive verification purpose but does not specify what the tool returns, whether it has side effects, or any caveats. For a trivial ping tool, this is acceptable but not richly transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no filler. Every word contributes to understanding the tool's purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity, the description is largely complete. It doesn't explain the return value, but an output schema exists, so that information is likely covered structurally. The placeholder wording appropriately signals limited utility.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema covers everything (100%). According to the rubric, a baseline of 4 applies when there are no parameters, and the description need not add parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: 'verify the server is wired up correctly.' This distinguishes it from sibling tools focused on transaction operations, making its health-check purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'to verify the server is wired up correctly' gives a clear context for when to use this tool. Although it doesn't explicitly mention alternatives or when not to use it, the purpose inherently implies it's for initial connectivity checks, and there are no competing tools for this behavior.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 4 tool updatesv0.1.0
    • First observedadd_transaction
    • First observedcategorize_transaction
    • First observedget_spending_summary
    • First observedping

TDQS

A3.9/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: ping for connectivity, add_transaction for inserting data, get_spending_summary for aggregating, and categorize_transaction for classification. There is no functional overlap between any two tools.

Naming Consistency4/5

The three functional tools follow a consistent verb_noun pattern (add_transaction, get_spending_summary, categorize_transaction). The 'ping' tool breaks the pattern by being a bare verb, but it's a standard placeholder and doesn't cause confusion.

Tool Count3/5

With only 4 tools (one being a placeholder), the server feels under-scoped for a budget application. The count is borderline acceptable, but the lack of essential operations makes it seem thin.

Completeness2/5

The server lacks core CRUD functionality: no way to list, update, or delete transactions, and no way to manage categories (add_transaction requires an existing category but there's no create_category tool). Also missing budget-setting features, making the surface significantly incomplete.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    A simple demonstration MCP server that provides basic greeting functionality and server information. Enables users to generate hello messages and retrieve server details through tools and resources.
    -
  • -
    license
    C
    quality
    Not graded
    maintenance
    A simple boilerplate MCP server that provides a basic greeting tool for demonstration purposes. Serves as a starting template for developers to quickly create and deploy custom MCP servers.
    1
    6 npm
    -
  • A
    license
    C
    quality
    D
    maintenance
    A simple MCP server that provides a basic greeting tool for saying hello with customizable names. Serves as a boilerplate template for developers to quickly create and deploy new MCP servers.
    1
    6 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    A simple demonstration MCP server that provides an echo tool and resource for learning how to build MCP servers. Serves as a starting point and template for creating custom MCP server implementations.
    1
    -