Skip to main content
Glama
reilly3000

Tool-Plaid

by reilly3000
README.md
# Tool-Plaid: MCP Server for Plaid

MCP (Model Context Protocol) server tool that exposes two tools for interacting with Plaid's financial data API:
- `sync_transactions` - Retrieve and sync transaction data
- `get_balance` - Get account balances

## Installation

### Development Installation

```bash
# Clone the repository
git clone https://github.com/reilly3000/tool-plaid.git
cd tool-plaid

# Install in development mode
pip install -e .

# Or with uv (recommended)
uv pip install -e .
```

### Production Installation

```bash
pip install tool-plaid
# or with uv
uv pip install tool-plaid
```

## Configuration

### Environment Variables

Create a `.env.agent` file in the project root (ignored by git) or set environment variables:

```bash
# Plaid Configuration
PLAID_ENV=sandbox|production
PLAID_CLIENT_ID=<your_client_id>
PLAID_SECRET=<your_secret>

# Security
ENCRYPTION_KEY=<your_32_byte_encryption_key>

# Storage
STORAGE_MODE=file|postgres
DATABASE_URL=postgresql://user:pass@host:port/dbname  # required if STORAGE_MODE=postgres

# MCP Server
MCP_TRANSPORT=stdio|streamable-http
MCP_PORT=8000

# Caching (optional)
BALANCE_CACHE_TTL=300  # seconds, default: 300 (5 minutes)
```

### Example .env File

```bash
# Sandbox Environment
PLAID_ENV=sandbox
PLAID_CLIENT_ID=62eacf714206f30013d6e722
PLAID_SECRET=6f85aa5808d484246313470945c515

# Generate a random 32-byte key
ENCRYPTION_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")

# Start with file storage
STORAGE_MODE=file
```

## Usage

### Running the Server

#### Local Development (STDIO)

```bash
# Set environment
export PLAID_ENV=sandbox
export PLAID_CLIENT_ID=<your_client_id>
export PLAID_SECRET=<your_secret>
export STORAGE_MODE=file

# Run with uv
uv run plaid-tool

# Or directly
python -m tool_plaid
```

#### Production (Streamable HTTP)

```bash
export PLAID_ENV=production
export DATABASE_URL=postgresql://...
export STORAGE_MODE=postgres
export MCP_TRANSPORT=streamable-http

# Run HTTP server
plaid-tool
```

### Configuration with Claude Desktop

Add this to your MCP configuration file (e.g., `claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "plaid": {
      "command": "plaid-tool",
      "env": {
        "PLAID_ENV": "sandbox"
      }
    }
  }
}
```

## Tools

### sync_transactions

Sync transactions from Plaid using cursor-based incremental updates.

**Parameters:**
- `item_id` (required): Plaid item identifier
- `force_refresh` (optional, default=False): Trigger Plaid refresh
- `days_requested` (optional, default=90, range 1-730): Days of history

**Returns:**
```json
{
  "added": [
    {
      "transaction_id": "string",
      "account_id": "string",
      "amount": 100.50,
      "date": "2025-01-15",
      "merchant_name": "Merchant Name",
      "category": "Food and Drink",
      "pending": false
    }
  ],
  "modified": [...],
  "removed": ["transaction_id_1", "transaction_id_2"],
  "next_cursor": "cursor_string",
  "has_more": false,
  "item_status": "HISTORICAL_UPDATE_COMPLETE",
  "summary": "Added 10, modified 2, removed 1 transactions"
}
```

### get_balance

Get account balances with intelligent caching.

**Parameters:**
- `item_id` (required): Plaid item identifier
- `account_ids` (optional, default=None): Filter specific accounts
- `force_refresh` (optional, default=False): Bypass cache

**Returns:**
```json
{
  "balances": [
    {
      "account_id": "string",
      "name": "Plaid Checking",
      "mask": "0000",
      "type": "depository",
      "available": 1000.00,
      "current": 1250.00,
      "iso_currency_code": "USD"
    }
  ],
  "cached": true,
  "timestamp": "2025-01-15T10:30:00Z"
}
```

## Architecture

### Storage Modes

**File Storage (Development)**
- JSONL files for transactions
- Simple key-value cursor tracking
- Text-based balance snapshots
- Directory: `data/items/{item_id}/`

**PostgreSQL (Production)**
- Async PostgreSQL with asyncpgres
- Tables: `access_tokens`, `transactions`, `balances`, `cursors`
- Connection pooling
- Migrations via alembic

### Security

- AES-256 encryption for access tokens at rest
- Encryption key from environment variable
- No logging of sensitive data (tokens, raw responses)
- Audit logging without sensitive data

## Development

### Running Tests

```bash
# Unit tests
pytest tests/ -v

# With coverage
pytest --cov=tool_plaid --cov-report=html
```

### End-to-End Testing (Sandbox)

1. Open `tests/plaid_link_test.html` in a browser
2. Link a test bank using credentials: `user_good` / `pass_good`
3. Copy the public token and run:
```bash
python tests/test_e2e.py <PUBLIC_TOKEN>
```

Note: Public tokens expire after ~30 minutes.

### Quick Verification

```bash
# Check config loads
python -c "from tool_plaid.config import Config; c = Config.load(); print(c.PLAID_CLIENT_ID)"

# Test encryption
python -c "from tool_plaid.utils.encryption import Encryptor; from tool_plaid.config import Config; e = Encryptor(Config.load().ENCRYPTION_KEY); print(e.decrypt(e.encrypt('test')))"
```

### Code Quality

```bash
# Format code
black tool_plaid

# Lint
ruff check tool_plaid

# Type check
mypy tool_plaid
```

## License

MIT

## Support

For issues and questions, please open an issue on GitHub.

Maintenance

ActivityInactive
ResponsivenessNo issues