@guiie/buda-mcp 1.5.1 → 1.5.2
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 +35 -0
- package/PUBLISH_CHECKLIST.md +39 -32
- package/dist/audit.d.ts +21 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +14 -0
- package/dist/http.js +25 -3
- 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 +1 -1
- package/dist/tools/batch_orders.d.ts.map +1 -1
- package/dist/tools/batch_orders.js +12 -2
- package/dist/tools/cancel_all_orders.d.ts +1 -1
- package/dist/tools/cancel_all_orders.d.ts.map +1 -1
- package/dist/tools/cancel_all_orders.js +10 -13
- package/dist/tools/cancel_order.d.ts +1 -1
- package/dist/tools/cancel_order.d.ts.map +1 -1
- package/dist/tools/cancel_order.js +9 -9
- package/dist/tools/cancel_order_by_client_id.d.ts +1 -1
- package/dist/tools/cancel_order_by_client_id.d.ts.map +1 -1
- package/dist/tools/cancel_order_by_client_id.js +9 -9
- 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 +1 -1
- package/dist/tools/lightning.d.ts.map +1 -1
- package/dist/tools/lightning.js +11 -9
- 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 +1 -1
- package/dist/tools/place_order.d.ts.map +1 -1
- package/dist/tools/place_order.js +22 -4
- package/dist/tools/price_history.js +1 -1
- package/dist/tools/quotation.js +1 -1
- package/dist/tools/receive_addresses.d.ts +1 -1
- package/dist/tools/receive_addresses.d.ts.map +1 -1
- package/dist/tools/receive_addresses.js +11 -11
- package/dist/tools/remittance_recipients.js +2 -2
- package/dist/tools/remittances.d.ts +2 -2
- package/dist/tools/remittances.d.ts.map +1 -1
- package/dist/tools/remittances.js +19 -20
- 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 +1 -1
- package/dist/tools/withdrawals.d.ts.map +1 -1
- package/dist/tools/withdrawals.js +10 -10
- package/dist/utils.d.ts +10 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +25 -0
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/audit.ts +24 -0
- package/src/http.ts +27 -3
- 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 +12 -1
- package/src/tools/cancel_all_orders.ts +10 -12
- package/src/tools/cancel_order.ts +9 -8
- package/src/tools/cancel_order_by_client_id.ts +9 -8
- 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 +12 -9
- 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 +24 -5
- package/src/tools/price_history.ts +1 -1
- package/src/tools/quotation.ts +1 -1
- package/src/tools/receive_addresses.ts +11 -10
- package/src/tools/remittance_recipients.ts +2 -2
- package/src/tools/remittances.ts +19 -18
- 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 +10 -9
- package/src/utils.ts +33 -0
- package/test/unit.ts +362 -4
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,41 @@ This project uses [Semantic Versioning](https://semver.org/).
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [1.5.2] – 2026-04-11
|
|
15
|
+
|
|
16
|
+
### Security
|
|
17
|
+
|
|
18
|
+
- **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.
|
|
19
|
+
|
|
20
|
+
- **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.
|
|
21
|
+
|
|
22
|
+
- **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).
|
|
23
|
+
|
|
24
|
+
- **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.
|
|
25
|
+
|
|
26
|
+
- **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.
|
|
27
|
+
|
|
28
|
+
- **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.
|
|
29
|
+
|
|
30
|
+
- **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.
|
|
31
|
+
|
|
32
|
+
- **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.
|
|
33
|
+
|
|
34
|
+
- **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.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- **`safeTokenEqual(a, b)` utility** — exported from `src/utils.ts`; constant-time string comparison using `crypto.timingSafeEqual`. Usable by any future code that compares secrets.
|
|
39
|
+
- **`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.
|
|
40
|
+
- **`handleCompareMarkets` exported handler** — `compare_markets.ts` logic extracted from the inline registration closure into a named, exported function for unit testability.
|
|
41
|
+
|
|
42
|
+
### Tests
|
|
43
|
+
|
|
44
|
+
- **+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).
|
|
45
|
+
- **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.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
14
49
|
## [1.5.1] – 2026-04-11
|
|
15
50
|
|
|
16
51
|
### Security
|
package/PUBLISH_CHECKLIST.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Publish Checklist — buda-mcp v1.5.
|
|
1
|
+
# Publish Checklist — buda-mcp v1.5.2
|
|
2
2
|
|
|
3
|
-
Steps to publish `v1.5.
|
|
3
|
+
Steps to publish `v1.5.2` 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.2
|
|
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.2`. 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.2
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
@@ -64,20 +64,23 @@ 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.2 — Security hardening (second pass)
|
|
68
68
|
|
|
69
69
|
Hi mcp.so team,
|
|
70
70
|
|
|
71
|
-
I've released v1.5.
|
|
71
|
+
I've released v1.5.2 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
|
-
-
|
|
80
|
-
-
|
|
74
|
+
- Constant-time token comparison (timing-safe Bearer token auth)
|
|
75
|
+
- Strict environment variable validation (PORT, MCP_RATE_LIMIT) with safe exit on bad config
|
|
76
|
+
- MCP_AUTH_TOKEN entropy warning (< 32 chars)
|
|
77
|
+
- trust proxy support for correct client IP detection behind reverse proxies
|
|
78
|
+
- Audit logging for all 11 destructive tool handlers (structured JSON to stderr)
|
|
79
|
+
- Dead man's switch: renew/disarm also blocked on HTTP transport
|
|
80
|
+
- validateCurrency() added to compare_markets tool
|
|
81
|
+
- Stronger BOLT-11 regex validation in lightning_withdrawal
|
|
82
|
+
- Internal API paths redacted from all error responses (31 tool handlers)
|
|
83
|
+
- 28 new unit tests (total now 184)
|
|
81
84
|
|
|
82
85
|
Links:
|
|
83
86
|
- npm: https://www.npmjs.com/package/@guiie/buda-mcp
|
|
@@ -96,24 +99,25 @@ Thank you!
|
|
|
96
99
|
**Message template:**
|
|
97
100
|
|
|
98
101
|
```
|
|
99
|
-
Subject: [Update] buda-mcp v1.5.
|
|
102
|
+
Subject: [Update] buda-mcp v1.5.2
|
|
100
103
|
|
|
101
104
|
Hi Glama team,
|
|
102
105
|
|
|
103
|
-
buda-mcp has been updated to v1.5.
|
|
106
|
+
buda-mcp has been updated to v1.5.2.
|
|
104
107
|
|
|
105
108
|
Package: @guiie/buda-mcp (npm)
|
|
106
109
|
Registry: io.github.gtorreal/buda-mcp (MCP Registry)
|
|
107
|
-
Version: 1.5.
|
|
108
|
-
|
|
109
|
-
Changes (security hardening):
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
110
|
+
Version: 1.5.2
|
|
111
|
+
|
|
112
|
+
Changes (security hardening, second pass):
|
|
113
|
+
- Constant-time token comparison (timing-safe auth)
|
|
114
|
+
- Strict env var validation (PORT, MCP_RATE_LIMIT)
|
|
115
|
+
- Audit logging for all destructive handlers
|
|
116
|
+
- Dead man's switch: renew/disarm also blocked on HTTP
|
|
117
|
+
- validateCurrency() in compare_markets
|
|
118
|
+
- Stronger BOLT-11 regex
|
|
119
|
+
- Internal paths redacted from error responses
|
|
120
|
+
- 184 unit tests
|
|
117
121
|
|
|
118
122
|
Quick start:
|
|
119
123
|
npx @guiie/buda-mcp
|
|
@@ -128,17 +132,20 @@ Thank you!
|
|
|
128
132
|
|
|
129
133
|
## 8. Post-publish verification
|
|
130
134
|
|
|
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.
|
|
135
|
+
- [ ] `npx @guiie/buda-mcp@1.5.2` starts successfully
|
|
136
|
+
- [ ] `npm info @guiie/buda-mcp version` returns `1.5.2`
|
|
137
|
+
- [ ] GitHub release tag `v1.5.2` is visible
|
|
138
|
+
- [ ] MCP Registry entry reflects v1.5.2
|
|
135
139
|
- [ ] Smithery server card lists all tools
|
|
136
|
-
- [ ] `GET /health` returns `"version":"1.5.
|
|
140
|
+
- [ ] `GET /health` returns `"version":"1.5.2"` on Railway deployment
|
|
137
141
|
- [ ] HTTP server exits if `BUDA_API_KEY` set but `MCP_AUTH_TOKEN` is absent
|
|
138
142
|
- [ ] `create_withdrawal` rejects a truncated BTC address with `INVALID_ADDRESS`
|
|
139
143
|
- [ ] `lightning_withdrawal` rejects a non-BOLT11 string with `INVALID_INVOICE`
|
|
140
144
|
- [ ] `place_batch_orders` with `max_notional` rejects over-cap batch before API call
|
|
141
145
|
- [ ] `schedule_cancel_all` via HTTP returns `TRANSPORT_NOT_SUPPORTED`
|
|
146
|
+
- [ ] `renew_cancel_timer` via HTTP returns `TRANSPORT_NOT_SUPPORTED`
|
|
147
|
+
- [ ] Error responses do NOT include internal `path` field
|
|
148
|
+
- [ ] Audit events appear in stderr as JSON with `audit: true`
|
|
142
149
|
- [ ] mcp.so listing updated
|
|
143
150
|
- [ ] Glama.ai listing updated
|
|
144
151
|
|
|
@@ -146,4 +153,4 @@ Thank you!
|
|
|
146
153
|
|
|
147
154
|
## ARCHIVED: previous checklists
|
|
148
155
|
|
|
149
|
-
See git tags `v1.5.0`, `v1.4.0`, `v1.4.1`, `v1.4.2` for previous release notes and verification steps.
|
|
156
|
+
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/http.js
CHANGED
|
@@ -4,6 +4,7 @@ import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mc
|
|
|
4
4
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
5
|
import { BudaClient } from "./client.js";
|
|
6
6
|
import { MemoryCache, CACHE_TTL } from "./cache.js";
|
|
7
|
+
import { safeTokenEqual, parseEnvInt } from "./utils.js";
|
|
7
8
|
import { VERSION } from "./version.js";
|
|
8
9
|
import { validateMarketId } from "./validation.js";
|
|
9
10
|
import * as markets from "./tools/markets.js";
|
|
@@ -41,7 +42,14 @@ import * as cancelOrderByClientId from "./tools/cancel_order_by_client_id.js";
|
|
|
41
42
|
import * as batchOrders from "./tools/batch_orders.js";
|
|
42
43
|
import * as lightning from "./tools/lightning.js";
|
|
43
44
|
import { handleMarketSummary } from "./tools/market_summary.js";
|
|
44
|
-
|
|
45
|
+
let PORT;
|
|
46
|
+
try {
|
|
47
|
+
PORT = parseEnvInt(process.env.PORT, 3000, 1, 65535, "PORT");
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
45
53
|
const client = new BudaClient(undefined, process.env.BUDA_API_KEY, process.env.BUDA_API_SECRET);
|
|
46
54
|
const authEnabled = client.hasAuth();
|
|
47
55
|
// Schemas for the Smithery server-card — assembled from the same definitions used in register().
|
|
@@ -187,6 +195,9 @@ function createServer() {
|
|
|
187
195
|
return server;
|
|
188
196
|
}
|
|
189
197
|
const app = express();
|
|
198
|
+
// Required for correct client IP detection behind Railway's reverse proxy.
|
|
199
|
+
// Without this, express-rate-limit sees the proxy IP instead of the real client.
|
|
200
|
+
app.set("trust proxy", 1);
|
|
190
201
|
app.use(express.json());
|
|
191
202
|
const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
|
|
192
203
|
if (authEnabled && !MCP_AUTH_TOKEN) {
|
|
@@ -195,9 +206,20 @@ if (authEnabled && !MCP_AUTH_TOKEN) {
|
|
|
195
206
|
" Set MCP_AUTH_TOKEN to a long random secret, or run in stdio mode instead.");
|
|
196
207
|
process.exit(1);
|
|
197
208
|
}
|
|
209
|
+
if (MCP_AUTH_TOKEN && MCP_AUTH_TOKEN.length < 32) {
|
|
210
|
+
console.warn("[buda-mcp] WARNING: MCP_AUTH_TOKEN has fewer than 32 characters. Use a longer random secret.");
|
|
211
|
+
}
|
|
212
|
+
let rateLimitMax;
|
|
213
|
+
try {
|
|
214
|
+
rateLimitMax = parseEnvInt(process.env.MCP_RATE_LIMIT, 120, 1, 10_000, "MCP_RATE_LIMIT");
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
198
220
|
const mcpRateLimiter = rateLimit({
|
|
199
221
|
windowMs: 60_000,
|
|
200
|
-
max:
|
|
222
|
+
max: rateLimitMax,
|
|
201
223
|
standardHeaders: true,
|
|
202
224
|
legacyHeaders: false,
|
|
203
225
|
message: { error: "Too many requests. Retry after 60 seconds.", code: "RATE_LIMITED" },
|
|
@@ -208,7 +230,7 @@ function mcpAuthMiddleware(req, res, next) {
|
|
|
208
230
|
return;
|
|
209
231
|
}
|
|
210
232
|
const auth = req.headers.authorization ?? "";
|
|
211
|
-
if (auth
|
|
233
|
+
if (!safeTokenEqual(auth, `Bearer ${MCP_AUTH_TOKEN}`)) {
|
|
212
234
|
res.status(401).json({ error: "Unauthorized" });
|
|
213
235
|
return;
|
|
214
236
|
}
|
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,7 +70,7 @@ 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;
|
|
@@ -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,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2BpE"}
|
|
@@ -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,9 +162,18 @@ 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
179
|
export function register(server, client) {
|
|
@@ -22,7 +22,7 @@ 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;
|
|
@@ -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,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBpE"}
|
|
@@ -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,23 +56,19 @@ 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
74
|
export function register(server, client) {
|
|
@@ -22,7 +22,7 @@ type CancelOrderArgs = {
|
|
|
22
22
|
order_id: number;
|
|
23
23
|
confirmation_token: string;
|
|
24
24
|
};
|
|
25
|
-
export declare function handleCancelOrder(args: CancelOrderArgs, client: BudaClient): Promise<{
|
|
25
|
+
export declare function handleCancelOrder(args: CancelOrderArgs, client: BudaClient, transport?: "http" | "stdio"): Promise<{
|
|
26
26
|
content: Array<{
|
|
27
27
|
type: "text";
|
|
28
28
|
text: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cancel_order.d.ts","sourceRoot":"","sources":["../../src/tools/cancel_order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"cancel_order.d.ts","sourceRoot":"","sources":["../../src/tools/cancel_order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;CAuBtB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,iBAAiB,CACrC,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,CAsChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAmBpE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { BudaApiError } from "../client.js";
|
|
3
|
+
import { logAudit } from "../audit.js";
|
|
3
4
|
export const toolSchema = {
|
|
4
5
|
name: "cancel_order",
|
|
5
6
|
description: "Cancel an open order by ID on Buda.com. " +
|
|
@@ -22,7 +23,7 @@ export const toolSchema = {
|
|
|
22
23
|
required: ["order_id", "confirmation_token"],
|
|
23
24
|
},
|
|
24
25
|
};
|
|
25
|
-
export async function handleCancelOrder(args, client) {
|
|
26
|
+
export async function handleCancelOrder(args, client, transport = "stdio") {
|
|
26
27
|
const { order_id, confirmation_token } = args;
|
|
27
28
|
if (confirmation_token !== "CONFIRM") {
|
|
28
29
|
return {
|
|
@@ -44,18 +45,17 @@ export async function handleCancelOrder(args, client) {
|
|
|
44
45
|
const data = await client.put(`/orders/${order_id}`, {
|
|
45
46
|
order: { state: "canceling" },
|
|
46
47
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
const result = { content: [{ type: "text", text: JSON.stringify(data.order, null, 2) }] };
|
|
49
|
+
logAudit({ ts: new Date().toISOString(), tool: "cancel_order", transport, args_summary: { order_id }, success: true });
|
|
50
|
+
return result;
|
|
50
51
|
}
|
|
51
52
|
catch (err) {
|
|
52
53
|
const msg = err instanceof BudaApiError
|
|
53
|
-
? { error: err.message, code: err.status
|
|
54
|
+
? { error: err.message, code: err.status }
|
|
54
55
|
: { error: String(err), code: "UNKNOWN" };
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
};
|
|
56
|
+
const result = { content: [{ type: "text", text: JSON.stringify(msg) }], isError: true };
|
|
57
|
+
logAudit({ ts: new Date().toISOString(), tool: "cancel_order", transport, args_summary: { order_id }, success: false, error_code: msg.code });
|
|
58
|
+
return result;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
export function register(server, client) {
|
|
@@ -22,7 +22,7 @@ type CancelOrderByClientIdArgs = {
|
|
|
22
22
|
client_id: string;
|
|
23
23
|
confirmation_token: string;
|
|
24
24
|
};
|
|
25
|
-
export declare function handleCancelOrderByClientId(args: CancelOrderByClientIdArgs, client: BudaClient): Promise<{
|
|
25
|
+
export declare function handleCancelOrderByClientId(args: CancelOrderByClientIdArgs, client: BudaClient, transport?: "http" | "stdio"): Promise<{
|
|
26
26
|
content: Array<{
|
|
27
27
|
type: "text";
|
|
28
28
|
text: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cancel_order_by_client_id.d.ts","sourceRoot":"","sources":["../../src/tools/cancel_order_by_client_id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"cancel_order_by_client_id.d.ts","sourceRoot":"","sources":["../../src/tools/cancel_order_by_client_id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;CAsBtB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAmCF,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,yBAAyB,EAC/B,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,CAuChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBpE"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { BudaApiError } from "../client.js";
|
|
3
3
|
import { flattenAmount } from "../utils.js";
|
|
4
|
+
import { logAudit } from "../audit.js";
|
|
4
5
|
export const toolSchema = {
|
|
5
6
|
name: "cancel_order_by_client_id",
|
|
6
7
|
description: "Cancel an open order by its client-assigned ID on Buda.com. " +
|
|
@@ -53,7 +54,7 @@ function normalizeOrder(o) {
|
|
|
53
54
|
paid_fee_currency: paidFee.currency,
|
|
54
55
|
};
|
|
55
56
|
}
|
|
56
|
-
export async function handleCancelOrderByClientId(args, client) {
|
|
57
|
+
export async function handleCancelOrderByClientId(args, client, transport = "stdio") {
|
|
57
58
|
const { client_id, confirmation_token } = args;
|
|
58
59
|
if (confirmation_token !== "CONFIRM") {
|
|
59
60
|
return {
|
|
@@ -73,18 +74,17 @@ export async function handleCancelOrderByClientId(args, client) {
|
|
|
73
74
|
}
|
|
74
75
|
try {
|
|
75
76
|
const data = await client.put(`/orders/by-client-id/${encodeURIComponent(client_id)}`, { order: { state: "canceling" } });
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const result = { content: [{ type: "text", text: JSON.stringify(normalizeOrder(data.order), null, 2) }] };
|
|
78
|
+
logAudit({ ts: new Date().toISOString(), tool: "cancel_order_by_client_id", transport, args_summary: {}, success: true });
|
|
79
|
+
return result;
|
|
79
80
|
}
|
|
80
81
|
catch (err) {
|
|
81
82
|
const msg = err instanceof BudaApiError
|
|
82
|
-
? { error: err.message, code: err.status
|
|
83
|
+
? { error: err.message, code: err.status }
|
|
83
84
|
: { error: String(err), code: "UNKNOWN" };
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
};
|
|
85
|
+
const result = { content: [{ type: "text", text: JSON.stringify(msg) }], isError: true };
|
|
86
|
+
logAudit({ ts: new Date().toISOString(), tool: "cancel_order_by_client_id", transport, args_summary: {}, success: false, error_code: msg.code });
|
|
87
|
+
return result;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
export function register(server, client) {
|
|
@@ -15,5 +15,14 @@ export declare const toolSchema: {
|
|
|
15
15
|
required: string[];
|
|
16
16
|
};
|
|
17
17
|
};
|
|
18
|
+
export declare function handleCompareMarkets(args: {
|
|
19
|
+
base_currency: string;
|
|
20
|
+
}, client: BudaClient, cache: MemoryCache): Promise<{
|
|
21
|
+
content: Array<{
|
|
22
|
+
type: "text";
|
|
23
|
+
text: string;
|
|
24
|
+
}>;
|
|
25
|
+
isError?: boolean;
|
|
26
|
+
}>;
|
|
18
27
|
export declare function register(server: McpServer, client: BudaClient, cache: MemoryCache): void;
|
|
19
28
|
//# sourceMappingURL=compare_markets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare_markets.d.ts","sourceRoot":"","sources":["../../src/tools/compare_markets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"compare_markets.d.ts","sourceRoot":"","sources":["../../src/tools/compare_markets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAkBtB,CAAC;AAEF,wBAAsB,oBAAoB,CACxC,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,EAC/B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,WAAW,GACjB,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,CAsEhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAaxF"}
|