Financial Context Engine
An MCP server that exposes personal financial data — transaction ledger, portfolio holdings, live/historical market prices, and quantitative risk metrics — as standardized tools, resources, and prompts, enabling natural language reasoning over real computed numbers.
README
Financial Context Engine
An MCP (Model Context Protocol) server that exposes personal financial data — transaction ledger, portfolio holdings, live/historical market prices, and quantitative risk metrics — as standardized Tools, Resources, and Prompts. Any MCP host (Claude Desktop, Claude.ai, Cursor) can connect to it and reason over real, deterministically computed numbers instead of estimating them.
This project is 100% pure Python. It runs natively on Windows — no WSL, no Docker, no Linux subsystem required. DuckDB, FastMCP, numpy/pandas, and yfinance are all pip-installable packages with native Windows wheels.
Architecture
┌──────────────────────────────────────────────┐
│ MCP HOST (Claude Desktop, etc.) │
└────────────────────┬───────────────────────────┘
│ MCP protocol (stdio)
┌────────────────────▼───────────────────────────┐
│ FINANCIAL CONTEXT ENGINE (this repo) │
│ ┌───────────┐ ┌────────────┐ ┌──────────────┐ │
│ │ RESOURCES │ │ TOOLS │ │ PROMPTS │ │
│ └─────┬─────┘ └─────┬──────┘ └──────┬───────┘ │
└────────┼─────────────┼───────────────┼──────────┘
│ │ │
┌────────▼─────────────▼───────────────▼──────────┐
│ DuckDB │ Rate Limiter + yfinance │ Quant │
│ (local) │ (token bucket, cached) │ (numpy) │
└───────────────────────────────────────────────────┘
No LLM lives inside this server. It's a data + compute backend that any MCP-compatible chat client connects to.
Setup on Windows (VS Code, no WSL)
1. Install Python
Python 3.11+ from python.org (check "Add to PATH" during install). Verify in a regular Windows PowerShell or VS Code terminal (not WSL):
python --version
2. Open the project folder in VS Code
File > Open Folder... → select the financial-context-engine folder.
3. Create a virtual environment
In the VS Code terminal (make sure it's PowerShell or Command Prompt, not a WSL terminal — check the terminal dropdown in the top-right of the terminal panel):
python -m venv .venv
.venv\Scripts\activate
Your prompt should now show (.venv). If PowerShell blocks the activation script with an execution-policy error, run this once (you've hit this before with other projects):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
4. Install dependencies
pip install -r requirements.txt
5. Copy the environment template
copy .env.example .env
Defaults work out of the box (in-memory rate limiting, no Redis needed). Only edit .env if you want an Alpha Vantage API key or Redis-backed rate limiting later.
6. Seed demo data
python -m db.seed
This creates data/finance.duckdb with ~6 months of synthetic transactions and 7 sample holdings — safe to demo, no real financial data involved.
7. Run the full test suite
pytest tests/ -v
You should see 33 passed.
8. Run the server in MCP Inspector (interactive dev mode)
fastmcp dev server.py
This opens a browser-based inspector where you can call every tool and view every resource manually — no LLM needed, no config files needed. This is the fastest way to confirm everything works after any change.
Connecting to Claude Desktop
Once you've verified the server works in MCP Inspector, add it to Claude Desktop's config so you can chat with it directly.
- Open Claude Desktop → Settings → Developer → Edit Config (or find
claude_desktop_config.jsondirectly — on Windows it's usually at%APPDATA%\Claude\claude_desktop_config.json). - Add an entry (use the full absolute Windows path to your project and to the venv's python.exe):
{
"mcpServers": {
"financial-context-engine": {
"command": "C:\\path\\to\\financial-context-engine\\.venv\\Scripts\\python.exe",
"args": ["C:\\path\\to\\financial-context-engine\\server.py"]
}
}
}
- Restart Claude Desktop. You should see a 🔨 tools icon indicating the server connected — try asking: "What's my current net worth?" or "Compute my portfolio's Sharpe ratio."
Project Structure
financial-context-engine/
├── server.py # MCP server entrypoint — run this
├── db/
│ ├── schema.sql # DuckDB table definitions
│ ├── models.py # Pydantic models (typed, shared everywhere)
│ ├── store.py # LedgerStore — the only module that touches SQL
│ └── seed.py # generates synthetic demo data
├── market/
│ ├── rate_limiter.py # token bucket (in-memory + Redis modes)
│ ├── client.py # yfinance wrapper: cache -> rate limiter -> fetch
│ ├── history.py # historical price fetching for quant calcs
│ └── demo.py # standalone script proving the limiter works
├── analytics/
│ └── quant.py # Sharpe, Monte Carlo VaR, correlation, HHI — pure numpy
├── mcpapp/ # (named mcpapp, not mcp, to avoid shadowing the MCP SDK)
│ ├── context.py # wires store + rate limiter + market client together
│ ├── tools.py # @mcp.tool() definitions
│ ├── resources.py # @mcp.resource() definitions
│ ├── prompts.py # @mcp.prompt() definitions
│ └── stream.py # background polling for "live" prices
└── tests/ # 33 tests across every module above
What Each Tool Does
| Tool | Purpose |
|---|---|
get_market_quote(symbols) |
Current price/P-E/52-week range, rate-limited + cached |
query_ledger(category, start_date, min_amount) |
Filter transaction history |
get_recent_transactions(days) |
Last N days of transactions |
get_net_worth() |
Cash + invested totals, per-account breakdown |
compute_portfolio_health_report() |
Sharpe ratio, Monte Carlo VaR (95%/99%, 1-day/1-month), correlation matrix, concentration (HHI) — all computed in Python, not estimated by the model |
get_live_prices() |
Latest background-polled prices for your holdings |
get_rebalance_suggestions(target_allocation) |
Dollar-value buy/sell suggestions vs. a target allocation |
What Each Resource Exposes
| Resource URI | Content |
|---|---|
finance://summary |
Net worth snapshot |
finance://transactions/recent |
Last 30 days of transactions |
finance://portfolio/holdings |
Current holdings |
finance://portfolio/live |
Background-polled live prices |
finance://api-usage |
Rate limiter decision log (allowed/blocked/cached) — transparency into throttling |
Design Notes
Why deterministic Python math instead of letting the LLM calculate? LLMs are unreliable at multi-step arithmetic, especially statistics like Sharpe ratio or Value-at-Risk where a small error compounds. Every number this server returns is computed by numpy/pandas from real data, so the model's job is reasoning and communication, not arithmetic.
Why rate-limit market data calls? Free-tier providers (yfinance's soft limits, Alpha Vantage's 25 calls/day) get exhausted fast if an LLM calls them on every message. The token-bucket limiter (reused from a standalone Distributed Rate Limiter project) plus a 60-second TTL cache keeps usage sane — see market/demo.py for a runnable proof: 50 rapid requests → 5 fetched, 30 cache hits, 15 correctly throttled.
Why polling instead of true SSE push for "live" prices? True MCP resource-subscription push depends on transport/session details that vary across FastMCP versions and host clients, and is genuinely fragile to get right without a Linux dev environment. A background-thread poller (mcpapp/stream.py) is the reliable choice here — it reads from the same rate-limited, cached client, so it never floods the market data provider even while "live." If you later deploy this on Linux/Codespaces, the polling loop can be swapped for mcp.send_resource_updated() calls without touching the state management.
Security & privacy:
- All credentials load from
.env(gitignored), never logged, never returned in tool output. data/finance.duckdbis local-only and gitignored — nothing syncs to the cloud.- The only outbound network calls are to the market data provider (ticker symbol only, no personal data).
- Redis mode (for shared rate-limiting across multiple server instances) is opt-in via
.env, not required for normal use.
Running Individual Test Files
pytest tests/test_store.py -v # data layer (6 tests)
pytest tests/test_rate_limiter.py -v # token bucket (6 tests)
pytest tests/test_market_client.py -v # market data + cache (5 tests)
pytest tests/test_quant.py -v # Sharpe/VaR/correlation (10 tests)
pytest tests/test_stream.py -v # live price polling (3 tests)
pytest tests/test_tools.py -v # MCP tool logic (3 tests)
python -m tests.smoke_test # end-to-end, no pytest needed
python -m market.demo # rate limiter demo output
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.