Expense Tracker MCP Server
# Expense Tracker MCP Server
A local Model Context Protocol (MCP) server that helps you track grocery and shopping expenses by parsing PDF receipts, automatically categorizing items, and storing them in a SQLite database for easy querying.
## Features
- **PDF Receipt Parsing**: Extract line items, prices, and metadata from PDF receipts
- **Smart Categorization**: Hybrid approach using static rules + LLM fallback for item classification
- **SQLite Storage**: Persistent local database for all your expense data
- **Query Tools**: Ask questions like "When did I last buy milk?" or "How often do I buy bread?"
- **Multi-Store Support**: Works with receipts from Walmart, Costco, Target, and more
## Installation
### Prerequisites
- Python 3.11 or higher
- [uv](https://docs.astral.sh/uv/) (recommended) or pip
### Step 1: Clone or Download
```bash
cd /Users/sharan/Desktop/expense_tracker_mcp
```
### Step 2: Install Dependencies
**Using uv (recommended):**
```bash
uv sync
```
**Using pip:**
```bash
pip install -r requirements.txt
```
### Step 3: Initialize Database
The database is automatically initialized when you first run the server. The SQLite database will be created at `data/expenses.db`.
## Running Locally
To test the server locally:
```bash
python main.py
```
or with uv:
```bash
uv run main.py
```
The server will start and listen on stdin/stdout (MCP protocol).
## Connecting to Claude Desktop
### Step 1: Locate Claude Desktop Config
The configuration file is located at:
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
### Step 2: Add MCP Server Configuration
Edit the config file and add this entry to `mcpServers`:
```json
{
"mcpServers": {
"expense-tracker": {
"command": "uv",
"args": [
"--directory",
"/Users/sharan/Desktop/expense_tracker_mcp",
"run",
"main.py"
]
}
}
}
```
**Alternative (using python directly):**
```json
{
"mcpServers": {
"expense-tracker": {
"command": "/Users/sharan/Desktop/expense_tracker_mcp/.venv/bin/python",
"args": [
"/Users/sharan/Desktop/expense_tracker_mcp/main.py"
]
}
}
}
```
### Step 3: Restart Claude Desktop
After saving the config, restart Claude Desktop to load the MCP server.
## Usage
Once connected to Claude Desktop, you can use these tools:
### 1. Import a Receipt
Upload a PDF receipt and the server will parse it:
```
Import this receipt: /path/to/walmart_receipt.pdf
```
**Example Response:**
```json
{
"status": "success",
"receipt_id": 1,
"store_name": "Walmart",
"purchase_date": "2025-01-15",
"total": 45.67,
"items_count": 12,
"item_types": {
"milk": 1,
"bread": 1,
"eggs": 1,
"veggies": 3,
"snacks": 2,
"beverages": 2,
"meat": 2
}
}
```
### 2. Query Item History
Ask when you last bought something:
```
When did I last buy milk?
```
or
```
Show me all my milk purchases in the last 6 months
```
**Example Response:**
```json
{
"item_type": "milk",
"purchases": [
{
"date": "2025-01-15",
"store": "Walmart",
"item_name": "Organic Milk 2%",
"quantity": 1.0,
"price": 4.99
},
{
"date": "2024-12-28",
"store": "Costco",
"item_name": "Kirkland Milk",
"quantity": 2.0,
"price": 6.99
}
],
"stats": {
"total_purchases": 2,
"last_purchase_date": "2025-01-15",
"first_purchase_date": "2024-12-28",
"average_days_between": 18.0,
"total_spent": 11.98
}
}
```
### 3. List All Categories
See all item types you've purchased:
```
What categories of items have I bought?
```
**Example Response:**
```json
{
"item_types": [
{
"item_type": "milk",
"total_purchases": 12,
"last_purchase_date": "2025-01-15",
"total_spent": 59.88
},
{
"item_type": "bread",
"total_purchases": 8,
"last_purchase_date": "2025-01-10",
"total_spent": 27.92
}
],
"total_categories": 15
}
```
## Supported Item Categories
The categorizer recognizes these item types out of the box:
**Dairy**: milk, oatmilk, eggs, cheese, yogurt, butter
**Grains**: bread, rice, lentils, pasta, cereal
**Produce**: veggies, fruits, potatoes
**Proteins**: meat, fish
**Snacks & Beverages**: snacks, beverages
**Pantry**: oil, spices, sauce
**Household**: cleaning, paper
**Fallback**: other (for unrecognized items)
### Adding New Categories
Edit `expense_tracker/categorizer.py` and add patterns to the `ITEM_TYPE_MAPPINGS` dictionary:
```python
ITEM_TYPE_MAPPINGS = {
# ... existing categories ...
"tofu": ["tofu", "bean curd", "soy protein"],
}
```
## Database Schema
The SQLite database (`data/expenses.db`) contains two main tables:
### receipts
- `id`: Auto-increment primary key
- `store_name`: Store name (e.g., "Walmart")
- `purchase_date`: ISO format date (YYYY-MM-DD)
- `subtotal`: Subtotal amount (nullable)
- `tax`: Tax amount (nullable)
- `total`: Total amount (required)
- `created_at`: Timestamp
### items
- `id`: Auto-increment primary key
- `receipt_id`: Foreign key to receipts table
- `item_name_raw`: Original item name from receipt
- `item_type`: Normalized category
- `quantity`: Item quantity (default: 1.0)
- `unit_price`: Price per unit (nullable)
- `line_total`: Total price for this line
- `created_at`: Timestamp
## How It Works
### 1. PDF Parsing
Uses **pdfplumber** to extract text from PDF files, then applies regex patterns to identify:
- Store name (Walmart, Costco, Target, etc.)
- Purchase date (multiple date formats supported)
- Line items with quantities and prices
- Totals (subtotal, tax, total)
### 2. Item Categorization
**Hybrid approach:**
1. **Static Rules** (fast, deterministic)
- Checks item name against pre-defined patterns
- Handles common grocery items with keyword matching
- ~90% accuracy for typical grocery items
2. **LLM Fallback** (smart, adaptive)
- Uses Claude via FastMCP's `Context.sample()` for unknown items
- Provides better accuracy for unusual or new items
- Automatically adapts to items not in static mappings
### 3. Database Storage
All data is stored in a local SQLite database with proper indexing for fast queries:
- Indexes on `purchase_date`, `store_name`, `item_type`
- Foreign key constraints for data integrity
- Support for aggregate queries and statistics
## Troubleshooting
### Server not appearing in Claude Desktop
1. Check that the path in `claude_desktop_config.json` is correct
2. Restart Claude Desktop completely
3. Check Claude Desktop logs for errors
### PDF parsing errors
- Ensure the PDF is text-based (not a scanned image)
- Try opening the PDF in a viewer to verify it contains selectable text
- Check that the file path is absolute, not relative
### Database locked errors
- Close any other tools accessing `data/expenses.db`
- Make sure only one instance of the server is running
## Development
### Running Tests
```bash
pytest tests/
```
### Adding New Features
The modular architecture makes it easy to extend:
- **New categorization rules**: Edit `expense_tracker/categorizer.py`
- **New receipt formats**: Update patterns in `expense_tracker/pdf_parser.py`
- **New MCP tools**: Add tool functions to `main.py` with `@mcp.tool` decorator
- **Database changes**: Modify schema in `expense_tracker/database.py`
## License
MIT License - feel free to use and modify for your needs.
## Contributing
Contributions welcome! Areas for improvement:
- Support for more receipt formats
- Better item categorization rules
- Export to CSV/Excel functionality
- Visualization dashboards
- Multi-user support
## Support
For issues or questions:
- Check the [FastMCP documentation](https://gofastmcp.com)
- Review [MCP protocol docs](https://modelcontextprotocol.io)
- File an issue on GitHub
---
**Built with [FastMCP](https://gofastmcp.com) - The fast, Pythonic way to build MCP servers**
TDQS
Scored across 3 tools
Each tool has a clearly distinct purpose: get_item_history retrieves detailed purchase history for a specific item, import_receipt_from_pdf processes new receipts into the database, and list_item_types provides an overview of all tracked categories. There is no overlap in functionality, and an agent could easily select the appropriate tool based on the task.
The tool names follow a consistent verb_noun pattern (get_item_history, import_receipt_from_pdf, list_item_types), making them predictable and readable. The minor deviation is that 'import_receipt_from_pdf' includes a preposition ('from'), but this does not significantly impact consistency or clarity.
With only 3 tools, the server feels slightly thin for an expense tracker domain, as it lacks operations like updating or deleting entries, or querying by other criteria (e.g., date ranges or stores). However, the tools cover core functionalities (import, query history, list categories), so it is borderline but functional.
The tool set covers basic import and query operations but has notable gaps: there are no tools for updating or deleting data, managing stores or receipts beyond import, or advanced filtering (e.g., by date or store). This could lead to agent failures if such operations are needed, though core workflows (adding receipts and viewing history) are supported.