Skip to main content
Glama
shiborgi

lastro

by shiborgi

Lastro

Self-hosted, MCP-first financial platform for personal, family, property, project and business finances. Each independent financial scope is a Book.

Lastro is built to be operated by an AI agent over MCP as its primary interface, with a compact web app for review and direct edits. PostgreSQL is the source of truth.

The one idea worth knowing

Lastro separates economic facts from cash movements:

Expense  ≠  Payment
Revenue  ≠  Receipt

An expense is split into settlements — its installments. A payment groups one or more settlements, may cover installments from several different expenses, and has its own due date. A payment's amount is derived from the active settlements it groups; it is never entered directly. The same holds for revenues and receipts.

That distinction is why a general "transactions" table appears nowhere in the schema.

Related MCP server: Agent Ledger

Quick start

Requires Bun 1.4+ and Docker.

cp .env.example .env
# set BETTER_AUTH_SECRET — openssl rand -base64 32

docker compose -f docker-compose.release.yml up -d --build
bun install
bun run bootstrap --email you@example.com --password 'a-long-passphrase'

That prints an MCP credential once. Then:

macOS on Apple Silicon can use Apple Container instead of Docker; see docs/install.md.

Connecting an agent

Lastro speaks MCP over Streamable HTTP and stdio. With the credential printed by bun run bootstrap:

{
  "mcpServers": {
    "lastro": {
      "url": "http://127.0.0.1:3002/mcp",
      "headers": { "Authorization": "Bearer <credentialId>.<secret>" }
    }
  }
}

A credential is bound to one Book. Calls name the Book they act on, and a credential issued for a different one is rejected rather than returning an empty result — so an agent cannot reach another agent's ledger even by asking for it. Give each agent its own Book and credential and they stay separated by construction:

bun run bootstrap --email you@example.com --password '...' --book Butler    --agent agent:butler
bun run bootstrap --email you@example.com --password '...' --book Bartender --agent agent:bartender

Send x-book-id as well to assert which Book you expect: a token for a different one is then rejected instead of writing to the wrong ledger.

The agent gets the whole product: catalog CRUD (institutions, accounts, parties, categories), the expense and revenue cycles, transfers, positions and cash flow. Every write takes a mandatory idempotency key, every destructive tool requires an explicit confirmation: "confirm", and every mutation appends an audit event naming the agent principal and the operator it acts for.

Architecture

apps/web       Next.js operator interface (Tailwind CSS v4 + shadcn/ui)
apps/api       authenticated HTTP/JSON API, hosts Better Auth
apps/mcp       MCP adapter — stdio and Streamable HTTP

packages/domain        entities and invariants, no framework
packages/application   commands, queries, authorization, ports
packages/db            PostgreSQL schema, migrations, port implementations
packages/contracts     Zod schemas shared by API, MCP and the web app
packages/auth          agent credentials, RBAC, Book membership
packages/config        validated environment configuration
packages/testing       PostgreSQL-backed integration suite

API, MCP and the web app call the same application handlers. Domain rules never live in routes, tools or components. Only packages/db knows SQL.

Details in docs/architecture.md.

Invariants

  • Money is a bigint amount plus an explicit currency; JSON carries amounts as validated decimal strings. No floats, anywhere.

  • Every command and query is scoped to an authenticated bookId.

  • A settlement may only connect records from the same Book and currency.

  • Active settlements may never exceed their expense's total.

  • Status is derived from active settlements, never set directly.

  • Confirmed settlements are voided and replaced, never edited in place.

  • Every mutation is idempotent and appends an AuditEvent.

Development

docker compose up -d          # PostgreSQL 16 on :5432
bun install
bun run db:init               # apply the schema
bun run check                 # typecheck, lint, unit tests, builds
bun run test:integration      # real PostgreSQL, api + mcp, end to end

Changing the schema: edit packages/db/src/schema.ts, then run bun run db:generate to emit a migration.

Contributing

See CONTRIBUTING.md. Security reports go to SECURITY.md.

License

MIT — see LICENSE. UI primitives are copied from shadcn/ui, also MIT; see THIRD_PARTY_NOTICES.md.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    A Model Context Protocol (MCP) server that keeps the books for your personal and business finances using double-entry accounting — driven entirely from an LLM.
    28
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Double-entry accounting ledger MCP server for autonomous agents that enables creating accounts, posting journal entries, and generating financial reports.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server for double-entry bookkeeping with idempotent writes, immutable entries, and audit trail. Enables trustworthy financial recording and verification through natural language.
    22
    MIT