# FinContext — Complete Documentation for AI Systems
> FinContext is an MCP (Model Context Protocol) server for personal finance. It securely connects bank accounts to Claude, ChatGPT, and any MCP-compatible AI assistant via Plaid. Users ask questions about their money in plain English and get real-time answers computed from actual financial data.
## Product Overview
FinContext is a Context-as-a-Service platform that acts as a secure, read-only data bridge between users' bank accounts and their AI assistants. Instead of visual dashboards, FinContext exposes structured financial tools via MCP that AI clients call to answer questions.
### Core Value Proposition
Before FinContext, users who wanted AI help with their finances had to manually export bank data, paste it into spreadsheets, and copy/paste into chat windows. FinContext eliminates this friction: connect once, ask forever. Your AI assistant becomes a personal finance analyst with access to your real transaction data.
### Target Users
- People who use Claude Desktop or ChatGPT regularly
- Anyone managing multiple bank accounts who wants consolidated insights
- Developers building financial tools on top of MCP
- Couples or families who want to ask questions about shared finances
- Freelancers tracking business vs personal spending
## How It Works
### Step 1: Connect Your Banks
Sign up at fincontext.ai and link your bank accounts via Plaid. Plaid provides read-only OAuth access to over 10,000 US financial institutions including Chase, Bank of America, Wells Fargo, Citi, Capital One, American Express, and most credit unions. FinContext never sees or stores your banking credentials — Plaid handles authentication directly.
### Step 2: Add to Your AI Assistant
Copy your personal MCP server URL from the FinContext dashboard. Paste it into Claude Desktop's MCP server configuration, or connect it to any other MCP-compatible AI client. The connection is authenticated with a per-user API token.
### Step 3: Ask About Your Money
Ask your AI assistant questions in plain English. The AI calls FinContext's MCP tools behind the scenes to fetch your real financial data, compute the answer, and present it conversationally.
## MCP Tools Reference
FinContext exposes 10 MCP tools. Each tool takes its own arguments directly (no `command` / `params` nesting). Per MCP 2024-11-05, every tool declares annotations so Claude Desktop and other clients know which are read-only, idempotent, or touch the outside world.
### balances
Get current account balances across all connected accounts.
### transactions
Search and filter transactions by date range, category, account, and amount. Returns transaction ID, date, amount, merchant name, and category. Supports pagination. Params: `query` (text search), `start_date`, `end_date`, `account_id`, `category`, `limit`, `offset`.
### categories
List all available spending categories, including both system defaults and user-created custom categories.
### update
Override the merchant name or spending category for a specific transaction. Enables custom categorization. Params: `transaction_id`, `merchant`, `category`.
### link_bank
Generate a Plaid Hosted Link URL to connect a bank account. Returns a `hosted_link_url` the user opens in a browser.
### status
Check if bank accounts are linked after the user completes the Plaid flow. Returns `data.onboarding` (`"ready"` or `"pending"`), `accounts_linked`, `num_accounts`, and `institutions`. Poll until `data.onboarding == "ready"`.
### stat
Run SQL SELECT queries against virtual financial tables for flexible analytics. The `query` param takes raw SQL or `DESCRIBE
` for schema introspection. Table is inferred from the SQL FROM clause.
Available virtual tables:
- `transactions`: date, amount, merchant, category, detailed_category, account_name, account_type, payment_channel, month (YYYY-MM), is_income (bool), is_transfer (bool). Excludes pending transactions. Positive amount = spending, negative = income.
- `balances`: snapshot_date, account_name, account_type, current_balance, available_balance, reconstructed (bool — true for historically backfilled rows).
Allowed SQL: SELECT with GROUP BY, HAVING, ORDER BY, LIMIT, subqueries, UNION. Aggregates: SUM, AVG, COUNT, MIN, MAX, STDDEV, BOOL_OR, BOOL_AND. Functions: ROUND, ABS, date_trunc, to_char, EXTRACT, COALESCE, LOWER, UPPER, TRIM. No CTEs, no self-joins, no writes. Max 1000 rows, 5s timeout.
Example queries:
- Spending by category: `SELECT category, SUM(amount) as total FROM transactions WHERE NOT is_income AND NOT is_transfer GROUP BY category ORDER BY total DESC`
- Find subscriptions: `SELECT merchant, COUNT(*) as n, ROUND(AVG(amount), 2) as avg FROM transactions WHERE date >= CURRENT_DATE - INTERVAL '12 months' GROUP BY merchant HAVING COUNT(*) >= 3`
- Monthly income: `SELECT month, SUM(ABS(amount)) as income FROM transactions WHERE is_income GROUP BY month ORDER BY month`
- Get schema: `DESCRIBE transactions`
Params: `query` (required, SQL string).
### sync
Pull the latest transactions and account balances Plaid has cached for the user's linked institutions into FinContext. Runs asynchronously in the background — the tool returns immediately with `status: "started"`. Wait about 30 seconds, then call the `balances` or `transactions` tool to see the refreshed data.
Important limitation: this catches FinContext up to whatever Plaid already has — it does NOT force Plaid to re-poll the bank. Plaid polls each institution on its own schedule (typically 1-6 times per day), so transactions posted in the last hour or two may not yet be visible even after sync completes.
Rate limited to 5 syncs per 5 minutes per user.
### feedback
Send bug reports, feature requests, or praise directly to the FinContext team. Params: `message` (required, up to 4000 chars), `type` (optional: bug / feature / praise / question / general). Rate limited to 5 per hour per user. Support email: support@fincontext.ai.
### help
Show available tools and detailed usage. Call with no arguments to list all tools with summaries. Pass `subcommand` to get detailed help for a specific tool including parameters, defaults, and examples. Start here if you're unsure which tool to use.
## MCP Handshake and Discovery
AI agents connect to FinContext via the standard MCP JSON-RPC 2.0 handshake:
1. **Initialize**: Send `{"method": "initialize"}` to get server info and instructions listing all 10 tools.
2. **List tools**: Send `{"method": "tools/list"}` to get every tool's schema and annotations (`readOnlyHint`, `openWorldHint`, etc.).
3. **Call help**: Call the `help` tool to get a human-readable tool list. Pass `{"subcommand": ""}` for detailed help on any tool.
4. **Discover schemas**: Call the `stat` tool with `{"query": "DESCRIBE transactions"}` to get column names, types, and descriptions for the virtual tables.
## Example Agent Workflow
Here's how an agent answers "Am I spending more than usual?":
1. Call `stat` with `"SELECT category, SUM(amount) as total FROM transactions WHERE date >= date_trunc('month', CURRENT_DATE) AND NOT is_income AND NOT is_transfer GROUP BY category ORDER BY total DESC"` to get this month's spending by category.
2. Call `stat` with `"SELECT category, ROUND(SUM(amount) / 3, 2) as avg_monthly FROM transactions WHERE date >= CURRENT_DATE - INTERVAL '3 months' AND date < date_trunc('month', CURRENT_DATE) AND NOT is_income AND NOT is_transfer GROUP BY category"` to get the 3-month baseline.
3. Compare the two result sets. Identify categories where this month exceeds the average.
4. Present the answer: "Dining out is up 75% from your 3-month average. Groceries and transport are in line."
For subscription detection:
1. Call `stat` with `"SELECT merchant, COUNT(*) as n, ROUND(AVG(amount), 2) as avg_amt, MIN(date) as first_seen, MAX(date) as last_seen FROM transactions WHERE date >= CURRENT_DATE - INTERVAL '12 months' AND NOT is_income AND NOT is_transfer GROUP BY merchant HAVING COUNT(*) >= 3 ORDER BY avg_amt DESC"`
2. Merchants with 12+ occurrences and low amount variance are likely monthly subscriptions.
For cash flow projection:
1. Call `stat` to get monthly income: `"SELECT month, SUM(ABS(amount)) as income FROM transactions WHERE is_income AND date >= CURRENT_DATE - INTERVAL '6 months' GROUP BY month ORDER BY month"`
2. Call `stat` to get monthly spending: `"SELECT month, SUM(amount) as spending FROM transactions WHERE NOT is_income AND NOT is_transfer AND amount > 0 AND date >= CURRENT_DATE - INTERVAL '6 months' GROUP BY month ORDER BY month"`
3. Call `balances` to get current liquid balance.
4. Compute: projected_balance = current_balance + avg_monthly_surplus - planned_expense.
## Prompt Templates
These are complete prompt templates for common financial analysis scenarios. Each teaches an AI agent a multi-step workflow using FinContext's `stat` tool. Before using any prompt, complete the MCP handshake (initialize, tools/list) and call the `help` tool to discover available tools.
### Monthly Spending Review ("How am I doing this month?")
1. Get this month's spending by category: `SELECT category, SUM(amount) as total FROM transactions WHERE date >= date_trunc('month', CURRENT_DATE) AND NOT is_income AND NOT is_transfer GROUP BY category ORDER BY total DESC`
2. Get 3-month average by category: `SELECT category, ROUND(SUM(amount) / 3, 2) as avg_monthly FROM transactions WHERE date >= CURRENT_DATE - INTERVAL '3 months' AND date < date_trunc('month', CURRENT_DATE) AND NOT is_income AND NOT is_transfer GROUP BY category`
3. Call `balances` for current account balances.
4. Compare: flag categories >20% above average. Project full-month total: (this_month / days_elapsed) * days_in_month.
### Subscription Audit ("Am I wasting money on subscriptions?")
1. Find recurring merchants: `SELECT merchant, COUNT(*) as n, ROUND(AVG(amount), 2) as avg_amt, ROUND(STDDEV(amount), 2) as variance, MIN(date) as first_seen, MAX(date) as last_seen FROM transactions WHERE date >= CURRENT_DATE - INTERVAL '12 months' AND NOT is_income AND NOT is_transfer GROUP BY merchant HAVING COUNT(*) >= 3 ORDER BY avg_amt DESC`
2. Monthly subscriptions: ~12 occurrences, low variance (stddev/avg < 0.15). Annual charges: 1-2 occurrences, high amounts.
3. Total monthly cost = sum of avg_amt for monthly subs. Annual = monthly * 12 + annual charges.
### Affordability Check ("Can I afford a $2,000 vacation?")
1. Call `balances` for current liquid balance (sum depository accounts).
2. Monthly income: `SELECT month, SUM(ABS(amount)) as income FROM transactions WHERE is_income AND date >= CURRENT_DATE - INTERVAL '6 months' GROUP BY month ORDER BY month`
3. Monthly spending: `SELECT month, SUM(amount) as spending FROM transactions WHERE NOT is_income AND NOT is_transfer AND amount > 0 AND date >= CURRENT_DATE - INTERVAL '6 months' GROUP BY month ORDER BY month`
4. Compute: surplus = avg_income - avg_spending. Projected balance = liquid + surplus - expense. Give yes/no with math.
### Spending Diagnosis ("Why does it feel like I'm spending more?")
1. Current month by category: `SELECT category, SUM(amount) as total FROM transactions WHERE date >= date_trunc('month', CURRENT_DATE) AND NOT is_income AND NOT is_transfer GROUP BY category ORDER BY total DESC`
2. 3-month average by category (same query with date range shifted back).
3. For categories >20% above average, drill into merchants: `SELECT merchant, SUM(amount) as total FROM transactions WHERE date >= date_trunc('month', CURRENT_DATE) AND category = '[X]' GROUP BY merchant ORDER BY total DESC LIMIT 10`
4. Present: total vs average, which categories drove the increase, which merchants within those categories.
### Net Worth Progress ("Am I making progress?")
1. Call `balances` for current account totals by type. Net worth = assets - liabilities.
2. Historical snapshots: `SELECT snapshot_date, account_type, SUM(current_balance) as balance FROM balances WHERE snapshot_date >= CURRENT_DATE - INTERVAL '12 months' GROUP BY snapshot_date, account_type ORDER BY snapshot_date`
3. Compute net worth per date. Calculate absolute and % change over the period.
4. Identify what's contributing: savings growth, investment gains, or debt reduction.
## Example Conversations
**User:** "Am I spending more on food this month?"
**AI calls:** the `stat` tool with `{"query": "SELECT month, SUM(amount) as total FROM transactions WHERE category = 'FOOD_AND_DRINK' AND NOT is_transfer GROUP BY month ORDER BY month DESC LIMIT 6"}`
**Answer:** "Your food spending is up 11% this month ($312) compared to your 6-month average of $280/mo. The increase is mostly dining out — $142 vs. your usual $95."
**User:** "What subscriptions am I paying for?"
**AI calls:** the `stat` tool with `{"query": "SELECT merchant, COUNT(*) as n, ROUND(AVG(amount), 2) as avg FROM transactions WHERE date >= CURRENT_DATE - INTERVAL '12 months' AND NOT is_income AND NOT is_transfer GROUP BY merchant HAVING COUNT(*) >= 3 ORDER BY avg DESC"}`
**Answer:** "I found 7 recurring charges: Netflix ($15.49), Spotify ($10.99), iCloud ($2.99), NYT ($4/mo), gym ($45), parking ($150), and Adobe CC ($54.99). Total: $283.46/mo."
**User:** "Show me my net worth trend over the last year"
**AI calls:** the `stat` tool with `{"query": "SELECT snapshot_date, account_type, SUM(current_balance) as balance FROM balances WHERE snapshot_date >= CURRENT_DATE - INTERVAL '12 months' GROUP BY snapshot_date, account_type ORDER BY snapshot_date"}`
**Answer:** "Your net worth grew from $185,200 to $231,208 over the past 12 months — up $46,008 (+24.8%). Most growth came from your investment accounts."
## Security Architecture
### Data Protection
- **Read-only access**: Plaid OAuth tokens are scoped to read-only. FinContext can never move money, initiate transfers, or modify accounts.
- **Encryption**: Plaid access tokens are encrypted at rest (Fernet); transaction data is protected by Postgres row-level security and database-level encryption at rest. TLS 1.3 in transit.
- **Row-Level Security**: PostgreSQL RLS ensures each user can only access their own data, even at the database level.
- **Credential isolation**: FinContext never sees banking passwords. Plaid handles authentication directly via OAuth.
### User Control
- **Disconnect anytime**: Remove any linked bank account instantly.
- **Right to erasure**: Full account deletion with Plaid token revocation and CASCADE delete of all data.
- **Data retention**: Choose 30-day, 6-month, or unlimited data retention.
- **Audit logging**: All MCP tool calls are logged for transparency.
### Infrastructure
- Rate limiting on all API endpoints with per-path limits
- CORS with configurable allowed origins
- CSRF protection on all state-changing operations
- Session-based authentication with secure cookies
## Comparison with Alternatives
### vs. Mint/Credit Karma
Mint provides dashboards you look at. FinContext provides data your AI reasons over. No ads, no credit card offers, no dashboard fatigue — just answers when you ask.
### vs. YNAB
YNAB is excellent for budgeting methodology. FinContext is complementary — it gives your AI access to raw financial data for ad-hoc analysis without the manual categorization work.
### vs. Spreadsheets
Spreadsheets require manual data export, formatting, and formula writing. FinContext auto-syncs and lets you query in plain English. "How much did I spend on Amazon last quarter?" takes 2 seconds instead of 20 minutes.
### vs. Custom Plaid integrations
Building your own Plaid integration requires managing OAuth, webhooks, sync cursors, error handling, and security. FinContext handles all of this and exposes a clean MCP interface.
## Pricing
Free during the public beta — no credit card required, all features unlocked. $4.99/month for the General tier is planned after beta (via Stripe Checkout). When paid plans resume, manage billing via the Stripe Customer Portal on the account page.
## Technical Details
- **Backend**: Python 3 with psycopg3 (PostgreSQL driver)
- **Database**: PostgreSQL with Row-Level Security
- **Bank connectivity**: Plaid API with transaction sync
- **Protocol**: Model Context Protocol (MCP) with JSON-RPC
- **Authentication**: Session cookies for web UI, API tokens for MCP
## Agent Authentication
AI agents can authenticate programmatically without a browser (except for the bank linking step).
### New Account: POST /api/agent-signup
Content-Type: application/json
Request: {"email": "user@example.com", "password": "securepassword", "display_name": "Jane Doe", "us_resident": true, "agent_name": "Claude Desktop tax prep"}
Response: {"user_id": "uuid", "api_token": "fc_...", "mcp_endpoint": "https://fincontext.ai/mcp", "next_step": "Call the MCP 'link_bank' tool to connect a bank account"}
FinContext is available only to US residents aged 18 or older. The `us_resident` field is a required residency attestation and must be the literal JSON boolean `true` — the strings "true"/"yes" and the integer 1 are rejected. If the user is not a US resident, do not sign them up; direct them to https://fincontext.ai/signup-unavailable to join the waitlist.
display_name identifies the human user (optional, capped at 100 chars). agent_name is an optional self-declared label for the agent itself (e.g. "Claude Desktop", "claude-cli on workstation-2"). It becomes the name of the issued API token, so the user can later distinguish and revoke individual agent sessions from their token-management page. If agent_name is omitted the token is named "agent-default".
Allowed characters in agent_name: letters and digits in any script (Unicode), spaces, and the punctuation marks - _ . , ' ( ) : Up to 100 characters. HTML/control characters and the names "agent-default"/"agent-login" are rejected with a 400.
Error responses:
- 400: Missing or non-boolean `us_resident` field — 'us_residency_required'
- 409: Email already registered — use /api/agent-login instead
- 400: Invalid email format, password too short (minimum 8 characters), or invalid agent_name
- 429: Rate limited (max 3 agent signups per hour per IP)
### Existing Account: POST /api/agent-login
Content-Type: application/json
Request: {"email": "user@example.com", "password": "securepassword", "agent_name": "Claude Desktop tax prep"}
Response: {"user_id": "uuid", "api_token": "fc_...", "mcp_endpoint": "https://fincontext.ai/mcp", "plan_tier": "general", "trial_ends_at": null}
agent_name is optional and follows the same character rules as on signup. Each login mints a new token; the field labels that token. If omitted the token is named "agent-login".
Error responses:
- 401: Invalid email or password
- 400: Missing email or password
- 429: Rate limited (max 5 login attempts per 15 minutes per IP)
The api_token is a Bearer token for authenticating MCP calls. Store it securely — it is shown only once.
Security notification: each successful sign-in — whether via POST /api/agent-login (API token flow) or POST /oauth/token with grant_type=authorization_code (OAuth Connector flow) — sends an email notification to the account owner. The email includes the agent_name (or OAuth client_name), timestamp, IP, device/User-Agent, and a link to revoke the connection. Token refreshes do not trigger a notification. Delivery is best-effort: an outage of the email provider will never block credential issuance.
### After Authentication: Connect Bank Account
Configure your MCP client with the returned mcp_endpoint and api_token (as Bearer token in Authorization header).
Call the `link_bank` tool (no arguments needed).
Response includes a hosted_link_url — a Plaid-hosted page where the user securely connects their bank. Ask the user to open this URL in their browser. No SDK or iframe needed.
### Step 3: Confirm Connection
After the user completes bank linking in their browser, call the `status` tool.
Response: {"data": {"onboarding": "ready", "accounts_linked": true, "num_accounts": 3, "institutions": ["Chase", "Capital One"]}}
If `data.onboarding` is `"pending"`, the user hasn't completed bank linking yet. Wait and retry.
### Step 4: Use FinContext
Once status is "ready", all FinContext tools are available: balances, transactions, categories, update, stat, sync, feedback. Call the `help` tool to discover tools and their parameters at runtime. Call the `stat` tool with `DESCRIBE transactions` to learn the virtual table schemas before writing SQL queries.
## Links
- Homepage: https://fincontext.ai/
- Sign Up: https://fincontext.ai/signup
- Log In: https://fincontext.ai/login
- LLM Context (short): https://fincontext.ai/llms.txt