JSJorge Sebastián Soriano ES

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.

Where it's used
Family finances, on a home server
Status
In use since August 2026
My role
Rules, integration into the existing app, tests and deployment. Code with AI
Technologies
PHP 8.4, Laravel, Pest, MySQL, React 19 + Inertia, TypeScript, MCP, Docker
Simulator comparing the savings from overpaying on three loans
Demo: the same amount applied to each loan. Fictitious household.

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.

AI assistantrequests an actionMCP serverclosed catalogueValidationextra field = rejectedPreviewexpires in 10 minConfirmationfresh, from the userTransaction+ audit log
  • 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

PartIn the demoDetail
Household, loans and transactionsSyntheticGenerated from scratch with a fixed seed.
Amortisation engine and MCP validatorRealTranslated to JavaScript from the original code, with 11 parity checks.
Conversations with the assistantSyntheticPrecomputed traces: the demo does not run the MCP server.
Full app, real data and Git historyNot includedPrivate 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.

One-off payment: where you save most
One-off payment: where you save most
Monthly extra, and a misconfigured loan that does not bring down the others
Monthly extra, and a misconfigured loan that does not bring down the others
Batch change: preview, confirmation and execution
Batch change: preview, confirmation and execution
What the assistant cannot do
What the assistant cannot do
Validator: a call with an extra field is rejected in full
Validator: a call with an extra field is rejected in full
How it is built
How it is built
Mobile view
Mobile view
Dark mode
Dark mode