I needed one answer: how much money does the company need to run for the next nine months? The data for it sat in six places. I had it all in one Google Sheet, with a month-by-month cash plan, in about an hour. A few years ago this was a job for several days of exports, copy and paste, and checking totals by hand.
Where the data came from
- Finance ledger, a Google Sheet with every transaction since the company started.
- Main bank account, exported as a camt XML file (ISO 20022).
- Card account, exported as CSV, four currencies in one file.
- USD account at Wise, exported as XLSX.
- Invoicing system, through its API: issued invoices and what is still unpaid.
- Email, to find a contractor invoice and check a few amounts.
The tools that made it fast
Over the last months I built small MCP servers for the systems I use every day. Four of my own did the heavy lifting here, plus two ready-made ones:
- mtl-finances (mine): reads the finance ledger, monthly totals, transactions by contractor and project, cash on hand.
- mtl-estimates (mine): Google Sheets read, write and new tabs. Its Python client also ran the formatting script.
- mtl-wfirma (mine): issued invoices, payment status and line items from the invoicing system.
- mtl-unsplash (mine): the photo for this post.
- Gmail connector: searching for a contractor invoice.
- Claude in Chrome: setting the date range and file type for the card statement export in the bank's web app.
Claude Code calls them directly. So "read the ledger", "list unpaid invoices for October" or "write this table to a new tab" is one request each, not a login, a filter and an export.
The bank files needed only a short parser per format. For the XML one it is a few lines:
import defusedxml.ElementTree as ET # bank files are downloads, so no stdlib XML parser
root = ET.parse(path).getroot()
for e in root.iter("Ntry"):
sign = -1 if e.findtext("CdtDbtInd") == "DBIT" else 1
amount = sign * float(e.find("Amt").text)
party = e.findtext(".//Cdtr/Nm") if sign < 0 else e.findtext(".//Dbtr/Nm")
title = e.findtext(".//RmtInf/Ustrd")
From there, a pivot by payee and month showed every recurring cost, with real amounts from the bank next to the plan from the ledger.
Let the bank exports be the source of truth and the ledger be the plan. Comparing the two side by side is the fastest way to find recurring costs and to check that both tell the same story.
How the budget is built
One tab, nine month columns, net amounts:
- Assumptions in yellow cells: hours and rate for the main contract, starting cash, a 10% reserve.
- Revenue: the contract, plus empty rows for anything that may come in later.
- Costs: one row per item. Yearly subscriptions sit in the month they are charged, not divided by twelve.
- One-offs, like invoices from last month paid this month, have their own rows without a reserve on top.
- Cash at the end of each month, and the funding needed if it ever goes below zero.
- Expected inflows with no date yet sit on the side, so the plan only counts money with a known month.
Then we went through the cost list together, line by line, and decided what stays. Each change was one sentence in the chat, and the sheet recalculated in seconds. The formatting comes from a small Python script on the Sheets API, so every rebuild looks the same.
Formulas, not values. Every total, reserve and cash balance is a formula, so anyone on the team can change one yellow cell and see the effect on July.
What it took
About an hour of talking to Claude Code, and months of small tool building before that. The tools are what turned days into an hour. Next time I start the same way: bank exports and unpaid invoices first, then the ledger, then the plan.

Related notes
C2PA in Music: A Claude MCP for Reading Content Provenance
C2PA is the open standard for content provenance, and it just landed in music files. I open-sourced an MCP server so you can read these manifests inside Claude Code.
Two Macs, one Claude Code setup: skills as plugins, not symlinks
I moved 36 Claude Code skills out of 17 tiny repos and a pile of symlinks into two plugins, one public and one private, with a make pull on the other machine. Here is what changed and why.



