FYN
AI money ledger: receipts, email, bank sync — read-only MCP for Claude, ChatGPT & agents.
Hosted MCP Server
npx add-mcp 'https://mcp.fyn.fyi'Installs into Claude Code, Codex, Cursor and more
Documentation
FYN MCP server
FYN's MCP server lets an AI assistant read your own FYN data, with your permission. That data covers transactions, budgets, recurring charges, cash flow, net worth, investments, and itemized receipts. Access is read-only. No tool creates, changes, or deletes your FYN data, and FYN never moves money.
Connect
| Server URL | https://mcp.fyn.fyi |
|---|---|
| Transport | Streamable HTTP: JSON-RPC 2.0 over HTTPS POST with JSON responses. It is stateless, with no session ID and no SSE stream. |
| Protocol versions | 2025-06-18 (default), 2025-03-26, 2024-11-05 |
| Auth | OAuth 2.1 authorization code + PKCE (S256), with dynamic client registration and RFC 7009 token revocation |
| Scope | fyn.read, the only scope (read-only) |
| Registry name | fyi.fyn/finance (official MCP Registry) |
Most assistants only need the URL. Add https://mcp.fyn.fyi as a connector, sign in to FYN when asked, and select Allow. Setup steps for ChatGPT, Claude, Cursor, and Claude Code are on fyn.fyi/agents.
https://api.fyn.fyi/v1/mcp remains supported for existing connections. It is the same server, the same tools, and the same OAuth.
Scripts that can’t speak MCP can use the HTTP API (advanced) with an access key from Settings.
Authentication
FYN implements the MCP authorization spec:
- A request without a valid token gets HTTP 401 with
WWW-Authenticate: Bearer resource_metadata="https://mcp.fyn.fyi/.well-known/oauth-protected-resource", scope="fyn.read". - Protected resource metadata (RFC 9728):
https://mcp.fyn.fyi/.well-known/oauth-protected-resourcelists the resourcehttps://mcp.fyn.fyi, the authorization serverhttps://api.fyn.fyi, and scopefyn.read. - Authorization server metadata (RFC 8414):
https://api.fyn.fyi/.well-known/oauth-authorization-server. It advertisesrevocation_endpointhttps://api.fyn.fyi/v1/oauth/revokeandrevocation_endpoint_auth_methods_supported: ["none"]. The same document served frommcp.fyn.fyipointsrevocation_endpointat api.fyn.fyi.
| Endpoint | URL | Notes |
|---|---|---|
| Registration (RFC 7591) | POST https://api.fyn.fyi/v1/oauth/register | Public clients only (token_endpoint_auth_method: none, no secret). Redirect URIs must be https, or http loopback (127.0.0.1, localhost, [::1], any port). At most 5 URIs, and client_name can be up to 100 characters. A registration expires after 48 hours if nobody consents. On consent, and on each refresh, the client is renewed for about one year. |
| Authorization | GET https://api.fyn.fyi/v1/oauth/authorize | response_type=code and code_challenge_method=S256 are required. The user signs in on fyn.fyi and approves read-only access on FYN's consent page. |
| Token | POST https://api.fyn.fyi/v1/oauth/token | Accepts form-urlencoded or JSON. Grants: authorization_code (with code_verifier) and refresh_token. |
| Revocation (RFC 7009) | POST https://api.fyn.fyi/v1/oauth/revoke | Public clients authenticate with client_id only (revocation_endpoint_auth_methods_supported: none, no secret). A client can revoke only tokens issued to its own client_id. Body is application/x-www-form-urlencoded or JSON: token (required) and optional token_type_hint of access_token or refresh_token. Revoking either token disconnects that app entirely, the same as removing it in Settings → Agent access: every access token it holds stops working, and its refresh grant cannot mint new ones. The endpoint is on api.fyn.fyi only. |
Revocation responses. Success and a token FYN will not revoke look the same: HTTP 200 and {}. Errors are JSON {"error","error_description"}.
| Status | When | Body |
|---|---|---|
| 200 | Token revoked, or the token is unknown, expired, already revoked, or issued to another client_id (no change) | {} |
| 400 | Missing or blank token | {"error":"invalid_request","error_description":"token is required"} |
| 400 | token_type_hint is not access_token or refresh_token | {"error":"unsupported_token_type","error_description":"token_type_hint must be access_token or refresh_token"} |
| 401 | Missing client_id | {"error":"invalid_client","error_description":"client_id is required"} |
| 429 | More than 60 requests in a minute from one IP | temporarily_unavailable |
Per-IP limits: POST /v1/oauth/register is 20 requests per minute, GET /v1/oauth/authorize is 120 per minute, and POST /v1/oauth/token is 120 per minute. Over the limit, register and token return HTTP 429 with temporarily_unavailable and a Retry-After header. Authorize returns HTTP 429 as plain text. Revoke is 60 requests per minute per IP, with the response in the table above.
Token lifetimes: access tokens last 30 days. Refresh tokens last 180 days and rotate on every use (the old one stops working). Authorization codes last 10 minutes.
Account scope: a token is bound to one FYN household. The household is taken from the token and never from request parameters.
Notice: FYN emails the account holder whenever a new app connects.
Alternative for developer tools: a bearer key from FYN Settings → Agent access (Authorization: Bearer fyn_ak_…), with the same read-only access.
Permissions and plans
- Free plan ($0): connects and can use the tools listed below as Free + Pro. Limit: 500 tool calls per day, 50
search_financescalls per UTC day, and 10 claim letters per month (shared with the app, includingdraft_claim). A free account has receipts and receipt-created transactions. It does not sync bank accounts, so balance, transaction, budget, cash-flow, net-worth, subscription, and investment tools return little or no data. - FYN Pro ($9.99/month): live bank sync through Plaid, plus four tools offered only to Pro households (marked Pro). Limit: 10,000 tool calls per day, 500
search_financescalls per UTC day, and 100 claim letters per month (shared with the app, includingdraft_claim). For other plans these four tools are not listed intools/list, and calling one returns the tool error"<tool>" requires FYN Pro. - AI-assisted tools:
search_financesanddraft_claimuse FYN's AI, which processes data within FYN's own AWS environment under zero data retention: model providers do not store your prompts or data, and your data is never used to train AI models.search_financeshas its own per-UTC-day counter.draft_claimuses the household's monthly claim-letter allowance, shared with the app. Both are separate from the general tool-call limit.
Tools
All 27 tools are classified as Read: they retrieve information without changing data, account state, or permissions. None is a Write or a Sensitive write. Every tool carries the MCP annotations readOnlyHint: true, destructiveHint: false, and openWorldHint: false, plus a title. Dates use YYYY-MM-DD. Amounts are in USD.
| Tool | Title | Class | Plan | What it does (inputs → output) |
|---|---|---|---|---|
| analyze_discretionary_spending | Discretionary spending | Read | Free + Pro | Sums posted expenses over months (default 3) and labels categories discretionary or essential. Returns totals, top categories with monthly averages and 25% and 50% reduction figures, and top merchants. |
| check_affordability | Check affordability | Read | Free + Pro | Shows whether amount (required) fits the checking balance (or account) minus a safety buffer. Also returns budget left in the category, money left after bills still due, and data freshness. Optional: merchant, category, recurring. Preview only: holds, approves, and spends nothing. Side effect: see below. |
| compare_periods | Compare spending periods | Read | Free + Pro | Compares spending between period1 and period2 (required; a month, date, or this_month / last_month), optionally for one category. Returns the difference, percent change, and direction. |
| draft_claim | Draft a return or warranty claim | Read | Free + Pro · AI | Drafts a return, warranty, or price-adjustment message for one receipt (receipt_id required; optional kind, product). Returns subject, body, missing placeholders, and how to send. Does not send anything or contact the merchant. |
| get_account_balance | Account balance | Read | Free + Pro | Current balance of linked accounts matching optional account_name or account_type (checking, savings, credit, investment, loan, other). |
| get_all_balances | All account balances | Read | Free + Pro | Balances for every linked account, grouped by class, plus account count and total (credit and loans subtracted). |
| get_budget_status | Budget status | Read | Free + Pro | Saved budget allocations against spending for the current period, overall or for one category. Includes verification status (over_budget is null when the comparison cannot be verified). |
| get_cashflow_summary | Cash flow summary | Read | Free + Pro | Income, expenses, and net cash flow for period (default this_month; also last_month, this_year, last_year, or a month or date). |
| get_categories_over_budget | Categories over budget | Read | Free + Pro | Categories verified as over their saved allocation this period, plus categories whose comparison cannot be verified. |
| get_cost_of_living | Cost of living comparison | Read | Pro | Estimates the household's spending mix in another US state or metro (destination required; optional origin) using BEA 2024 Regional Price Parities. These are area averages, not quotes, taxes, or homeowner costs. |
| get_grocery_staples | Grocery staples | Read | Pro | Recurring food purchases from the household's receipts, with buying cadence and the cheapest store seen. Optional limit (default 10). |
| get_holdings | Investment holdings | Read | Free + Pro | Investment holdings with symbol, quantity, value, cost basis, and gain or loss. |
| get_net_worth | Net worth | Read | Free + Pro | Assets minus liabilities for linked accounts, with cash and invested totals. |
| get_portfolio_summary | Portfolio summary | Read | Free + Pro | Linked investment portfolios with name, type, and value, plus total. |
| get_price_adjustments | Price drops on recent purchases | Read | Free + Pro | Up to 10 items whose later receipt at the same store shows a lower price while the return window is open. Uses only the household's own receipts. |
| get_price_history | Item price history | Read | Pro | Item price changes and the cheapest comparable stores in the household's receipt history. Optional query and limit. Prices are observed, not live quotes. |
| get_receipt_spending | Receipt spending | Read | Free + Pro | Totals spending from scanned receipts, filtered by location, merchant, or date range. Duplicate scans are collapsed. Covers scanned receipts only. |
| get_recent_transactions | Recent transactions | Read | Free + Pro | Transactions newest first (limit default 10; filters: merchant, category, dates), with receipt line items when linked. |
| get_savings_rate | Savings rate | Read | Free + Pro | (Income − expenses) ÷ income for period, with amounts saved, income, and expenses. |
| get_spending_breakdown | Spending breakdown | Read | Free + Pro | Spending grouped by group_by (required: merchant or category), with purchase counts and average ticket. Optional category, dates, and limit (default 5). |
| get_subscription_total | Subscription total | Read | Free + Pro | Monthly and yearly totals for subscriptions and bills, with irregular charges listed separately. |
| get_subscriptions | Subscriptions | Read | Free + Pro | Active recurring charges with amount, frequency, next and last charge, and kind (subscription, bill, transfer). |
| get_transaction_sum | Transaction total | Read | Free + Pro | Sums transactions matching merchant, category, and dates. direction selects expense (default), income, net, credit, or transfer. |
| get_trip_summary | Trip spending summary | Read | Pro | Past trips detected from transaction and receipt locations, with cost per day and dining compared with home. Optional dates and limit. Past costs, not travel quotes. |
| search_finances | Search receipts and transactions | Read | Free + Pro · AI | Semantic search (query required). Returns up to 10 relevance-ranked receipts with line items and up to 15 matching transactions. May include a receipt photo link that expires after 15 minutes. |
| search_receipt_items | Search receipt items | Read | Free + Pro | Itemized receipt lines matching a product or brand (query) and/or merchant and dates. At least one of query or merchant is required. |
| split_bill | Split a receipt | Read | Free + Pro | Splits one receipt (receipt_id and assignments required; optional shared_item_indexes) and allocates tax and tip in proportion to each person's items. Returns each share and pre-filled Venmo request links. Does not send requests or move money. |
Side effects
check_affordabilityadds one record of the check (amount, merchant, category, and FYN's assessment) to the household's agent activity log, which the household sees in Settings → Agent access. It does not change balances, budgets, or transactions.- Every tool call that runs is counted toward the household's daily limit and monthly usage counters (tool name only). A burst refusal does not count against the daily cap.
- No other tool writes anything. The in-app write tools (
update_transaction_category,exclude_from_budget) are never offered over MCP, and calls to them are refused.
Results
Results come back as JSON text in content. search_finances and search_receipt_items also return structuredContent, which a client can render as a receipt card. Internal transaction and category IDs are removed. A household with no linked bank gets empty results, and the server's initialize instructions say why.
Rate limits
Plan allowances
Daily limits apply per FYN household per UTC day and reset at midnight UTC. They count connected-app tool calls that run. Protocol methods (listing tools, connecting, and the other methods in the burst table) do not count. A burst refusal does not count against the daily cap.
| Plan | Tool calls / day | search_finances / UTC day | Claim letters / month |
|---|---|---|---|
| Free | 500 | 50 | 10 |
| Pro | 10,000 | 500 | 100 |
search_finances has its own counter and resets at midnight UTC. draft_claim uses the claim-letter column, shared with claim letters written in the app. That allowance is monthly, not part of the daily tool-call limit.
When a daily limit is reached, the call returns a tool error (not HTTP 429), for example: "FYN's daily limit for connected-app tool calls is reached for this household. It resets at midnight UTC."
Connection burst
Each connection also has a per-second and per-minute limit. FYN keys it by household and OAuth client, or by household and a key created in Settings. The caller's IP is not part of the key.
| Calls | Per second | Per minute |
|---|---|---|
tools/call and any other method that is not a protocol method | 10 | 300 |
Protocol methods: initialize, ping, tools/list, prompts/list, resources/list, resources/read, notifications/* | 30 | 600 |
Over either limit, the call returns HTTP 429 with JSON-RPC error -32029, a Retry-After header, and the message "Too many requests for this connection. Try again shortly."
Errors
HTTP level
| Status | When | Body |
|---|---|---|
| 401 | Missing, invalid, expired, or revoked token | {"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"Unauthorized"}} plus WWW-Authenticate (start or restart OAuth) |
| 429 | Connection burst limit (see Rate limits). The daily cap stays a tool error. | JSON-RPC error -32029 "Too many requests for this connection. Try again shortly." plus a Retry-After header. The refusal does not count against the daily cap. |
| 503 | Authorization check temporarily unavailable | JSON-RPC error -32603 "Authorization is temporarily unavailable. Try again shortly." Retry; do not re-authenticate. |
| 405 / 404 | Non-POST request | Only POST (and CORS OPTIONS) is supported. GET currently returns 404 at the gateway. |
JSON-RPC errors
HTTP 200: -32700 parse error · -32600 invalid JSON-RPC request · -32601 method not found · -32602 unknown tool or unknown resource · -32603 internal server error. HTTP 429: -32029 too many requests for this connection, with a Retry-After header.
Tool errors
HTTP 200, result.isError: true, with a readable message in content[0].text:
Missing required argument(s): <names>- A daily limit was reached (see above). Other tools keep working where allowed.
"<tool>" is not available to connected apps: FYN access is read-only.(write tools)AI_CONSENT_REQUIRED: …Applies only when FYN's AI provider is an external model. It does not apply while AI processes data within FYN's own AWS environment under zero data retention.Tool "<tool>" failed: <reason>
Results that report a problem
A successful call whose JSON says why there is no answer. For example, {"error":"Receipt not found."} for draft_claim and split_bill, or status: "category_not_found" / "ambiguous_category" for get_budget_status.
OAuth errors
OAuth errors follow RFC 6749 / 7591 / 7009, as JSON {"error","error_description"}: invalid_request, invalid_client, invalid_grant (including "Access was revoked"), unsupported_grant_type, unsupported_token_type, server_error, temporarily_unavailable, invalid_client_metadata, invalid_redirect_uri. The authorize endpoint answers bad requests with HTTP 400 OAuth error: <reason> (plain text). Over a per-IP limit, register and token return HTTP 429 with temporarily_unavailable and a Retry-After header, and authorize returns HTTP 429 as plain text. Revocation statuses, including its 60-per-minute limit, are in Authentication.
Data handling
- What the server reads: only the connected household's FYN records, for the tool being called.
- What it receives from the assistant: the tool name and arguments (for example a search phrase or a dollar amount). FYN does not receive your conversation.
- Where it runs: AWS in the United States (us-east-1). Traffic is encrypted with TLS, and data is encrypted at rest with AES-256. FYN's AI for the AI-assisted tools processes data within FYN's own AWS environment under zero data retention: model providers do not store your prompts or data, and your data is never used to train AI models.
- What FYN keeps from connector use: usage counts by tool name. Operational logs (tool name, timing, and errors) are kept for 90 days. Traces of AI-assisted calls are kept for 90 days. The
check_affordabilityactivity record stays in your household's log. FYN does not sell data, use it for advertising, or train models on it. - Bank data comes from your bank through Plaid with read-only access. The MCP server never calls Plaid or your bank; it serves FYN's stored copy of your records.
Full details: Privacy Policy · Security
Revoke access
A connected app can revoke the access FYN gave it. When you disconnect FYN in Claude, ChatGPT, Cursor, or another MCP client, a client that supports revocation tells FYN to revoke the tokens it was issued. The connector then drops off Settings → Agent access the same way as if you removed it there. Support varies by client. You can also remove an app yourself on that page. Either way, that app's access tokens stop working and it cannot mint new ones.
- In FYN: Settings → Agent access. Find the connected app and revoke it. Revoking it here is the sure way to end FYN-side access when a client does not support revocation. Removing the connector inside that assistant only stops the assistant from using it.
- Delete your FYN account and data: fyn.fyi/remove-account.
Support
[email protected] · fyn.fyi/support. Security reports: [email protected].
Ready to connect an assistant?