;
abstract getConfigSchema(): ConfigField[];
}
```
## Provider Setup Guides
### Enable Banking (PSD2)
**What you need:**
- [ ] An [Enable Banking](https://enablebanking.com) account with a registered app
- [ ] Your RSA private key (`.pem` file, downloaded when you created the app)
```bash
npx @bank-mcp/server init
# Select: Enable Banking โ enter App ID + key path
# Pick your country โ select your bank
# Log in at your bank โ paste the redirect URL
# โ Session created, accounts verified!
```
> **Tip:** The wizard handles the entire OAuth flow โ redirect URI setup, bank selection, and session creation. Sessions expire after 90 days (PSD2 regulation); re-run `init` to refresh.
### Teller (US Banks)
**What you need:**
- [ ] A [Teller](https://teller.io) developer account
- [ ] Your Application ID (from the Teller dashboard)
```bash
npx @bank-mcp/server init
# Select: Teller โ enter Application ID
# Pick environment (sandbox for testing)
# โ Teller Connect opens in your browser
# โ Link your bank, token captured automatically!
```
> **Tip:** Start with **sandbox** โ no certificates needed, instant test data. For development/production, the wizard prompts for mTLS certificate paths. Free tier supports up to 100 live connections.
### Plaid (US/CA/EU)
**What you need:**
- [ ] A [Plaid](https://plaid.com) developer account (free signup)
- [ ] Your Client ID and Secret (from the [Plaid dashboard](https://dashboard.plaid.com/developers/keys))
```bash
npx @bank-mcp/server init
# Select: Plaid โ enter client ID + secret
# Pick environment (sandbox for testing)
# โ Sandbox: token created automatically!
# โ Dev/Prod: paste an existing access token
```
> **Tip:** Start with **sandbox** โ the wizard auto-creates a test token, no browser needed. Plaid provides the richest transaction categorization โ 104 sub-categories with confidence scores โ ideal for LLM-driven spending analysis.
### Tink (EU Open Banking)
**What you need:**
- [ ] A [Tink](https://tink.com) developer account (free for testing)
- [ ] Your Client ID and Client Secret (from the [Tink Console](https://console.tink.com))
```bash
npx @bank-mcp/server init
# Select: Tink โ enter Client ID + Secret
# Pick your market (country)
# โ Tink Link opens in your browser
# โ Connect your bank, paste redirect URL
```
> **Tip:** Tink covers 3,400+ banks across Europe. For sandbox, use Demo Bank with test credentials (shown in the wizard). Transactions include PFM categories with merchant enrichment.
## Caching
All data is cached in-memory (no disk persistence โ cache dies with the process):
| Data | TTL | Why |
|------|-----|-----|
| Account list | 1 hour | Accounts rarely change; minimizes API calls |
| Transactions | 15 minutes | Balances new transactions vs freshness |
| Balances | 5 minutes | Most time-sensitive; users expect current data |
Cache is per-connection and per-account. Restarting the server clears all caches.
## Multiple Connections
Configure as many bank connections as you need โ even across different providers:
```json
{
"connections": [
{ "id": "ing-main", "provider": "enable-banking", "..." : "..." },
{ "id": "chase-checking", "provider": "plaid", "..." : "..." },
{ "id": "revolut", "provider": "tink", "..." : "..." }
]
}
```
All tools accept an optional `connectionId` parameter to target a specific connection. When omitted, every connection is queried and results are merged โ so "show all my balances" works across banks automatically.
## Security
### Design Principles
bank-mcp handles sensitive financial credentials. Its security posture is built on minimizing attack surface:
- **Read-only by design** โ the `BankProvider` interface exposes only read methods (`listAccounts`, `listTransactions`, `getBalance`). There are no write methods โ no transfers, no account modifications, no payment initiation. This is enforced at the type level, not by convention.
- **No network listener** โ bank-mcp runs as a stdio process (stdin/stdout), not an HTTP server. There is no open port, no attack surface from the network.
- **Minimal dependencies** โ only 4 runtime dependencies (`@modelcontextprotocol/sdk`, `@clack/prompts`, `jsonwebtoken`, `zod`). Fewer dependencies means fewer supply chain risks.
- **Open source** โ every line is auditable. No obfuscated code, no compiled blobs, no telemetry.
### Credential Storage
- Config file at `~/.bank-mcp/config.json` is created with **`600` permissions** (owner read/write only)
- RSA keys and certificates are stored in `~/.bank-mcp/keys/` with the same restrictive permissions
- Credentials are **never logged** โ the server sanitizes config objects before any debug output
- No credential caching beyond the process lifetime โ when the server stops, credentials exist only on disk
### Data Flow
```
Your Bank's API โ HTTPS โ bank-mcp (local process) โ stdio โ MCP Client (local)
```
- Transaction data flows directly from your bank's API to your local MCP client
- **Nothing is stored remotely** โ no cloud relay, no proxy server, no intermediate storage
- **No telemetry** โ zero analytics, no crash reports, no usage tracking, no phone-home
- In-memory cache is per-process and dies when the server stops
### What Your MCP Client Sees
The MCP client (Claude, Cursor, etc.) receives structured tool results containing:
- Account names, types, and balances
- Transaction descriptions, amounts, dates, and categories
- Spending summaries
The LLM processes this in its context window. Be aware that cloud-hosted LLMs send your conversation (including tool results) to their servers. If this is a concern, use a local model or review your provider's data retention policy.
### Recommendations
- **Rotate tokens** โ if your banking provider supports token rotation, enable it
- **Use sandbox first** โ test your setup with mock data or Plaid sandbox before connecting live accounts
- **Review permissions** โ ensure `~/.bank-mcp/` is not world-readable (`ls -la ~/.bank-mcp/`)
- **Scope access** โ if your provider supports it, request the minimum scopes needed (read-only account and transaction access)
### Reporting Vulnerabilities
If you discover a security issue, please email the maintainer directly rather than opening a public issue. See [CONTRIBUTING.md](CONTRIBUTING.md) for contact details.
## Adding a New Provider
The pluggable architecture makes it straightforward to add support for additional banking APIs:
1. **Create your provider** at `src/providers/your-provider/index.ts`
2. **Extend `BankProvider`** โ implement `listAccounts`, `listTransactions`, `getBalance`, and `getConfigSchema`
3. **Register it** in `src/providers/registry.ts`
4. **Add an init flow** at `src/init/flows/your-provider.ts` โ interactive setup using `@clack/prompts`
See [`src/providers/enable-banking/`](src/providers/enable-banking/) as a reference implementation. The mock provider at [`src/providers/mock/`](src/providers/mock/) is also useful for understanding the expected data shapes.
## Troubleshooting
**`npx` is running an old version**
npx caches packages. Force the latest:
```bash
npx @bank-mcp/server@latest
```
**"Permission denied" reading config**
The config file should be readable by your user:
```bash
ls -la ~/.bank-mcp/config.json
# Should show: -rw------- (600)
# Fix: chmod 600 ~/.bank-mcp/config.json
```
**"Session expired" (Enable Banking)**
PSD2 sessions expire after 90 days. Re-run the init wizard:
```bash
npx @bank-mcp/server init
# Select your existing Enable Banking connection to update the session
```
**Tools not showing up in your MCP client**
1. Verify the server starts: `npx @bank-mcp/server --mock` (should output MCP protocol on stdout)
2. Check your config file path matches your client's expected location
3. Restart your MCP client after adding the config
4. Check your client's MCP logs for connection errors
**"ETLS" or certificate errors (Teller)**
Teller requires mTLS. Verify your certificate files:
```bash
ls -la ~/.bank-mcp/keys/teller/
# Should contain: certificate.pem, private_key.pem
# Both should be chmod 600
```
## Development
```bash
git clone https://github.com/elcukro/bank-mcp.git
cd bank-mcp
npm install
npm test # Run tests (vitest)
npm run build # Compile TypeScript
npm run dev # Watch mode (recompile on change)
npm run lint # ESLint
```
## Contributing
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
If you're adding a new provider, open an issue first to discuss the approach โ we want to make sure the integration fits the project's architecture.
## License
[MIT](LICENSE) โ use it however you want.
---
Built for the Model Context Protocol ecosystem