I earn money from 23 different places.
Not big money. A few Stripe products, an Amazon affiliate link, some scrapers on a marketplace, an iOS app that makes $6.99 a month, the occasional PDF sale. The smallest one earned $0.01 last month. The biggest earned $224.
Added together, that's most of my income. And until recently I had no idea what the number was on any given day.
The problem isn't a missing dashboard
Revenue dashboards exist. Baremetrics, ChartMogul, ProfitWell — they're good products. They're also built for a completely different shape of business: one Stripe account, analysed deeply, priced from around $129/month for companies with a single product and a growth team.
My shape is the opposite. Many tiny streams, and — this is the part that matters — roughly half of them publish no earnings API at all.
I checked, carefully, because I wanted to automate it:
- Amazon Associates: no OAuth, no public earnings API. The PA-API returns product data, not what you earned. There's an S3 data feed, granted at Amazon's discretion, and small publishers don't qualify.
- Most ad networks: same story.
- Apify (where I sell scrapers): earnings live in the console only. No API.
So any tool built purely on integrations is structurally blind to that money. Not "hasn't gotten around to it" — blind by architecture. You cannot integrate with an API that does not exist.
That's the gap I built into: automate what has an API, and make manual entry take ten seconds for everything else. One monthly total, typed once, joining the same charts and averages and goals as the automatic sources. Unglamorous. It's the whole product.
Why I built an MCP server instead of a mobile app
Here's the decision I'm actually happy about.
The obvious next step for a dashboard is a mobile app. I didn't build one, because I noticed something about how I use the thing: I never wanted to look at a chart. I wanted to ask a question.
"How much did I make this month across everything?"
That's not a visual query. It's conversational. So instead of an app, I shipped an MCP server. Now I ask Claude and get an answer built from my real numbers:
you ▸ how much did I make this month across everything?
ai ▸ $412.30 this month (avg $14.22/day). Top: Amazon $109.18,
Rotate First Officer $98.14, Checkride PDF $47.28.
You're 94% to your monthly goal.
Four tools: get_income_summary, get_sources, get_month, log_monthly_income. That last one means I can log income by talking, which turns the most tedious part of the whole product into a sentence.
The auth problem nobody warns you about
This is where it got interesting technically.
The hosted app authenticates with Supabase magic links, which produce a JWT that expires in an hour. That's correct for a browser. It's useless for a CLI: an MCP server running under Claude Desktop cannot refresh a browser session.
So for a while my MCP only worked against self-hosted instances, which meant anyone discovering it had to deploy their own Postgres to use it. Not exactly a funnel.
The fix is personal API tokens, and the details are the whole point:
Store a hash, never the token. The plaintext is shown once, at creation. The database keeps a SHA-256 hash. A database leak yields nothing usable.
export function generateToken() {
const token = 'iok_' + randomBytes(24).toString('hex');
return { token, hash: hashToken(token), prefix: token.slice(0, 12) };
}
Show a prefix and a last-used timestamp. A credential you can't see is a credential you can't audit. If a token says "never used" six months in, you know to kill it.
A token cannot mint another token. This one I think is underrated:
function isBrowserSession(req: NextRequest): boolean {
return !(req.headers.get('authorization') || '').includes('iok_');
}
Creating and revoking tokens requires a real browser session. Otherwise one leaked token becomes permanent, self-renewing access — it can quietly issue siblings for itself faster than you can revoke them.
And be honest that a token bypasses 2FA. It does. That's what it is — the machine's replacement for a second factor. GitHub makes the same trade with personal access tokens. The mitigation isn't pretending otherwise, it's making tokens named, scoped to one purpose, individually revocable, and visible.
The mistake that cost me a month
Now the part that's actually useful to you.
I launched the hosted version and it made zero dollars for 26 days. I assumed pricing, or onboarding, or that the market didn't want it.
Then I read my own landing page.
Every call-to-action pointed at the GitHub repo. And near the bottom, still live, in the present tense:
"IncomeOS Cloud **is coming* — join the waitlist and get early access."*
The product had been live and charging for 26 days. My own website was telling every visitor it didn't exist yet, and offering them a waitlist. That waitlist had zero signups, which in hindsight was the only honest metric on the page.
It wasn't a conversion problem. Nobody had ever seen the product.
I have a rule now, and I'd offer it to anyone shipping alone: before you optimise anything, verify a stranger can physically travel from your homepage to your checkout. Click it yourself, in an incognito window, like you've never seen it before. I had built the cash register and forgotten to put a door on the building.
The second lesson from that week: I had zero analytics. No funnel, nothing. Which means every theory I had about why it wasn't converting was a story I told myself. If you're guessing about your funnel, you don't have a hypothesis — you have a feeling.
Where it stands
MIT licensed, self-hostable on Supabase + Vercel in about five minutes. There's a hosted version because I got tired of maintaining my own deploy, and $9/month with a trial felt more honest than a donate button.
- Repo: github.com/Perufitlife/incomeos
- MCP:
npx -y incomeos-mcp
If you also earn from a pile of small places, I'd genuinely like to know how you track it today — especially the sources with no API. That's the part I keep discovering I've underestimated.
Top comments (1)
I was particularly interested in your decision to build an MCP server instead of a mobile app, as it highlights the importance of understanding how users interact with the product. By recognizing that your primary use case was asking questions like "How much did I make this month across everything?", you were able to design a more conversational interface that leverages the strengths of MCP. The use of personal API tokens to authenticate with the MCP server also shows a thoughtful approach to security, and I appreciate the details you provided on storing hashes and showing prefixes with last-used timestamps. Have you considered expanding the MCP server to support more complex queries or integrating it with other tools in your workflow?