@guiie/buda-mcp 1.5.1 → 1.5.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/CHANGELOG.md +61 -0
- package/PUBLISH_CHECKLIST.md +56 -36
- package/dist/audit.d.ts +21 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +14 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +6 -1
- package/dist/http.js +47 -15
- package/dist/tools/account.js +1 -1
- package/dist/tools/arbitrage.js +1 -1
- package/dist/tools/balance.js +1 -1
- package/dist/tools/balances.js +1 -1
- package/dist/tools/banks.js +1 -1
- package/dist/tools/batch_orders.d.ts +2 -2
- package/dist/tools/batch_orders.d.ts.map +1 -1
- package/dist/tools/batch_orders.js +14 -4
- package/dist/tools/cancel_all_orders.d.ts +2 -2
- package/dist/tools/cancel_all_orders.d.ts.map +1 -1
- package/dist/tools/cancel_all_orders.js +12 -15
- package/dist/tools/cancel_order.d.ts +2 -2
- package/dist/tools/cancel_order.d.ts.map +1 -1
- package/dist/tools/cancel_order.js +11 -11
- package/dist/tools/cancel_order_by_client_id.d.ts +2 -2
- package/dist/tools/cancel_order_by_client_id.d.ts.map +1 -1
- package/dist/tools/cancel_order_by_client_id.js +11 -11
- package/dist/tools/compare_markets.d.ts +9 -0
- package/dist/tools/compare_markets.d.ts.map +1 -1
- package/dist/tools/compare_markets.js +63 -53
- package/dist/tools/dead_mans_switch.d.ts +1 -1
- package/dist/tools/dead_mans_switch.d.ts.map +1 -1
- package/dist/tools/dead_mans_switch.js +35 -3
- package/dist/tools/deposits.js +2 -2
- package/dist/tools/fees.js +1 -1
- package/dist/tools/lightning.d.ts +2 -2
- package/dist/tools/lightning.d.ts.map +1 -1
- package/dist/tools/lightning.js +13 -11
- package/dist/tools/market_sentiment.js +1 -1
- package/dist/tools/market_summary.js +1 -1
- package/dist/tools/markets.js +1 -1
- package/dist/tools/order_lookup.js +2 -2
- package/dist/tools/orderbook.js +1 -1
- package/dist/tools/orders.js +1 -1
- package/dist/tools/place_order.d.ts +2 -2
- package/dist/tools/place_order.d.ts.map +1 -1
- package/dist/tools/place_order.js +24 -6
- package/dist/tools/price_history.js +1 -1
- package/dist/tools/quotation.js +1 -1
- package/dist/tools/receive_addresses.d.ts +2 -2
- package/dist/tools/receive_addresses.d.ts.map +1 -1
- package/dist/tools/receive_addresses.js +13 -13
- package/dist/tools/remittance_recipients.js +2 -2
- package/dist/tools/remittances.d.ts +3 -3
- package/dist/tools/remittances.d.ts.map +1 -1
- package/dist/tools/remittances.js +22 -23
- package/dist/tools/simulate_order.js +1 -1
- package/dist/tools/spread.js +1 -1
- package/dist/tools/technical_indicators.js +1 -1
- package/dist/tools/ticker.js +1 -1
- package/dist/tools/trades.js +1 -1
- package/dist/tools/volume.js +1 -1
- package/dist/tools/withdrawals.d.ts +2 -2
- package/dist/tools/withdrawals.d.ts.map +1 -1
- package/dist/tools/withdrawals.js +12 -12
- package/dist/utils.d.ts +10 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +25 -0
- package/package.json +2 -1
- package/server.json +2 -2
- package/src/audit.ts +24 -0
- package/src/client.ts +9 -1
- package/src/http.ts +50 -15
- package/src/tools/account.ts +1 -1
- package/src/tools/arbitrage.ts +1 -1
- package/src/tools/balance.ts +1 -1
- package/src/tools/balances.ts +1 -1
- package/src/tools/banks.ts +1 -1
- package/src/tools/batch_orders.ts +18 -3
- package/src/tools/cancel_all_orders.ts +16 -14
- package/src/tools/cancel_order.ts +15 -10
- package/src/tools/cancel_order_by_client_id.ts +15 -10
- package/src/tools/compare_markets.ts +78 -61
- package/src/tools/dead_mans_switch.ts +37 -2
- package/src/tools/deposits.ts +2 -2
- package/src/tools/fees.ts +1 -1
- package/src/tools/lightning.ts +18 -11
- package/src/tools/market_sentiment.ts +1 -1
- package/src/tools/market_summary.ts +1 -1
- package/src/tools/markets.ts +1 -1
- package/src/tools/order_lookup.ts +2 -2
- package/src/tools/orderbook.ts +1 -1
- package/src/tools/orders.ts +1 -1
- package/src/tools/place_order.ts +30 -7
- package/src/tools/price_history.ts +1 -1
- package/src/tools/quotation.ts +1 -1
- package/src/tools/receive_addresses.ts +17 -12
- package/src/tools/remittance_recipients.ts +2 -2
- package/src/tools/remittances.ts +26 -21
- package/src/tools/simulate_order.ts +1 -1
- package/src/tools/spread.ts +1 -1
- package/src/tools/technical_indicators.ts +1 -1
- package/src/tools/ticker.ts +1 -1
- package/src/tools/trades.ts +1 -1
- package/src/tools/volume.ts +1 -1
- package/src/tools/withdrawals.ts +16 -11
- package/src/utils.ts +33 -0
- package/test/unit.ts +362 -4
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,67 @@ This project uses [Semantic Versioning](https://semver.org/).
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [1.5.3] – 2026-04-11
|
|
15
|
+
|
|
16
|
+
### Security
|
|
17
|
+
|
|
18
|
+
- **Upstream API errors no longer forwarded to MCP clients** — `BudaClient.handleResponse` now logs the full Buda API error detail (status, path, message) to `process.stderr` as structured JSON and returns only a generic message to the MCP caller (e.g. `"Buda API error 404 on /path."`). Previously, raw upstream error messages including potential internal details were forwarded directly to clients.
|
|
19
|
+
|
|
20
|
+
- **Audit log transport field corrected for HTTP** — nine destructive tool handlers (`place_order`, `cancel_order`, `cancel_all_orders`, `cancel_order_by_client_id`, `place_batch_orders`, `create_withdrawal`, `lightning_withdrawal`, `create_receive_address`, `quote_remittance`, `accept_remittance_quote`) now correctly log `transport: "http"` when invoked via the HTTP server. Previously their `register()` functions defaulted to `"stdio"`, making all HTTP audit events appear as stdio traffic.
|
|
21
|
+
|
|
22
|
+
- **HTTP security headers via `helmet`** — Express HTTP server now applies `helmet()` as the first middleware, adding `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, `X-DNS-Prefetch-Control`, `X-Download-Options`, and removing `X-Powered-By`.
|
|
23
|
+
|
|
24
|
+
- **Request body size limit** — `express.json()` now enforces an explicit `limit: "10kb"` on the `/mcp` endpoint, reducing the memory/CPU surface for oversized body attacks in combination with the existing rate limiter.
|
|
25
|
+
|
|
26
|
+
- **Rate limiting extended to `/health` and `/.well-known/mcp/server-card.json`** — a `staticRateLimiter` (60 req/min) now protects these endpoints, which previously had no throttling. Sufficient for all legitimate uptime monitors and Smithery discovery.
|
|
27
|
+
|
|
28
|
+
- **`trust proxy` topology documented** — added inline comment to `app.set("trust proxy", 1)` explaining the single-hop assumption (Railway), the impact on `req.ip` and `express-rate-limit` client IP detection, and the action required if an additional proxy layer is added.
|
|
29
|
+
|
|
30
|
+
### Pending (manual)
|
|
31
|
+
|
|
32
|
+
- **CI binary pinning** — `publish.yml` should pin `mcp-publisher` to a fixed version with SHA256 verification instead of downloading `releases/latest`. Target version: `v1.5.0`, SHA256: `79bbb73ba048c5906034f73ef6286d7763bd53cf368ea0b358fc593ed360cbd5`. See `PUBLISH_CHECKLIST.md` for the exact step.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- `helmet` dependency (v8.x) — HTTP security headers middleware.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## [1.5.2] – 2026-04-11
|
|
41
|
+
|
|
42
|
+
### Security
|
|
43
|
+
|
|
44
|
+
- **Trust proxy configured for Railway** — added `app.set("trust proxy", 1)` to Express before any middleware. Without this, `express-rate-limit` saw the proxy IP for every request instead of the real client IP, making per-IP rate limiting effectively useless in the Railway deployment.
|
|
45
|
+
|
|
46
|
+
- **Constant-time bearer token comparison** — `mcpAuthMiddleware` now uses `crypto.timingSafeEqual` via a new `safeTokenEqual()` helper (exported from `src/utils.ts`) instead of plain string equality, eliminating the theoretical timing side-channel on the `MCP_AUTH_TOKEN` comparison.
|
|
47
|
+
|
|
48
|
+
- **PORT and MCP_RATE_LIMIT startup validation** — both environment variables are now parsed through a new `parseEnvInt(raw, fallback, min, max, name)` helper that throws a descriptive error and exits on `NaN` or out-of-range values, preventing silent misconfigurations (e.g. `MCP_RATE_LIMIT=abc` previously resolved to `NaN` and could disable the rate limiter).
|
|
49
|
+
|
|
50
|
+
- **MCP_AUTH_TOKEN entropy warning** — server now emits a `console.warn` at startup if `MCP_AUTH_TOKEN` is set but shorter than 32 characters, nudging operators toward adequately random secrets.
|
|
51
|
+
|
|
52
|
+
- **Dead man's switch fully isolated to stdio transport** — `renew_cancel_timer` and `disarm_cancel_timer` now also return `TRANSPORT_NOT_SUPPORTED` on HTTP transport (previously only `schedule_cancel_all` was blocked). An attacker with HTTP access could previously disarm or renew a timer armed via the stdio process, since both share the same module-level `timers` Map.
|
|
53
|
+
|
|
54
|
+
- **Input validation in `compare_markets`** — `base_currency` is now validated with `validateCurrency()` before fetching tickers, consistent with all other tools that accept a currency parameter. Arbitrary-length strings no longer reach the cache or API.
|
|
55
|
+
|
|
56
|
+
- **BOLT-11 invoice regex strengthened** — regex updated from `/^ln(bc|tb|bcrt)\d/i` to `/^ln(bc|tb|bcrt)\d*[munp]?1[a-z0-9]{20,}$/i`. The new pattern requires the bech32 separator `1`, at least 20 characters of bech32 data after it, and anchors at `$` — rejecting malformed strings that happen to start with the right prefix.
|
|
57
|
+
|
|
58
|
+
- **API path redaction from error responses** — removed the `path` field from all `BudaApiError` catch blocks across 31 tool handlers. The field was included in MCP tool responses, leaking internal API endpoint patterns (e.g. `/currencies/BTC/withdrawals`) to clients. The `path` property still exists on `BudaApiError` for internal use in audit logs.
|
|
59
|
+
|
|
60
|
+
- **Structured audit logging for destructive operations** — new `src/audit.ts` module with `logAudit(event: AuditEvent)` writes newline-delimited JSON to `process.stderr` for all 11 handlers with financial side-effects: `place_order`, `cancel_order`, `cancel_all_orders`, `cancel_order_by_client_id`, `place_batch_orders`, `create_withdrawal`, `lightning_withdrawal`, `create_receive_address`, `quote_remittance`, `accept_remittance_quote`, `schedule_cancel_all`. Audit events include `ts`, `tool`, `transport`, `args_summary` (sanitized — never includes `confirmation_token`, `invoice`, or `address`), `success`, and `error_code`. Each handler exposes an optional `transport` parameter (default `"stdio"`) for future HTTP-aware logging.
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- **`safeTokenEqual(a, b)` utility** — exported from `src/utils.ts`; constant-time string comparison using `crypto.timingSafeEqual`. Usable by any future code that compares secrets.
|
|
65
|
+
- **`parseEnvInt(raw, fallback, min, max, name)` utility** — exported from `src/utils.ts`; safe environment variable integer parsing with range validation. Used for `PORT` and `MCP_RATE_LIMIT` at startup.
|
|
66
|
+
- **`handleCompareMarkets` exported handler** — `compare_markets.ts` logic extracted from the inline registration closure into a named, exported function for unit testability.
|
|
67
|
+
|
|
68
|
+
### Tests
|
|
69
|
+
|
|
70
|
+
- **+28 unit tests** covering all new security behaviors: `safeTokenEqual` (5 cases), `parseEnvInt` (6 cases), `handleCompareMarkets` validateCurrency guard (4 cases), improved BOLT-11 regex (3 cases), DMS HTTP transport guard for renew and disarm (4 cases), `logAudit` output format and secret redaction (3 cases), audit integration with `handlePlaceOrder` (1 case), `path` field absence in error responses (2 cases).
|
|
71
|
+
- **Updated 3 existing test fixtures** — replaced placeholder invoice string `"lnbc1000u1ptest..."` (which contained dots — invalid bech32) with a well-formed test value that satisfies the improved BOLT-11 regex.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
14
75
|
## [1.5.1] – 2026-04-11
|
|
15
76
|
|
|
16
77
|
### Security
|
package/PUBLISH_CHECKLIST.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Publish Checklist — buda-mcp v1.5.
|
|
1
|
+
# Publish Checklist — buda-mcp v1.5.3
|
|
2
2
|
|
|
3
|
-
Steps to publish `v1.5.
|
|
3
|
+
Steps to publish `v1.5.3` to npm, the MCP registry, and notify community directories.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ Steps to publish `v1.5.1` to npm, the MCP registry, and notify community directo
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
# Confirm version
|
|
11
|
-
node -e "console.log(require('./package.json').version)" # should print 1.5.
|
|
11
|
+
node -e "console.log(require('./package.json').version)" # should print 1.5.3
|
|
12
12
|
|
|
13
13
|
# Build and test
|
|
14
14
|
npm run build
|
|
@@ -37,9 +37,9 @@ Verify: https://www.npmjs.com/package/@guiie/buda-mcp
|
|
|
37
37
|
|
|
38
38
|
## 3. GitHub release
|
|
39
39
|
|
|
40
|
-
Tag and release already created via `gh release create v1.5.
|
|
40
|
+
Tag and release already created via `gh release create v1.5.3`. Verify at:
|
|
41
41
|
|
|
42
|
-
https://github.com/gtorreal/buda-mcp/releases/tag/v1.5.
|
|
42
|
+
https://github.com/gtorreal/buda-mcp/releases/tag/v1.5.3
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
@@ -64,20 +64,18 @@ Verify: https://smithery.ai/server/@guiie/buda-mcp
|
|
|
64
64
|
**Email/message template:**
|
|
65
65
|
|
|
66
66
|
```
|
|
67
|
-
Subject: [Update] buda-mcp v1.5.
|
|
67
|
+
Subject: [Update] buda-mcp v1.5.3 — Security hardening (third pass)
|
|
68
68
|
|
|
69
69
|
Hi mcp.so team,
|
|
70
70
|
|
|
71
|
-
I've released v1.5.
|
|
71
|
+
I've released v1.5.3 of buda-mcp (@guiie/buda-mcp on npm).
|
|
72
72
|
|
|
73
73
|
Key changes (security hardening, no new tools):
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
- place_batch_orders: optional max_notional spending cap
|
|
80
|
-
- 156 unit tests (was 136)
|
|
74
|
+
- Upstream API errors no longer forwarded to MCP clients (generic messages only, detail logged server-side)
|
|
75
|
+
- Audit log transport field corrected for HTTP (9 handlers previously showed "stdio" for HTTP traffic)
|
|
76
|
+
- HTTP security headers via helmet (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, etc.)
|
|
77
|
+
- Request body size limit enforced (10kb) on /mcp endpoint
|
|
78
|
+
- Rate limiting extended to /health and /.well-known/mcp/server-card.json endpoints
|
|
81
79
|
|
|
82
80
|
Links:
|
|
83
81
|
- npm: https://www.npmjs.com/package/@guiie/buda-mcp
|
|
@@ -96,24 +94,23 @@ Thank you!
|
|
|
96
94
|
**Message template:**
|
|
97
95
|
|
|
98
96
|
```
|
|
99
|
-
Subject: [Update] buda-mcp v1.5.
|
|
97
|
+
Subject: [Update] buda-mcp v1.5.3
|
|
100
98
|
|
|
101
99
|
Hi Glama team,
|
|
102
100
|
|
|
103
|
-
buda-mcp has been updated to v1.5.
|
|
101
|
+
buda-mcp has been updated to v1.5.3.
|
|
104
102
|
|
|
105
103
|
Package: @guiie/buda-mcp (npm)
|
|
106
104
|
Registry: io.github.gtorreal/buda-mcp (MCP Registry)
|
|
107
|
-
Version: 1.5.
|
|
105
|
+
Version: 1.5.3
|
|
108
106
|
|
|
109
|
-
Changes (security hardening):
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
- 156 unit tests
|
|
107
|
+
Changes (security hardening, third pass):
|
|
108
|
+
- Upstream API errors no longer forwarded to MCP clients
|
|
109
|
+
- Audit log transport field corrected for HTTP (9 handlers)
|
|
110
|
+
- HTTP security headers via helmet
|
|
111
|
+
- Request body size limit (10kb) on /mcp endpoint
|
|
112
|
+
- Rate limiting on /health and server-card endpoints
|
|
113
|
+
- 184 unit tests
|
|
117
114
|
|
|
118
115
|
Quick start:
|
|
119
116
|
npx @guiie/buda-mcp
|
|
@@ -128,22 +125,45 @@ Thank you!
|
|
|
128
125
|
|
|
129
126
|
## 8. Post-publish verification
|
|
130
127
|
|
|
131
|
-
- [ ] `npx @guiie/buda-mcp@1.5.
|
|
132
|
-
- [ ] `npm info @guiie/buda-mcp version` returns `1.5.
|
|
133
|
-
- [ ] GitHub release tag `v1.5.
|
|
134
|
-
- [ ] MCP Registry entry reflects v1.5.
|
|
128
|
+
- [ ] `npx @guiie/buda-mcp@1.5.3` starts successfully
|
|
129
|
+
- [ ] `npm info @guiie/buda-mcp version` returns `1.5.3`
|
|
130
|
+
- [ ] GitHub release tag `v1.5.3` is visible
|
|
131
|
+
- [ ] MCP Registry entry reflects v1.5.3
|
|
135
132
|
- [ ] Smithery server card lists all tools
|
|
136
|
-
- [ ] `GET /health` returns `"version":"1.5.
|
|
137
|
-
- [ ]
|
|
138
|
-
- [ ] `
|
|
139
|
-
- [ ]
|
|
140
|
-
- [ ]
|
|
141
|
-
- [ ]
|
|
133
|
+
- [ ] `GET /health` returns `"version":"1.5.3"` on Railway deployment
|
|
134
|
+
- [ ] `GET /health` responds with `X-Content-Type-Options: nosniff` header (helmet active)
|
|
135
|
+
- [ ] `GET /health` rate-limited at 60 req/min
|
|
136
|
+
- [ ] Error responses from the MCP server show generic message (not raw Buda API detail)
|
|
137
|
+
- [ ] Audit log shows `"transport":"http"` for HTTP-triggered destructive tools
|
|
138
|
+
- [ ] Pending: manually apply CI binary pinning to `publish.yml` (see CHANGELOG v1.5.3)
|
|
142
139
|
- [ ] mcp.so listing updated
|
|
143
140
|
- [ ] Glama.ai listing updated
|
|
144
141
|
|
|
145
142
|
---
|
|
146
143
|
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 9. Pending manual fix — CI binary pinning
|
|
147
|
+
|
|
148
|
+
Edit `.github/workflows/publish.yml`, replace the `Install mcp-publisher` step with:
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
- name: Install mcp-publisher
|
|
152
|
+
env:
|
|
153
|
+
MCP_PUBLISHER_VERSION: "v1.5.0"
|
|
154
|
+
MCP_PUBLISHER_SHA256: "79bbb73ba048c5906034f73ef6286d7763bd53cf368ea0b358fc593ed360cbd5"
|
|
155
|
+
run: |
|
|
156
|
+
curl -fsSL "https://github.com/modelcontextprotocol/registry/releases/download/${MCP_PUBLISHER_VERSION}/mcp-publisher_linux_amd64.tar.gz" \
|
|
157
|
+
-o mcp-publisher.tar.gz
|
|
158
|
+
echo "${MCP_PUBLISHER_SHA256} mcp-publisher.tar.gz" | sha256sum --check
|
|
159
|
+
tar xz -f mcp-publisher.tar.gz mcp-publisher
|
|
160
|
+
sudo mv mcp-publisher /usr/local/bin/
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
SHA256 verified against GitHub release `v1.5.0` on 2026-04-11. Update both values when bumping `mcp-publisher`.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
147
167
|
## ARCHIVED: previous checklists
|
|
148
168
|
|
|
149
|
-
See git tags `v1.5.0`, `v1.4.0`, `v1.4.1`, `v1.4.2` for previous release notes and verification steps.
|
|
169
|
+
See git tags `v1.5.0`, `v1.5.1`, `v1.4.0`, `v1.4.1`, `v1.4.2` for previous release notes and verification steps.
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured audit logging for destructive MCP tool calls.
|
|
3
|
+
*
|
|
4
|
+
* Writes newline-delimited JSON to stderr so it never pollutes the stdio MCP transport
|
|
5
|
+
* and is captured by Railway / any log aggregator attached to the process.
|
|
6
|
+
*
|
|
7
|
+
* Rules for args_summary:
|
|
8
|
+
* - Include: market_id, currency, price_type, type, amount ranges
|
|
9
|
+
* - NEVER include: confirmation_token, invoice, address, bank_account_id
|
|
10
|
+
*/
|
|
11
|
+
export interface AuditEvent {
|
|
12
|
+
ts: string;
|
|
13
|
+
tool: string;
|
|
14
|
+
transport: "http" | "stdio";
|
|
15
|
+
ip?: string;
|
|
16
|
+
args_summary: Record<string, unknown>;
|
|
17
|
+
success: boolean;
|
|
18
|
+
error_code?: string | number;
|
|
19
|
+
}
|
|
20
|
+
export declare function logAudit(event: AuditEvent): void;
|
|
21
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAEhD"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured audit logging for destructive MCP tool calls.
|
|
3
|
+
*
|
|
4
|
+
* Writes newline-delimited JSON to stderr so it never pollutes the stdio MCP transport
|
|
5
|
+
* and is captured by Railway / any log aggregator attached to the process.
|
|
6
|
+
*
|
|
7
|
+
* Rules for args_summary:
|
|
8
|
+
* - Include: market_id, currency, price_type, type, amount ranges
|
|
9
|
+
* - NEVER include: confirmation_token, invoice, address, bank_account_id
|
|
10
|
+
*/
|
|
11
|
+
export function logAudit(event) {
|
|
12
|
+
process.stderr.write(JSON.stringify({ audit: true, ...event }) + "\n");
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=audit.js.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,qBAAa,YAAa,SAAQ,KAAK;aAEnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;aAEZ,YAAY,CAAC,EAAE,MAAM;gBAHrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,YAAY,CAAC,EAAE,MAAM,YAAA;CAKxC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;gBAG7C,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM;IAOpB,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,WAAW;IAWnB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;;OAIG;YACW,cAAc;YA2Bd,cAAc;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,qBAAa,YAAa,SAAQ,KAAK;aAEnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;aAEZ,YAAY,CAAC,EAAE,MAAM;gBAHrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,YAAY,CAAC,EAAE,MAAM,YAAA;CAKxC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;gBAG7C,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM;IAOpB,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,WAAW;IAWnB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;;OAIG;YACW,cAAc;YA2Bd,cAAc;IAsBtB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoB1E,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBnD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAmBpF"}
|
package/dist/client.js
CHANGED
|
@@ -90,7 +90,12 @@ export class BudaClient {
|
|
|
90
90
|
catch {
|
|
91
91
|
// ignore parse error, use statusText
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
// Log full upstream detail server-side only — never forward to MCP caller
|
|
94
|
+
process.stderr.write(JSON.stringify({ buda_api_error: true, status: response.status, path, detail }) + "\n");
|
|
95
|
+
const clientMsg = response.status === 429
|
|
96
|
+
? `Rate limit exceeded on ${path}. Retry later.`
|
|
97
|
+
: `Buda API error ${response.status} on ${path}.`;
|
|
98
|
+
throw new BudaApiError(response.status, path, clientMsg);
|
|
94
99
|
}
|
|
95
100
|
return response.json();
|
|
96
101
|
}
|
package/dist/http.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import express from "express";
|
|
2
|
+
import helmet from "helmet";
|
|
2
3
|
import rateLimit from "express-rate-limit";
|
|
3
4
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
5
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
6
|
import { BudaClient } from "./client.js";
|
|
6
7
|
import { MemoryCache, CACHE_TTL } from "./cache.js";
|
|
8
|
+
import { safeTokenEqual, parseEnvInt } from "./utils.js";
|
|
7
9
|
import { VERSION } from "./version.js";
|
|
8
10
|
import { validateMarketId } from "./validation.js";
|
|
9
11
|
import * as markets from "./tools/markets.js";
|
|
@@ -41,7 +43,14 @@ import * as cancelOrderByClientId from "./tools/cancel_order_by_client_id.js";
|
|
|
41
43
|
import * as batchOrders from "./tools/batch_orders.js";
|
|
42
44
|
import * as lightning from "./tools/lightning.js";
|
|
43
45
|
import { handleMarketSummary } from "./tools/market_summary.js";
|
|
44
|
-
|
|
46
|
+
let PORT;
|
|
47
|
+
try {
|
|
48
|
+
PORT = parseEnvInt(process.env.PORT, 3000, 1, 65535, "PORT");
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
45
54
|
const client = new BudaClient(undefined, process.env.BUDA_API_KEY, process.env.BUDA_API_SECRET);
|
|
46
55
|
const authEnabled = client.hasAuth();
|
|
47
56
|
// Schemas for the Smithery server-card — assembled from the same definitions used in register().
|
|
@@ -119,22 +128,22 @@ function createServer() {
|
|
|
119
128
|
if (authEnabled) {
|
|
120
129
|
balances.register(server, client);
|
|
121
130
|
orders.register(server, client);
|
|
122
|
-
placeOrder.register(server, client);
|
|
123
|
-
cancelOrder.register(server, client);
|
|
131
|
+
placeOrder.register(server, client, "http");
|
|
132
|
+
cancelOrder.register(server, client, "http");
|
|
124
133
|
deadMansSwitch.register(server, client, "http");
|
|
125
134
|
account.register(server, client);
|
|
126
135
|
balance.register(server, client);
|
|
127
136
|
orderLookup.register(server, client);
|
|
128
137
|
networkFees.register(server, client);
|
|
129
138
|
deposits.register(server, client);
|
|
130
|
-
withdrawals.register(server, client);
|
|
131
|
-
receiveAddresses.register(server, client);
|
|
132
|
-
remittances.register(server, client);
|
|
139
|
+
withdrawals.register(server, client, "http");
|
|
140
|
+
receiveAddresses.register(server, client, "http");
|
|
141
|
+
remittances.register(server, client, "http");
|
|
133
142
|
remittanceRecipients.register(server, client);
|
|
134
|
-
cancelAllOrders.register(server, client);
|
|
135
|
-
cancelOrderByClientId.register(server, client);
|
|
136
|
-
batchOrders.register(server, client);
|
|
137
|
-
lightning.register(server, client);
|
|
143
|
+
cancelAllOrders.register(server, client, "http");
|
|
144
|
+
cancelOrderByClientId.register(server, client, "http");
|
|
145
|
+
batchOrders.register(server, client, "http");
|
|
146
|
+
lightning.register(server, client, "http");
|
|
138
147
|
}
|
|
139
148
|
// MCP Resources
|
|
140
149
|
server.resource("buda-markets", "buda://markets", async (uri) => {
|
|
@@ -187,7 +196,12 @@ function createServer() {
|
|
|
187
196
|
return server;
|
|
188
197
|
}
|
|
189
198
|
const app = express();
|
|
190
|
-
app.use(
|
|
199
|
+
app.use(helmet());
|
|
200
|
+
// trust proxy: 1 = trust exactly one hop (Railway's reverse proxy).
|
|
201
|
+
// If Cloudflare or another proxy is added in front, increment this value.
|
|
202
|
+
// Affects: req.ip and express-rate-limit client IP detection.
|
|
203
|
+
app.set("trust proxy", 1);
|
|
204
|
+
app.use(express.json({ limit: "10kb" }));
|
|
191
205
|
const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
|
|
192
206
|
if (authEnabled && !MCP_AUTH_TOKEN) {
|
|
193
207
|
console.error("[buda-mcp] FATAL: BUDA_API_KEY/BUDA_API_SECRET are set but MCP_AUTH_TOKEN is not.\n" +
|
|
@@ -195,27 +209,45 @@ if (authEnabled && !MCP_AUTH_TOKEN) {
|
|
|
195
209
|
" Set MCP_AUTH_TOKEN to a long random secret, or run in stdio mode instead.");
|
|
196
210
|
process.exit(1);
|
|
197
211
|
}
|
|
212
|
+
if (MCP_AUTH_TOKEN && MCP_AUTH_TOKEN.length < 32) {
|
|
213
|
+
console.warn("[buda-mcp] WARNING: MCP_AUTH_TOKEN has fewer than 32 characters. Use a longer random secret.");
|
|
214
|
+
}
|
|
215
|
+
let rateLimitMax;
|
|
216
|
+
try {
|
|
217
|
+
rateLimitMax = parseEnvInt(process.env.MCP_RATE_LIMIT, 120, 1, 10_000, "MCP_RATE_LIMIT");
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
198
223
|
const mcpRateLimiter = rateLimit({
|
|
199
224
|
windowMs: 60_000,
|
|
200
|
-
max:
|
|
225
|
+
max: rateLimitMax,
|
|
201
226
|
standardHeaders: true,
|
|
202
227
|
legacyHeaders: false,
|
|
203
228
|
message: { error: "Too many requests. Retry after 60 seconds.", code: "RATE_LIMITED" },
|
|
204
229
|
});
|
|
230
|
+
const staticRateLimiter = rateLimit({
|
|
231
|
+
windowMs: 60_000,
|
|
232
|
+
max: 60,
|
|
233
|
+
standardHeaders: true,
|
|
234
|
+
legacyHeaders: false,
|
|
235
|
+
message: { error: "Too many requests.", code: "RATE_LIMITED" },
|
|
236
|
+
});
|
|
205
237
|
function mcpAuthMiddleware(req, res, next) {
|
|
206
238
|
if (!MCP_AUTH_TOKEN) {
|
|
207
239
|
next();
|
|
208
240
|
return;
|
|
209
241
|
}
|
|
210
242
|
const auth = req.headers.authorization ?? "";
|
|
211
|
-
if (auth
|
|
243
|
+
if (!safeTokenEqual(auth, `Bearer ${MCP_AUTH_TOKEN}`)) {
|
|
212
244
|
res.status(401).json({ error: "Unauthorized" });
|
|
213
245
|
return;
|
|
214
246
|
}
|
|
215
247
|
next();
|
|
216
248
|
}
|
|
217
249
|
// Health check for Railway / uptime monitors
|
|
218
|
-
app.get("/health", (_req, res) => {
|
|
250
|
+
app.get("/health", staticRateLimiter, (_req, res) => {
|
|
219
251
|
res.json({
|
|
220
252
|
status: "ok",
|
|
221
253
|
server: "buda-mcp",
|
|
@@ -225,7 +257,7 @@ app.get("/health", (_req, res) => {
|
|
|
225
257
|
});
|
|
226
258
|
// Smithery static server card — assembled programmatically from tool definitions.
|
|
227
259
|
// Adding a new tool only requires exporting its toolSchema; this handler needs no changes.
|
|
228
|
-
app.get("/.well-known/mcp/server-card.json", (_req, res) => {
|
|
260
|
+
app.get("/.well-known/mcp/server-card.json", staticRateLimiter, (_req, res) => {
|
|
229
261
|
res.json({
|
|
230
262
|
serverInfo: { name: "buda-mcp", version: VERSION },
|
|
231
263
|
authentication: { required: authEnabled },
|
package/dist/tools/account.js
CHANGED
|
@@ -35,7 +35,7 @@ export async function handleGetAccountInfo(client) {
|
|
|
35
35
|
}
|
|
36
36
|
catch (err) {
|
|
37
37
|
const msg = err instanceof BudaApiError
|
|
38
|
-
? { error: err.message, code: err.status
|
|
38
|
+
? { error: err.message, code: err.status }
|
|
39
39
|
: { error: String(err), code: "UNKNOWN" };
|
|
40
40
|
return {
|
|
41
41
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/dist/tools/arbitrage.js
CHANGED
|
@@ -118,7 +118,7 @@ export async function handleArbitrageOpportunities({ base_currency, threshold_pc
|
|
|
118
118
|
}
|
|
119
119
|
catch (err) {
|
|
120
120
|
const msg = err instanceof BudaApiError
|
|
121
|
-
? { error: err.message, code: err.status
|
|
121
|
+
? { error: err.message, code: err.status }
|
|
122
122
|
: { error: String(err), code: "UNKNOWN" };
|
|
123
123
|
return {
|
|
124
124
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/dist/tools/balance.js
CHANGED
|
@@ -56,7 +56,7 @@ export async function handleGetBalance(args, client) {
|
|
|
56
56
|
}
|
|
57
57
|
catch (err) {
|
|
58
58
|
const msg = err instanceof BudaApiError
|
|
59
|
-
? { error: err.message, code: err.status
|
|
59
|
+
? { error: err.message, code: err.status }
|
|
60
60
|
: { error: String(err), code: "UNKNOWN" };
|
|
61
61
|
return {
|
|
62
62
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/dist/tools/balances.js
CHANGED
|
@@ -39,7 +39,7 @@ export function register(server, client) {
|
|
|
39
39
|
}
|
|
40
40
|
catch (err) {
|
|
41
41
|
const msg = err instanceof BudaApiError
|
|
42
|
-
? { error: err.message, code: err.status
|
|
42
|
+
? { error: err.message, code: err.status }
|
|
43
43
|
: { error: String(err), code: "UNKNOWN" };
|
|
44
44
|
return {
|
|
45
45
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/dist/tools/banks.js
CHANGED
|
@@ -52,7 +52,7 @@ export async function handleGetAvailableBanks(args, client, cache) {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
const msg = err instanceof BudaApiError
|
|
55
|
-
? { error: err.message, code: err.status
|
|
55
|
+
? { error: err.message, code: err.status }
|
|
56
56
|
: { error: String(err), code: "UNKNOWN" };
|
|
57
57
|
return {
|
|
58
58
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -70,13 +70,13 @@ type BatchOrdersArgs = {
|
|
|
70
70
|
max_notional?: number;
|
|
71
71
|
confirmation_token: string;
|
|
72
72
|
};
|
|
73
|
-
export declare function handlePlaceBatchOrders(args: BatchOrdersArgs, client: BudaClient): Promise<{
|
|
73
|
+
export declare function handlePlaceBatchOrders(args: BatchOrdersArgs, client: BudaClient, transport?: "http" | "stdio"): Promise<{
|
|
74
74
|
content: Array<{
|
|
75
75
|
type: "text";
|
|
76
76
|
text: string;
|
|
77
77
|
}>;
|
|
78
78
|
isError?: boolean;
|
|
79
79
|
}>;
|
|
80
|
-
export declare function register(server: McpServer, client: BudaClient): void;
|
|
80
|
+
export declare function register(server: McpServer, client: BudaClient, transport?: "http" | "stdio"): void;
|
|
81
81
|
export {};
|
|
82
82
|
//# sourceMappingURL=batch_orders.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch_orders.d.ts","sourceRoot":"","sources":["../../src/tools/batch_orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"batch_orders.d.ts","sourceRoot":"","sources":["../../src/tools/batch_orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CtB,CAAC;AAEF,QAAA,MAAM,UAAU;;;;;;;;;;;;iBAMd,CAAC;AAEH,KAAK,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAWnD,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,UAAU,EAClB,SAAS,GAAE,MAAM,GAAG,OAAiB,GACpC,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA2IhF;AAED,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,GAAE,MAAM,GAAG,OAAiB,GACpC,IAAI,CA2BN"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { BudaApiError } from "../client.js";
|
|
3
3
|
import { validateMarketId } from "../validation.js";
|
|
4
|
+
import { logAudit } from "../audit.js";
|
|
4
5
|
export const toolSchema = {
|
|
5
6
|
name: "place_batch_orders",
|
|
6
7
|
description: "Place multiple orders sequentially on Buda.com (up to 20). " +
|
|
@@ -48,7 +49,7 @@ const orderShape = z.object({
|
|
|
48
49
|
amount: z.number().positive(),
|
|
49
50
|
limit_price: z.number().positive().optional(),
|
|
50
51
|
});
|
|
51
|
-
export async function handlePlaceBatchOrders(args, client) {
|
|
52
|
+
export async function handlePlaceBatchOrders(args, client, transport = "stdio") {
|
|
52
53
|
const { orders, max_notional, confirmation_token } = args;
|
|
53
54
|
if (confirmation_token !== "CONFIRM") {
|
|
54
55
|
return {
|
|
@@ -161,12 +162,21 @@ export async function handlePlaceBatchOrders(args, client) {
|
|
|
161
162
|
if (failed > 0 && succeeded > 0) {
|
|
162
163
|
response.warning = "Some orders failed. Already-placed orders were NOT rolled back.";
|
|
163
164
|
}
|
|
165
|
+
const isError = failed > 0 && succeeded === 0 ? true : undefined;
|
|
166
|
+
logAudit({
|
|
167
|
+
ts: new Date().toISOString(),
|
|
168
|
+
tool: "place_batch_orders",
|
|
169
|
+
transport,
|
|
170
|
+
args_summary: { order_count: orders.length, succeeded, failed },
|
|
171
|
+
success: !isError,
|
|
172
|
+
error_code: isError ? "PARTIAL_OR_FULL_FAILURE" : undefined,
|
|
173
|
+
});
|
|
164
174
|
return {
|
|
165
175
|
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
166
|
-
isError
|
|
176
|
+
isError,
|
|
167
177
|
};
|
|
168
178
|
}
|
|
169
|
-
export function register(server, client) {
|
|
179
|
+
export function register(server, client, transport = "stdio") {
|
|
170
180
|
server.tool(toolSchema.name, toolSchema.description, {
|
|
171
181
|
orders: z
|
|
172
182
|
.array(orderShape)
|
|
@@ -183,6 +193,6 @@ export function register(server, client) {
|
|
|
183
193
|
confirmation_token: z
|
|
184
194
|
.string()
|
|
185
195
|
.describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute."),
|
|
186
|
-
}, (args) => handlePlaceBatchOrders(args, client));
|
|
196
|
+
}, (args) => handlePlaceBatchOrders(args, client, transport));
|
|
187
197
|
}
|
|
188
198
|
//# sourceMappingURL=batch_orders.js.map
|
|
@@ -22,13 +22,13 @@ type CancelAllOrdersArgs = {
|
|
|
22
22
|
market_id: string;
|
|
23
23
|
confirmation_token: string;
|
|
24
24
|
};
|
|
25
|
-
export declare function handleCancelAllOrders(args: CancelAllOrdersArgs, client: BudaClient): Promise<{
|
|
25
|
+
export declare function handleCancelAllOrders(args: CancelAllOrdersArgs, client: BudaClient, transport?: "http" | "stdio"): Promise<{
|
|
26
26
|
content: Array<{
|
|
27
27
|
type: "text";
|
|
28
28
|
text: string;
|
|
29
29
|
}>;
|
|
30
30
|
isError?: boolean;
|
|
31
31
|
}>;
|
|
32
|
-
export declare function register(server: McpServer, client: BudaClient): void;
|
|
32
|
+
export declare function register(server: McpServer, client: BudaClient, transport?: "http" | "stdio"): void;
|
|
33
33
|
export {};
|
|
34
34
|
//# sourceMappingURL=cancel_all_orders.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cancel_all_orders.d.ts","sourceRoot":"","sources":["../../src/tools/cancel_all_orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"cancel_all_orders.d.ts","sourceRoot":"","sources":["../../src/tools/cancel_all_orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;CAuBtB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,UAAU,EAClB,SAAS,GAAE,MAAM,GAAG,OAAiB,GACpC,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAqDhF;AAED,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,GAAE,MAAM,GAAG,OAAiB,GACpC,IAAI,CAkBN"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { BudaApiError } from "../client.js";
|
|
3
3
|
import { validateMarketId } from "../validation.js";
|
|
4
|
+
import { logAudit } from "../audit.js";
|
|
4
5
|
export const toolSchema = {
|
|
5
6
|
name: "cancel_all_orders",
|
|
6
7
|
description: "Cancel all open orders on Buda.com, optionally filtered by a specific market. " +
|
|
@@ -23,7 +24,7 @@ export const toolSchema = {
|
|
|
23
24
|
required: ["market_id", "confirmation_token"],
|
|
24
25
|
},
|
|
25
26
|
};
|
|
26
|
-
export async function handleCancelAllOrders(args, client) {
|
|
27
|
+
export async function handleCancelAllOrders(args, client, transport = "stdio") {
|
|
27
28
|
const { market_id, confirmation_token } = args;
|
|
28
29
|
if (confirmation_token !== "CONFIRM") {
|
|
29
30
|
return {
|
|
@@ -55,26 +56,22 @@ export async function handleCancelAllOrders(args, client) {
|
|
|
55
56
|
try {
|
|
56
57
|
const params = market_id !== "*" ? { market_id: market_id.toLowerCase() } : undefined;
|
|
57
58
|
const data = await client.delete(`/orders`, params);
|
|
58
|
-
|
|
59
|
-
content: [
|
|
60
|
-
{
|
|
61
|
-
type: "text",
|
|
62
|
-
text: JSON.stringify({ canceled_count: data.canceled_count, market_id }),
|
|
63
|
-
},
|
|
64
|
-
],
|
|
59
|
+
const result = {
|
|
60
|
+
content: [{ type: "text", text: JSON.stringify({ canceled_count: data.canceled_count, market_id }) }],
|
|
65
61
|
};
|
|
62
|
+
logAudit({ ts: new Date().toISOString(), tool: "cancel_all_orders", transport, args_summary: { market_id }, success: true });
|
|
63
|
+
return result;
|
|
66
64
|
}
|
|
67
65
|
catch (err) {
|
|
68
66
|
const msg = err instanceof BudaApiError
|
|
69
|
-
? { error: err.message, code: err.status
|
|
67
|
+
? { error: err.message, code: err.status }
|
|
70
68
|
: { error: String(err), code: "UNKNOWN" };
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
69
|
+
const result = { content: [{ type: "text", text: JSON.stringify(msg) }], isError: true };
|
|
70
|
+
logAudit({ ts: new Date().toISOString(), tool: "cancel_all_orders", transport, args_summary: { market_id }, success: false, error_code: msg.code });
|
|
71
|
+
return result;
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
|
-
export function register(server, client) {
|
|
74
|
+
export function register(server, client, transport = "stdio") {
|
|
78
75
|
server.tool(toolSchema.name, toolSchema.description, {
|
|
79
76
|
market_id: z
|
|
80
77
|
.string()
|
|
@@ -84,6 +81,6 @@ export function register(server, client) {
|
|
|
84
81
|
.string()
|
|
85
82
|
.describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute. " +
|
|
86
83
|
"Any other value will reject the request without canceling."),
|
|
87
|
-
}, (args) => handleCancelAllOrders(args, client));
|
|
84
|
+
}, (args) => handleCancelAllOrders(args, client, transport));
|
|
88
85
|
}
|
|
89
86
|
//# sourceMappingURL=cancel_all_orders.js.map
|