Skip to main content
Glama
borgels

mcp-server-enablebanking

by borgels

mcp-server-enablebanking

An MCP server for company bank accounts through Enable Banking (PSD2 account information): list accounts, read balances, read transactions.

It is read-only by construction — the client has no payment or transfer call, and the Enable Banking application is not registered for payment initiation. And it is hard-scoped to one company per instance: which account belongs to which company is decided by a reviewed registry, never by the bank consent or by a tool argument.

Who owns an account

A bank consent is a poor authority for that. One MitID business login often reaches the accounts of several companies, and a consent happily contains accounts nobody has decided about. So the server does not trust it:

  • The account registry decides (ENABLEBANKING_ACCOUNTS_PATH, see deploy/accounts.example.json). One file for all companies: CVR, name, and the IBANs that belong to each. An IBAN under two companies, a bad checksum or a duplicate id fails startup.

  • The instance is pinned to one company (ENABLEBANKING_COMPANY). No tool takes a company argument.

  • Binding happens once, narrowly. When a consent is completed, only accounts whose IBAN is registered to this company are kept. The uids of other companies' accounts are discarded — the store never holds a handle on them — and a consent containing nothing of this company is revoked at the bank immediately.

  • Checked again on every call. A read resolves the account through the registry now, then through the consent. Remove an IBAN from the registry and the next call is refused; nothing at the bank has to change.

  • The bank must agree. Account details are compared with the registered IBAN; a uid that suddenly answers for another account is refused.

  • Isolation at rest. Bank sessions are encrypted (AES-256-GCM) with keys derived per company, and the store file is bound to its company; a store mounted into the wrong instance cannot be opened.

Unregistered accounts found in a consent are reported to the admin in full (so they can be added to the registry, followed by enablebanking_refresh_consent); accounts registered to another company are reported masked only.

Related MCP server: openbanking-mcp

Tools

Read (everyone in the endpoint's group):

Tool

enablebanking_search_capabilities

find the right tool

enablebanking_list_accounts

the company's registered accounts, consent status and expiry

enablebanking_get_balances

booked/available balance of one account

enablebanking_get_account_details

the bank's product, currency, credit limit

enablebanking_list_transactions

bank lines in a period, newest first, with totals; filter by text, direction, amount

Accounts are named by their registry id (drift) or IBAN. Amounts are decimal strings (never floats); negative means money left the account; totals are summed in minor units.

Consent (only with ENABLEBANKING_ENABLE_CONSENT=true; gated by a duty group at the gateway and, optionally, ENABLEBANKING_CONSENT_ADMINS):

Tool

enablebanking_list_banks

banks in a country, with maximum consent length

enablebanking_start_consent

returns the bank's MitID link; renewing replaces (and revokes) the previous consent at that bank

enablebanking_complete_consent

takes the address the browser landed on; binds this company's registered accounts

enablebanking_refresh_consent

re-binds an existing consent against the registry as it is now — no MitID

enablebanking_revoke_consent

closes the consent at the bank and forgets it

The consent state is HMAC-signed and carries company, user, and a 30-minute expiry; it is single-use. A redirect cannot be completed on another company's endpoint, by another user, twice, or late. Two ways to finish a consent:

  • Confirmation page (ENABLEBANKING_CONSENT_CALLBACK=true): the server answers GET on the path of ENABLEBANKING_REDIRECT_URL, completes the consent there and shows which accounts were bound (IBANs masked), with a button back to the chat (ENABLEBANKING_RETURN_URL). That path is the only one that must be reachable without the gateway; it does nothing without a valid, unused state, and the bank's code is worthless without the application's private key. The page is static HTML with no-store, no-referrer and a CSP that allows no script.

  • Paste (callback off): the redirect only needs to land on a URL registered with the application; nothing has to listen there. The admin copies the address from the browser into enablebanking_complete_consent — no extra public surface at all.

Either way, the consent belongs to the company, not to the person who gave it: once one authorised person has approved it with MitID, everyone the gateway lets onto the endpoint reads the accounts without MitID of their own, until the consent expires.

Bank limits

Banks may cap account reads made without the account holder present — PSD2 allows as few as four per account per day. Answers are cached per account and query (ENABLEBANKING_CACHE_SECONDS, default 300), and the instructions ask the model to fetch a period in one call. Consents are time-limited (often 180 days at most); enablebanking_list_accounts shows days left, and an expired or revoked consent is reported as "renew with enablebanking_start_consent" rather than as a bank error.

In restricted production mode Enable Banking only serves accounts linked to the application in its control panel — one more gate, outside this server.

Identity and audit

Behind an authenticating MCP gateway (ENABLEBANKING_TRUST_FORWARDED_USER=true) every request must carry the verified user in X-MCP-User; requests without it are refused. Each tool call is written to ENABLEBANKING_AUDIT_LOG with company, user, tool and account id; arguments are hashed, and balances, transactions and the consent code are never logged. Keep your gateway's own audit as well.

Deployment

Run one container per company, each with its own ENABLEBANKING_COMPANY, data directory and encryption key, all mounting the same read-only registry and private key (see .env.example). Put the HTTP transport behind a gateway that authenticates users, forwards X-MCP-User, and holds the upstream MCP_HTTP_TOKEN. Gate the consent tools separately there (a duty group), and keep the registry in your operations repository — it names real accounts and does not belong next to the code.

The container runs as uid 1000; the data directory and key file must be readable by it (key: mode 600).

Run

npm install
npm test
npm run dev:http        # streamable HTTP on :3000/mcp (stateless)
npm run check:accounts -- path/to/accounts.json

Licence

Apache-2.0.

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    F
    maintenance
    Enables interaction with bank accounts via TrueLayer API, supporting listing accounts and retrieving transactions.
    9
    1
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables read-only access to personal bank accounts via the TrueLayer API, allowing querying of accounts, balances, transactions, and generating financial analytics such as spending by category, subscriptions, and monthly summaries.
    9
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables reading C6 Bank account balances, statements, credit card bills, and investments via Open Finance Brasil. It is read-only and regulated by the Central Bank of Brazil.
    MIT
  • 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