bankmcp 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  **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.
4
4
 
5
5
  BankMCP™ is not a bank. It is a small open-source server you host yourself
6
- (package name `bank-mcp`). It connects to your banks
6
+ (npm package `bankmcp`). It connects to your banks
7
7
  through [Enable Banking](https://enablebanking.com), which wraps 2,700+
8
8
  European banks in one PSD2 API, and exposes them to any MCP client as a
9
9
  connector. Read-only, no payments, no third party holding your data.
@@ -24,8 +24,11 @@ Your assistant ──OAuth──▶ your BankMCP™ server ──JWT──▶ En
24
24
  - **Your server** holds the Enable Banking application key, the bank consents
25
25
  and your account ids. It does not store balances or transactions and sends no
26
26
  telemetry.
27
- - **Enable Banking** is the licensed provider. You log in at your bank's own
28
- site to approve access; nobody sees your bank credentials.
27
+ - **Enable Banking** is the licensed provider between your server and your
28
+ bank. Every balance and transaction you ask for passes through their
29
+ servers on the way to yours; they do not store it, and they do not see your
30
+ bank credentials, since you log in at your bank's own site. This hop is how
31
+ PSD2 works and is the one part of the chain that is not on your machine.
29
32
 
30
33
  ## Setup
31
34
 
@@ -38,6 +41,10 @@ minutes.
38
41
 
39
42
  ### On your own machine
40
43
 
44
+ The server and its state live on your computer, and no AI vendor or app
45
+ maker sees your data. The bank connection is not on your computer: it goes
46
+ through Enable Banking, as described above.
47
+
41
48
  Requires [Node 24](https://nodejs.org) or newer. Add BankMCP™ to your client:
42
49
 
43
50
  Claude Code:
@@ -180,7 +187,7 @@ service to others. This project does not change those terms.
180
187
  | `create_watch`, `list_watches`, `delete_watch`, `check_watches` | background rules with webhook notifications |
181
188
 
182
189
  **Prompts**: `connect-bank`, `monthly-summary`, `build-budget`,
183
- `subscription-audit`, `unusual-transactions`.
190
+ `savings-scan`, `subscription-audit`, `unusual-transactions`.
184
191
 
185
192
  **Watches** run on the server. Rules: balance below or above an amount, a
186
193
  single debit over an amount, an incoming or outgoing payment matching a name,
@@ -194,9 +201,10 @@ is polled. There is no way around that under PSD2.
194
201
  ## Claude Code plugin
195
202
 
196
203
  The repository is also a Claude Code plugin marketplace. The `bank` plugin
197
- bundles the connector entry and a skill that encodes how to work with the
198
- data: an account map, categorisation rules, the monthly review format and when
199
- to create watches.
204
+ brings three skills: `/bank:setup` walks you through installing BankMCP™ on
205
+ your machine, `/bank:deploy` through hosting it, and `bank` encodes how to work
206
+ with the data: an account map, categorisation rules, the monthly review format
207
+ and when to create watches.
200
208
 
201
209
  Point it at your server, then install:
202
210
 
package/dist/lib/data.js CHANGED
@@ -17,10 +17,15 @@ export function simplifyTransaction(t) {
17
17
  }
18
18
  export function simplifyBalances(balances) {
19
19
  const byType = (types) => balances.find((b) => types.includes(b.balance_type));
20
- const booked = byType(["CLBD"]) ?? byType(["ITBD"]) ?? byType(["CLAV"]);
20
+ // Preference order: closing booked, interim booked, closing available, interim
21
+ // available, expected, then whatever the bank sent. Some banks (Revolut, for
22
+ // one) report a single ITAV balance and nothing else; an account must never
23
+ // vanish from a total because of the label its bank chose.
24
+ const booked = byType(["CLBD"]) ?? byType(["ITBD"]) ?? byType(["CLAV"]) ?? byType(["ITAV"]) ?? byType(["XPCD"]) ?? balances[0];
21
25
  const available = byType(["XPCD"]) ?? balances.find((b) => /avail/i.test(b.name ?? "") || /avail/i.test(b.balance_type));
22
26
  return {
23
27
  booked: booked ? round2(Number(booked.balance_amount.amount)) : undefined,
28
+ booked_type: booked?.balance_type,
24
29
  available: available && available !== booked ? round2(Number(available.balance_amount.amount)) : undefined,
25
30
  currency: (booked ?? balances[0])?.balance_amount.currency,
26
31
  reference_date: (booked ?? balances[0])?.reference_date,
package/dist/lib/mcp.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { registerTools } from "./tools.js";
3
3
  import { registerPrompts } from "./prompts.js";
4
- export const VERSION = "0.1.1";
4
+ export const VERSION = "0.1.3";
5
5
  export function createServer() {
6
6
  const server = new McpServer({ name: "bank", version: VERSION }, {
7
7
  instructions: [
@@ -23,6 +23,19 @@ export function registerPrompts(server) {
23
23
  3. When I say I am done, call consent_status and list_accounts. Summarise what got linked.
24
24
  4. Suggest a short label for each account based on its name and product, and offer to set them with set_account_label so I can refer to accounts by name.
25
25
 
26
+ ${accountsContext()}`));
27
+ server.registerPrompt("savings-scan", {
28
+ title: "Savings scan",
29
+ description: "For the vague 'how am I doing?' question. A 90-day scan that returns at most three findings ranked by money at stake and urgency: about to run short, a needless cost, or a regular payment that changed. Each with a concrete action. Not a monthly category review.",
30
+ }, () => text(`Give me a 90-day money-saving scan: prevent harm or leave me better off. At most three findings.
31
+
32
+ 1. Call list_accounts with include_balances, then get_transactions on each current account for the last 90 days (follow continuation keys). Skip loan and mortgage accounts for spending findings; note their booked balance only if cash is tight. Do not fetch any other window. If a range comes back empty, say the bank returned nothing.
33
+ 2. Work out each account's role from what flows through it: everyday account (salary in, cards and bills out), transfer or holding account (mostly moves between my own accounts), savings, or liability. Use the role so you do not misread things: a transfer account running low means "top up", not "short before payday". Do not lead with the role; offer set_account_label only as a follow-up. Do not invent accounts I have not linked; if a payee suggests one (a card bill, a rent payment), say so.
34
+ 3. Main currency is the one my income arrives in and my cards are paid from, not an empty travel wallet. Quote and rank in it. Do not invent exchange rates. If a charge was billed in another currency, keep the billed currency; show both only for a currency-fee finding.
35
+ 4. Scan for: (a) running short: project the next low point from the usual cadence of income and bills, and flag overdraft or failed-payment risk if the booked balance looks tight. (b) needless cost: duplicates (same name, same amount, days apart), recurring charges that look forgotten or are new, a merchant whose amount stepped up, avoidable currency or card fees. (c) changed without asking: a regular debit rose, a regular credit shrank or missed, a new regular payment appeared. For each: amount at stake per month or per year, urgency (cash-tight first), confidence (low when names are vague or the history is short).
36
+ 5. Output at most three findings, most expensive or most urgent first, and say in one line if you dropped others. Each finding: one sentence of fact, the amount, the confidence, then one concrete action (cancel, query this charge, top up before a date, connect the account a bill suggests). Give an estimated monthly or yearly saving when the finding is a cost; for running short, give a date instead. If nothing is worth doing, say so in one line and ask one useful question.
37
+ 6. Offer, not perform: subscription-audit for the full recurring table, unusual-transactions if I suspect something is wrong beyond these three, build-budget if I want a plan.
38
+
26
39
  ${accountsContext()}`));
27
40
  server.registerPrompt("monthly-summary", {
28
41
  title: "Monthly summary",
package/dist/lib/stdio.js CHANGED
@@ -11,5 +11,9 @@ const { ensureLocalServer } = await import("./local.js");
11
11
  ensureLocalServer().catch((err) => console.error("[bank] could not start the local server:", err.message));
12
12
  if (!isConfigured())
13
13
  console.error("[bank] not configured yet: ask your assistant anything and it will point you to the setup page");
14
- await createServer().connect(new StdioServerTransport());
14
+ const transport = new StdioServerTransport();
15
+ // Exit with the client: when stdin closes, the localhost listener must not keep the process alive.
16
+ transport.onclose = () => process.exit(0);
17
+ process.stdin.on("end", () => process.exit(0));
18
+ await createServer().connect(transport);
15
19
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bankmcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "BankMCP™: self-hosted, read-only MCP server that lets any AI assistant (Claude, ChatGPT, Mistral, Cursor, or a local model) answer questions about your own bank accounts via open banking (Enable Banking, PSD2)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "bank",
3
- "version": "0.1.0",
4
- "description": "BankMCP™: work with your own bank accounts through an bank-mcp (Enable Banking, open banking) connector: account mapping, categorisation rules and the monthly review format.",
5
- "author": { "name": "Nils Smed" },
3
+ "version": "0.1.1",
4
+ "description": "BankMCP™: work with your own bank accounts through a bankmcp server (Enable Banking, open banking) connector: account mapping, categorisation rules and the monthly review format.",
5
+ "author": {
6
+ "name": "Nils Smed"
7
+ },
6
8
  "homepage": "https://github.com/noskillish/bankmcp",
7
9
  "license": "MIT",
8
- "keywords": ["banking", "personal-finance", "psd2", "enable-banking", "mcp"]
10
+ "keywords": [
11
+ "banking",
12
+ "personal-finance",
13
+ "psd2",
14
+ "enable-banking",
15
+ "mcp"
16
+ ]
9
17
  }
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: deploy
3
+ description: Deploy BankMCP™ to a small server so it works in claude.ai and on the phone: Railway or Fly.io, volume, domain, setup page, connector. Use when the user says "deploy bankmcp", "host it", "/deploy", "use it on my phone", or "add it to claude.ai".
4
+ ---
5
+
6
+ # Deploy BankMCP™ to a server
7
+
8
+ Guide one person through a hosted deployment. Prefer Railway unless the user names another host. Run what you can with the CLI; the user does the dashboard clicks, their bank login and their claude.ai settings.
9
+
10
+ ## 1. Choose the host
11
+
12
+ Ask which they have: Railway, Fly.io, or their own box with Docker. If none, recommend Railway (https://railway.com) and wait until they have an account.
13
+
14
+ ## 2. Railway
15
+
16
+ If the `railway` CLI is installed and logged in (`railway whoami`), do it from the terminal:
17
+
18
+ ```
19
+ railway init
20
+ railway add --service bankmcp --repo noskillish/bankmcp --branch main
21
+ railway volume add -m /data
22
+ railway domain --port 8080
23
+ ```
24
+
25
+ Otherwise, in the Railway dashboard: New Project, Deploy from GitHub repo `noskillish/bankmcp`; add a Volume mounted at `/data`; Settings, Networking, Generate Domain on port 8080.
26
+
27
+ Report the public address. No variables are needed; the server detects its own address on Railway.
28
+
29
+ ## 3. Fly.io or Docker
30
+
31
+ Fly: `fly launch --no-deploy` from a clone of the repo, `fly volumes create data --size 1`, add a `[mounts]` entry for `/data`, `fly deploy`. Docker: `docker compose up -d` from a clone, then a TLS proxy in front and `BASE_URL` set to the public https address.
32
+
33
+ ## 4. Setup page
34
+
35
+ Tell the user to open the public address. It shows a setup page with the values for Enable Banking's form. Walk them through registering the application as in the `setup` skill (environment, redirect URL, description, privacy and terms URLs, key download), then entering the application id, the `.pem` file and a password of twelve characters or more. The status page then shows the connector URL.
36
+
37
+ ## 5. Connector
38
+
39
+ claude.ai (personal Pro or Max account): Settings, Connectors, Add custom connector, name `BankMCP™`, URL `https://<address>/mcp`, leave OAuth fields empty, Add, Connect, enter the password.
40
+
41
+ Team or Enterprise workspaces only allow Owners to add custom connectors; say so if the button is missing.
42
+
43
+ Claude Code: `claude mcp add --transport http bankmcp https://<address>/mcp`, then `/mcp` to sign in.
44
+
45
+ ## 6. Bank
46
+
47
+ In the connected client: "connect my bank". Same flow as locally; the redirect returns to the server's `/callback`.
48
+
49
+ ## Notes
50
+
51
+ - Changing the password later logs every client out; that is the kill switch.
52
+ - Set `NOTIFY_WEBHOOK_URL` to a Slack incoming webhook for sign-in alerts and watch notifications.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: setup
3
+ description: Set up BankMCP™ on this machine step by step: check Node, register the local MCP server, walk through the Enable Banking application, finish the setup page and connect the first bank. Use when the user says "set up bankmcp", "install bankmcp", "/setup", "connect my bank for the first time", or has BankMCP tools that report "not set up yet".
4
+ ---
5
+
6
+ # Set up BankMCP™ locally
7
+
8
+ You are guiding one person through running BankMCP™ on their own machine. Do the steps in order, one at a time, and confirm each before the next. Run commands yourself where you can; ask the user to do the parts that need their browser or their bank login. Do not guess values; read them from command output.
9
+
10
+ ## 1. Node
11
+
12
+ Run `node --version`. BankMCP needs 24 or newer. If it is older or missing, tell the user to install the current LTS from https://nodejs.org and stop until it is done.
13
+
14
+ ## 2. Register the server with Claude Code
15
+
16
+ Run:
17
+
18
+ ```
19
+ claude mcp add --scope user bankmcp -- npx -y bankmcp
20
+ ```
21
+
22
+ Then tell the user to restart Claude Code (or run `/mcp`) so the `bankmcp` tools appear. Wait for them to confirm the tools are listed.
23
+
24
+ ## 3. Find the setup page
25
+
26
+ Call any BankMCP tool, for example `list_accounts`. On a fresh install it answers with a localhost address such as `https://localhost:8080`. Give the user that exact address and tell them:
27
+
28
+ - their browser will warn about a self-signed certificate on localhost; they should continue past it, it is the server they just started;
29
+ - the page lists four values for Enable Banking's form, each with a Copy button.
30
+
31
+ ## 4. Enable Banking application
32
+
33
+ Tell the user to open https://enablebanking.com/cp/applications in another tab, create an account if needed, and add an application:
34
+
35
+ - Environment: **Production** for real accounts, **Sandbox** to try with test data.
36
+ - Paste the redirect URL, description, privacy URL and terms URL from the setup page.
37
+ - Keep "generate private key" selected. On Save a `.pem` file downloads once; the application id (a UUID) is shown after saving.
38
+
39
+ For Production, mention that the application starts Inactive and that clicking **Activate by linking accounts** and logging in at their bank is what activates it for their own accounts.
40
+
41
+ ## 5. Finish the setup page
42
+
43
+ Back on the localhost page: paste the application id, choose the downloaded `.pem`, set the country, click Finish setup. The page turns into a status page. Confirm with the user.
44
+
45
+ ## 6. Connect the first bank
46
+
47
+ Call `list_banks` with the user's country and let them pick. Call `start_consent` with the exact bank name and give them the URL. They log in at the bank and land on a "Bank connected" page. Then call `list_accounts` and show what got linked. Offer labels with `set_account_label`.
48
+
49
+ ## If something fails
50
+
51
+ - Tool says "not set up yet" after setup: the server may need a restart; run `/mcp` and reconnect `bankmcp`.
52
+ - "redirect_uri" errors from Enable Banking: the redirect URL on the application must be exactly the one the setup page showed, including `https://` and the port.
53
+ - Port in use: set `PORT` for the server (for example `claude mcp add --scope user -e PORT=8085 bankmcp -- npx -y bankmcp`) and register the matching redirect URL.