mcp-server-billing
README.md
# mcp-server-billing
MCP server that gives an AI agent guarded access to a B2B SaaS billing database
(customers, subscriptions, invoices, credit notes) and live ECB exchange rates. Six
tools: five reads covering the whole billing surface, one carefully fenced write.
Runs locally over stdio against docker-compose Postgres, or on AWS behind a Lambda
Function URL for about **$7.67/month**.
Full design rationale, protocol-version notes, and every decision's trade-off:
**[SPEC.md](./SPEC.md)**. Implementation conventions and the code review checklist:
**[CODING_STYLE.md](./CODING_STYLE.md)**.
## Tools
| Tool | Purpose | Read-only | Idempotent |
|---|---|:--:|:--:|
| `billing_search_customers` | Find customers by name, email, domain, status, country | ✓ | ✓ |
| `billing_get_customer` | One customer with subscriptions and open balance | ✓ | ✓ |
| `billing_list_invoices` | Invoices filtered by customer, status, date range | ✓ | ✓ |
| `billing_revenue_summary` | Monthly MRR/ARR, new vs. churned, by plan or country | ✓ | ✓ |
| `billing_convert_currency` | Convert an amount via live ECB rates ([frankfurter.dev](https://frankfurter.dev)) | ✓ | ✗ |
| `billing_issue_credit_note` | **The one write.** Credit an open invoice, capped and idempotency-keyed | ✗ | ✓ |
Plus one resource (`billing://schema`, the live DDL) and one prompt (`revenue_review`,
a guided monthly review). Full schemas, annotations, and example calls: [SPEC.md §5](./SPEC.md#5-tool-inventory).
## Run it (60 seconds)
```bash
docker compose up -d && npm run db:seed
npm run build
cp .env.example .env # fill in MCP_BEARER_TOKEN if you'll also try http/lambda
npm run inspect
```
The Inspector opens in your browser against the six tools, live, against seeded data
(~200 customers, ~2,000 invoices). **Requires Node ≥22.19** for the Inspector itself
(this repo's own code targets Node ≥20 — the gap is the Inspector CLI, not the
server; see [SPEC.md §9](./SPEC.md#9-testing) for what was verified without it).
## Wire it to Claude Desktop
```json
{
"mcpServers": {
"billing": {
"command": "node",
"args": ["/absolute/path/to/mcp-server-aws/dist/stdio.js"],
"env": {
"DATABASE_URL_READER": "postgres://mcp_reader:reader_local_pw@localhost:5434/billing",
"DATABASE_URL_WRITER": "postgres://mcp_writer:writer_local_pw@localhost:5434/billing"
}
}
}
}
```
Use an absolute path — Claude Desktop does not resolve `~` or relative paths.
## Deploy to AWS
```bash
npm run lambda:prepare # builds + stages dist/ + prod deps + db/init/*.sql
cd terraform
cp terraform.tfvars.example terraform.tfvars # fill in mcp_bearer_token
terraform init && terraform apply
terraform output -raw migrate_command | bash # applies schema, rotates role passwords
```
| | $/month |
|---|---|
| RDS `db.t4g.micro`, 11h/day (power-scheduled) | 5.35 |
| gp3 storage, 20 GB | 2.30 |
| Lambda + Function URL, VPC, SSM | ~0.02 |
| **Total** | **≈ 7.67** |
No NAT Gateway: Lambda reaches [frankfurter.dev](https://frankfurter.dev) over IPv6
through an egress-only internet gateway (verified live — Frankfurter has AAAA records)
instead of a ~$32.85/month NAT Gateway. `terraform destroy` takes it to $0. Full cost
breakdown and the architecture diagram: [SPEC.md §3](./SPEC.md#3-architecture).
## Eval questions
Five questions an agent should answer using only these tools — multi-tool, verifiable
against the seed data, one deliberately negative (does the agent respect the credit
cap, or try to split it?). [SPEC.md §9](./SPEC.md#9-testing).
## Development
```bash
npm test # unit + integration (needs docker compose up -d)
npm run lint # eslint
npm run typecheck # tsc --noEmit
npm run format:check # prettier
```
Before opening a PR, run the [code review checklist](./CODING_STYLE.md#12-code-review-checklist).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues