monobank-mcp 2.0.0
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 +174 -0
- package/dist/cache/dedup.d.ts +1 -0
- package/dist/cache/dedup.js +10 -0
- package/dist/cache/dedup.js.map +1 -0
- package/dist/cache/ttl-cache.d.ts +6 -0
- package/dist/cache/ttl-cache.js +20 -0
- package/dist/cache/ttl-cache.js.map +1 -0
- package/dist/client/base.d.ts +5 -0
- package/dist/client/base.js +25 -0
- package/dist/client/base.js.map +1 -0
- package/dist/client/corporate.d.ts +26 -0
- package/dist/client/corporate.js +70 -0
- package/dist/client/corporate.js.map +1 -0
- package/dist/client/personal.d.ts +10 -0
- package/dist/client/personal.js +34 -0
- package/dist/client/personal.js.map +1 -0
- package/dist/client/retry.d.ts +1 -0
- package/dist/client/retry.js +32 -0
- package/dist/client/retry.js.map +1 -0
- package/dist/client/signing.d.ts +6 -0
- package/dist/client/signing.js +24 -0
- package/dist/client/signing.js.map +1 -0
- package/dist/errors/index.d.ts +12 -0
- package/dist/errors/index.js +25 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +89 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/account.d.ts +4 -0
- package/dist/tools/account.js +75 -0
- package/dist/tools/account.js.map +1 -0
- package/dist/tools/corporate-auth.d.ts +3 -0
- package/dist/tools/corporate-auth.js +71 -0
- package/dist/tools/corporate-auth.js.map +1 -0
- package/dist/tools/corporate-settings.d.ts +3 -0
- package/dist/tools/corporate-settings.js +62 -0
- package/dist/tools/corporate-settings.js.map +1 -0
- package/dist/tools/currency.d.ts +4 -0
- package/dist/tools/currency.js +51 -0
- package/dist/tools/currency.js.map +1 -0
- package/dist/tools/jars.d.ts +4 -0
- package/dist/tools/jars.js +59 -0
- package/dist/tools/jars.js.map +1 -0
- package/dist/tools/statement.d.ts +4 -0
- package/dist/tools/statement.js +159 -0
- package/dist/tools/statement.js.map +1 -0
- package/dist/tools/webhook.d.ts +4 -0
- package/dist/tools/webhook.js +101 -0
- package/dist/tools/webhook.js.map +1 -0
- package/dist/types/monobank.d.ts +58 -0
- package/dist/types/monobank.js +13 -0
- package/dist/types/monobank.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://upload.wikimedia.org/wikipedia/commons/d/db/Monobank_logo.svg" alt="Monobank" width="280" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">monobank-mcp</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
MCP server for Monobank Open API — accounts, transactions, exchange rates, jars & webhooks for Claude and other LLM clients.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/monobank-mcp"><img src="https://img.shields.io/npm/v/monobank-mcp" alt="npm version" /></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/monobank-mcp"><img src="https://img.shields.io/npm/dm/monobank-mcp" alt="npm downloads" /></a>
|
|
14
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a>
|
|
15
|
+
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen?logo=node.js&logoColor=white" alt="Node.js" /></a>
|
|
16
|
+
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white" alt="TypeScript" /></a>
|
|
17
|
+
<a href="https://modelcontextprotocol.io"><img src="https://badge.mcpx.dev?type=server&features=tools,resources,prompts" alt="MCP" /></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="https://insiders.vscode.dev/redirect/mcp/install?name=monobank&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22monobank-mcp%22%5D%2C%22env%22%3A%7B%22MONOBANK_TOKEN%22%3A%22%24%7Binput%3Amonobank-token%7D%22%7D%7D"><img src="https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white" alt="Install in VS Code" /></a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
- **8 Personal API tools** — accounts, statements, exchange rates, jars, webhooks
|
|
29
|
+
- **4 Corporate API tools** — ECDSA signing, multi-user auth flow, zero rate limits
|
|
30
|
+
- **Smart caching** — respects Monobank's 1 req/60s limit automatically
|
|
31
|
+
- **Retry with backoff** — exponential retry on transient failures
|
|
32
|
+
- **Request deduplication** — concurrent identical calls merged into one HTTP request
|
|
33
|
+
- **Resources & Prompts** — exchange rates as context, spending analysis template
|
|
34
|
+
- **English-first docs** — full API reference, agent setup guide, corporate guide
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
Get your token at **https://api.monobank.ua/** (scan QR with Monobank app), then:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx -y monobank-mcp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
### Claude Desktop
|
|
47
|
+
|
|
48
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"monobank": {
|
|
54
|
+
"command": "npx",
|
|
55
|
+
"args": ["-y", "monobank-mcp"],
|
|
56
|
+
"env": {
|
|
57
|
+
"MONOBANK_TOKEN": "your_token_here"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### VS Code / Cursor
|
|
65
|
+
|
|
66
|
+
Add to `.vscode/mcp.json` or `.cursor/mcp.json`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"servers": {
|
|
71
|
+
"monobank": {
|
|
72
|
+
"command": "npx",
|
|
73
|
+
"args": ["-y", "monobank-mcp"],
|
|
74
|
+
"env": {
|
|
75
|
+
"MONOBANK_TOKEN": "your_token_here"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Claude Code
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
claude mcp add monobank -- npx -y monobank-mcp
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Then set `MONOBANK_TOKEN` in your environment.
|
|
89
|
+
|
|
90
|
+
## Tools
|
|
91
|
+
|
|
92
|
+
### Personal API
|
|
93
|
+
|
|
94
|
+
| Tool | Description |
|
|
95
|
+
|------|-------------|
|
|
96
|
+
| `get_client_info` | Client profile, all accounts and jars with balances, IBANs |
|
|
97
|
+
| `get_statement` | Transaction history for any date range (max 31 days) |
|
|
98
|
+
| `get_recent_transactions` | Latest N transactions from the last X minutes |
|
|
99
|
+
| `get_exchange_rates` | Current UAH/USD/EUR and 100+ exchange rate pairs |
|
|
100
|
+
| `get_jars` | Savings jars with balances, goals, and progress |
|
|
101
|
+
| `set_webhook` | Register a URL for real-time transaction events |
|
|
102
|
+
| `delete_webhook` | Stop receiving webhook notifications |
|
|
103
|
+
| `get_webhook_status` | Check currently registered webhook URL |
|
|
104
|
+
|
|
105
|
+
### Corporate API
|
|
106
|
+
|
|
107
|
+
Available when `MONOBANK_AUTH_MODE=corporate`. See [Corporate API Setup](docs/CORPORATE_API.md).
|
|
108
|
+
|
|
109
|
+
| Tool | Description |
|
|
110
|
+
|------|-------------|
|
|
111
|
+
| `initiate_authorization` | Start user auth flow, returns Monobank app URL |
|
|
112
|
+
| `check_authorization` | Check if user approved the auth request |
|
|
113
|
+
| `get_corp_settings` | Get corporate app settings (key, name, webhook) |
|
|
114
|
+
| `set_corp_webhook` | Set webhook URL for the corporate application |
|
|
115
|
+
|
|
116
|
+
## Resources
|
|
117
|
+
|
|
118
|
+
| Resource | URI | Description |
|
|
119
|
+
|----------|-----|-------------|
|
|
120
|
+
| Exchange Rates | `monobank://exchange-rates` | Current exchange rates as background context |
|
|
121
|
+
|
|
122
|
+
## Prompts
|
|
123
|
+
|
|
124
|
+
| Prompt | Description |
|
|
125
|
+
|--------|-------------|
|
|
126
|
+
| `spending-analysis` | Analyze spending patterns for a given period (week / month / quarter) |
|
|
127
|
+
|
|
128
|
+
## Rate Limits
|
|
129
|
+
|
|
130
|
+
| Endpoint | Personal API | Corporate API |
|
|
131
|
+
|----------|-------------|---------------|
|
|
132
|
+
| `client-info` | 1 req / 60s | Unlimited |
|
|
133
|
+
| `statement` | 1 req / 60s | Unlimited |
|
|
134
|
+
| `currency` | No limit | No limit |
|
|
135
|
+
| `webhook` | No limit | No limit |
|
|
136
|
+
|
|
137
|
+
The server caches responses automatically (59s for rate-limited endpoints, 5 min for exchange rates). Retry with exponential backoff handles transient failures.
|
|
138
|
+
|
|
139
|
+
## Environment Variables
|
|
140
|
+
|
|
141
|
+
| Variable | Required | Description |
|
|
142
|
+
|----------|----------|-------------|
|
|
143
|
+
| `MONOBANK_TOKEN` | Personal mode | Token from https://api.monobank.ua/ |
|
|
144
|
+
| `MONOBANK_AUTH_MODE` | No | `personal` (default) or `corporate` |
|
|
145
|
+
| `MONOBANK_KEY_ID` | Corporate mode | SHA1 hash of your public key |
|
|
146
|
+
| `MONOBANK_PRIVATE_KEY_PATH` | Corporate mode | Path to ECDSA secp256k1 private key |
|
|
147
|
+
| `MONOBANK_PRIVATE_KEY_PEM` | Corporate mode | PEM string (alternative to file path) |
|
|
148
|
+
|
|
149
|
+
## Docker
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
docker build -t monobank-mcp .
|
|
153
|
+
docker run -e MONOBANK_TOKEN=your_token monobank-mcp
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Development
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
git clone https://github.com/serhiizghama/monobank-mcp.git
|
|
160
|
+
cd monobank-mcp
|
|
161
|
+
npm install
|
|
162
|
+
npm run build
|
|
163
|
+
npm test
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Documentation
|
|
167
|
+
|
|
168
|
+
- [API Reference](docs/API_REFERENCE.md) — full tool/resource/prompt reference with examples
|
|
169
|
+
- [Corporate API Setup](docs/CORPORATE_API.md) — ECDSA key generation, auth flow
|
|
170
|
+
- [Agent Setup Guide](docs/AGENT_SETUP.md) — instructions for AI agents to auto-install
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function dedup<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const inflight = new Map();
|
|
2
|
+
export async function dedup(key, fn) {
|
|
3
|
+
const existing = inflight.get(key);
|
|
4
|
+
if (existing)
|
|
5
|
+
return existing;
|
|
6
|
+
const promise = fn().finally(() => inflight.delete(key));
|
|
7
|
+
inflight.set(key, promise);
|
|
8
|
+
return promise;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=dedup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/cache/dedup.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,KAAK,CAAI,GAAW,EAAE,EAAoB;IAC9D,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ;QAAE,OAAO,QAAsB,CAAC;IAE5C,MAAM,OAAO,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class TtlCache {
|
|
2
|
+
store = new Map();
|
|
3
|
+
get(key) {
|
|
4
|
+
const entry = this.store.get(key);
|
|
5
|
+
if (!entry)
|
|
6
|
+
return undefined;
|
|
7
|
+
if (Date.now() > entry.expiresAt) {
|
|
8
|
+
this.store.delete(key);
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
return entry.data;
|
|
12
|
+
}
|
|
13
|
+
set(key, data, ttlSeconds) {
|
|
14
|
+
this.store.set(key, { data, expiresAt: Date.now() + ttlSeconds * 1000 });
|
|
15
|
+
}
|
|
16
|
+
invalidate(key) {
|
|
17
|
+
this.store.delete(key);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ttl-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ttl-cache.js","sourceRoot":"","sources":["../../src/cache/ttl-cache.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,QAAQ;IACX,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IAEvD,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,IAAS,CAAC;IACzB,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,IAAO,EAAE,UAAkB;QAC7C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,UAAU,CAAC,GAAW;QACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AuthError, MonobankError, RateLimitError } from '../errors/index.js';
|
|
2
|
+
const BASE_URL = 'https://api.monobank.ua';
|
|
3
|
+
export async function apiFetch(path, options = {}) {
|
|
4
|
+
const response = await fetch(`${BASE_URL}${path}`, {
|
|
5
|
+
method: options.method ?? 'GET',
|
|
6
|
+
headers: { 'Content-Type': 'application/json', ...options.headers },
|
|
7
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
8
|
+
});
|
|
9
|
+
if (response.ok) {
|
|
10
|
+
const text = await response.text();
|
|
11
|
+
return text ? JSON.parse(text) : undefined;
|
|
12
|
+
}
|
|
13
|
+
if (response.status === 401)
|
|
14
|
+
throw new AuthError();
|
|
15
|
+
if (response.status === 403)
|
|
16
|
+
throw new AuthError('Access denied. Token may lack required permissions.');
|
|
17
|
+
if (response.status === 429) {
|
|
18
|
+
const retryAfter = parseInt(response.headers.get('Retry-After') ?? '60', 10);
|
|
19
|
+
throw new RateLimitError(retryAfter);
|
|
20
|
+
}
|
|
21
|
+
const errorBody = await response.text().catch(() => '');
|
|
22
|
+
const message = errorBody || `HTTP ${response.status}`;
|
|
23
|
+
throw new MonobankError('server', message, undefined, response.status);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/client/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE9E,MAAM,QAAQ,GAAG,yBAAyB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,UAII,EAAE;IAEN,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,GAAG,IAAI,EAAE,EAAE;QACjD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;QAC/B,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE;QACnE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9D,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAO,CAAC,CAAC,CAAE,SAAe,CAAC;IAC3D,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,MAAM,IAAI,SAAS,EAAE,CAAC;IACnD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAC;IAExG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7E,MAAM,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,SAAS,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;IACvD,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ClientInfo, ExchangeRate, StatementItem } from '../types/monobank.js';
|
|
2
|
+
export interface CorpSettings {
|
|
3
|
+
pubkey: string;
|
|
4
|
+
name: string;
|
|
5
|
+
permission: string;
|
|
6
|
+
logo: string;
|
|
7
|
+
webhook: string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare class CorporateClient {
|
|
10
|
+
private readonly signingConfig;
|
|
11
|
+
constructor(keyId: string, privateKeyPem: string);
|
|
12
|
+
private userHeaders;
|
|
13
|
+
private corpHeaders;
|
|
14
|
+
getClientInfo(requestId: string): Promise<ClientInfo>;
|
|
15
|
+
getStatement(requestId: string, accountId: string, from: number, to?: number): Promise<StatementItem[]>;
|
|
16
|
+
initiateAuthorization(callbackUrl: string, permissions?: string): Promise<{
|
|
17
|
+
tokenRequestId: string;
|
|
18
|
+
acceptUrl: string;
|
|
19
|
+
}>;
|
|
20
|
+
checkAuthorization(requestId: string): Promise<{
|
|
21
|
+
status: string;
|
|
22
|
+
}>;
|
|
23
|
+
getCorpSettings(): Promise<CorpSettings>;
|
|
24
|
+
setCorpWebhook(url: string): Promise<void>;
|
|
25
|
+
getExchangeRates(): Promise<ExchangeRate[]>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { dedup } from '../cache/dedup.js';
|
|
2
|
+
import { apiFetch } from './base.js';
|
|
3
|
+
import { withRetry } from './retry.js';
|
|
4
|
+
import { signRequest } from './signing.js';
|
|
5
|
+
export class CorporateClient {
|
|
6
|
+
signingConfig;
|
|
7
|
+
constructor(keyId, privateKeyPem) {
|
|
8
|
+
this.signingConfig = { keyId, privateKeyPem };
|
|
9
|
+
}
|
|
10
|
+
userHeaders(path, requestId) {
|
|
11
|
+
return {
|
|
12
|
+
...signRequest(this.signingConfig, path, requestId),
|
|
13
|
+
'X-Request-Id': requestId,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
corpHeaders(path) {
|
|
17
|
+
return signRequest(this.signingConfig, path, '');
|
|
18
|
+
}
|
|
19
|
+
// --- Per-user endpoints (require requestId from auth flow) ---
|
|
20
|
+
async getClientInfo(requestId) {
|
|
21
|
+
const path = '/personal/client-info';
|
|
22
|
+
return dedup(`corp:client-info:${requestId}`, () => withRetry(() => apiFetch(path, { headers: this.userHeaders(path, requestId) })));
|
|
23
|
+
}
|
|
24
|
+
async getStatement(requestId, accountId, from, to) {
|
|
25
|
+
const path = to
|
|
26
|
+
? `/personal/statement/${accountId}/${from}/${to}`
|
|
27
|
+
: `/personal/statement/${accountId}/${from}`;
|
|
28
|
+
return dedup(`corp:statement:${path}:${requestId}`, () => withRetry(() => apiFetch(path, { headers: this.userHeaders(path, requestId) })));
|
|
29
|
+
}
|
|
30
|
+
// --- Auth flow endpoints ---
|
|
31
|
+
async initiateAuthorization(callbackUrl, permissions = 'sp') {
|
|
32
|
+
const path = '/personal/auth/request';
|
|
33
|
+
const sigHeaders = signRequest(this.signingConfig, path, permissions);
|
|
34
|
+
return withRetry(() => apiFetch(path, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: {
|
|
37
|
+
...sigHeaders,
|
|
38
|
+
'X-Callback': callbackUrl,
|
|
39
|
+
'X-Permissions': permissions,
|
|
40
|
+
},
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
async checkAuthorization(requestId) {
|
|
44
|
+
const path = '/personal/auth/request';
|
|
45
|
+
const sigHeaders = signRequest(this.signingConfig, path, requestId);
|
|
46
|
+
return withRetry(() => apiFetch(path, {
|
|
47
|
+
headers: {
|
|
48
|
+
...sigHeaders,
|
|
49
|
+
'X-Request-Id': requestId,
|
|
50
|
+
},
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
// --- Corp-level endpoints (no user context) ---
|
|
54
|
+
async getCorpSettings() {
|
|
55
|
+
const path = '/personal/corp/settings';
|
|
56
|
+
return withRetry(() => apiFetch(path, { headers: this.corpHeaders(path) }));
|
|
57
|
+
}
|
|
58
|
+
async setCorpWebhook(url) {
|
|
59
|
+
const path = '/personal/corp/webhook';
|
|
60
|
+
await withRetry(() => apiFetch(path, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: this.corpHeaders(path),
|
|
63
|
+
body: { webHookUrl: url },
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
async getExchangeRates() {
|
|
67
|
+
return dedup('exchange-rates', () => withRetry(() => apiFetch('/bank/currency')));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=corporate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"corporate.js","sourceRoot":"","sources":["../../src/client/corporate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ClientInfo, ExchangeRate, StatementItem } from '../types/monobank.js';
|
|
2
|
+
export declare class PersonalClient {
|
|
3
|
+
private readonly token;
|
|
4
|
+
constructor(token: string);
|
|
5
|
+
private headers;
|
|
6
|
+
getClientInfo(): Promise<ClientInfo>;
|
|
7
|
+
getStatement(accountId: string, from: number, to?: number): Promise<StatementItem[]>;
|
|
8
|
+
setWebhook(url: string): Promise<void>;
|
|
9
|
+
getExchangeRates(): Promise<ExchangeRate[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { dedup } from '../cache/dedup.js';
|
|
2
|
+
import { apiFetch } from './base.js';
|
|
3
|
+
import { withRetry } from './retry.js';
|
|
4
|
+
export class PersonalClient {
|
|
5
|
+
token;
|
|
6
|
+
constructor(token) {
|
|
7
|
+
this.token = token;
|
|
8
|
+
}
|
|
9
|
+
headers() {
|
|
10
|
+
return { 'X-Token': this.token };
|
|
11
|
+
}
|
|
12
|
+
async getClientInfo() {
|
|
13
|
+
return dedup('client-info', () => withRetry(() => apiFetch('/personal/client-info', {
|
|
14
|
+
headers: this.headers(),
|
|
15
|
+
})));
|
|
16
|
+
}
|
|
17
|
+
async getStatement(accountId, from, to) {
|
|
18
|
+
const path = to
|
|
19
|
+
? `/personal/statement/${accountId}/${from}/${to}`
|
|
20
|
+
: `/personal/statement/${accountId}/${from}`;
|
|
21
|
+
return dedup(`statement:${path}`, () => withRetry(() => apiFetch(path, { headers: this.headers() })));
|
|
22
|
+
}
|
|
23
|
+
async setWebhook(url) {
|
|
24
|
+
await withRetry(() => apiFetch('/personal/webhook', {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: this.headers(),
|
|
27
|
+
body: { webHookUrl: url },
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
async getExchangeRates() {
|
|
31
|
+
return dedup('exchange-rates', () => withRetry(() => apiFetch('/bank/currency')));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=personal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"personal.js","sourceRoot":"","sources":["../../src/client/personal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;IAAG,CAAC;IAEtC,OAAO;QACb,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,OAAO,KAAK,CAAC,aAAa,EAAE,GAAG,EAAE,CAC/B,SAAS,CAAC,GAAG,EAAE,CACb,QAAQ,CAAa,uBAAuB,EAAE;YAC5C,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;SACxB,CAAC,CACH,CACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,SAAiB,EACjB,IAAY,EACZ,EAAW;QAEX,MAAM,IAAI,GAAG,EAAE;YACb,CAAC,CAAC,uBAAuB,SAAS,IAAI,IAAI,IAAI,EAAE,EAAE;YAClD,CAAC,CAAC,uBAAuB,SAAS,IAAI,IAAI,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC,aAAa,IAAI,EAAE,EAAE,GAAG,EAAE,CACrC,SAAS,CAAC,GAAG,EAAE,CACb,QAAQ,CAAkB,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAC7D,CACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAW;QAC1B,MAAM,SAAS,CAAC,GAAG,EAAE,CACnB,QAAQ,CAAO,mBAAmB,EAAE;YAClC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;YACvB,IAAI,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE;SAC1B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO,KAAK,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAClC,SAAS,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAiB,gBAAgB,CAAC,CAAC,CAC5D,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function withRetry<T>(fn: () => Promise<T>, maxAttempts?: number): Promise<T>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AuthError, MonobankError, RateLimitError } from '../errors/index.js';
|
|
2
|
+
const BACKOFF_DELAYS_MS = [2000, 4000, 8000, 16000, 32000];
|
|
3
|
+
function sleep(ms) {
|
|
4
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
}
|
|
6
|
+
export async function withRetry(fn, maxAttempts = 3) {
|
|
7
|
+
let lastError;
|
|
8
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
9
|
+
try {
|
|
10
|
+
return await fn();
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
lastError = err;
|
|
14
|
+
if (err instanceof AuthError)
|
|
15
|
+
throw err;
|
|
16
|
+
if (err instanceof MonobankError && err.category === 'validation')
|
|
17
|
+
throw err;
|
|
18
|
+
if (err instanceof RateLimitError) {
|
|
19
|
+
const delay = err.retryAfterSeconds
|
|
20
|
+
? err.retryAfterSeconds * 1000
|
|
21
|
+
: (BACKOFF_DELAYS_MS[attempt] ?? 32000);
|
|
22
|
+
await sleep(delay);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (attempt < maxAttempts - 1) {
|
|
26
|
+
await sleep(BACKOFF_DELAYS_MS[attempt] ?? 32000);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
throw lastError;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/client/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE9E,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAE3D,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,WAAW,GAAG,CAAC;IAEf,IAAI,SAAkB,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAEhB,IAAI,GAAG,YAAY,SAAS;gBAAE,MAAM,GAAG,CAAC;YACxC,IAAI,GAAG,YAAY,aAAa,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY;gBAAE,MAAM,GAAG,CAAC;YAE7E,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;gBAClC,MAAM,KAAK,GAAG,GAAG,CAAC,iBAAiB;oBACjC,CAAC,CAAC,GAAG,CAAC,iBAAiB,GAAG,IAAI;oBAC9B,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC;gBAC1C,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;gBACnB,SAAS;YACX,CAAC;YAED,IAAI,OAAO,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createSign } from 'node:crypto';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
export function signRequest(config, requestPath, secondIngredient = '') {
|
|
4
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
5
|
+
const dataToSign = `${timestamp}${secondIngredient}${requestPath}`;
|
|
6
|
+
const signer = createSign('SHA256');
|
|
7
|
+
signer.update(dataToSign);
|
|
8
|
+
const signature = signer.sign(config.privateKeyPem, 'base64');
|
|
9
|
+
return {
|
|
10
|
+
'X-Key-Id': config.keyId,
|
|
11
|
+
'X-Time': timestamp.toString(),
|
|
12
|
+
'X-Sign': signature,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function loadPrivateKey() {
|
|
16
|
+
if (process.env.MONOBANK_PRIVATE_KEY_PEM) {
|
|
17
|
+
return process.env.MONOBANK_PRIVATE_KEY_PEM.replace(/\\n/g, '\n');
|
|
18
|
+
}
|
|
19
|
+
const path = process.env.MONOBANK_PRIVATE_KEY_PATH;
|
|
20
|
+
if (path)
|
|
21
|
+
return readFileSync(path, 'utf-8');
|
|
22
|
+
throw new Error('Corporate API requires MONOBANK_PRIVATE_KEY_PEM or MONOBANK_PRIVATE_KEY_PATH');
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../src/client/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAOvC,MAAM,UAAU,WAAW,CACzB,MAAqB,EACrB,WAAmB,EACnB,mBAA2B,EAAE;IAE7B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,GAAG,SAAS,GAAG,gBAAgB,GAAG,WAAW,EAAE,CAAC;IAEnE,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC1B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAE9D,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,KAAK;QACxB,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE;QAC9B,QAAQ,EAAE,SAAS;KACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC;QACzC,OAAO,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACnD,IAAI,IAAI;QAAE,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;AAClG,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class MonobankError extends Error {
|
|
2
|
+
readonly category: 'auth' | 'rate_limit' | 'validation' | 'not_found' | 'server';
|
|
3
|
+
readonly retryAfterSeconds?: number | undefined;
|
|
4
|
+
readonly statusCode?: number | undefined;
|
|
5
|
+
constructor(category: 'auth' | 'rate_limit' | 'validation' | 'not_found' | 'server', message: string, retryAfterSeconds?: number | undefined, statusCode?: number | undefined);
|
|
6
|
+
}
|
|
7
|
+
export declare class RateLimitError extends MonobankError {
|
|
8
|
+
constructor(retryAfterSeconds: number);
|
|
9
|
+
}
|
|
10
|
+
export declare class AuthError extends MonobankError {
|
|
11
|
+
constructor(message?: string);
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class MonobankError extends Error {
|
|
2
|
+
category;
|
|
3
|
+
retryAfterSeconds;
|
|
4
|
+
statusCode;
|
|
5
|
+
constructor(category, message, retryAfterSeconds, statusCode) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.category = category;
|
|
8
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
this.name = 'MonobankError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class RateLimitError extends MonobankError {
|
|
14
|
+
constructor(retryAfterSeconds) {
|
|
15
|
+
super('rate_limit', `Rate limit exceeded. Retry after ${retryAfterSeconds} seconds.`, retryAfterSeconds);
|
|
16
|
+
this.name = 'RateLimitError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class AuthError extends MonobankError {
|
|
20
|
+
constructor(message = 'Invalid or missing token. Get your token at https://api.monobank.ua/') {
|
|
21
|
+
super('auth', message, undefined, 401);
|
|
22
|
+
this.name = 'AuthError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,aAAc,SAAQ,KAAK;IAEpB;IAEA;IACA;IAJlB,YACkB,QAAuE,EACvF,OAAe,EACC,iBAA0B,EAC1B,UAAmB;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,aAAQ,GAAR,QAAQ,CAA+D;QAEvE,sBAAiB,GAAjB,iBAAiB,CAAS;QAC1B,eAAU,GAAV,UAAU,CAAS;QAGnC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,aAAa;IAC/C,YAAY,iBAAyB;QACnC,KAAK,CACH,YAAY,EACZ,oCAAoC,iBAAiB,WAAW,EAChE,iBAAiB,CAClB,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,SAAU,SAAQ,aAAa;IAC1C,YAAY,OAAO,GAAG,sEAAsE;QAC1F,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createServer } from './server.js';
|
|
4
|
+
async function main() {
|
|
5
|
+
const transport = new StdioServerTransport();
|
|
6
|
+
const server = createServer();
|
|
7
|
+
await server.connect(transport);
|
|
8
|
+
console.error('Monobank MCP server running on stdio');
|
|
9
|
+
}
|
|
10
|
+
main().catch((error) => {
|
|
11
|
+
console.error('Fatal error:', error);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;AACxD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED