# 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**