Skip to main content
Glama
GuoHaoyu1688

Debt Payoff Planner MCP Server

by GuoHaoyu1688

Debt Payoff Planner

Compare debt snowball, avalanche, custom-priority, and minimum-only repayment plans on your own computer. Track actual payments separately from forecasts, inspect finance charges, and see when a budget cannot support the required payments.

Python 3.11+ · SQLite · CLI · MCP stdio · offline Web dashboard · MIT

Fictional debt comparison dashboard

Install

git clone https://github.com/GuoHaoyu1688/debt-payoff-planner.git
cd debt-payoff-planner
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e .

Installation downloads open-source dependencies. The installed application runs locally without API keys, bank connections, telemetry, product recommendations, or runtime internet access. It never transfers money. The Web server binds to loopback only.

Related MCP server: monter-mcp

Three-command quick start

After installation, run these from the repository root:

debt --config examples/config.yaml import examples/five_debts.json --json
debt --config examples/config.yaml compare --budget 600 --start 2026-10 --json
debt --config examples/config.yaml report --budget 600 --start 2026-10 --md --json

The fictional example has five debts totaling 9,800.00 CNY principal, plus 86.40 CNY retained installment fees. The default monthly budget is 600; a stored December 2026 override raises that month's total budget to 1,000. Import creates five debts and one budget override. Repeating the unchanged import skips identical records.

Strategy

Payoff month

Months

Finance charges

Saved vs baseline

Minimum-only baseline

2036-07

118

4,170.36 CNY

0.00 CNY

Snowball

2028-03

18

1,251.45 CNY

2,918.91 CNY

Avalanche

2028-03

18

1,128.82 CNY

3,041.54 CNY

Custom priority

2028-03

18

1,260.02 CNY

2,910.34 CNY

The exact comparison snapshot, including each debt's payoff date, is in examples/expected_comparison.json. Tests verify it. The Markdown report and two charts are written to data/demo/reports/.

debt --config examples/config.yaml serve --port 8768

Open http://127.0.0.1:8768. Compare strategies, select a monthly plan, inspect debt allocations, search debts, save a plan, record an actual payment, and compare progress with the saved snapshot. Desktop and mobile layouts use local HTML/CSS/JS without a build step or CDN. /openapi.json describes the local API.

Debt models

Every amount uses integer cents in storage and output. Input money is a decimal string with at most two decimal places. All debts share the configured two-decimal reporting currency; there is no FX conversion. Annual interest is a nominal rate, distinct from fee-inclusive IRR or effective annual yield.

start_date is the date of the opening principal snapshot. Enter the outstanding balance and remaining term at that date. Use the original borrowing date only when you will also enter the complete payment history from that date. The first due date is the first configured due day on or after the snapshot date. Days 29–31 clamp at the end of shorter months.

Type

Required parameters and monthly convention

credit_card

Annual/daily rate; minimum_ratio defaults to 10%. Minimum is the greater of the specified cash minimum and the ratio of principal plus assessed charges. Optional explicit grace_until suppresses monthly interest through that due date.

equal_installment

Remaining term_months and rate. Fixed principal-and-interest payment from the amortization formula; the last payment clears rounding residue.

equal_principal

Remaining term_months and rate. Fixed principal step plus interest on the remaining principal.

interest_only

Maturity date or term. Interest-only payments until all remaining principal becomes due in the maturity month.

fee_installment

Remaining term and monthly flat fee_rate applied to original snapshot principal. Nominal interest is zero; fees still have a real financing cost.

personal

Flexible borrowing, optionally interest-free. User-supplied minimum; an optional maturity date makes the remainder due then.

--minimum is a cash floor on the computed requirement. Priority is a nonnegative integer; smaller numbers come first. Tags are not used; store context in --note. No model adds new borrowing, late fees, penalty rates, insurance, or taxes.

Amortization and independent checks

For principal P, monthly nominal rate r = annual_rate / 12, and n remaining installments:

  • Equal installment: A = P × r / (1 − (1+r)^(-n)); for zero interest, A = P/n.

  • Equal principal: monthly principal step P/n, plus that month's interest on remaining principal.

  • Interest rounds ROUND_HALF_UP to cents each month. The final maturity payment clears the exact remaining principal and charges.

Example: P = 1,200, annual rate 12%, and two installments gives a rounded regular payment of 609.01. First-month interest is 12.00, leaving 602.99 principal; next interest is 6.03, so the final payment is 609.02, not 609.01. Total interest is 18.03. Equal principal over three months gives payments of 412.00, 408.00, and 404.00, totaling 24.00 interest. These independent arithmetic cases are asserted in tests.

The CFPB explains the separation between principal and interest and how the interest share decreases under amortization. The formulas above implement a fixed monthly planning model consistent with those principles. CFPB: amortization, CFPB: paying down a mortgage.

Flat fees, APR, and IRR

debt apr --fee-rate 0.6% --months 12 --json
debt apr --fee-rate 7.2% --months 12 --fee-mode total --json
debt apr --fee-rate 5% --months 12 --fee-mode upfront --json
debt apr --daily-rate 0.05% --json

The default fee calculator assumes a monthly fee on the original principal and equal month-end principal repayments. total spreads one total fee over the installments; upfront subtracts the fee from the initial amount advanced. A bounded Decimal bisection solves the discounted cash-flow equation. Results separately expose monthly IRR, nominal annualized IRR (12 × monthly IRR), and effective annual rate ((1 + monthly IRR)^12 − 1). These are planning yields, not jurisdiction-specific legal APR disclosures. The CFPB likewise distinguishes a loan's interest rate from a broader APR measure that includes applicable fees. CFPB: interest rate and APR.

A daily rate of 0.05% converts to a nominal annual rate of 18.25% using 365 days. Its effective annual yield is higher if interest compounds daily. The repayment simulator uses nominal annual / 12; it does not pretend to calculate statement-specific daily accrual.

Fee installments default to --fee-policy retain: unassessed future fees remain owed after principal is repaid, and additional money can prepay those fees. --fee-policy waive cancels unassessed fees once principal reaches zero. Verify the lender's contract before selecting waiver. For a 1,200 principal installment with a 0.6% monthly fee over 12 months, total retained fees are 86.40. Immediate principal repayment does not magically save those retained fees. With waiver, a first-month full payoff costs 1,207.20 instead of 1,286.40.

Strategies, variable budgets, and failure behavior

All strategies first satisfy every debt's required minimum and maturity obligation. Snowball then prioritizes the smallest remaining obligation; avalanche prioritizes the highest nominal interest rate (fee debt uses its nominal annualized IRR); custom uses numeric priority or an explicit complete code order. Ties are deterministic. Baseline pays only required minimums. Fixed payments/principal steps are preserved after extra payments, shortening the term rather than automatically reducing future installments.

debt budget set 2026-12 --amount 1000 --json
debt simulate --strategy custom --budget 600 --start 2026-10 --order PERSONAL-E,FEE-D,LOAN-C,LOAN-B,CARD-A --save --json
debt extra --amount 1000 --month 2026-12 --budget 600 --start 2026-10 --json

A stored budget is a replacement total for that month, not an addition. Unused budget is not carried forward. Actual payments already recorded in a simulated month consume that month's total budget. The extra-payment evaluator adds funds in the selected month, satisfies minimums, directs available extra funds to each candidate, and compares complete outcomes. Surplus follows the chosen strategy. A target already settled before it can receive extra money is marked ineligible.

If a budget cannot cover minimums or a balloon, simulation stops before that month's projected payments and returns complete: false, failure.code: MINIMUM_BUDGET_SHORTFALL, and the exact required/available/shortfall amounts. The horizon defaults to 600 months and is capped at 1,200. Unpaid balances at the bound produce HORIZON_EXCEEDED; there is no infinite loop. A zero-minimum, interest-free personal debt never clears under baseline unless it has a maturity date. Incomplete baselines produce null savings, not a fabricated zero or a comparison against partial lifetime costs.

The JSON envelope can have ok: true for a successfully computed infeasible scenario. Always inspect data.complete and data.failure. An exit code of zero alone does not mean a repayment plan is affordable.

Actual payments and progress

debt pay CARD-A --amount 200 --date 2026-10-10 --interest 70 --idempotency-key fictional-statement-1 --json
debt payments --json
debt plans --json
debt progress --plan PLAN_ID --as-of 2026-10-15 --json
debt due --within 7d --json

Payment allocation is assessed finance charges first, principal second, retained future fees last. The journal stores the original amount, principal/finance-charge split, and before/after balance snapshots. Payments must be chronological, cannot be future-dated, and cannot exceed the remaining obligation. Retry keys deduplicate identical requests and reject changed content.

Without --interest, the first actual payment in a month estimates newly accrued monthly charges from the opening/last-assessed month; subsequent payments do not charge that month twice. Missing months accrue charges on the unchanged recorded principal. Unpaid assessed charges remain separate and do not compound. --interest supplies newly assessed charges from a statement, replacing this estimate; it does not erase previously assessed unpaid charges. For fee installments, interest_cents includes fees. Use the statement override whenever lender timing differs from this monthly model.

The model does not reconstruct overdue contractual principal installments or a lender's arrears accounting. Start with a current opening snapshot, include actual statement minimums/arrears in your inputs, and verify lender notices. Credit-card grace is a simplified explicit date, with no retroactive grace-loss interest or new purchases.

Save a plan before recording payments. Principal progress is measured against that immutable snapshot. Lead/lag in days uses the first scheduled principal milestone at or below actual principal; where actual and planned payoff dates both exist, their day difference is exact. This is a planning milestone comparison, not a lender delinquency calculation. Progress bars show principal repayment only; retained fees may still remain when principal reaches zero.

CLI reference

Global flags work before or after subcommands: --data-dir, --config, --json, --quiet, --progress, --version. Every command is noninteractive; no TTY is required. Normal output is a single JSON object; progress logs go to stderr.

Command

Arguments

init, list

Initialize storage / list current debt snapshots

add

--code --type --balance [--annual-rate 12% | --daily-rate 0.05%] [--minimum] [--due-day 15] [--start-date] [--maturity-date] [--term-months] [--priority] [--note] [--fee-rate] [--fee-policy retain|waive] [--minimum-ratio] [--grace-until]

update ID_OR_CODE

--data '{"minimum":"120","priority":1}'; supports annual_rate, minimum, due_day, maturity_date, priority, note, minimum_ratio, grace_until, fee_policy

pay ID_OR_CODE

--amount --date [--interest] [--note] [--idempotency-key]

payments

Read the actual payment journal

budget set MONTH / budget list

set requires --amount; repeat replaces that month's total

simulate

--strategy snowball|avalanche|custom|baseline [--budget] [--start YYYY-MM] [--months 600] [--order A,B] [--save]

compare

[--budget] [--start] [--months] [--order]

extra

--amount --month [--budget] [--start] [--strategy avalanche] [--months]

apr

--fee-rate [--months 12] [--fee-mode monthly|total|upfront], or --daily-rate

due

[--within 7d] [--as-of DATE]

plans, progress

Progress requires --plan ID; optional --as-of DATE

report

[--budget] [--start] [--months] [--md] [--out PATH]

import FILE

JSON or CSV snapshot import

export

--format json|csv --out PATH [--utf8]

backup

[--out PATH]; defaults to dated ZIP

serve

[--host 127.0.0.1] [--port 8768]; loopback only

mcp

Official SDK stdio service

Budget can come from --budget or a configured default_budget. A missing default is an argument error; the application never silently guesses an affordable amount. Changing an equal-installment rate recomputes its payment from current principal and remaining calendar term; other payment history remains unchanged. Direct balance edits and payment deletion are not provided. Restore a prior backup to correct a mistaken journal entry.

Success: {"ok":true,"data":...,"warnings":[]}. Errors: {"ok":false,"error":{"code":"INVALID_ARGUMENT","message":"..."}}. Exit codes: 0 command success, 1 I/O/database failure, 2 invalid or conflicting input, 3 missing debt/plan. Long chart generation may initialize the local Matplotlib font cache on first use; --progress reports execution on stderr.

Configuration, interchange, and backup

data_dir: ./data
timezone: Asia/Shanghai
currency: CNY
default_budget: '600.00'

Data directory precedence is CLI → DEBT_DATA_DIR → YAML → ./data. --config overrides DEBT_CONFIG. Relative YAML paths resolve beside the config; relative CLI/environment paths resolve from the working directory. Storage is debts.db, with debts, payments, budgets, and plans tables. Runtime data and .coverage* are ignored by Git.

JSON exports are arrays of objects with record_type identifying one of those four tables. CSV uses the same columns and defaults to UTF-8 BOM; --utf8 omits it. Monetary columns are integer _cents, rates are decimal strings, and payment/plan JSON snapshots are serialized strings. All records need stable IDs, except budgets keyed by month. examples/five_debts.json is a complete reusable fixture.

Import is an atomic snapshot operation: it imports balances and journal records together, and never subtracts principal a second time. Identical IDs are skipped; conflicting content aborts the entire import. Payment splits must reconcile, and each final debt balance must match its latest payment snapshot. Import a modified snapshot into a fresh data directory rather than overwriting an active ledger. Treat CSV code/note columns as text when opening with spreadsheet software.

backup uses SQLite's online backup API and writes a dated ZIP with debts.db and settings.json. To restore, stop ledger processes, extract into a fresh directory, translate the saved settings into YAML or command arguments, and point --data-dir there. Never replace a live database. Back up before changing debt assumptions, budget overrides, restoring snapshots, or correcting actual-payment history. Reports use deterministic date-containing names and overwrite the corresponding previous report.

MCP for agents

{
  "mcpServers": {
    "debt-planner": {
      "command": "/workspace/apps/debt-payoff-planner/.venv/bin/debt",
      "args": ["--data-dir", "/workspace/data/debt-payoff-planner", "mcp"]
    }
  }
}

Tools share the exact CLI core: list_debts, simulate_plan(strategy, budget, start=null, months=600, order=null), compare_strategies(budget, start=null, months=600), record_payment(debt_id, amount, date, interest=null, note="", idempotency_key=null), and upcoming_payments(days=7, as_of=null). record_payment writes locally; other tools are read-only. Inputs use decimal strings and ISO dates, outputs use integer cents, and invalid inputs become MCP tool errors. Stdio never logs normal text to stdout. See AGENTS.md for headless installation and recipes.

Validation, FAQ, and roadmap

python -m pip install -e '.[dev]'
ruff check .
ruff format --check .
pytest -q --cov=debt_payoff_planner --cov-report=term-missing

CI runs Python 3.11 and 3.12 on Ubuntu. Independent tests cover amortization, equal principal, balloons, grace, flat-fee IRR, actual payments, budget shortfalls, bounded failure, concurrent idempotency, import/export/backup, the five-debt report snapshot, every MCP tool, a real stdio handshake, and REST. Browser acceptance is recorded in docs/VALIDATION.md.

Why are savings unavailable? At least one compared path is incomplete. Partial finance charges cannot represent a full lifetime cost.

Why did an extra fee-installment payment save no fees? Retained fees remain owed. Select waiver only when the contract supports it.

Why is my statement different? Day-count methods, grace rules, penalties, variable rates, and arrears differ by lender. Use actual statement charges and minimums; this model does not certify a lender's payoff quote.

Can multiple currencies or remote users share a ledger? This release uses one configured two-decimal currency and a trusted local user. There is no authentication or multi-currency conversion. Do not expose the server to an untrusted network.

Roadmap: explicit arrears schedules, lender-specific day-count/grace conventions, statement reconciliation, payment correction entries, and optional encrypted backups. No lender integrations or product recommendations are planned.

This is a planning and recordkeeping tool, not financial advice. Verify contractual terms and actual statements before making financial decisions. MIT license; see LICENSE and CHANGELOG.md.

Related MCP Connectors

  • SmartMoney77 MCP v0.6.0 — 14 public tools that turn financial questions into exact numbers and citable links. New: historical_investment_return and compare_investments, which compute "what if I had invested" results from real yearly price data. Also compound interest, FIRE number, credit-card payoff, emergency fund, inflation, latte factor, investment fees, cost of waiting, plus discovery/deep-link/share-pack tools for a catalog of calculators in 6 languages (he/en/ar/es/pt/in). Public, no login. Endpoint: https://smartmoney77.com/mcp

  • Personal finance for AI agents — onboard, import statements, categorize & budget over MCP.

  • Personal finance for AI agents: accounts, budgets, goals, 9-strategy debt payoff, reports. OAuth 2.1

  • Track budgets from your AI chat: envelopes, monthly limits, variance reports. All data is local.

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides tools for managing personal finances via MCP, including accounts, transactions, debts, savings, budgets, and asset tracking, with summaries and reporting capabilities.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables local analysis of personal finance data from a Monter JSON export, answering questions about spending, subscriptions, debts, and more via MCP-capable assistants without any cloud servers.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables self-hosted personal finance management for MCP clients by connecting read-only bank accounts via SimpleFIN, syncing transactions into a local SQLite database, and exposing tools to query balances, spending, budgets, cash flow, and net worth.
    -
  • A
    license
    B
    quality
    A
    maintenance
    A read-only MCP server that connects AI clients to your own bank, credit card, loan, and brokerage data through Plaid or Teller, letting you query accounts, balances, transactions, holdings, liabilities, identity, income, and run debt avalanche/snowball payoff analysis. Credentials and access tokens stay locally in a chmod-600 SQLite file, with outbound calls limited to the provider's API.
    24
    1
    MIT