cver-me

EU Open Banking MCP

Community cver-me
Updated

Self-hosted, read-only MCP server for accessing personal European bank accounts through Enable Banking, secured and deployed on Cloudflare Workers.

EU Open Banking MCP

A self-hosted, read-only MCP server for accessing personal European bank accounts through Enable Banking, secured and deployed on Cloudflare Workers.

Deploy to Cloudflare

[!IMPORTANT]Treat every deployment as a private financial system. The repository is open source; your Worker, MCP URL, secrets, session IDs, account IDs, and financial data are private.

Why this exists

ChatGPT Finances shows what becomes possible when an assistant can reason over real balances and transactions. Its account connection is powered by Plaid and is currently available in the United States.

I built this project because I could not find a comparably direct, self-hostable path for European personal accounts. Europe has Open Banking, but individuals still reach bank data through regulated providers whose production onboarding and APIs vary. Plaid's published MCP servers are useful for developer tooling and production diagnostics; they do not expose a person's balances and transactions as personal-finance MCP tools.

This project fills that narrow gap: one person deploys one private MCP, authorizes only their own bank accounts, and lets their chosen MCP clients perform bounded read-only analysis. It is infrastructure for personal use, not a hosted financial product or a multi-user aggregator.

Why Enable Banking

Of the providers evaluated, Enable Banking offered the simplest fit for a self-hosted personal deployment. Its restricted-production mode explicitly allows an application to be activated by linking the owner's own accounts before signing a commercial agreement, including for individual non-commercial use. The application can then read only those linked accounts. See Enable Banking's restricted-production account guide.

That model matches this project's security boundary:

  • the Enable Banking dashboard is the account whitelist;
  • the bank's authorization flow creates the revocable API consent;
  • the MCP exposes only fixed read operations over accounts covered by both.

Dashboard linking is not itself API authorization. After deployment, /setup still sends the owner through their bank's consent flow and stores the resulting Enable Banking session ID. This second step is required even when the same account was already linked in the dashboard.

Architecture

flowchart LR
  C[ChatGPT, Codex, or another MCP client] --> A[Cloudflare Access]
  A -->|platform-validated ctx.access| W[Stateless MCP Worker]
  W -->|session IDs only| K[Workers KV]
  W -->|fresh RS256 JWT per call| E[Enable Banking]
  E --> B[Your bank]
  • Client → MCP: Cloudflare Access Managed OAuth, restricted to the deployment owner.
  • MCP → Enable Banking: a one-hour RS256 JWT signed from a private key stored as a Worker secret.
  • Storage: KV contains only Enable Banking session IDs created through the protected setup flow.
  • Online account reads: the Worker forwards Cloudflare's connecting-client IP and the MCP client'sUser-Agent as Enable Banking's Psu-Ip-Address and Psu-User-Agent headers. These request-scopedvalues are not stored or logged. This tells the bank that the signed-in owner actively requestedthe data.

The Worker does not store balances, transactions, account UUIDs, IBANs, authorization codes, or provider responses. Responses use Cache-Control: no-store.

Tools

Tool Purpose Bounds
finance_list_accounts Discover active accounts and bank-provided metadata 20 authorized sessions, 20 active accounts
finance_get_balances One discovered account or all active accounts Partial per-account results; sequential within each bank
finance_list_transactions Paginated normalized transactions 366 days, 200 results per response
finance_search_transactions Text search over transaction metadata 366 days, 5 provider pages, 100 matches
finance_summarize_cash_flow Booked credit/debit/net totals by currency 366 days, 20 pages, 10,000 transactions

finance_list_accounts returns an opaque, session-specific accountId. Tools that target one account accept that ID and verify it against the active Enable Banking sessions before use. No aliases or manually copied account UUIDs are required.

Pagination nextCursor values contain encoded continuation state; they are opaque but not confidential. Return them unchanged with the same account and filters. The Worker validates their embedded context before use.

Every tool is read-only, non-destructive, and idempotent. Provider codes are normalized into descriptive values such as interim_available, booked, and professional. Multiple balances for one account are alternative measurements and must never be added together. Monetary calculations use decimal arithmetic and never combine currencies.

For a complete balance refresh, call finance_get_balances once without an accountId. It discoversall active sessions itself, so a preceding finance_list_accounts call is unnecessary. The responsekeeps successful balances when another account fails and reports safe per-account errors separately.Do not immediately retry accounts reporting aspsp_rate_limited.

Installation

Installation establishes three separate trust relationships: the Worker proves its identity to Enable Banking, the bank grants the Worker a revocable consent, and Cloudflare Access limits who can call the MCP.

Step What it establishes Why it exists
Register the Enable Banking application Worker → Enable Banking identity The application UUID and RSA key sign provider requests
Link accounts in the Enable Banking dashboard Production account whitelist A restricted application may fetch data only from pre-approved personal accounts
Deploy the Worker Private MCP runtime and session storage Cloudflare runs the code and provisions KV for session IDs only
Enable Cloudflare Access and Managed OAuth MCP client → Worker identity The private Worker rejects callers who are not explicitly allowed
Connect each bank through /setup Bank consent and active Enable Banking session Whitelisting limits scope; bank authorization actually grants API access

1. Prepare Cloudflare and Enable Banking

You need:

  • a Cloudflare account with a workers.dev subdomain and Zero Trust;
  • an Enable Banking restricted-production application;
  • the application's UUID and RSA private key.

Choose the Worker name before registering the Enable Banking application. Register this callback URL, replacing both placeholders:

https://<worker-name>.<account-subdomain>.workers.dev/callback

Register a production application, generate its RSA key outside the browser, and upload the matching public certificate in PEM format. Keep the private key: the deploy flow will store it as a Worker secret, and it must never be committed or shared.

In the Enable Banking Control Panel, link every account the restricted application may access. Dashboard linking is the production whitelist; it does not authorize a session for the application. The Worker completes that second authorization through /setup after deployment. See Enable Banking's linked-account guide.

This repository is intended for personal, non-commercial use. Confirm that your deployment complies with Enable Banking's current terms.

2. Deploy to Cloudflare

Use the Deploy to Cloudflare button above. Cloudflare's deploy flow will:

  1. copy the repository into the user's GitHub or GitLab account;
  2. ask for ENABLE_BANKING_APPLICATION_ID and ENABLE_BANKING_PRIVATE_KEY_PEM;
  3. provision the SESSION_STORE KV namespace;
  4. attach the Cloudflare Access policy required by this project;
  5. build and deploy the Worker with Workers Builds.

The two secret fields initially contain masked placeholder values read from .dev.vars.example: an all-zero UUID and a replace-me private key. They are not existing credentials. Replace both fields with the production application UUID and private key before deploying.

Cloudflare presents Access as optional because Workers can be public, but it is required by this project. On the deployment page, enable Protect with Cloudflare Access, choose All traffic, and add an authentication policy. For a personal deployment, allow only your exact identity (or your Cloudflare account if only trusted members belong to it). Previews only does not protect the production Worker.

Cloudflare documents this behavior in Deploy to Cloudflare buttons.

3. Enable Managed OAuth

  1. Open Zero Trust → Access controls → Applications → the Access application created during deployment.
  2. Open Advanced settings, enable Managed OAuth, and save.

If Protect with Cloudflare Access was not enabled during deployment, attach Worker-level Access manually before continuing. Until Access is attached, the Worker fails closed with 403 access_required because Cloudflare did not provide ctx.access. Worker-level Access protects /, /setup, /callback, and /mcp across the Worker's associated domains. See Cloudflare's Worker-level Access guide.

Managed OAuth exposes the protected-resource and authorization-server discovery metadata used by MCP clients. Cloudflare validates the request before Worker invocation; this project does not duplicate Cloudflare's JWT verifier.

4. Authorize your banks

  1. Open https://<your-worker>.workers.dev/setup.
  2. Choose the country and whether the login is personal or business, then select the bank from Enable Banking's live supported-bank list.
  3. Authorize access at the bank. The callback validates state, exchanges the one-time code, and stores only the resulting session ID in KV.
  4. Repeat for each separate bank login. One authorization may expose multiple accounts.

If consent expires or is revoked, return to /setup, remove the inactive session, and connect the bank again. Removing a connection also asks Enable Banking to close its consent. Enable Banking creates new session and account IDs during reauthorization; the MCP discovers them automatically.

5. Connect an MCP client

Use this MCP URL:

https://<your-worker>.workers.dev/mcp

Verification

Before connecting a model, confirm:

  • unauthenticated requests are rejected by Access;
  • /setup lists only sessions created by this deployment;
  • MCP tools/list exposes exactly the five tools above;
  • finance_list_accounts returns opaque account IDs but no IBANs;
  • a small balance and transaction request succeeds;
  • one all-account balance request returns successful accounts even when another account fails;
  • Cloudflare logs contain no financial payloads, secrets, authorization codes, or session IDs.

There is intentionally no /health endpoint. Cloudflare Workers do not require one, and /mcp plus the protected setup page are the meaningful application checks.

Security properties

  • Fixed upstream origin: requests can only go to https://api.enablebanking.com.
  • Fixed provider operations: setup can start, complete, and close account authorization; MCP tools perform only documented read calls.
  • User-triggered account reads forward bounded Psu-Ip-Address and Psu-User-Agent values derivedfrom the incoming Cloudflare request; session discovery and authorization requests do not receivethose headers.
  • Account enforcement: every supplied account ID must belong to an active stored session.
  • Setup and callback routes are behind Worker-level Access and validate origin/state.
  • Authorization codes are exchanged immediately and never persisted.
  • KV stores only session IDs and is encrypted at rest by Cloudflare.
  • Bounded inputs, dates, pages, results, upstream responses, and timeouts.
  • Provider failures log only a normalized operation, HTTP status, allowlisted provider error code,and bounded Retry-After value—never identifiers, request headers, provider bodies, or financial data.
  • No payments, generic HTTP tools, financial-data persistence, response caching, CORS, or sensitive logging.

See SECURITY.md for the threat model and disclosure policy.

Development

bun run typecheck
bun run test
bun run check

Tests run in the Cloudflare Workers runtime and cover configuration, Access fail-closed behavior, setup authorization, session discovery, account enforcement, MCP tool schemas, Enable Banking JWT construction, normalization, and bounded responses.

Provider scope

Enable Banking is the first provider module. Future providers should expose the same narrow normalized finance interface rather than leaking generic provider HTTP operations into MCP tools. Contributions must remain read-only from MCP and include tests for identifier validation and response normalization.

MCP Server · Populars

MCP Server · New

    qcri

    🦡 codebadger

    🦡 codebadger is a containerized Model Context Protocol (MCP) server that gives AI agents and LLMs deep, queryable access to a codebase's structure and data flow through Joern Code Property Graphs (CPGs).

    Community qcri
    boringSQL

    DryRun PostgreSQL MCP

    PostgreSQL schema intelligence MCP server with offline linting, migration safety, query validation for AI coding assistants.

    Community boringSQL
    emerzon

    mtdata

    A MetaTrader 5 research toolkit with 90+ AI tools for forecasting, regime detection, pattern recognition, and live trading.

    Community emerzon
    OpenImageDebugger

    Open Image Debugger: Enabling visualization of in-memory buffers on GDB/LLDB

    An advanced in-memory image visualization plugin for GDB and LLDB on Linux, with experimental support for MacOS and Windows. Previously known as gdb-imagewatch. Also available as an extension for VSCode and forks

    Community OpenImageDebugger
    HQBase

    HQBase

    Your team's email workspace. In your Cloudflare account.

    Community HQBase