Skip to main content
Glama
Mannu-Thakur

Expense MCP Server

by Mannu-Thakur

Expense MCP Server

A personal expense ledger exposed as eight Model Context Protocol (MCP) tools. Local clients use STDIO. Hosted clients use authenticated Streamable HTTP and PostgreSQL.

The server uses MCP Python SDK 2.3.0, which supports the 2026-07-28 protocol revision and earlier clients. Its HTTP resource server requires OAuth before any MCP request reaches a tool.

Supported tools

  • add_expense

  • list_expenses

  • update_expense

  • delete_expense

  • search_expenses

  • monthly_summary

  • category_summary

  • top_merchants

The server keeps each authenticated HTTP user's ledger separate using a SHA-256 hash of the verified issuer and subject. Reads require expenses:read; writes require both expenses:read and expenses:write. User identity is never accepted as a tool argument. When the OAuth settings are missing, the HTTP service can start for its database health check but the MCP route returns 503; partial OAuth settings fail startup. SSE is disabled.

Related MCP server: Expense Tracker MCP

Local STDIO with PostgreSQL

The included Compose file starts a local PostgreSQL 16 database only. Its development password is fixed and the database port is bound to loopback; do not expose this setup to a network.

  1. Install Python 3.11 and Docker Desktop.

  2. Start PostgreSQL:

    docker compose up -d postgres
  3. Create a virtual environment and install dependencies:

    python -m venv .venv
    # Windows PowerShell: .venv\Scripts\Activate.ps1
    # macOS/Linux: source .venv/bin/activate
    python -m pip install -r requirements.txt
  4. Copy .env.example to .env if you do not already have a local .env. The example connects to the Compose PostgreSQL database and uses STDIO. Keep .env private.

  5. Run python run.py, or configure your MCP client to launch that command as a local STDIO server.

For lightweight local experiments, SQLite is supported when APP_ENV is not production. SQLite does not enforce fixed decimal precision at the database layer; tool inputs are validated by the application. Production startup rejects SQLite.

Authenticated Streamable HTTP

HTTP requires an external OpenID Connect/OAuth provider that issues signed JWT access tokens. This project verifies tokens; it does not create users, issue tokens, or manage provider accounts. Set these environment variables in the server runtime:

Variable

Purpose

OAUTH_ISSUER_URL

Exact issuer URL expected in the token's iss claim.

OAUTH_JWKS_URL

HTTPS URL for the issuer's public signing keys.

OAUTH_AUDIENCE

Expected token audience.

OAUTH_RESOURCE_URL

Public MCP URL ending in /mcp.

OAUTH_JWT_ALGORITHM

Optional asymmetric algorithm; defaults to RS256. Supported: RS256, RS384, RS512, ES256, ES384.

Tokens must have valid signatures and include exp, iss, sub, aud, and a scope or scp claim. They must carry expenses:read; mutations also require expenses:write. The verifier uses the configured JWKS, issuer, audience, and algorithm, with a short network timeout and cached signing keys. Production issuer, JWKS, and resource URLs must use HTTPS. Loopback HTTP is allowed only outside production.

The /health route is public for hosting-platform health checks and returns 503 when PostgreSQL is unavailable. If no OAuth settings are configured, /mcp returns 503 so Render can replace an older revision without opening an unauthenticated MCP endpoint. Once OAuth is configured, the MCP endpoint and its tools require a valid token. Do not use a hosted MCP endpoint until the provider has been configured and the HTTP auth flow has been tested with real credentials.

PostgreSQL and schema migration

PostgreSQL is required when APP_ENV=production; there is no SQLite fallback. The application checks database connectivity before serving requests, applies a migration to existing expenses tables, creates missing tables, and ensures an owner index exists. Legacy amounts are rounded to the supported currency precision during migration (zero fractional digits for JPY, two for other supported currencies); blank currency values become INR and existing currency codes are trimmed and uppercased. Migration stops without truncating currency values longer than three characters or accepting NULL amounts, categories, or dates. Back up existing data before deploying this migration.

For Render, the Blueprint creates a free PostgreSQL database for demos. Render's free databases expire after 30 days and do not include backups, so do not store expense data you need to retain there. Upgrade the database plan before using it for ongoing data.

The Blueprint declares OAUTH_ISSUER_URL, OAUTH_JWKS_URL, OAUTH_AUDIENCE, and OAUTH_RESOURCE_URL as operator-supplied values. This repository does not contain identity-provider credentials. On an existing Blueprint-managed service, Render does not prompt again for newly added sync: false variables during a later Blueprint sync; add these values manually on the service's Environment page, then save and deploy. See Render's Blueprint environment-variable behavior.

For OAUTH_RESOURCE_URL, use the public Render service URL with /mcp appended. The issuer must exactly match the token's iss claim, the JWKS URL must be the issuer's signing-key endpoint, and the audience must match the access tokens issued for this MCP server. Grant expenses:read for reads and expenses:write for mutations. Do not guess these values or copy them from another identity provider.

For a step-by-step Auth0 setup that maps the provider values to this Render service, see AUTH0_RENDER_SETUP.md.

After deployment, verify the protected-resource metadata at /.well-known/oauth-protected-resource/mcp, then send an MCP initialize request to /mcp without a bearer token and confirm it returns 401. A successful /health response alone proves only that PostgreSQL is reachable; it does not prove the MCP endpoint is protected. Until these checks pass, do not use a hosted endpoint for expense data. If a previously deployed revision remains active after a failed deploy, suspend that Render web service until OAuth is configured and the authenticated flow is verified.

Validation

Run the unit suite with:

python -m pytest -q

PostgreSQL migration tests run when TEST_POSTGRES_URL points to a disposable test database. The GitHub Actions workflow provisions PostgreSQL and runs both the suite and startup checks on pushes and pull requests.

Agent skill package

skills/expense-tracker-mcp-companion/SKILL.md contains the companion instructions for compatible agents. The skill requires this MCP server to be installed and connected separately; it does not include or host the server or its database. Use a private local STDIO connection for personal ledgers unless hosted OAuth authentication has been configured and verified.

License

No license file is included. The repository does not grant permission to redistribute the server source.

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    A remote MCP server for expense tracking, providing tools to add, list, update, delete expenses, and generate summaries, budget status, and monthly trends.
    8
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    A simple MCP server for tracking expenses in a local SQLite database, enabling add, read, update, delete, and summarization of expenses with predefined categories.
    -
  • F
    license
    B
    quality
    B
    maintenance
    An AI-powered MCP server for personal and group expense management, providing CRUD operations, advanced filtering, analytics, Splitwise-style splitting, budget tracking, and report generation.
    38
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A production-grade MCP server for personal finance management, enabling AI agents to add, update, search expenses, manage budgets and credit cards, and generate financial reports.
    2
    MIT