Skip to main content
Glama
Mannu-Thakur

Expense MCP Server

by Mannu-Thakur

πŸ’Έ Expense MCP Server

A production-ready Model Context Protocol (MCP) server for managing personal expenses β€” built with FastMCP, SQLAlchemy, and Pydantic. Deploys as a Docker container on Render with PostgreSQL, and connects to Claude Desktop, Cursor, VS Code, or any MCP-compatible client.


Status

βœ… Live on Render β€” Docker Β· PostgreSQL Β· Streamable HTTP

Transport

Streamable HTTP

Database

PostgreSQL (Render managed)

Health endpoint

/health

MCP endpoint

/mcp


Related MCP server: expense-tracker-mcp-server

Architecture

Claude Desktop / Cursor / VS Code MCP
            β”‚
            β”‚  MCP over Streamable HTTP
            β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  Expense MCP Server β”‚  Docker Β· Render
   β”‚  FastMCP + Uvicorn  β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚   Expense Service   β”‚  Business logic
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚     Repository      β”‚  Data access layer
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  SQLAlchemy ORM     β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  PostgreSQL / SQLiteβ”‚  Prod / Dev
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

API Request Flow

Claude  β†’  MCP Tool  β†’  FastMCP  β†’  Expense Service  β†’  Repository  β†’  SQLAlchemy  β†’  PostgreSQL

✨ Features

  • 8 MCP Tools β€” add, list, update, delete, search expenses, and get monthly/category/merchant summaries

  • Dual transport β€” STDIO (local Claude Desktop) and Streamable HTTP (remote/Docker/Render)

  • Dual database β€” SQLite for local development, PostgreSQL for production

  • Production-ready β€” structured logging, custom exceptions, connection pooling, non-root Docker user

  • 31 tests β€” full repository, service, and tool coverage with in-memory SQLite isolation

  • One-command deploy β€” render.yaml Blueprint auto-provisions PostgreSQL + Docker web service

Production Features

Feature

Detail

βœ“ Docker multi-stage image

Minimal, hardened runtime layer

βœ“ PostgreSQL

Render-managed with connection pooling

βœ“ Render Blueprint

Auto-provisions all infrastructure

βœ“ Health endpoint

/health for Render and load balancer checks

βœ“ Remote HTTP MCP

Accessible at /mcp from any MCP client

βœ“ Connection pooling

pool_size=5, max_overflow=10, pool_recycle=1800

βœ“ Structured logging

ISO timestamps, log levels, logger names

βœ“ Non-root container

appuser with no escalation

βœ“ Automatic DB provisioning

Tables created on first startup


Compatible Clients

βœ… Claude Desktop
βœ… Cursor
βœ… VS Code MCP extension
βœ… Any MCP client supporting Streamable HTTP


Transport Modes

Transport

When to use

stdio

Local Claude Desktop β€” server runs as a child process

streamable-http

Remote deployment, Docker, Render β€” server listens on HTTP


πŸ—‚ Project Structure

expense-mcp-server/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ config.py              # Pydantic Settings (reads from .env)
β”‚   β”œβ”€β”€ exceptions.py          # ExpenseNotFoundError, ExpenseValidationError
β”‚   β”œβ”€β”€ logging_config.py      # Structured logging setup
β”‚   β”œβ”€β”€ mcp_instance.py        # FastMCP instance + /health endpoint
β”‚   β”œβ”€β”€ server.py              # Registers all 8 tools
β”‚   β”œβ”€β”€ database/
β”‚   β”‚   β”œβ”€β”€ db.py              # Engine, SessionLocal, validate_connection()
β”‚   β”‚   └── models.py          # Expense SQLAlchemy model
β”‚   β”œβ”€β”€ schemas/
β”‚   β”‚   └── expense.py         # ExpenseCreate, ExpenseUpdate (Pydantic)
β”‚   β”œβ”€β”€ repositories/
β”‚   β”‚   └── expense_repository.py
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   └── expense_service.py
β”‚   β”œβ”€β”€ tools/
β”‚   β”‚   β”œβ”€β”€ add_expense.py
β”‚   β”‚   β”œβ”€β”€ list_expenses.py
β”‚   β”‚   β”œβ”€β”€ update_expense.py
β”‚   β”‚   β”œβ”€β”€ delete_expense.py
β”‚   β”‚   β”œβ”€β”€ search_expenses.py
β”‚   β”‚   β”œβ”€β”€ monthly_summary.py
β”‚   β”‚   β”œβ”€β”€ category_summary.py
β”‚   β”‚   └── top_merchants.py
β”‚   └── utils/
β”‚       β”œβ”€β”€ dates.py
β”‚       └── currency.py
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ conftest.py            # In-memory SQLite fixtures + monkeypatch
β”‚   └── test_expense.py        # 31 tests
β”œβ”€β”€ run.py                     # Entry point
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ Dockerfile                 # Multi-stage Docker build
β”œβ”€β”€ docker-compose.yml         # App + PostgreSQL local stack
β”œβ”€β”€ render.yaml                # Render Blueprint (PostgreSQL + Docker web service)
└── .env                       # Local environment variables

πŸ›  MCP Tools

Tool

Description

add_expense

Add a new expense with amount, category, date, merchant, currency

list_expenses

List all expenses sorted by date descending

update_expense

Update any field of an existing expense by ID

delete_expense

Delete an expense by ID

search_expenses

Search by category, description, or merchant

monthly_summary

Total, count, average, and max for the current month

category_summary

Spending totals grouped by category

top_merchants

Top merchants by total spending


βš™οΈ Environment Variables

Variable

Default

Description

APP_ENV

development

development or production

LOG_LEVEL

INFO

Python log level

MCP_SERVER_NAME

Expense Tracker

Name shown in Claude Desktop

TRANSPORT

stdio

stdio or streamable-http

HOST

0.0.0.0

Bind host (HTTP mode only)

PORT

8000

Bind port for local/Docker. Render injects PORT=10000 automatically β€” no manual configuration needed.

DATABASE_URL

sqlite:///./expenses.db

SQLite or PostgreSQL connection string


πŸš€ Getting Started

Option A β€” Local Development (STDIO + SQLite)

1. Clone and create a virtual environment

git clone https://github.com/your-username/expense-mcp-server.git
cd expense-mcp-server
python -m venv .venv

2. Activate the virtual environment

# Windows
.venv\Scripts\activate

# macOS / Linux
source .venv/bin/activate

3. Install dependencies

pip install -r requirements.txt

4. Configure .env

APP_ENV=development
LOG_LEVEL=INFO
MCP_SERVER_NAME=Expense Tracker
TRANSPORT=stdio
HOST=0.0.0.0
PORT=8000
DATABASE_URL=sqlite:///./expenses.db

5. Run the server

python run.py

The server starts in STDIO mode β€” ready to be used with Claude Desktop.


Option B β€” Local Docker + PostgreSQL (HTTP)

1. Start the full stack

docker-compose up --build

This starts:

  • expense_postgres β€” PostgreSQL 16 on port 5432

  • expense_mcp β€” MCP server on port 8000 (Streamable HTTP transport)

The app waits for PostgreSQL to pass its health check before starting.

2. Verify it's running

curl http://localhost:8000/health

Option C β€” Deploy to Render (Docker + PostgreSQL)

The project deploys as a Docker multi-stage image on Render.

1. Push your repo to GitHub

2. Go to render.com β†’ New β†’ Blueprint

3. Connect your GitHub repo β€” Render auto-detects render.yaml and automatically creates:

  • A managed PostgreSQL database

  • A Docker web service running run.py

  • All required environment variables

  • Database connection wired via fromDatabase.connectionString

4. Your server will be live at:

https://<your-render-service>.onrender.com

Replace <your-render-service> with your actual Render service name (shown in the dashboard after deployment).


πŸ” Health Check

The server exposes /health for Render and load balancer health checks.

curl https://<your-render-service>.onrender.com/health

Response:

{"status": "ok"}

πŸ”Œ Verify the MCP Endpoint

GET https://<your-render-service>.onrender.com/mcp

Note: A browser will show 405 Method Not Allowed. This is expected β€” /mcp speaks the MCP protocol (not plain HTTP GET). Use an MCP client to connect.


πŸ–₯ Claude Desktop Configuration

Add to %APPDATA%\Claude\claude_desktop_config.json (Windows) or
~/Library/Application Support/Claude/claude_desktop_config.json (macOS).

Option A β€” Local STDIO

{
  "mcpServers": {
    "expense-tracker": {
      "command": "C:\\path\\to\\expense-mcp-server\\.venv\\Scripts\\python.exe",
      "args": ["C:\\path\\to\\expense-mcp-server\\run.py"]
    }
  }
}

Option B β€” Render (Remote HTTP)

{
  "mcpServers": {
    "expense-tracker": {
      "type": "streamable-http",
      "url": "https://<your-render-service>.onrender.com/mcp"
    }
  }
}

Option C β€” Docker (Local HTTP)

{
  "mcpServers": {
    "expense-tracker": {
      "type": "streamable-http",
      "url": "http://localhost:8000/mcp"
    }
  }
}

You can include all three entries simultaneously β€” just give each a unique key.


πŸ§ͺ Running Tests

python -m pytest tests/ -v

Expected output:

31 passed in ~1s

The test suite covers:

  • TestExpenseRepository β€” 13 tests (CRUD + search + summaries)

  • TestExpenseService β€” 10 tests (business logic + error handling)

  • TestTools β€” 8 tests (MCP tool integration)

Tests use an in-memory SQLite database with full transaction rollback isolation between each test.


πŸ—ƒ Database

SQLite (Local)

Zero configuration. The expenses.db file is created automatically on first run.

DATABASE_URL=sqlite:///./expenses.db

PostgreSQL (Docker / Production)

DATABASE_URL=postgresql://expense_user:expense_pass@localhost:5432/expense_db

The Expense table is created automatically via Base.metadata.create_all() on startup.

Column

Type

Notes

id

Integer

Primary key

amount

Float

Required, must be > 0

category

String

Required

description

String

Optional

merchant

String

Optional

payment_method

String

Optional

currency

String

Default: INR

expense_date

Date

Required

created_at

DateTime

Auto-set to UTC now


πŸ“¦ Tech Stack

Layer

Library

Version

MCP Framework

mcp (FastMCP)

1.28.1

Settings

pydantic-settings

2.14.2

ORM

SQLAlchemy

2.0.51

Validation

pydantic

2.13.4

PostgreSQL driver

psycopg2-binary

2.9.10

HTTP server

uvicorn + starlette

β€”

Testing

pytest

9.1.1


πŸ“„ License

MIT

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

–Maintainers
–Response time
–Release cycle
–Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mannu-Thakur/expense-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server