BankMCP
BankMCP is a read-only, self-hosted MCP server that connects your AI assistant to your European bank accounts via Enable Banking, letting you query balances, transactions, and set up automated monitoring rules.
Connect and manage banks: list available banks, start consents (log in at your bank), check consent status, and disconnect banks.
View accounts and balances: list all linked accounts (with IBAN, currency, consent expiry), optionally fetch booked balances for each, label accounts for easier reference, and get detailed booked/available balances for a single account.
Retrieve transactions: fetch transaction history for an account (signed amounts, counterparty, description), with date filtering, pagination via continuation keys, and optional raw bank data.
Create and manage watches (background alerts): set rules like balance thresholds, large debits, matching credits/debits, or missing credits by a deadline; list, delete, or force-check watches; notifications go to the operator-configured webhook (Slack/JSON).
Use prompts and tools from any MCP client: leverage built-in prompts (connect-bank, monthly-summary, build-budget, savings-scan, subscription-audit, unusual-transactions) and all tools via standard MCP over stdio or HTTP.
Deploy locally or on a server: run on your machine for desktop clients or host remotely (Docker, Railway, Fly.io, Render) for cloud/phone access; supports OAuth 2.1 with password authentication and optional environment configuration.
Experiment with local models: bridge Ollama or other local MCP clients to the same tools, keeping data off commercial AI servers (though Enable Banking still mediates bank access).
Sends watch notifications and sign-in alerts to Slack via an incoming webhook.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@BankMCPwhat did I spend on groceries last month?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
BankMCP™
Your AI now reads your bank. Ask it anything about your accounts. Read-only, self-hosted, one user. Standard MCP; tested with Claude and Ollama.
BankMCP™ is not a bank. It is a small open-source server you host yourself
(npm package bankmcp). It connects to your banks
through Enable Banking, which wraps 2,700+
European banks in one PSD2 API, and exposes them to any MCP client as a
connector. Read-only, no payments, no third party holding your data.
"Has the invoice from Acme been paid?" · "What did we spend on groceries in August?" · "Which subscriptions am I paying for, and what do they cost per year?" · "Tell me when my balance drops below 5,000."
How it works
Your assistant ──OAuth──▶ your BankMCP™ server ──JWT──▶ Enable Banking ──PSD2──▶ your bankYour assistant (Claude, ChatGPT, Cursor, or any MCP client) talks to your server as a connector. You sign in once with a password; tokens handle the rest.
Your server holds the Enable Banking application key, the bank consents and your account ids. It does not store balances or transactions and sends no telemetry.
Enable Banking is the licensed provider between your server and your bank. Every balance and transaction you ask for passes through their servers on the way to yours; they do not store it, and they do not see your bank credentials, since you log in at your bank's own site. This hop is how PSD2 works and is the one part of the chain that is not on your machine.
Related MCP server: plaid-mcp
Setup
Two ways to run it. Both need a free Enable Banking account and about ten minutes.
On your own machine for Claude Desktop, Claude Code, Cursor and other desktop MCP clients. Nothing to deploy, no password.
On a small server when you want it in claude.ai or on your phone.
On your own machine
The server and its state live on your computer, and no AI vendor or app maker sees your data. The bank connection is not on your computer: it goes through Enable Banking, as described above.
Requires Node 24 or newer. Add BankMCP™ to your client:
Claude Code:
claude mcp add bankmcp -- npx -y bankmcpClaude Desktop: download
bankmcp.mcpb
and open it; Claude Desktop installs it as an extension. Or add it by hand in
claude_desktop_config.json:
{ "mcpServers": { "bankmcp": { "command": "npx", "args": ["-y", "bankmcp"] } } }Cursor and others: the same command, npx -y bankmcp, as a stdio server.
Then ask your assistant anything about your bank. It will answer with a localhost address. Open it: the setup page lists the values to register an application at Enable Banking, then takes the application id and the key file. Your browser will warn once about the certificate on localhost, which the server made for itself because Enable Banking requires https for the bank redirect. Continue past it. Say "connect my bank" and log in at your bank.
To avoid the warning altogether, use a certificate your browser already
trusts: mkcert makes one with
mkcert localhost 127.0.0.1; point TLS_CERT_PATH and TLS_KEY_PATH at the
two files and the server uses them instead of generating its own. BankMCP™
itself does not touch your system's trust store.
State lives in ~/.bankmcp. Delete the folder to forget everything.
On a server
1. Deploy
Any container host works. The server needs a persistent volume at /data
and a public https address; it asks you for everything else in the browser.
A prebuilt image is published on every release:
ghcr.io/noskillish/bankmcp (built by GitHub Actions
from the tagged source, linux/amd64 and linux/arm64).
Railway:
deploys the published image with a volume at
/data and a domain, nothing
to fill in. Or by hand: New Project, Deploy from GitHub repo, pick this
repo, add a volume mounted at /data and generate a domain (Settings,
Networking, port 8080). The server learns its own address from Railway.
Fly.io: three commands from a checkout, using fly.toml:
fly launch --copy-config --no-deploy # pick an app name and region
fly volumes create data --size 1
fly deployRender:
uses render.yaml. Render's persistent disks need a paid
instance.
Docker on your own box:
docker run -d --name bankmcp --restart unless-stopped \
-p 8080:8080 -v bankmcp-data:/data ghcr.io/noskillish/bankmcp:latestor docker compose up -d with compose.yaml. Then put a TLS
terminator in front (Caddy needs two lines:
YOUR-HOST { reverse_proxy localhost:8080 }) and set BASE_URL to the
public address.
Open the address. A fresh server shows a setup page.
2. Register an Enable Banking application
The setup page can do this for you. Enter the email of your Enable Banking account (or the one you want to create it with) and press Send me the sign-in link. Enable Banking emails you a one-time link; paste it on the next page. Your server signs in with it once, creates the application with the right redirect and policy addresses, generates the key pair and stores the id and the key. The sign-in is not kept. On a local server the click on the link does the same without pasting.
Or by hand: the setup page lists the exact values Enable Banking's form asks
for, with Copy buttons. At https://enablebanking.com/cp/applications create
an application with them, keep generate private key selected, and save. A
.pem file downloads once; that is the key. Paste the application id and
choose the .pem file on the setup page. Before anything is stored, the id
and key are checked against Enable Banking.
Either way: Production for your real accounts, Sandbox for test data. A production application for your own accounts is activated once in the Control Panel with Activate by linking accounts; see Going live below.
3. Finish setup
Choose a password of twelve characters or more. A Ready page then shows what was checked: the application, whether its redirect URL is registered and whether it is active, and the connector address to copy.
Prefer configuration by environment? Set these and the setup page does not appear:
4. Add the connector in your assistant
In claude.ai (or the desktop app): Settings → Connectors → Add custom
connector. Name it BankMCP™, paste https://YOUR-HOST/mcp, save, then click
Connect. Your server shows a password page; enter the admin password. That
is the only login you will do.
In Claude Code:
claude mcp add --transport http bank https://YOUR-HOST/mcpthen run /mcp inside Claude Code to sign in.
Other MCP clients (ChatGPT, Mistral Le Chat, Cursor, VS Code) work the same
way: add the URL as a remote MCP server, sign in with the password. Tested
with Claude, Claude Code and Ollama; the others follow the same standard.
A client whose domain is not in ALLOWED_REDIRECT_HOSTS needs adding there.
5. Connect your bank
In your assistant, say "connect my bank" (or use the connect-bank prompt). It
looks up your bank, gives you a link, you log in at the bank and approve, and
the accounts appear. Consents last up to 180 days; you are told when one
is about to expire and the same conversation renews it.
Give accounts labels ("Everyday", "Joint expenses", "Mortgage") when it suggests them. Every tool accepts labels instead of ids.
Going live with your own accounts
Enable Banking's production environment normally requires a contract, but it has a restricted mode for accessing your own accounts, explicitly allowed for individual non-commercial use. After registering a Production application:
On the (Inactive) application click Activate by linking accounts.
Log in at your bank and approve. Repeat for each bank you want.
The application becomes active and the API returns only the accounts you linked this way.
Read the Restriction of Use section of Enable Banking's Terms of Service before you rely on it: restricted mode is for your own accounts, not for offering a service to others. This project does not change those terms.
What you get
Tools (all read-only):
Tool | What it does |
| connect and manage banks |
| accounts with booked balances; your own names for them |
| booked and available balance for one account |
| signed amounts, one counterparty, one description; paginated |
| background rules with webhook notifications |
Prompts: connect-bank, monthly-summary, build-budget,
savings-scan, subscription-audit, unusual-transactions.
Watches run on the server. Rules: balance below or above an amount, a
single debit over an amount, an incoming or outgoing payment matching a name,
and "tell me if this payment has not arrived by this date". Accounts are
checked at most four times a day, the PSD2 limit for unattended access.
Notifications go to NOTIFY_WEBHOOK_URL as a Slack message or a JSON POST.
Enable Banking's own webhooks cover payment initiation only, so account data is polled. There is no way around that under PSD2.
Claude Code plugin
The repository is also a Claude Code plugin marketplace. The bank plugin
brings three skills: /bank:setup walks you through installing BankMCP™ on
your machine, /bank:deploy through hosting it, and bank encodes how to work
with the data: an account map, categorisation rules, the monthly review format
and when to create watches.
Point it at your server, then install:
export OPENBANK_URL=https://YOUR-HOST/mcp # put this in your shell profile/plugin marketplace add noskillish/bankmcp
/plugin install bank@bankThen /mcp, select bank, Authenticate, and enter your password. No
organisation admin is involved; plugins are per user.
The skill lives at plugin/skills/bank/SKILL.md. Copy it into your own skills to fill in the account map and your merchant rules. The server stays generic; your rules stay yours.
Local models (experimental)
The server does not care which model asks. npm run chat bridges an
Ollama model to the same tools over stdio, so no AI
vendor sees a transaction:
ollama pull qwen3:8b
npm run chat -- "what's my balance?"Measured on a MacBook Air with 24 GB: correct per-account balances, a wrong
total, ten minutes per answer. An 8B model is not yet trustworthy with money;
a 30B-class model on a machine with a real GPU is where it gets useful. Any
MCP client with tool calling (LM Studio, Goose, Jan) can also point at
node src/stdio.ts directly. Enable Banking still sits between you and the
bank either way; that part is regulated and unavoidable.
Security notes
The server is a complete OAuth 2.1 authorization server with one user. Discovery, dynamic client registration and PKCE come from the MCP SDK; tokens are stored hashed; five wrong passwords lock an address out for fifteen minutes.
State is one JSON file in
DATA_DIR: consents, account ids, watches (with the ids of transactions that already fired) and OAuth tokens. Balances and transactions are not written to disk. Your assistant keeps the conversation as any chat does, and a watch notification carries the matched transaction to your webhook. Back the file up if you care about not re-consenting; delete it to forget everything.Only clients that redirect back to a known MCP client domain (Claude, ChatGPT, Mistral, Cursor, VS Code) or localhost can register (
ALLOWED_REDIRECT_HOSTS), which stops a phishing link from routing your sign-in to another site. Using a client not on the list? Add its domain. The sign-in page also names the host you will be sent back to.Notifications go to one destination only: the
NOTIFY_WEBHOOK_URLthe operator sets on the host, and it must be https. A watch cannot name its own webhook, so a client or an assistant that has been talked into it cannot point transaction data at another address or at something inside the server's network.Where the checks are, for anyone reading the code: every
/mcprequest passesrequireBearerAuthinsrc/app.tsbefore any tool runs; tokens are issued and verified bySingleUserProviderinsrc/auth.ts, after the password check incompleteLogin. There is one user, so a valid token is the whole authorisation and the tools carry no further per-user checks. In local mode (npx bankmcp) there is no OAuth: the client on your machine talks to the server over stdio, and whoever can run processes on that machine can use it.Anyone with the admin password can read your accounts. Use a long one. Every successful sign-in is logged and, if
NOTIFY_WEBHOOK_URLis set, sent to you as a message. A sign-in you did not make is your alarm.Forgot the password? Set
ADMIN_PASSWORD(orADMIN_PASSWORD_HASH) on the host and restart; the environment wins over the value stored at setup.Changing
ADMIN_PASSWORD_HASH(orADMIN_PASSWORD) and restarting logs every client out. That is the kill switch. Revoking the consents at your bank, or deleting the state file, is the step beyond it.There are no payment tools. Payments need a licensed PISP and a very different security model, so they are out of scope.
Commands
npm start # http server (reads env from the environment)
npm run dev # same, with reload and .env
npm run check # verify config and the Enable Banking application
npm run hash-password # produce ADMIN_PASSWORD_HASH
npm run watch -- --force # run all watches once, print what fired
npm test # unit tests (node:test)
npm run typecheck
sh scripts/build-mcpb.sh # Claude Desktop bundle → dist/bankmcp.mcpb
npm run banks # refresh docs/banks/banks.json from Enable Banking's bank list
npm run site # build the subpages of the landing page into docs/Requires Node 24 or newer (runs TypeScript directly, no build step).
Layout
src/stdio.ts entry point for npx bankmcp: stdio server plus the localhost https side
src/server.ts entry point for a hosted deployment: OAuth, /mcp, callback, status page
src/app.ts the Express app shared by both entry points
src/local.ts localhost https server and self-signed certificate for local mode
src/mcp.ts McpServer factory (tools, prompts, instructions)
src/tools.ts the MCP tools
src/prompts.ts the MCP prompts
src/watcher.ts background rule checks and notifications
src/auth.ts single-user OAuth provider
src/setup.ts first-run setup: validates and stores id, key and password
src/pages.ts the HTML pages: setup, sign-in, connected, status, privacy, terms
src/config.ts environment and data-directory configuration
src/enablebanking.ts JWT signing and a thin typed API client
src/store.ts the JSON state file
src/data.ts shaping balances and transactions for an assistant
src/cli.ts check, hash-password, watch
bin/bankmcp.js the npx entry; dispatches to stdio or cli
scripts/ build-mcpb.sh (Claude Desktop bundle), banks.ts and site.ts (landing subpages), local-chat.ts (Ollama bridge)
plugin/ Claude Code plugin: setup and deploy skills, bank skill
docs/ landing page (GitHub Pages, bankmcp.dk); docs/banks holds the bank list and its pagesWhat this is, and is not
BankMCP™ is software, not a service. There is no hosted BankMCP™, no account to sign up for, and nobody but you handles your server, your key or your bank consents. Each person who uses it deploys their own copy and is the sole operator of that copy: they register their own Enable Banking application, accept Enable Banking's terms themselves, and are responsible for their own hosting, password and security.
The authors publish the code and nothing else. They do not run any instance for others, receive no data, and are not affiliated with Enable Banking, Anthropic or any bank. BankMCP™ is not a bank, does not hold money, and gives no financial advice.
Use at your own risk. If you deploy it, you own that deployment and its security. The software is provided as is, without warranty of any kind, and the authors accept no liability for how it is used or for any loss that follows. MIT licence below.
License
MIT
Available Tools
12 toolscheck_watchesCheck watches nowA
Evaluate every active watch right now (counts as an attended check, so it does not wait for the polling slot) and return what fired.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral burden, and it discloses a non-obvious side effect: the invocation counts as an attended check and bypasses the normal polling slot. It also specifies that it evaluates all active watches and returns only those that fired. This gives enough detail for an agent to understand the action, though it does not discuss error cases or state changes beyond the check count.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that leads with the core action, then provides the key nuance in a parenthetical, then states the return. No redundant or filler wording is present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless action with no output schema and no annotations, the description is sufficiently complete: it defines the scope ('every active watch'), the timing ('right now'), the behavioral consequence ('counts as an attended check'), and the response ('return what fired'). An agent can invoke and interpret the result without further documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, and the schema is an empty object, so there is nothing for the description to add. The baseline of 4 for parameterless tools applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Evaluate every active watch right now') and a concrete return ('return what fired'). It is clearly distinct from watch lifecycle siblings (create/list/delete) by focusing on immediate evaluation, though it does not explicitly name an alternative, so it stops short of a full 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'counts as an attended check' with 'does not wait for the polling slot' gives clear context for when to invoke: when an immediate, on-demand evaluation is wanted instead of waiting for scheduled polling. No exclusion criteria or alternative tool is mentioned, but the usage context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
consent_statusConsent statusA
Which banks are connected, how many days each consent has left, and any bank logins that were started but not finished.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of explaining behavior. It discloses the output categories, including the non-obvious 'started but not finished' logins, but does not explicitly state that the tool is read-only or whether it refreshes consent data from the banks.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the central question and packs three distinct output facets without waste or repetition. Every clause carries meaningful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter status tool with no output schema, the description explains the return content in enough detail to call correctly. It is missing only an explicit read-only statement or a pointer to sibling list_banks for distinguishing available vs connected banks.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the schema confirms this with 100% coverage, so the description has no parameter documentation burden to carry. The baseline for zero-parameter tools applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as a status/read operation and enumerates what it reports: connected banks, consent days remaining, and incomplete bank logins. This content is specific enough to distinguish it from siblings like list_banks or get_balances, though it lacks an explicit verb like 'retrieves'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use is implied: use when you need consent expiry information or unfinished login flows. However, there is no explicit statement of when to prefer this over alternatives such as list_banks or check_watches, and no when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_watchCreate a watchA
Watch an account in the background and send a notification to the webhook the server's operator configured (NOTIFY_WEBHOOK_URL; Slack or any URL) when a rule fires. The destination cannot be chosen here. Accounts are checked at most 4 times a day, the limit PSD2 sets for unattended access. Rules: balance_below / balance_above: amount threshold on the booked balance. large_debit: any single outgoing payment of at least amount. credit_matching / debit_matching: an incoming / outgoing transaction whose counterparty or description contains match (optionally at least min_amount). credit_missing_by: notify on by_date if no incoming transaction matching match has arrived since the watch was created; also notifies when it does arrive.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Shown in the notification, e.g. 'Invoice 2024-17 from Acme' | |
| type | Yes | ||
| match | No | Text to look for in counterparty/description | |
| amount | No | Threshold for balance_* and large_debit | |
| account | Yes | Account uid or label | |
| by_date | No | Deadline for credit_missing_by | |
| min_amount | No | Minimum amount for *_matching and credit_missing_by |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It covers key behavioral aspects: the notification destination is fixed (NOTIFY_WEBHOOK_URL, cannot be chosen), checks occur at most 4 times a day (PSD2 limit), and each rule type's exact triggering conditions are detailed (e.g., credit_missing_by notifies on by_date and also when the matching transaction arrives). It does not disclose the response format or error behavior, but the provided details are substantial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but each sentence earns its place. It opens with the core purpose, then states key constraints (webhook destination, rate limit), and then systematically explains each rule type with its parameters. It is front-loaded with the primary action and avoids redundancy. While it could be more compact, the detail is necessary given the complexity of six rule types and multiple parameters.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has no output schema, so the description should ideally clarify what the call returns (e.g., a watch ID or confirmation). This is omitted. However, the description fully covers the input semantics, constraints, and rule behaviors, which is the bulk of what an agent needs to invoke the tool correctly. The missing return information is a minor gap, but the overall context is highly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers 86% of parameters with descriptions, but the description adds significant context beyond the schema. For each rule type, it explains how the parameters apply (e.g., 'balance_below / balance_above: amount threshold on the booked balance', 'credit_matching / debit_matching: an incoming / outgoing transaction whose counterparty or description contains match'). This maps parameter meanings to specific rules, going beyond the generic schema descriptions and clarifying optional interactions like min_amount.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's core action: 'Watch an account in the background and send a notification to the webhook... when a rule fires.' It specifies the resource (account), the action (create watch), and the outcome (notification). The enumeration of rule types (balance_below, balance_above, etc.) further clarifies the purpose and distinguishes it from sibling tools like list_watches or delete_watch.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool (for automated background monitoring) but does not explicitly contrast it with alternatives. It doesn't state 'use this when you need to set up a rule-based alert' or mention that list_watches is for viewing existing watches. The context is clear enough to infer usage, but the description misses direct guidance on when not to use it or when to prefer a sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_watchDelete a watchA
Remove a watch by id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It communicates that deletion happens but does not disclose consequences such as irreversibility, side effects on related resources, authorization requirements, or behavior when the id does not exist.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no filler. Every word carries meaning and it is immediately scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple: one required string parameter and no output schema. The description is almost sufficient for an agent to call it correctly. It only lacks a brief note on failure/not-found behavior or irreversibility, which prevents a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema gives only a required string named 'id' with 0% description coverage. The description's 'by id' confirms that the parameter is the identifier of the watch to remove, which is useful but minimal; it does not add format, source, or lifecycle context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Remove') with a specific resource ('a watch') and the exact selector ('by id'). It is distinct from watch siblings like create_watch, list_watches, and check_watches, so an agent can tell what this tool does without inspecting further.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use or when-not-to-use guidance, and no alternative tool is named. However, the delete semantics are clear enough that the intended use (when a watch must be removed) is implied by the verb and resource.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disconnect_bankDisconnect a bankA
Revoke a bank consent at Enable Banking and forget its accounts, labels and watches on this server.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | From consent_status |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It tells the agent the operation is destructive by explicitly listing what is forgotten: accounts, labels, and watches. It stops short of stating irreversibility or access requirements, but the disclosed side effects are substantial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence with the key verb first and side effects following. No filler or redundant restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with no output schema, the description provides enough to understand the action and its consequences. It could mention that the action cannot be undone, but complexity is low and the core behavior is covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the parameter description already tells the agent session_id comes from consent_status. The tool description adds no further parameter semantics, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly names the action (revoke a bank consent), the provider (Enable Banking), and the local side effects (forget accounts, labels, watches). This distinguishes it from sibling tools like list_banks or create_watch.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the use case: when a bank connection should be removed. It does not explicitly state alternatives or conditions when not to use it, such as using delete_watch instead when only a watch should be removed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_balancesGet balancesA
Current balances of one account. booked is the cleared balance (use this for net worth); available is what the bank says can be spent, which for credit and mortgage accounts includes the credit line.
| Name | Required | Description | Default |
|---|---|---|---|
| account | Yes | Account uid or label |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must carry the behavioral transparency burden. It adds valuable context by defining booked versus available balances, but it does not disclose potential side effects (it is read-only by nature), authorization requirements, or error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences efficiently front-load the core purpose and then explain the critical distinction between booked and available balances. There is no redundancy or unnecessary elaboration.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with one well-documented parameter, and the description covers the key return semantics of balances, which is enough to make a correct call. However, without an output schema or annotation support, it could provide more detail on the response structure or error cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema fully documents the single `account` parameter as 'Account uid or label' (100% coverage). The description adds no new semantic detail about the parameter beyond repeating the 'one account' constraint, so it stays at the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Current balances of one account', which clearly identifies the tool's verb, resource, and scope. It implicitly distinguishes itself from siblings like list_accounts and get_transactions by focusing on balance data for a single account.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides useful usage context, such as 'use this for net worth' for the booked balance and explains what available means for credit/mortgage accounts. However, it does not explicitly say when to prefer this tool over an alternative or mention any prerequisites like a valid consent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transactionsGet transactionsA
Transactions of one account, newest first. Amounts are signed (negative = money out). Defaults to the last 30 days. Banks return limited history (often 90 days, some up to 2 years). If the result has continuation, pass it back to fetch more.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | YYYY-MM-DD, default today | |
| from | No | YYYY-MM-DD, default 30 days ago | |
| account | Yes | Account uid or label | |
| max_pages | No | Pages to fetch in one call | |
| include_raw | No | Include the bank's raw transaction objects | |
| continuation | No | Continuation key from a previous call |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations to carry the safety profile, the description adds meaningful behavior: signed amounts, newest-first ordering, default date range, limited bank history, and continuation-based pagination. It does not detail error behavior or output shape, but the core operational traits are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five short sentences, each carrying distinct information: scope/order, sign convention, default range, history limits, and pagination. Core facts are front-loaded and no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter tool with no output schema and no annotations, the description covers the important operational context: ordering, sign convention, defaults, and continuation. It does not enumerate return fields, but the schema already documents parameters and the core call behavior is clear.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value beyond the schema by explaining the continuation mechanism, the 30-day default context, and the practical bank history limit, which helps an agent decide parameters correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: it fetches transactions for one account, with ordering ('newest first'). This is enough to distinguish it from sibling tools like get_balances or list_accounts without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description establishes clear context: use it for a single account's transaction history, defaulting to 30 days, and mentions pagination for longer histories. It does not explicitly name alternatives or state when not to use it, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_accountsList accountsA
All linked accounts with bank, IBAN, currency and consent expiry. With include_balances the booked balance is fetched for each account (one bank call per account). Use the booked balance for totals; available may include credit lines.
| Name | Required | Description | Default |
|---|---|---|---|
| include_balances | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does meaningful work: it discloses a per-account bank call cost, explains that booked balance is the reliable total, and warns that available may include credit lines. It does not mention pagination or error behavior, but the disclosed traits go well beyond a bare listing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, with the core purpose first, the optional parameter behavior second, and the balance-totals caveat last. No repetition of schema fields and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-optional-parameter list tool with no output schema, the description covers return fields, optional balance retrieval, and the network cost. It is slightly light on when to choose this over balance-specific siblings, but nothing needed to make a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides only a boolean name and default with no property description, so the description fully compensates by explaining the effect of include_balances and the meaning of booked vs available balances. This is exactly the semantic detail needed for correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns all linked accounts with the key fields (bank, IBAN, currency, consent expiry). The optional balance behavior distinguishes it from list_banks and get_balances, giving the agent enough to know exactly what this tool retrieves.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives practical parameter guidance: set include_balances to fetch booked balances and use booked rather than available for totals. However, it does not explicitly state when to choose this tool over siblings like get_balances or list_banks, leaving usage-vs-alternative decisions to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_banksList banksA
Banks available through Enable Banking in a country, with the maximum consent length. Use the exact name with start_consent.
| Name | Required | Description | Default |
|---|---|---|---|
| search | No | Filter by (part of) the bank name | |
| country | No | ISO country code, default DK |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, and the description implies a read-only listing operation but does not explicitly state side effects, safety, or ordering/pagination behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loaded with the core purpose, and includes a practical pointer for using the returned bank name with start_consent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple listing tool with no output schema, the description gives enough information about what is returned and how to use it downstream.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already fully describes the search and country parameters with defaults, so the description adds little semantic value beyond what is provided.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the tool lists banks available through Enable Banking in a country and includes maximum consent length. This distinguishes it from sibling list tools like list_accounts and list_watches.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides workflow context by telling the agent to use the exact bank name with start_consent, but does not explicitly compare against alternative tools or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_watchesList watchesB
All watches with their rule, status and when they last fired.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It does not explicitly state that the operation is read-only, has no side effects, or whether any prior state (e.g., consent) is required. Only the returned fields are mentioned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence that immediately names the resource and its contents. No filler or redundancy; every word contributes meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter list tool without an output schema, the description adequately states the return values (rule, status, last fired). It is slightly under-specified regarding the exact scope of 'all' and the distinction from check_watches, but remains largely complete for its simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema is empty with zero parameters and 100% schema description coverage, so the baseline for parameter semantics is 4. The description has no need to add parameter details since there are none.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource (watches) and the exact fields returned (rule, status, last fired), making it clear this is a list/read operation. It differentiates from create_watch and delete_watch via the listing nature, but does not explicitly distinguish itself from check_watches, a sibling of unknown behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to use list_watches versus check_watches, create_watch, or delete_watch. The description only states what the tool returns and does not include any conditions, alternatives, or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_account_labelLabel an accountA
Give an account a name you will recognise, e.g. 'Joint expenses' or 'Mortgage'. Labels can be used instead of uids in every other tool.
| Name | Required | Description | Default |
|---|---|---|---|
| label | Yes | ||
| account | Yes | Account uid, or current label/name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral burden. It discloses the core effect and that labels are usable across tools, but does not mention whether an existing label is overwritten, whether labels must be unique, or any side effects. Acceptable for a simple setter, but some transparency is missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences carry purpose, examples, and cross-tool relevance. No filler or redundancy; the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter tool with no output schema, the description covers purpose, parameter interpretation, and why labeling is useful. It omits edge-case behavior like overwriting or label removal, but these are not critical to invoking the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50%: 'account' is documented in the schema, but 'label' is not. The description compensates by explaining what a label is, giving examples, and noting that labels can replace uids everywhere. This adds meaning beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear action ('Give an account a name') on a specific resource (account) and provides concrete examples. It is immediately distinguishable from the sibling list/get/consent tools, none of which involve labeling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool: to assign a recognizable name so labels can replace uids in other tools. It lacks explicit exclusions or alternatives, but since no sibling tool performs labeling, this is clear and sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_consentConnect a bankA
Start linking a bank. Returns a URL the account holder must open in a browser to log in at their bank and approve read-only access. After approval the bank redirects back to this server and the accounts appear in list_accounts. Consents last up to 180 days.
| Name | Required | Description | Default |
|---|---|---|---|
| bank | Yes | Exact bank name from list_banks | |
| country | No | ISO country code, default DK | |
| customer_type | No | personal |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral disclosure burden. It explains the external-browser redirect flow, the read-only nature of the consent, the callback to the server, the appearance of accounts afterward, and the 180-day expiry. This is comprehensive and leaves no major behavioral surprises.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences deliver the core action, the multi-step flow, and the consent lifetime with no filler. The main purpose is front-loaded in the first sentence, and every following sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema, the description gives the essential return semantics (a URL), the required follow-up action (open in browser and approve), the post-approval effect (redirect and accounts in list_accounts), and the consent duration. Nothing an agent needs to correctly invoke and understand the outcome is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds no parameter-specific meaning, while the schema already covers bank (exact name from list_banks) and country (ISO code, default DK). The customer_type parameter is documented only through its enum values and default. With 67% schema coverage, the description does not need to compensate heavily, but it also contributes nothing beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Start linking a bank.' It then explains the exact mechanism (returns a URL for browser login/approval) and clearly differentiates from siblings like consent_status (checking status) and disconnect_bank (ending a consent). The role of the tool is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear contextual guidance: it is the initiation step, and after approval the accounts will appear in list_accounts. This strongly implies when to use it relative to other tools. However, it does not explicitly name alternatives or state when not to use it, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.14- Changed
create_watch1 field changed- removed
Input schema / properties / webhook_urlRemoved value: -{ - "description": "Override the server's NOTIFY_WEBHOOK_URL for this watch", - "format": "uri", - "type": "string" -}
12 tool updates
v0.1.5- First observed
check_watches - First observed
consent_status - First observed
create_watch - First observed
delete_watch - First observed
disconnect_bank - First observed
get_balances - First observed
get_transactions - First observed
list_accounts - First observed
list_banks - First observed
list_watches - First observed
set_account_label - First observed
start_consent
TDQS
Scored across 12 tools
Tools are mostly distinct: account queries (get_balances, get_transactions), consent lifecycle (start_consent, consent_status, disconnect_bank), account listing/labeling, and watch management (create_watch, list_watches, delete_watch, check_watches). Minor overlap between list_accounts and get_balances (both return booked balances) and between check_watches and create_watch's notification behavior, but descriptions clarify the differences.
Most tools follow a clear verb_noun pattern: get_balances, get_transactions, list_banks, list_accounts, list_watches, start_consent, delete_watch, disconnect_bank. Minor deviations: create_watch vs. delete_watch/list_watches (could be add_watch for consistency), and consent_status/check_watches/set_account_label are noun-ish or verb_noun but not perfectly parallel. Overall predictable.
12 tools is well-scoped for a banking aggregation server. Each tool covers a distinct part of the workflow: bank discovery, consent management, account access, labeling, transaction history, and watch rules. No redundant or filler tools.
The surface covers the core banking aggregation lifecycle: connect banks, list accounts, read balances/transactions, label accounts, and manage watches. Minor gaps: no tool to update a watch or refresh a consent, and no explicit way to fetch a single transaction or account detail beyond balances, but agents can work around these with existing tools.
Maintenance
Related MCP Connectors
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Personal finance for AI agents — onboard, import statements, categorize & budget over MCP.
- ZapierOAuthcom.zapier
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn 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-
- FlicenseNot gradedqualityCmaintenanceSelf-hosted MCP server enabling Claude to query bank accounts, balances, and transactions through Plaid with OAuth and TLS.-
- AlicenseNot gradedqualityBmaintenanceA read-only MCP server that securely connects Swedish/Nordic bank accounts to AI assistants, keeping all financial data local and encrypted.9 npmMIT
- AlicenseBqualityBmaintenanceA read-only MCP server that exposes Turkish open banking data (accounts, balances, transactions, cash flow, and cards) to AI agents via the ÖHVPS 2.0.0 standard.5MIT