Ledgewise

Ledgewise MCP reference

A read-only Model Context Protocol server exposing a user's Ledgewise budget, transactions, spending insights, cash-flow forecast, debt accounts, payoff plan and what-if scenarios to AI assistants such as Meta Muse, with the user's explicit OAuth consent.

Overview

ItemValue
MCP endpointPOST https://mcp.ledgewise.app/mcp
TransportStreamable HTTP, single JSON response per POST (no SSE stream). GET returns 405.
Protocol versions2026-07-28, 2025-06-18, 2025-03-26, 2024-11-05 (the requested version is echoed if supported)
Capabilitiestools only. No resources, prompts or sampling.
Authorization serverhttps://auth.ledgewise.app
AccessRead-only, with one exception: ledgewise_request_payment_instructions records a request that the user must confirm in the Ledgewise app. No tool changes the user's budget or debts, and no tool moves money. Reading a tool never writes to the user's data.
Tiers4 tools are free; 10 require a Ledgewise Premium subscription (see Tools).
Currency / unitsUSD. All amounts are integer cents. Positive transaction amounts are spend; negative are income.

Authentication

OAuth 2.1 authorization code flow with PKCE (S256 only) and RFC 8707 resource indicators. API keys are not supported. Every request to /mcp needs Authorization: Bearer <access_token>.

Discovery

DocumentURL
Protected resource metadata (RFC 9728)https://mcp.ledgewise.app/.well-known/oauth-protected-resource
Authorization server metadata (RFC 8414)https://auth.ledgewise.app/.well-known/oauth-authorization-server

An unauthenticated or invalid request returns 401 with WWW-Authenticate: Bearer resource_metadata="https://mcp.ledgewise.app/.well-known/oauth-protected-resource".

Endpoints

PurposeURL
AuthorizationGET https://auth.ledgewise.app/authorize
TokenPOST https://auth.ledgewise.app/token (form-encoded)
RevocationPOST https://auth.ledgewise.app/revoke

Flow

  1. Client sends the user to /authorize with response_type=code, client_id, a pre-registered redirect_uri, scope, state, code_challenge (S256), code_challenge_method=S256 and resource=https://mcp.ledgewise.app.
  2. The user signs in to Ledgewise and approves the consent screen, which lists each requested permission.
  3. Ledgewise redirects to redirect_uri with code and state (or error=access_denied).
  4. Client POSTs to /token with grant_type=authorization_code, code, redirect_uri, client_id, code_verifier and the same resource.
{
  "access_token": "…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "…",
  "scope": "budget:read forecast:read transactions:read insights:read debt:read"
}

Token lifetimes and rules

Scopes

ScopeGrantsTool(s)
budget:readCurrent month budget and safe-to-spend figureledgewise_get_budget_summary, ledgewise_get_safe_to_spend
transactions:readRecent transactionsledgewise_get_transactions
insights:readMonth-over-month spending insights and spending patterns (pay-cycle timing)ledgewise_get_insights, ledgewise_get_spending_patterns
forecast:readProjected balanceledgewise_get_forecast
debt:readDebt list, payoff plan, what-if scenarios, payoff changes (including income changes), pace and monthly commitment totalsledgewise_get_debt_accounts, ledgewise_get_debt_payoff_plan, ledgewise_simulate_scenario, ledgewise_get_payoff_changes, ledgewise_get_payoff_pace, ledgewise_get_monthly_commitment
payments:instructionAsk to see this month's payment instructions; the user confirms each request in the Ledgewise app first and can stop sharing. Held only by clients Ledgewise has approved: never a generic custom connector or a client that identifies itself by metadata URL.ledgewise_request_payment_instructions, ledgewise_get_payment_instructions

tools/list returns only the tools whose scope the token holds. The consent screen requests the client's full registered scope set; users approve or deny it as a whole.

Protocol

JSON-RPC 2.0 over POST /mcp. Supported methods: initialize, tools/list, tools/call.

POST /mcp
Authorization: Bearer <access_token>
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}
{"jsonrpc":"2.0","id":1,"result":{
  "protocolVersion":"2025-06-18",
  "capabilities":{"tools":{}},
  "serverInfo":{"name":"ledgewise-mcp","version":"1.0.0","url":"https://mcp.ledgewise.app"}}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
  "name":"ledgewise_get_transactions","arguments":{"limit":5}}}

Tool results are returned as a single text content item containing a JSON string, with isError: false.

Tools

Amounts are integer cents. "Premium" tools return a tool error (see Errors) for free accounts.

ledgewise_get_budget_summary Free

Current month's budget: income, total assigned, ready-to-assign, and a per-envelope breakdown. Scope: budget:read. Works with manual data; no bank link required.

Input: none.

{"month":"September 2026","income_cents":480000,"total_assigned_cents":253000,
 "ready_to_assign_cents":227000,"total_spent_cents":61200,"currency":"USD",
 "envelopes":[{"name":"Groceries","budgeted_cents":45000,"spent_cents":18400,
               "available_cents":26600,"children":[]}]}

ledgewise_get_transactions Free

The user's most recent transactions. Scope: transactions:read.

Input: limit (integer 1–100, default 20).

{"transactions":[{"date":"2026-09-28","merchant_name":"Trader Joe's","description":"Trader Joe's",
   "amount_cents":8420,"category_id":"…","is_reviewed":true}],
 "unreviewed_count":7,"currency":"USD"}

ledgewise_get_insights Free

Month-over-month spending comparison and a pace alert when spending is off-trend. Scope: insights:read.

Input: none.

{"current_month":{"year":2026,"month":9,"spent_cents":61200},
 "previous_month":{"year":2026,"month":8,"spent_cents":224000},
 "delta_pct":-72.7,"pace_alert":null,"currency":"USD"}

ledgewise_get_forecast Premium

Projects the user's checking and savings balance to a target date, up to 90 days out, using recurring income, bills and debt minimums plus recent net spending. Scope: forecast:read.

Input: target_date (string, YYYY-MM-DD, today to +90 days; default +30 days).

{"requested_date":"2026-10-30","projected_balance_cents":298500,"days_until":30,
 "starting_balance_cents":474000,"currency":"USD","status":"ok"}

If no checking or savings balance has synced yet, projected_balance_cents and starting_balance_cents are null and status is "no_balance_data".

ledgewise_get_safe_to_spend Premium

The amount the user can spend today without running short over the next 60 days, after upcoming bills and debt minimums. Scope: budget:read.

Input: none.

{"safe_to_spend_cents":112000,"per_day_cents":1866,"current_balance_cents":474000,
 "debt_minimums_cents":29500,"is_danger":false,"shortfall_cents":0,
 "horizon_days":60,"status":"ok","has_income_data":true}

ledgewise_get_debt_accounts Free

The user's active debts (credit cards, loans, mortgages), largest balance first. Use the ids with the payoff and scenario tools. Scope: debt:read.

Input: none.

{"accounts":[{"id":"…","name":"Visa Platinum","creditor":"Chase","account_type":"credit_card",
   "balance_cents":500000,"apr_bps":2400,"minimum_payment_cents":15000,"due_day":15,
   "imported_from_bank":true,"apr_needs_review":false}],
 "count":1,"total_balance_cents":500000,"total_minimum_payment_cents":15000,"currency":"USD"}

apr_bps is the annual rate in basis points (2400 = 24%). apr_needs_review is true for a bank-imported debt at 0% that the user has not confirmed, since banks that report no rate import as 0% and that makes payoff look faster than it is. Bank account and provider ids are never returned.

ledgewise_get_debt_payoff_plan Premium

A payoff plan over the user's active debts using avalanche (highest APR first) or snowball (lowest balance first). Scope: debt:read.

Input:

FieldTypeNotes
strategystringavalanche (default) or snowball
monthly_extra_centsinteger0–100,000,000. Extra monthly payment above minimums. Default 0.
{"strategy":"avalanche","monthly_extra_cents":20000,
 "ordered_debt_ids":["…","…","…"],"payoff_date":"2029-04-01",
 "total_interest_cents":318400,"interest_saved_cents":204100,
 "monthly_schedule":[…first 36 months…],"never_pays_off":false,"problem_debt_ids":[]}

If a debt can't be paid off at its minimum, never_pays_off is true and payoff_date is null.

ledgewise_simulate_scenario Premium

A what-if for debt payoff. Compares the user's current plan with a different monthly extra and/or a one-time lump sum, and reports months sooner and interest saved. Read-only: it never moves money or changes a plan. Scope: debt:read.

Input: at least one of monthly_extra_cents (different from the baseline) or lump_sum_cents (above 0) is required.

FieldTypeNotes
strategystringavalanche (default) or snowball
baseline_extra_centsinteger0–100,000,000. Extra per month the user pays today. Default 0.
monthly_extra_centsinteger0–100,000,000. Extra per month in the scenario. Defaults to the baseline.
lump_sum_centsinteger0–100,000,000,000. One-time payment now, applied in payoff order. Default 0. Anything above the total owed is not applied.
{"strategy":"avalanche","ordered_debt_ids":["…","…"],
 "baseline":{"monthly_extra_cents":0,"never_pays_off":false,"payoff_date":"2031-06-01","months":56,"total_interest_cents":507829},
 "scenario":{"monthly_extra_cents":0,"lump_sum_cents":300000,"lump_sum_applied_cents":300000,
             "never_pays_off":false,"payoff_date":"2030-02-01","months":40,"total_interest_cents":173832},
 "months_sooner":16,"interest_saved_cents":333997,"scenario_makes_payoff_possible":false,
 "has_debts":true,"focus_order":[{"id":"…","name":"Visa Platinum"},{"id":"…","name":"Car loan"}],"currency":"USD"}

months_sooner and interest_saved_cents are baseline minus scenario (negative means the scenario is worse) and are null unless both plans pay everything off. scenario_makes_payoff_possible is true when the current plan never pays off but the scenario does. A debt cleared by the lump sum still rolls its minimum onto the next debt. If the lump sum clears every debt, months is 0, total_interest_cents is 0 and payoff_date is today. With no active debts the result is {"strategy":…,"has_debts":false,"currency":"USD"}.

ledgewise_get_payoff_changes Premium

What changed since the user last looked at their payoff plan (a new debt, rising balances, a rate or income change) and what it did to the debt-free date, with ready-made explanations. Totals only, no debt names. Scope: debt:read.

Input: none.

{"has_baseline":true,"changed":true,"months_delta":3,
 "baseline":{"date":"2026-09-01","payoff_date":"2029-03-01","never_pays_off":false,"total_balance_cents":500000},
 "current":{"payoff_date":"2029-06-01","never_pays_off":false,"total_balance_cents":650000,"strategy":"avalanche","monthly_extra_cents":10000},
 "events":[{"type":"balances_rose","amount_cents":150000}],
 "explanations":["Your debt-free date moved 3 months later, to Jun 2029.","Balances rose by $1,500 (new charges or interest)."],"currency":"USD"}

has_baseline is false until the user viewed a payoff plan 7 to 120 days ago.

ledgewise_get_payoff_pace Premium

How fast the user is paying down debt compared with other Ledgewise users. Only available once the comparison group is large enough to be anonymous. Scope: debt:read.

Input: none.

{"available":true,"your_pct_per_90d":12.0,"cohort_median_pct_per_90d":9.0,"percentile":70,"cohort_min":50}
{"available":false,"reason":"cohort_too_small"}

ledgewise_get_spending_patterns Premium

When the user tends to overspend (the week after payday, weekends), roughly how much extra, and whether today is inside such a window. Pattern types and amounts only; no merchants or categories. Scope: insights:read.

Input: none.

{"has_enough_data":true,"patterns":[{"type":"payday_spike","ratio":2.7,"extra_cents":26688,"window_days":7,"cycles":8}],
 "risk":{"type":"payday_spike","days_left":5},"analyzed_days":120,"pay_interval_days":14,"currency":"USD"}

ledgewise_get_monthly_commitment Premium

The user's standing monthly payoff commitment and where this month stands: the reminder day, the status and the totals. Read-only, and it saves nothing. The per-debt lines (who to pay, how much, by when) are payment instructions and are not included: ask for them with ledgewise_request_payment_instructions. Scope: debt:read.

Input: none.

{"committed":true,"month":"2026-10","day_of_month":5,"reminders":true,"strategy":"avalanche","monthly_extra_cents":20000,
 "due_date":"2026-10-05","status":"due","total_cents":40000,"remaining_cents":40000,"debts_on_checklist":2,"currency":"USD"}

status is upcoming, due, done, skipped or nothing_due. {"committed":false} when there is no commitment.

ledgewise_request_payment_instructions Premium

Ask to see the user's payment instructions (who to pay, how much, by when). The user must confirm the request in the Ledgewise app first, so this returns input_required. Asking again while a request is open returns the same one (and does not notify the user again); at most 5 new requests per hour, and none for an hour after the user declines or stops sharing. A request waits 30 minutes for the user's answer. Ledgewise never moves money. Scope: payments:instruction (held only by clients Ledgewise has approved).

Input: none. The calling app and, if sent, the Mcp-Session-Id header are recorded with the request, along with when the user answered and how many times the answer was read. Records are removed after 90 days. The confirmation gates the payment instructions (what to pay each debt this month and by when); it does not hide the debt list or payoff plan from a client that holds debt:read.

{"status":"input_required","request_id":"6f1c…","expires_at":"2026-10-06T15:30:00+00:00",
 "message":"Waiting for the user to confirm this request in the Ledgewise app. …"}

ledgewise_get_payment_instructions Premium

Read the answer to a request. Returns input_required until the user confirms, then the instructions for their approved plan, readable for 10 minutes from the confirmation (the user can stop sharing sooner); a tool error if they declined, stopped sharing or the request expired. Only the app that made the request can read it. Scope: payments:instruction.

Input: request_id (string, required).

{"status":"confirmed","strategy":"avalanche","monthly_extra_cents":20000,"never_pays_off":false,"total_cents":40000,
 "instructions":[{"debt_id":"…","name":"Visa","creditor":"Chase","amount_cents":35000,"minimum_cents":15000,"extra_cents":20000,
   "due_date":"2026-10-15","no_payment_planned":false,"paid_this_month_cents":0}],
 "currency":"USD","note":"Instruction only. …"}

Errors

ConditionResponse
Missing/invalid/expired token, or wrong audienceHTTP 401 + WWW-Authenticate header
Rate limit exceededHTTP 429
Malformed JSON, non-object body, bad jsonrpc or methodHTTP 400, JSON-RPC error -32700 / -32600
Unknown method or toolJSON-RPC error -32601
Bad params shapeJSON-RPC error -32602
Token lacks the tool's scopeTool error: Missing required scope: <scope>
Free account calling a Premium toolTool error: Ledgewise Premium subscription required for this tool
Invalid tool arguments (e.g. limit: 500)Tool error describing the constraint
Unexpected server errorTool error: An unexpected error occurred. Please try again.

A "tool error" is a normal JSON-RPC result with isError: true and a text content item:

{"jsonrpc":"2.0","id":3,"result":{
  "content":[{"type":"text","text":"Ledgewise Premium subscription required for this tool"}],
  "isError":true}}

Limits

Testing

Reviewer accounts with sample data (one Free, one Premium) are provided in the submission notes. Sign in with them on the Ledgewise consent page when prompted. To verify the server without OAuth, an unauthenticated call should return 401:

curl -i -X POST https://mcp.ledgewise.app/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

With a valid token, tools/list returns the tools in the table above. A Premium account sees and can call all eight; a Free account sees all eight but the four Premium tools return the subscription error.

Data & privacy