Case study · AI agents with limits
Círculo: smarter loan overpayments and an AI assistant with limits
Círculo is my family's finance app: a private version of Whisper Money, which is open source (CC BY-NC 4.0), running on a computer at home. Here I show only what I added: an overpayment simulator and a secure MCP server.
The problem
- Overpaying. The bank's app tells you how much you owe, but it does not compare loans. “Overpay the one with the highest rate” does not always maximise total savings, and mixing the payments the bank shows with the theoretical balance curve gives wrong figures.
- The assistant. Asking “how much did I spend in August?” or saying “put these transactions under Groceries” is convenient. But the original MCP server allowed broad writes, and a model that makes a mistake, or reads malicious text in a transaction description, should not be able to delete data or change amounts.
How I restrict what an assistant can do
The principle
Security lives in the server, not in the prompt. Instructions to the model help, but the guarantee is that the server does not expose SQL, shell, files, deletions or amount changes.
- Closed catalogue of 19 tools: 12 aggregated reads, 3 single-item writes, 2 previews, confirm and undo. Anything not on the list does not exist.
- Strict validation before touching data: exact types, UUIDs, real dates and limits. An unexpected field (
amount,sql,path) invalidates the whole call. - Writes with guarantees: an explicit request, a unique identifier (idempotency) and the revision read beforehand (concurrency). They run in a locked transaction and are recorded in an insert-only audit log.
- Batch changes: a frozen, single-use preview that expires after 10 minutes. It only runs after a fresh confirmation, and undo also asks for confirmation.
- Minimal data exposed: no IBAN, and merchant text is treated as untrusted.
The overpayment simulator
- Before and after on the same curve. An early version calculated “before” with the bank's payments and “after” with the balance curve. On two almost identical loans, that reversed which one was worth overpaying. Now both scenarios come from the same calculation and a test locks it in.
- Whole cents and interest rounded every month, like a real amortisation schedule.
- Per-loan degradation. If a payment does not cover the interest, that loan returns an error and the others are still simulated.
- Three modes: shorten the term, lower the payment or add a monthly extra, after deducting the early repayment charge.
What is real and what is demo
| Part | In the demo | Detail |
|---|---|---|
| Household, loans and transactions | Synthetic | Generated from scratch with a fixed seed. |
| Amortisation engine and MCP validator | Real | Translated to JavaScript from the original code, with 11 parity checks. |
| Conversations with the assistant | Synthetic | Precomputed traces: the demo does not run the MCP server. |
| Full app, real data and Git history | Not included | Private use. |
Results
19MCP toolsclosed catalogue
48demo tests40 for calculation and validator, 8 for data
17dangerous calls rejectedvalidator cases
The savings figures in the demo belong to the fictitious household. I do not publish real data.
Limitations and next steps
- The rate is assumed constant: it does not model Euribor reviews or tax.
- The metric is total interest saved, not the equivalent annual return or the opportunity cost of investing.
- To do: simulate rate changes in stages.
Base: Whisper Money, licence CC BY-NC 4.0. Extensions by Jorge Sebastián Soriano.
Demo screenshots
All with synthetic data. The demo interface is in Spanish.







