Skip to main content
Glama
vishnujayvel

Splitwise MCP Server

by vishnujayvel
README.md
# Splitwise MCP Server

A Model Context Protocol (MCP) server that enables AI assistants like Claude to manage Splitwise expenses with atomic duplicate prevention.

## Features

- **Atomic Duplicate Prevention**: Reserve-then-create pattern prevents accidental duplicate expenses from race conditions
- **Smart Duplicate Detection**: Fuzzy matching on description, amount, and date within configurable windows
- **Local SQLite Cache**: Fast duplicate checks without excessive API calls
- **Flexible Split Ratios**: Support for any split percentage (50/50, 75/25, 100/0, etc.)
- **Order ID Tracking**: Link expenses back to source orders (Amazon, Instacart, etc.) for traceability

## Requirements

- Python 3.10+
- Splitwise API key
- MCP-compatible client (Claude Code, etc.)

## Installation

```bash
# Clone the repository
git clone https://github.com/vishnujayvel/splitwise-mcp.git
cd splitwise-mcp

# Install in development mode
pip install -e .

# Or install with dev dependencies for testing
pip install -e .[dev]
```

## Configuration

The server supports multiple configuration methods, checked in this order:

### Option 1: Environment Variables (Recommended for production)

```bash
export SPLITWISE_API_KEY="your_api_key"
export SPLITWISE_GROUP_ID="your_group_id"
export SPLITWISE_PAYER_ID="your_user_id"
export SPLITWISE_PARTNER_ID="partner_user_id"

# Optional: custom config file path
export SPLITWISE_CONFIG_PATH="/path/to/config.json"

# Optional: logging level (DEBUG, INFO, WARNING, ERROR)
export LOG_LEVEL="INFO"

# Optional: custom cache database path
export SPLITWISE_CACHE_PATH="./splitwise_cache.db"
```

### Option 2: Configuration File

Create a `config.json` file (see `config.example.json`):

```json
{
  "splitwise": {
    "api_key": "YOUR_SPLITWISE_API_KEY",
    "group_id": "YOUR_GROUP_ID",
    "payer_id": "YOUR_USER_ID",
    "partner_id": "PARTNER_USER_ID"
  }
}
```

### Getting Your Splitwise Credentials

1. **API Key**:
   - Go to https://secure.splitwise.com/apps
   - Click "Register your application"
   - Fill in the application details
   - Copy the API key

2. **User IDs and Group ID**:
   - Go to https://secure.splitwise.com/api/v3.0/get_current_user (with authentication)
   - Or use the Splitwise API to query your groups and members
   - Your user ID and your partner's user ID are in the group members list

## Usage with Claude Code

Add to your `.mcp.json` file:

```json
{
  "mcpServers": {
    "splitwise": {
      "command": "python",
      "args": ["-m", "splitwise_mcp.server"],
      "cwd": "/path/to/splitwise-mcp/src",
      "env": {
        "SPLITWISE_API_KEY": "your_api_key",
        "SPLITWISE_GROUP_ID": "your_group_id",
        "SPLITWISE_PAYER_ID": "your_user_id",
        "SPLITWISE_PARTNER_ID": "partner_user_id"
      }
    }
  }
}
```

## MCP Tools

### splitwise_check_duplicate

Check if an expense would be a duplicate based on description, amount, and date similarity.

**Input:**
```json
{
  "description": "Amazon - Electronics",
  "amount": 49.99,
  "date": "2024-12-30",
  "group_id": "YOUR_GROUP_ID"
}
```

**Output:**
```json
{
  "is_duplicate": false,
  "reason": "No duplicate found",
  "existing_expense_id": null,
  "similarity_score": 0.0
}
```

### splitwise_reserve_expense

Atomically reserve an expense slot to prevent race conditions. Must be called before creating an expense.

**Input:**
```json
{
  "description": "Amazon - Electronics",
  "amount": 49.99,
  "date": "2024-12-30",
  "group_id": "YOUR_GROUP_ID",
  "order_id": "123-4567890-1234567"
}
```

**Output:**
```json
{
  "reservation_id": "temp_abc123def456",
  "expires_at": "2024-12-30T12:05:00",
  "is_duplicate": false,
  "reason": "Reservation created successfully",
  "existing_expense_id": null
}
```

### splitwise_create_expense

Create an expense in Splitwise and confirm the reservation.

**Input:**
```json
{
  "reservation_id": "temp_abc123def456",
  "description": "Amazon - Electronics",
  "amount": 49.99,
  "date": "2024-12-30",
  "group_id": "YOUR_GROUP_ID",
  "payer_id": "YOUR_USER_ID",
  "partner_id": "PARTNER_USER_ID",
  "order_id": "123-4567890-1234567",
  "split_ratio": "50/50"
}
```

**Output:**
```json
{
  "status": "created",
  "expense_id": "987654321",
  "payer_owes": 24.99,
  "partner_owes": 25.00,
  "total": 49.99,
  "url": "https://secure.splitwise.com/#/expenses/987654321"
}
```

### splitwise_sync_cache

Sync the local cache with Splitwise API. Fetches recent expenses and updates the cache.

**Input:**
```json
{
  "group_id": "YOUR_GROUP_ID",
  "since_date": "2024-12-01",
  "limit": 100
}
```

**Output:**
```json
{
  "synced_count": 15,
  "last_sync_at": "2024-12-30T12:00:00",
  "cache_size": 42
}
```

### splitwise_get_expenses

Query expenses from the local cache (fast, no API call).

**Input:**
```json
{
  "group_id": "YOUR_GROUP_ID",
  "start_date": "2024-12-01",
  "end_date": "2024-12-31"
}
```

**Output:**
```json
{
  "expenses": [
    {
      "id": "987654321",
      "description": "Amazon - Electronics",
      "amount": 49.99,
      "date": "2024-12-30",
      "payer_owes": 24.99,
      "partner_owes": 25.00
    }
  ],
  "total_count": 1
}
```

### splitwise_delete_expense

Delete an expense from Splitwise and remove it from the cache.

**Input:**
```json
{
  "expense_id": "987654321",
  "group_id": "YOUR_GROUP_ID"
}
```

**Output:**
```json
{
  "status": "deleted",
  "expense_id": "987654321"
}
```

### splitwise_find_by_order_id

Find an expense by order ID (most reliable duplicate detection method).

**Input:**
```json
{
  "order_id": "123-4567890-1234567"
}
```

**Output:**
```json
{
  "found": true,
  "expense": {
    "expense_id": "987654321",
    "description": "Amazon - Electronics",
    "cost": 49.99,
    "date": "2024-12-30",
    "order_id": "123-4567890-1234567",
    "group_id": "YOUR_GROUP_ID"
  }
}
```

## Known Limitations

This is an early release optimized for **two-person expense splitting** (couples, roommates). The following features are not yet supported:

| Feature | Status | Notes |
|---------|--------|-------|
| Groups with 3+ members | Not supported | Hardcoded to payer + partner |
| Multiple groups | Not supported | Single group_id in config |
| Variable payer | Not supported | Payer always pays upfront |
| Expense categories | Not supported | - |
| Balance queries | Not supported | Use Splitwise app |
| Payment/settle-up | Not supported | Use Splitwise app |
| Expense editing | Not supported | Delete and recreate |
| Receipt images | Not supported | - |

Contributions welcome for any of these features!

## Troubleshooting

### "Missing required configuration fields"

Ensure all required environment variables or config file fields are set:
- `SPLITWISE_API_KEY` / `api_key`
- `SPLITWISE_GROUP_ID` / `group_id`
- `SPLITWISE_PAYER_ID` / `payer_id`
- `SPLITWISE_PARTNER_ID` / `partner_id`

### "Splitwise API error 401"

Your API key is invalid or expired. Generate a new one at https://secure.splitwise.com/apps

### "Reservation expired"

Reservations expire after 5 minutes. Create the expense immediately after reserving, or reserve again.

### Duplicate not detected

1. Run `splitwise_sync_cache` to update the local cache
2. Check that the expense date is within the duplicate detection window (default: 7 days)

## Development

```bash
# Install dev dependencies
pip install -e .[dev]

# Run tests
PYTHONPATH=src pytest tests/ -v

# Run the server for testing
python -m splitwise_mcp.server
```

## License

MIT License - see [LICENSE](LICENSE) file for details.