@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
|
@@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { MemoryCache, CACHE_TTL } from "../cache.js";
|
|
5
|
+
import { validateCurrency } from "../validation.js";
|
|
5
6
|
import type { AllTickersResponse } from "../types.js";
|
|
6
7
|
|
|
7
8
|
export const toolSchema = {
|
|
@@ -24,6 +25,82 @@ export const toolSchema = {
|
|
|
24
25
|
},
|
|
25
26
|
};
|
|
26
27
|
|
|
28
|
+
export async function handleCompareMarkets(
|
|
29
|
+
args: { base_currency: string },
|
|
30
|
+
client: BudaClient,
|
|
31
|
+
cache: MemoryCache,
|
|
32
|
+
): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
33
|
+
const { base_currency } = args;
|
|
34
|
+
|
|
35
|
+
const currencyError = validateCurrency(base_currency);
|
|
36
|
+
if (currencyError) {
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: "text", text: JSON.stringify({ error: currencyError, code: "INVALID_CURRENCY" }) }],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const base = base_currency.toUpperCase();
|
|
45
|
+
const data = await cache.getOrFetch<AllTickersResponse>(
|
|
46
|
+
"tickers:all",
|
|
47
|
+
CACHE_TTL.TICKER,
|
|
48
|
+
() => client.get<AllTickersResponse>("/tickers"),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const matching = data.tickers.filter((t) => {
|
|
52
|
+
const [tickerBase] = t.market_id.split("-");
|
|
53
|
+
return tickerBase === base;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (matching.length === 0) {
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: JSON.stringify({
|
|
62
|
+
error: `No markets found for base currency '${base}'.`,
|
|
63
|
+
code: "NOT_FOUND",
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const result = {
|
|
72
|
+
base_currency: base,
|
|
73
|
+
markets: matching.map((t) => ({
|
|
74
|
+
market_id: t.market_id,
|
|
75
|
+
last_price: parseFloat(t.last_price[0]),
|
|
76
|
+
last_price_currency: t.last_price[1],
|
|
77
|
+
best_bid: t.max_bid ? parseFloat(t.max_bid[0]) : null,
|
|
78
|
+
best_ask: t.min_ask ? parseFloat(t.min_ask[0]) : null,
|
|
79
|
+
volume_24h: t.volume ? parseFloat(t.volume[0]) : null,
|
|
80
|
+
price_change_24h: t.price_variation_24h
|
|
81
|
+
? parseFloat((parseFloat(t.price_variation_24h) * 100).toFixed(4))
|
|
82
|
+
: null,
|
|
83
|
+
price_change_7d: t.price_variation_7d
|
|
84
|
+
? parseFloat((parseFloat(t.price_variation_7d) * 100).toFixed(4))
|
|
85
|
+
: null,
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
91
|
+
};
|
|
92
|
+
} catch (err) {
|
|
93
|
+
const msg =
|
|
94
|
+
err instanceof BudaApiError
|
|
95
|
+
? { error: err.message, code: err.status }
|
|
96
|
+
: { error: String(err), code: "UNKNOWN" };
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
99
|
+
isError: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
27
104
|
export function register(server: McpServer, client: BudaClient, cache: MemoryCache): void {
|
|
28
105
|
server.tool(
|
|
29
106
|
toolSchema.name,
|
|
@@ -35,66 +112,6 @@ export function register(server: McpServer, client: BudaClient, cache: MemoryCac
|
|
|
35
112
|
"Base currency to compare across all available markets (e.g. 'BTC', 'ETH', 'XRP').",
|
|
36
113
|
),
|
|
37
114
|
},
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
const base = base_currency.toUpperCase();
|
|
41
|
-
const data = await cache.getOrFetch<AllTickersResponse>(
|
|
42
|
-
"tickers:all",
|
|
43
|
-
CACHE_TTL.TICKER,
|
|
44
|
-
() => client.get<AllTickersResponse>("/tickers"),
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
const matching = data.tickers.filter((t) => {
|
|
48
|
-
const [tickerBase] = t.market_id.split("-");
|
|
49
|
-
return tickerBase === base;
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
if (matching.length === 0) {
|
|
53
|
-
return {
|
|
54
|
-
content: [
|
|
55
|
-
{
|
|
56
|
-
type: "text",
|
|
57
|
-
text: JSON.stringify({
|
|
58
|
-
error: `No markets found for base currency '${base}'.`,
|
|
59
|
-
code: "NOT_FOUND",
|
|
60
|
-
}),
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
isError: true,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const result = {
|
|
68
|
-
base_currency: base,
|
|
69
|
-
markets: matching.map((t) => ({
|
|
70
|
-
market_id: t.market_id,
|
|
71
|
-
last_price: parseFloat(t.last_price[0]),
|
|
72
|
-
last_price_currency: t.last_price[1],
|
|
73
|
-
best_bid: t.max_bid ? parseFloat(t.max_bid[0]) : null,
|
|
74
|
-
best_ask: t.min_ask ? parseFloat(t.min_ask[0]) : null,
|
|
75
|
-
volume_24h: t.volume ? parseFloat(t.volume[0]) : null,
|
|
76
|
-
price_change_24h: t.price_variation_24h
|
|
77
|
-
? parseFloat((parseFloat(t.price_variation_24h) * 100).toFixed(4))
|
|
78
|
-
: null,
|
|
79
|
-
price_change_7d: t.price_variation_7d
|
|
80
|
-
? parseFloat((parseFloat(t.price_variation_7d) * 100).toFixed(4))
|
|
81
|
-
: null,
|
|
82
|
-
})),
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
87
|
-
};
|
|
88
|
-
} catch (err) {
|
|
89
|
-
const msg =
|
|
90
|
-
err instanceof BudaApiError
|
|
91
|
-
? { error: err.message, code: err.status, path: err.path }
|
|
92
|
-
: { error: String(err), code: "UNKNOWN" };
|
|
93
|
-
return {
|
|
94
|
-
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
95
|
-
isError: true,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
},
|
|
115
|
+
(args) => handleCompareMarkets(args, client, cache),
|
|
99
116
|
);
|
|
100
117
|
}
|
|
@@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { validateMarketId } from "../validation.js";
|
|
5
|
+
import { logAudit } from "../audit.js";
|
|
5
6
|
import type { OrdersResponse, OrderResponse } from "../types.js";
|
|
6
7
|
|
|
7
8
|
// ---- Module-level timer state (persists across HTTP requests / tool invocations) ----
|
|
@@ -125,6 +126,7 @@ type ScheduleArgs = {
|
|
|
125
126
|
export async function handleScheduleCancelAll(
|
|
126
127
|
args: ScheduleArgs,
|
|
127
128
|
client: BudaClient,
|
|
129
|
+
transport: "http" | "stdio" = "stdio",
|
|
128
130
|
): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
129
131
|
const { market_id, ttl_seconds, confirmation_token } = args;
|
|
130
132
|
|
|
@@ -173,6 +175,7 @@ export async function handleScheduleCancelAll(
|
|
|
173
175
|
const id = market_id.toLowerCase();
|
|
174
176
|
const entry = armTimer(id, ttl_seconds, client);
|
|
175
177
|
|
|
178
|
+
logAudit({ ts: new Date().toISOString(), tool: "schedule_cancel_all", transport, args_summary: { market_id: market_id.toUpperCase(), ttl_seconds }, success: true });
|
|
176
179
|
return {
|
|
177
180
|
content: [
|
|
178
181
|
{
|
|
@@ -334,7 +337,23 @@ export function register(
|
|
|
334
337
|
.string()
|
|
335
338
|
.describe("Market ID whose timer should be renewed (e.g. 'BTC-CLP')."),
|
|
336
339
|
},
|
|
337
|
-
(args) =>
|
|
340
|
+
(args) => {
|
|
341
|
+
if (transport === "http") {
|
|
342
|
+
return Promise.resolve({
|
|
343
|
+
content: [{
|
|
344
|
+
type: "text" as const,
|
|
345
|
+
text: JSON.stringify({
|
|
346
|
+
error:
|
|
347
|
+
"renew_cancel_timer is not available on the HTTP transport. " +
|
|
348
|
+
"Timer state is process-local and only meaningful in stdio mode on a persistent local process.",
|
|
349
|
+
code: "TRANSPORT_NOT_SUPPORTED",
|
|
350
|
+
}),
|
|
351
|
+
}],
|
|
352
|
+
isError: true,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
return Promise.resolve(handleRenewCancelTimer(args, client));
|
|
356
|
+
},
|
|
338
357
|
);
|
|
339
358
|
|
|
340
359
|
server.tool(
|
|
@@ -345,6 +364,22 @@ export function register(
|
|
|
345
364
|
.string()
|
|
346
365
|
.describe("Market ID whose timer should be disarmed (e.g. 'BTC-CLP')."),
|
|
347
366
|
},
|
|
348
|
-
(args) =>
|
|
367
|
+
(args) => {
|
|
368
|
+
if (transport === "http") {
|
|
369
|
+
return Promise.resolve({
|
|
370
|
+
content: [{
|
|
371
|
+
type: "text" as const,
|
|
372
|
+
text: JSON.stringify({
|
|
373
|
+
error:
|
|
374
|
+
"disarm_cancel_timer is not available on the HTTP transport. " +
|
|
375
|
+
"Timer state is process-local and only meaningful in stdio mode on a persistent local process.",
|
|
376
|
+
code: "TRANSPORT_NOT_SUPPORTED",
|
|
377
|
+
}),
|
|
378
|
+
}],
|
|
379
|
+
isError: true,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
return Promise.resolve(handleDisarmCancelTimer(args));
|
|
383
|
+
},
|
|
349
384
|
);
|
|
350
385
|
}
|
package/src/tools/deposits.ts
CHANGED
|
@@ -104,7 +104,7 @@ export async function handleGetDepositHistory(
|
|
|
104
104
|
} catch (err) {
|
|
105
105
|
const msg =
|
|
106
106
|
err instanceof BudaApiError
|
|
107
|
-
? { error: err.message, code: err.status
|
|
107
|
+
? { error: err.message, code: err.status }
|
|
108
108
|
: { error: String(err), code: "UNKNOWN" };
|
|
109
109
|
return {
|
|
110
110
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -189,7 +189,7 @@ export async function handleCreateFiatDeposit(
|
|
|
189
189
|
} catch (err) {
|
|
190
190
|
const msg =
|
|
191
191
|
err instanceof BudaApiError
|
|
192
|
-
? { error: err.message, code: err.status
|
|
192
|
+
? { error: err.message, code: err.status }
|
|
193
193
|
: { error: String(err), code: "UNKNOWN" };
|
|
194
194
|
return {
|
|
195
195
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/fees.ts
CHANGED
|
@@ -69,7 +69,7 @@ export async function handleGetNetworkFees(
|
|
|
69
69
|
} catch (err) {
|
|
70
70
|
const msg =
|
|
71
71
|
err instanceof BudaApiError
|
|
72
|
-
? { error: err.message, code: err.status
|
|
72
|
+
? { error: err.message, code: err.status }
|
|
73
73
|
: { error: String(err), code: "UNKNOWN" };
|
|
74
74
|
return {
|
|
75
75
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/lightning.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { flattenAmount } from "../utils.js";
|
|
5
|
+
import { logAudit } from "../audit.js";
|
|
5
6
|
import type { LightningWithdrawalResponse, LightningInvoiceResponse } from "../types.js";
|
|
6
7
|
|
|
7
8
|
export const lightningWithdrawalToolSchema = {
|
|
@@ -69,6 +70,7 @@ type CreateLightningInvoiceArgs = {
|
|
|
69
70
|
export async function handleLightningWithdrawal(
|
|
70
71
|
args: LightningWithdrawalArgs,
|
|
71
72
|
client: BudaClient,
|
|
73
|
+
transport: "http" | "stdio" = "stdio",
|
|
72
74
|
): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
73
75
|
const { invoice, confirmation_token } = args;
|
|
74
76
|
|
|
@@ -91,7 +93,7 @@ export async function handleLightningWithdrawal(
|
|
|
91
93
|
};
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
const BOLT11_RE = /^ln(bc|tb|bcrt)\d
|
|
96
|
+
const BOLT11_RE = /^ln(bc|tb|bcrt)\d*[munp]?1[a-z0-9]{20,}$/i;
|
|
95
97
|
if (!BOLT11_RE.test(invoice)) {
|
|
96
98
|
return {
|
|
97
99
|
content: [{
|
|
@@ -117,10 +119,10 @@ export async function handleLightningWithdrawal(
|
|
|
117
119
|
const amount = flattenAmount(lw.amount);
|
|
118
120
|
const fee = flattenAmount(lw.fee);
|
|
119
121
|
|
|
120
|
-
|
|
122
|
+
const result = {
|
|
121
123
|
content: [
|
|
122
124
|
{
|
|
123
|
-
type: "text",
|
|
125
|
+
type: "text" as const,
|
|
124
126
|
text: JSON.stringify(
|
|
125
127
|
{
|
|
126
128
|
id: lw.id,
|
|
@@ -138,15 +140,16 @@ export async function handleLightningWithdrawal(
|
|
|
138
140
|
},
|
|
139
141
|
],
|
|
140
142
|
};
|
|
143
|
+
logAudit({ ts: new Date().toISOString(), tool: "lightning_withdrawal", transport, args_summary: {}, success: true });
|
|
144
|
+
return result;
|
|
141
145
|
} catch (err) {
|
|
142
146
|
const msg =
|
|
143
147
|
err instanceof BudaApiError
|
|
144
|
-
? { error: err.message, code: err.status
|
|
148
|
+
? { error: err.message, code: err.status }
|
|
145
149
|
: { error: String(err), code: "UNKNOWN" };
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
};
|
|
150
|
+
const result = { content: [{ type: "text" as const, text: JSON.stringify(msg) }], isError: true as const };
|
|
151
|
+
logAudit({ ts: new Date().toISOString(), tool: "lightning_withdrawal", transport, args_summary: {}, success: false, error_code: msg.code });
|
|
152
|
+
return result;
|
|
150
153
|
}
|
|
151
154
|
}
|
|
152
155
|
|
|
@@ -192,7 +195,7 @@ export async function handleCreateLightningInvoice(
|
|
|
192
195
|
} catch (err) {
|
|
193
196
|
const msg =
|
|
194
197
|
err instanceof BudaApiError
|
|
195
|
-
? { error: err.message, code: err.status
|
|
198
|
+
? { error: err.message, code: err.status }
|
|
196
199
|
: { error: String(err), code: "UNKNOWN" };
|
|
197
200
|
return {
|
|
198
201
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -118,7 +118,7 @@ export async function handleMarketSentiment(
|
|
|
118
118
|
} catch (err) {
|
|
119
119
|
const msg =
|
|
120
120
|
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) }],
|
|
@@ -101,7 +101,7 @@ export async function handleMarketSummary(
|
|
|
101
101
|
} catch (err) {
|
|
102
102
|
const msg =
|
|
103
103
|
err instanceof BudaApiError
|
|
104
|
-
? { error: err.message, code: err.status
|
|
104
|
+
? { error: err.message, code: err.status }
|
|
105
105
|
: { error: String(err), code: "UNKNOWN" };
|
|
106
106
|
return {
|
|
107
107
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/markets.ts
CHANGED
|
@@ -68,7 +68,7 @@ export function register(server: McpServer, client: BudaClient, cache: MemoryCac
|
|
|
68
68
|
} catch (err) {
|
|
69
69
|
const msg =
|
|
70
70
|
err instanceof BudaApiError
|
|
71
|
-
? { error: err.message, code: err.status
|
|
71
|
+
? { error: err.message, code: err.status }
|
|
72
72
|
: { error: String(err), code: "UNKNOWN" };
|
|
73
73
|
return {
|
|
74
74
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -88,7 +88,7 @@ export async function handleGetOrder(
|
|
|
88
88
|
} catch (err) {
|
|
89
89
|
const msg =
|
|
90
90
|
err instanceof BudaApiError
|
|
91
|
-
? { error: err.message, code: err.status
|
|
91
|
+
? { error: err.message, code: err.status }
|
|
92
92
|
: { error: String(err), code: "UNKNOWN" };
|
|
93
93
|
return {
|
|
94
94
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -109,7 +109,7 @@ export async function handleGetOrderByClientId(
|
|
|
109
109
|
} catch (err) {
|
|
110
110
|
const msg =
|
|
111
111
|
err instanceof BudaApiError
|
|
112
|
-
? { error: err.message, code: err.status
|
|
112
|
+
? { error: err.message, code: err.status }
|
|
113
113
|
: { error: String(err), code: "UNKNOWN" };
|
|
114
114
|
return {
|
|
115
115
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/orderbook.ts
CHANGED
|
@@ -83,7 +83,7 @@ export function register(server: McpServer, client: BudaClient, cache: MemoryCac
|
|
|
83
83
|
} catch (err) {
|
|
84
84
|
const msg =
|
|
85
85
|
err instanceof BudaApiError
|
|
86
|
-
? { error: err.message, code: err.status
|
|
86
|
+
? { error: err.message, code: err.status }
|
|
87
87
|
: { error: String(err), code: "UNKNOWN" };
|
|
88
88
|
return {
|
|
89
89
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/orders.ts
CHANGED
|
@@ -135,7 +135,7 @@ export function register(server: McpServer, client: BudaClient): void {
|
|
|
135
135
|
} catch (err) {
|
|
136
136
|
const msg =
|
|
137
137
|
err instanceof BudaApiError
|
|
138
|
-
? { error: err.message, code: err.status
|
|
138
|
+
? { error: err.message, code: err.status }
|
|
139
139
|
: { error: String(err), code: "UNKNOWN" };
|
|
140
140
|
return {
|
|
141
141
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/place_order.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { validateMarketId } from "../validation.js";
|
|
5
|
+
import { logAudit } from "../audit.js";
|
|
5
6
|
import type { OrderResponse } from "../types.js";
|
|
6
7
|
|
|
7
8
|
export const toolSchema = {
|
|
@@ -91,6 +92,7 @@ type PlaceOrderArgs = {
|
|
|
91
92
|
export async function handlePlaceOrder(
|
|
92
93
|
args: PlaceOrderArgs,
|
|
93
94
|
client: BudaClient,
|
|
95
|
+
transport: "http" | "stdio" = "stdio",
|
|
94
96
|
): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
95
97
|
const {
|
|
96
98
|
market_id,
|
|
@@ -243,18 +245,35 @@ export async function handlePlaceOrder(
|
|
|
243
245
|
payload,
|
|
244
246
|
);
|
|
245
247
|
|
|
246
|
-
|
|
247
|
-
content: [{ type: "text", text: JSON.stringify(data.order, null, 2) }],
|
|
248
|
+
const result = {
|
|
249
|
+
content: [{ type: "text" as const, text: JSON.stringify(data.order, null, 2) }],
|
|
248
250
|
};
|
|
251
|
+
logAudit({
|
|
252
|
+
ts: new Date().toISOString(),
|
|
253
|
+
tool: "place_order",
|
|
254
|
+
transport,
|
|
255
|
+
args_summary: { market_id, type, price_type, amount },
|
|
256
|
+
success: true,
|
|
257
|
+
});
|
|
258
|
+
return result;
|
|
249
259
|
} catch (err) {
|
|
250
260
|
const msg =
|
|
251
261
|
err instanceof BudaApiError
|
|
252
|
-
? { error: err.message, code: err.status
|
|
262
|
+
? { error: err.message, code: err.status }
|
|
253
263
|
: { error: String(err), code: "UNKNOWN" };
|
|
254
|
-
|
|
255
|
-
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
264
|
+
const result = {
|
|
265
|
+
content: [{ type: "text" as const, text: JSON.stringify(msg) }],
|
|
256
266
|
isError: true,
|
|
257
267
|
};
|
|
268
|
+
logAudit({
|
|
269
|
+
ts: new Date().toISOString(),
|
|
270
|
+
tool: "place_order",
|
|
271
|
+
transport,
|
|
272
|
+
args_summary: { market_id, type, price_type, amount },
|
|
273
|
+
success: false,
|
|
274
|
+
error_code: msg.code,
|
|
275
|
+
});
|
|
276
|
+
return result;
|
|
258
277
|
}
|
|
259
278
|
}
|
|
260
279
|
|
|
@@ -108,7 +108,7 @@ export function register(server: McpServer, client: BudaClient, _cache: MemoryCa
|
|
|
108
108
|
} catch (err) {
|
|
109
109
|
const msg =
|
|
110
110
|
err instanceof BudaApiError
|
|
111
|
-
? { error: err.message, code: err.status
|
|
111
|
+
? { error: err.message, code: err.status }
|
|
112
112
|
: { error: String(err), code: "UNKNOWN" };
|
|
113
113
|
return {
|
|
114
114
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/quotation.ts
CHANGED
|
@@ -100,7 +100,7 @@ export async function handleGetRealQuotation(
|
|
|
100
100
|
} catch (err) {
|
|
101
101
|
const msg =
|
|
102
102
|
err instanceof BudaApiError
|
|
103
|
-
? { error: err.message, code: err.status
|
|
103
|
+
? { error: err.message, code: err.status }
|
|
104
104
|
: { error: String(err), code: "UNKNOWN" };
|
|
105
105
|
return {
|
|
106
106
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { validateCurrency } from "../validation.js";
|
|
5
|
+
import { logAudit } from "../audit.js";
|
|
5
6
|
import type { ReceiveAddressesResponse, SingleReceiveAddressResponse, ReceiveAddress } from "../types.js";
|
|
6
7
|
|
|
7
8
|
export const createReceiveAddressToolSchema = {
|
|
@@ -114,7 +115,7 @@ export async function handleListReceiveAddresses(
|
|
|
114
115
|
} catch (err) {
|
|
115
116
|
const msg =
|
|
116
117
|
err instanceof BudaApiError
|
|
117
|
-
? { error: err.message, code: err.status
|
|
118
|
+
? { error: err.message, code: err.status }
|
|
118
119
|
: { error: String(err), code: "UNKNOWN" };
|
|
119
120
|
return {
|
|
120
121
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -147,7 +148,7 @@ export async function handleGetReceiveAddress(
|
|
|
147
148
|
} catch (err) {
|
|
148
149
|
const msg =
|
|
149
150
|
err instanceof BudaApiError
|
|
150
|
-
? { error: err.message, code: err.status
|
|
151
|
+
? { error: err.message, code: err.status }
|
|
151
152
|
: { error: String(err), code: "UNKNOWN" };
|
|
152
153
|
return {
|
|
153
154
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -159,6 +160,7 @@ export async function handleGetReceiveAddress(
|
|
|
159
160
|
export async function handleCreateReceiveAddress(
|
|
160
161
|
args: { currency: string; confirmation_token: string },
|
|
161
162
|
client: BudaClient,
|
|
163
|
+
transport: "http" | "stdio" = "stdio",
|
|
162
164
|
): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
163
165
|
const { currency, confirmation_token } = args;
|
|
164
166
|
|
|
@@ -193,18 +195,17 @@ export async function handleCreateReceiveAddress(
|
|
|
193
195
|
`/currencies/${currency.toUpperCase()}/receive_addresses`,
|
|
194
196
|
{},
|
|
195
197
|
);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
198
|
+
const result = { content: [{ type: "text" as const, text: JSON.stringify(normalizeAddress(data.receive_address), null, 2) }] };
|
|
199
|
+
logAudit({ ts: new Date().toISOString(), tool: "create_receive_address", transport, args_summary: { currency }, success: true });
|
|
200
|
+
return result;
|
|
199
201
|
} catch (err) {
|
|
200
202
|
const msg =
|
|
201
203
|
err instanceof BudaApiError
|
|
202
|
-
? { error: err.message, code: err.status
|
|
204
|
+
? { error: err.message, code: err.status }
|
|
203
205
|
: { error: String(err), code: "UNKNOWN" };
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
};
|
|
206
|
+
const result = { content: [{ type: "text" as const, text: JSON.stringify(msg) }], isError: true as const };
|
|
207
|
+
logAudit({ ts: new Date().toISOString(), tool: "create_receive_address", transport, args_summary: { currency }, success: false, error_code: msg.code });
|
|
208
|
+
return result;
|
|
208
209
|
}
|
|
209
210
|
}
|
|
210
211
|
|
|
@@ -87,7 +87,7 @@ export async function handleListRemittanceRecipients(
|
|
|
87
87
|
} catch (err) {
|
|
88
88
|
const msg =
|
|
89
89
|
err instanceof BudaApiError
|
|
90
|
-
? { error: err.message, code: err.status
|
|
90
|
+
? { error: err.message, code: err.status }
|
|
91
91
|
: { error: String(err), code: "UNKNOWN" };
|
|
92
92
|
return {
|
|
93
93
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -108,7 +108,7 @@ export async function handleGetRemittanceRecipient(
|
|
|
108
108
|
} catch (err) {
|
|
109
109
|
const msg =
|
|
110
110
|
err instanceof BudaApiError
|
|
111
|
-
? { error: err.message, code: err.status
|
|
111
|
+
? { error: err.message, code: err.status }
|
|
112
112
|
: { error: String(err), code: "UNKNOWN" };
|
|
113
113
|
return {
|
|
114
114
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/remittances.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { flattenAmount } from "../utils.js";
|
|
5
5
|
import { validateCurrency } from "../validation.js";
|
|
6
|
+
import { logAudit } from "../audit.js";
|
|
6
7
|
import type { RemittancesResponse, SingleRemittanceResponse, Remittance } from "../types.js";
|
|
7
8
|
|
|
8
9
|
export const listRemittancesToolSchema = {
|
|
@@ -152,7 +153,7 @@ export async function handleListRemittances(
|
|
|
152
153
|
} catch (err) {
|
|
153
154
|
const msg =
|
|
154
155
|
err instanceof BudaApiError
|
|
155
|
-
? { error: err.message, code: err.status
|
|
156
|
+
? { error: err.message, code: err.status }
|
|
156
157
|
: { error: String(err), code: "UNKNOWN" };
|
|
157
158
|
return {
|
|
158
159
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -173,7 +174,7 @@ export async function handleGetRemittance(
|
|
|
173
174
|
} catch (err) {
|
|
174
175
|
const msg =
|
|
175
176
|
err instanceof BudaApiError
|
|
176
|
-
? { error: err.message, code: err.status
|
|
177
|
+
? { error: err.message, code: err.status }
|
|
177
178
|
: { error: String(err), code: "UNKNOWN" };
|
|
178
179
|
return {
|
|
179
180
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
@@ -185,6 +186,7 @@ export async function handleGetRemittance(
|
|
|
185
186
|
export async function handleQuoteRemittance(
|
|
186
187
|
args: { currency: string; amount: number; recipient_id: number; confirmation_token: string },
|
|
187
188
|
client: BudaClient,
|
|
189
|
+
transport: "http" | "stdio" = "stdio",
|
|
188
190
|
): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
189
191
|
const { currency, amount, recipient_id, confirmation_token } = args;
|
|
190
192
|
|
|
@@ -222,24 +224,24 @@ export async function handleQuoteRemittance(
|
|
|
222
224
|
recipient_id,
|
|
223
225
|
},
|
|
224
226
|
});
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
227
|
+
const result = { content: [{ type: "text" as const, text: JSON.stringify(normalizeRemittance(data.remittance), null, 2) }] };
|
|
228
|
+
logAudit({ ts: new Date().toISOString(), tool: "quote_remittance", transport, args_summary: { currency, amount, recipient_id }, success: true });
|
|
229
|
+
return result;
|
|
228
230
|
} catch (err) {
|
|
229
231
|
const msg =
|
|
230
232
|
err instanceof BudaApiError
|
|
231
|
-
? { error: err.message, code: err.status
|
|
233
|
+
? { error: err.message, code: err.status }
|
|
232
234
|
: { error: String(err), code: "UNKNOWN" };
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
};
|
|
235
|
+
const result = { content: [{ type: "text" as const, text: JSON.stringify(msg) }], isError: true as const };
|
|
236
|
+
logAudit({ ts: new Date().toISOString(), tool: "quote_remittance", transport, args_summary: { currency, amount, recipient_id }, success: false, error_code: msg.code });
|
|
237
|
+
return result;
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
|
|
240
241
|
export async function handleAcceptRemittanceQuote(
|
|
241
242
|
args: { id: number; confirmation_token: string },
|
|
242
243
|
client: BudaClient,
|
|
244
|
+
transport: "http" | "stdio" = "stdio",
|
|
243
245
|
): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
244
246
|
const { id, confirmation_token } = args;
|
|
245
247
|
|
|
@@ -264,18 +266,17 @@ export async function handleAcceptRemittanceQuote(
|
|
|
264
266
|
const data = await client.put<SingleRemittanceResponse>(`/remittances/${id}`, {
|
|
265
267
|
remittance: { state: "confirming" },
|
|
266
268
|
});
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
269
|
+
const result = { content: [{ type: "text" as const, text: JSON.stringify(normalizeRemittance(data.remittance), null, 2) }] };
|
|
270
|
+
logAudit({ ts: new Date().toISOString(), tool: "accept_remittance_quote", transport, args_summary: { remittance_id: id }, success: true });
|
|
271
|
+
return result;
|
|
270
272
|
} catch (err) {
|
|
271
273
|
const msg =
|
|
272
274
|
err instanceof BudaApiError
|
|
273
|
-
? { error: err.message, code: err.status
|
|
275
|
+
? { error: err.message, code: err.status }
|
|
274
276
|
: { error: String(err), code: "UNKNOWN" };
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
};
|
|
277
|
+
const result = { content: [{ type: "text" as const, text: JSON.stringify(msg) }], isError: true as const };
|
|
278
|
+
logAudit({ ts: new Date().toISOString(), tool: "accept_remittance_quote", transport, args_summary: { remittance_id: id }, success: false, error_code: msg.code });
|
|
279
|
+
return result;
|
|
279
280
|
}
|
|
280
281
|
}
|
|
281
282
|
|
|
@@ -148,7 +148,7 @@ export async function handleSimulateOrder(
|
|
|
148
148
|
} catch (err) {
|
|
149
149
|
const msg =
|
|
150
150
|
err instanceof BudaApiError
|
|
151
|
-
? { error: err.message, code: err.status
|
|
151
|
+
? { error: err.message, code: err.status }
|
|
152
152
|
: { error: String(err), code: "UNKNOWN" };
|
|
153
153
|
return {
|
|
154
154
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|
package/src/tools/spread.ts
CHANGED
|
@@ -86,7 +86,7 @@ export function register(server: McpServer, client: BudaClient, cache: MemoryCac
|
|
|
86
86
|
} catch (err) {
|
|
87
87
|
const msg =
|
|
88
88
|
err instanceof BudaApiError
|
|
89
|
-
? { error: err.message, code: err.status
|
|
89
|
+
? { error: err.message, code: err.status }
|
|
90
90
|
: { error: String(err), code: "UNKNOWN" };
|
|
91
91
|
return {
|
|
92
92
|
content: [{ type: "text", text: JSON.stringify(msg) }],
|