Skip to main content
Glama
falkensson

Erik Finance MCP

by falkensson

Erik Finance MCP

Read-only company finance stack for Erik (Grok Bot CFO for Falkenssons Production AB).

Forked/adapted from Mark's personal stack. Defaults:

  • ASPSP: Handelsbanken, country SE, psu_type business

  • Local API port 8797, MCP HTTP 8798 (Mark uses 8787/8788)

  • Redirect: https://127.0.0.1:8797/auth/callback

  • Never reuse Mark's Enable Banking application id or PEM


Read-only personal finance stack for Mark (Grok Bot personal finance assistant).

Nordea (Sweden, personal AIS)
        ↓
Enable Banking Open Banking API
        ↓
this server (Finance API + local SQLite)
        ↓
MCP tools (stdio or Streamable HTTP)
        ↓
Cursor / Grok Bot

v1 is API + MCP + local store. Notion sync is later.

Hard constraints

  • Read-only AIS only: accounts, balances, transactions.

  • No payment initiation endpoints, MCP tools, or code paths.

  • Never log or store BankID credentials or bank passwords. The only secret this repo uses is the Enable Banking application JWT signing key, plus session ids and consent metadata.

  • Works against Enable Banking sandbox and restricted production (own accounts linked/whitelisted for individual non-commercial use).

  • Default ASPSP: Nordea, country SE, psu_type personal.

Related MCP server: saldo-mcp

Architecture

Piece

Role

Finance API (npm run api)

Local HTTP: start AIS consent, callback, query store, trigger sync

Sync CLI (npm run sync)

Pull balances + transactions since last cursor, upsert, categorize

SQLite (data/finance.db)

Sessions, account uids, sync cursors, normalized transactions

MCP stdio (npm run mcp)

Cursor / local hosts

MCP HTTP (npm run mcp:http)

Grok Bot AddMcpServer (Streamable HTTP at /mcp)

Category buckets (editable rules in config/category-rules.json):

mat · bil · abonnemang · nöjen · fasta · inkomst · sparande · övrigt

Enable Banking signup

  1. Open Enable Banking Control Panel and sign in with email.

  2. Register an API application: API applications.

  3. Sandbox: keep Sandbox, let the browser generate the application private key. The downloaded .pem filename is the application id.

  4. Whitelist the redirect URL you will use, e.g. http://127.0.0.1:8787/auth/callback.

  5. Store the .pem outside git (see ENABLEBANKING_PRIVATE_KEY_PATH).

Docs:

Restricted production (own Nordea SE accounts)

For real balances (individual non-commercial use):

  1. Register a Production application (status starts as Inactive).

  2. Use Activate by linking accounts and complete Nordea Sweden authorization so your own accounts are whitelisted.

  3. Restricted apps can only fetch data from linked accounts until a commercial contract exists.

  4. Linking does not create an AIS session for this server. You still run POST /auth → BankID → POST /sessions here.

Sandbox and production use the same API host (https://api.enablebanking.com). The environment is the application key you configured.

Environment

Copy .env.example to .env. Never commit .env, *.pem, or the SQLite file.

Variable

Purpose

ENABLEBANKING_APPLICATION_ID

Application id (kid in the JWT)

ENABLEBANKING_PRIVATE_KEY_PATH

Path to the application RSA private key

ENABLEBANKING_PRIVATE_KEY

PEM contents if you cannot use a file (\n allowed)

ENABLEBANKING_API_BASE

Default https://api.enablebanking.com

ENABLEBANKING_REDIRECT_URL

Must match a whitelisted redirect URL

ASPSP_NAME / ASPSP_COUNTRY / PSU_TYPE

Default Nordea / SE / personal

CONSENT_VALID_DAYS

Default 180 (capped by ASPSP maximum_consent_validity)

DATABASE_PATH

Default ./data/finance.db

CATEGORY_RULES_PATH

Default ./config/category-rules.json

API_HOST / API_PORT

Finance API bind (default loopback :8787)

API_TOKEN

Optional bearer for the Finance API

MCP_HTTP_HOST / MCP_HTTP_PORT

MCP HTTP bind (default loopback :8788)

MCP_HTTP_TOKEN

Bearer for MCP HTTP. Set this before exposing a tunnel.

JWT shape (RS256), sent on every Enable Banking call:

  • header kid = application id

  • iss = enablebanking.com

  • aud = api.enablebanking.com

  • iat / exp (~1 hour)

Run

Requires Node.js 22.5+ (built-in SQLite).

cp .env.example .env
# put the application id + pem path in .env
npm install
npm test
npm run build

1. Authorize AIS (Nordea SE personal)

npm run api
# elsewhere:
npm run auth:start

Open the returned url, complete Nordea BankID, and land on /auth/callback. The callback exchanges code for a session and stores session_id + account uids.

Equivalent: GET/POST /auth/start then GET /auth/callback?code=...&state=....

2. Sync

npm run sync

Pulls balances and transactions since the last booking-date cursor (2-day overlap), upserts, and categorizes.

3. Local demo without bank credentials

npm run seed
npm run api

Then GET /accounts, /transactions, /spending/monthly?month=2026-09.

MCP tools (read-only)

Tool

Arguments

What it reads

get_accounts

Stored accounts

get_balances

optional account_uid

Last synced balances

get_transactions

from_date, to_date, optional account_uid

Inclusive date range

get_transactions_since_last_report

Tx since report cursor, then advances it

get_monthly_spending

optional month (YYYY-MM)

Category totals

get_sync_status

Consent expiry + sync cursors

There are no payment tools.

Cursor (stdio)

After npm run build, add to ~/.cursor/mcp.json or .cursor/mcp.json:

{
  "mcpServers": {
    "mark-finance": {
      "command": "node",
      "args": ["--experimental-sqlite", "/ABS/PATH/mark-finance-mcp/dist/mcp/stdio.js"],
      "env": {
        "DATABASE_PATH": "/ABS/PATH/mark-finance-mcp/data/finance.db",
        "CATEGORY_RULES_PATH": "/ABS/PATH/mark-finance-mcp/config/category-rules.json"
      }
    }
  }
}

Dev equivalent: npm run mcp (tsx + stdio). See .cursor/mcp.json.example.

Grok Bot (AddMcpServer)

Grok Bot cannot spawn local stdio. Expose Streamable HTTP:

export MCP_HTTP_TOKEN="$(openssl rand -hex 32)"
npm run mcp:http

Tunnel that process (Tailscale, Cloudflare Tunnel, etc.) so the Bot can reach it. In Grok Bot → Add MCP server:

  • Name: mark-finance

  • URL: https://<public-host>/mcp (path must be /mcp)

  • Headers: Authorization: Bearer <MCP_HTTP_TOKEN>

  • Transport: Streamable HTTP

Do not point Grok Bot at localhost. Confirm the Bot lists the six tools above.

Enable Banking sessions are valid until access.valid_until (Nordea typically allows up to ~180 days / maximum_consent_validity). When get_sync_status shows few days remaining, run auth-start again, complete BankID, and keep using the new session id. This app stores consent metadata only — not BankID.

Security

  • Bind Finance API and MCP HTTP to 127.0.0.1 unless you intentionally tunnel.

  • Set MCP_HTTP_TOKEN / API_TOKEN before any public URL.

  • Store the application PEM with filesystem permissions for your user only.

  • Logs redact JWTs, tokens, auth codes, and PEM material.

  • Restricted production is for your linked accounts, not third-party aggregation.

Finance API routes

Method

Path

Notes

GET

/health

read_only: true, payments: false

GET/POST

/auth/start

Starts AIS authorization

GET/POST

/auth/callback

Exchanges code → session

GET

/accounts

Local store

GET

/accounts/:uid/balances

Local store

GET

/transactions

from_date, to_date, account_uid

GET

/transactions/since-last-report

Advances report cursor

GET

/spending/monthly

month=YYYY-MM

GET

/sync/status

Consent + cursors

POST

/sync

Bank pull (needs credentials)

GET/PUT

/rules

Editable category rules

POST

/recategorize

Re-apply rules

No /payments route exists.

Category rules

Edit config/category-rules.json or PUT /rules. Fields: category, pattern (JS regex), optional field (any | remittance | counterparty | credit), priority (lower wins). Then npm run recategorize.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that exposes Enable Banking API tools for interacting with bank accounts through Open Banking. It enables users to authenticate sessions, list accounts, and fetch transaction history or balances via a secure self-hosted server.
    2
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    A read-only MCP server that securely connects Swedish/Nordic bank accounts to AI assistants, keeping all financial data local and encrypted.
    19 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables financial data access from connected bank accounts via MCP tools, allowing natural language queries about balances, transactions, subscriptions, investments, and more, with a focus on privacy and read-only access.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables secure, read-only access to personal European bank accounts through Enable Banking and Cloudflare Workers, allowing MCP clients to list accounts, retrieve balances, search transactions, and summarize cash flow.
    1
    MIT