@guiie/buda-mcp 1.5.0 → 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.
Files changed (123) hide show
  1. package/.cursor/rules/marketplace-docs-sync.mdc +32 -0
  2. package/CHANGELOG.md +75 -0
  3. package/PUBLISH_CHECKLIST.md +48 -89
  4. package/README.md +446 -78
  5. package/dist/audit.d.ts +21 -0
  6. package/dist/audit.d.ts.map +1 -0
  7. package/dist/audit.js +14 -0
  8. package/dist/client.d.ts +1 -0
  9. package/dist/client.d.ts.map +1 -1
  10. package/dist/client.js +2 -1
  11. package/dist/http.js +65 -7
  12. package/dist/index.js +12 -3
  13. package/dist/tools/account.js +1 -1
  14. package/dist/tools/arbitrage.js +1 -1
  15. package/dist/tools/balance.js +1 -1
  16. package/dist/tools/balances.js +1 -1
  17. package/dist/tools/banks.js +1 -1
  18. package/dist/tools/batch_orders.d.ts +6 -1
  19. package/dist/tools/batch_orders.d.ts.map +1 -1
  20. package/dist/tools/batch_orders.js +47 -3
  21. package/dist/tools/cancel_all_orders.d.ts +1 -1
  22. package/dist/tools/cancel_all_orders.d.ts.map +1 -1
  23. package/dist/tools/cancel_all_orders.js +10 -13
  24. package/dist/tools/cancel_order.d.ts +1 -1
  25. package/dist/tools/cancel_order.d.ts.map +1 -1
  26. package/dist/tools/cancel_order.js +10 -10
  27. package/dist/tools/cancel_order_by_client_id.d.ts +1 -1
  28. package/dist/tools/cancel_order_by_client_id.d.ts.map +1 -1
  29. package/dist/tools/cancel_order_by_client_id.js +9 -9
  30. package/dist/tools/compare_markets.d.ts +9 -0
  31. package/dist/tools/compare_markets.d.ts.map +1 -1
  32. package/dist/tools/compare_markets.js +63 -53
  33. package/dist/tools/dead_mans_switch.d.ts +2 -2
  34. package/dist/tools/dead_mans_switch.d.ts.map +1 -1
  35. package/dist/tools/dead_mans_switch.js +68 -6
  36. package/dist/tools/deposits.js +2 -2
  37. package/dist/tools/fees.js +1 -1
  38. package/dist/tools/lightning.d.ts +1 -1
  39. package/dist/tools/lightning.d.ts.map +1 -1
  40. package/dist/tools/lightning.js +25 -9
  41. package/dist/tools/market_sentiment.js +1 -1
  42. package/dist/tools/market_summary.js +1 -1
  43. package/dist/tools/markets.js +1 -1
  44. package/dist/tools/order_lookup.js +2 -2
  45. package/dist/tools/orderbook.js +1 -1
  46. package/dist/tools/orders.js +1 -1
  47. package/dist/tools/place_order.d.ts +1 -1
  48. package/dist/tools/place_order.d.ts.map +1 -1
  49. package/dist/tools/place_order.js +53 -4
  50. package/dist/tools/price_history.js +1 -1
  51. package/dist/tools/quotation.js +1 -1
  52. package/dist/tools/receive_addresses.d.ts +6 -1
  53. package/dist/tools/receive_addresses.d.ts.map +1 -1
  54. package/dist/tools/receive_addresses.js +37 -13
  55. package/dist/tools/remittance_recipients.js +2 -2
  56. package/dist/tools/remittances.d.ts +7 -2
  57. package/dist/tools/remittances.d.ts.map +1 -1
  58. package/dist/tools/remittances.js +46 -23
  59. package/dist/tools/simulate_order.js +1 -1
  60. package/dist/tools/spread.js +1 -1
  61. package/dist/tools/technical_indicators.d.ts.map +1 -1
  62. package/dist/tools/technical_indicators.js +3 -2
  63. package/dist/tools/ticker.js +1 -1
  64. package/dist/tools/trades.js +1 -1
  65. package/dist/tools/volume.js +1 -1
  66. package/dist/tools/withdrawals.d.ts +1 -1
  67. package/dist/tools/withdrawals.d.ts.map +1 -1
  68. package/dist/tools/withdrawals.js +21 -11
  69. package/dist/utils.d.ts +10 -0
  70. package/dist/utils.d.ts.map +1 -1
  71. package/dist/utils.js +29 -1
  72. package/dist/validation.d.ts +6 -0
  73. package/dist/validation.d.ts.map +1 -1
  74. package/dist/validation.js +26 -0
  75. package/dist/version.d.ts.map +1 -1
  76. package/dist/version.js +8 -1
  77. package/marketplace/README.md +1 -1
  78. package/marketplace/claude-listing.md +75 -4
  79. package/marketplace/gemini-tools.json +325 -2
  80. package/marketplace/openapi.yaml +160 -1
  81. package/package.json +2 -1
  82. package/server.json +2 -2
  83. package/src/audit.ts +24 -0
  84. package/src/client.ts +3 -1
  85. package/src/http.ts +75 -7
  86. package/src/index.ts +10 -3
  87. package/src/tools/account.ts +1 -1
  88. package/src/tools/arbitrage.ts +1 -1
  89. package/src/tools/balance.ts +1 -1
  90. package/src/tools/balances.ts +1 -1
  91. package/src/tools/banks.ts +1 -1
  92. package/src/tools/batch_orders.ts +52 -2
  93. package/src/tools/cancel_all_orders.ts +10 -12
  94. package/src/tools/cancel_order.ts +10 -9
  95. package/src/tools/cancel_order_by_client_id.ts +9 -8
  96. package/src/tools/compare_markets.ts +78 -61
  97. package/src/tools/dead_mans_switch.ts +76 -5
  98. package/src/tools/deposits.ts +2 -2
  99. package/src/tools/fees.ts +1 -1
  100. package/src/tools/lightning.ts +28 -9
  101. package/src/tools/market_sentiment.ts +1 -1
  102. package/src/tools/market_summary.ts +1 -1
  103. package/src/tools/markets.ts +1 -1
  104. package/src/tools/order_lookup.ts +2 -2
  105. package/src/tools/orderbook.ts +1 -1
  106. package/src/tools/orders.ts +1 -1
  107. package/src/tools/place_order.ts +56 -5
  108. package/src/tools/price_history.ts +1 -1
  109. package/src/tools/quotation.ts +1 -1
  110. package/src/tools/receive_addresses.ts +40 -13
  111. package/src/tools/remittance_recipients.ts +2 -2
  112. package/src/tools/remittances.ts +49 -22
  113. package/src/tools/simulate_order.ts +1 -1
  114. package/src/tools/spread.ts +1 -1
  115. package/src/tools/technical_indicators.ts +3 -2
  116. package/src/tools/ticker.ts +1 -1
  117. package/src/tools/trades.ts +1 -1
  118. package/src/tools/volume.ts +1 -1
  119. package/src/tools/withdrawals.ts +22 -10
  120. package/src/utils.ts +36 -1
  121. package/src/validation.ts +29 -0
  122. package/src/version.ts +11 -3
  123. package/test/unit.ts +623 -22
@@ -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 CHANGED
@@ -10,6 +10,7 @@ export declare class BudaClient {
10
10
  private readonly apiSecret;
11
11
  constructor(baseUrl?: string, apiKey?: string, apiSecret?: string);
12
12
  hasAuth(): boolean;
13
+ private _nonceCounter;
13
14
  private nonce;
14
15
  private sign;
15
16
  private authHeaders;
@@ -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,KAAK;IAIb,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,WAAW;IAWnB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;;OAIG;YACW,cAAc;YA2Bd,cAAc;IActB,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"}
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;IActB,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
@@ -25,8 +25,9 @@ export class BudaClient {
25
25
  hasAuth() {
26
26
  return Boolean(this.apiKey && this.apiSecret);
27
27
  }
28
+ _nonceCounter = 0;
28
29
  nonce() {
29
- return String(Math.floor(Date.now() * 1000));
30
+ return String(Date.now() * 1000 + (this._nonceCounter++ % 1000));
30
31
  }
31
32
  sign(method, pathWithQuery, body, nonce) {
32
33
  const encodedBody = body ? Buffer.from(body).toString("base64") : "";
package/dist/http.js CHANGED
@@ -1,9 +1,12 @@
1
1
  import express from "express";
2
+ import rateLimit from "express-rate-limit";
2
3
  import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
3
4
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
5
  import { BudaClient } from "./client.js";
5
6
  import { MemoryCache, CACHE_TTL } from "./cache.js";
7
+ import { safeTokenEqual, parseEnvInt } from "./utils.js";
6
8
  import { VERSION } from "./version.js";
9
+ import { validateMarketId } from "./validation.js";
7
10
  import * as markets from "./tools/markets.js";
8
11
  import * as ticker from "./tools/ticker.js";
9
12
  import * as orderbook from "./tools/orderbook.js";
@@ -39,7 +42,14 @@ import * as cancelOrderByClientId from "./tools/cancel_order_by_client_id.js";
39
42
  import * as batchOrders from "./tools/batch_orders.js";
40
43
  import * as lightning from "./tools/lightning.js";
41
44
  import { handleMarketSummary } from "./tools/market_summary.js";
42
- const PORT = parseInt(process.env.PORT ?? "3000", 10);
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
+ }
43
53
  const client = new BudaClient(undefined, process.env.BUDA_API_KEY, process.env.BUDA_API_SECRET);
44
54
  const authEnabled = client.hasAuth();
45
55
  // Schemas for the Smithery server-card — assembled from the same definitions used in register().
@@ -119,7 +129,7 @@ function createServer() {
119
129
  orders.register(server, client);
120
130
  placeOrder.register(server, client);
121
131
  cancelOrder.register(server, client);
122
- deadMansSwitch.register(server, client);
132
+ deadMansSwitch.register(server, client, "http");
123
133
  account.register(server, client);
124
134
  balance.register(server, client);
125
135
  orderLookup.register(server, client);
@@ -148,7 +158,11 @@ function createServer() {
148
158
  };
149
159
  });
150
160
  server.resource("buda-ticker", new ResourceTemplate("buda://ticker/{market}", { list: undefined }), async (uri, params) => {
151
- const marketId = params.market.toLowerCase();
161
+ const raw = params.market;
162
+ const validationError = validateMarketId(raw);
163
+ if (validationError)
164
+ throw new Error(validationError);
165
+ const marketId = raw.toLowerCase();
152
166
  const data = await reqCache.getOrFetch(`ticker:${marketId}`, CACHE_TTL.TICKER, () => client.get(`/markets/${marketId}/ticker`));
153
167
  return {
154
168
  contents: [
@@ -161,9 +175,13 @@ function createServer() {
161
175
  };
162
176
  });
163
177
  server.resource("buda-summary", new ResourceTemplate("buda://summary/{market}", { list: undefined }), async (uri, params) => {
164
- const marketId = params.market.toUpperCase();
178
+ const raw = params.market;
179
+ const validationError = validateMarketId(raw);
180
+ if (validationError)
181
+ throw new Error(validationError);
182
+ const marketId = raw.toUpperCase();
165
183
  const result = await handleMarketSummary({ market_id: marketId }, client, reqCache);
166
- const text = result.content[0].text;
184
+ const text = result.content[0]?.text ?? JSON.stringify({ error: "No content returned" });
167
185
  return {
168
186
  contents: [
169
187
  {
@@ -177,7 +195,47 @@ function createServer() {
177
195
  return server;
178
196
  }
179
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);
180
201
  app.use(express.json());
202
+ const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
203
+ if (authEnabled && !MCP_AUTH_TOKEN) {
204
+ console.error("[buda-mcp] FATAL: BUDA_API_KEY/BUDA_API_SECRET are set but MCP_AUTH_TOKEN is not.\n" +
205
+ " The /mcp endpoint would be publicly accessible with full account access.\n" +
206
+ " Set MCP_AUTH_TOKEN to a long random secret, or run in stdio mode instead.");
207
+ process.exit(1);
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
+ }
220
+ const mcpRateLimiter = rateLimit({
221
+ windowMs: 60_000,
222
+ max: rateLimitMax,
223
+ standardHeaders: true,
224
+ legacyHeaders: false,
225
+ message: { error: "Too many requests. Retry after 60 seconds.", code: "RATE_LIMITED" },
226
+ });
227
+ function mcpAuthMiddleware(req, res, next) {
228
+ if (!MCP_AUTH_TOKEN) {
229
+ next();
230
+ return;
231
+ }
232
+ const auth = req.headers.authorization ?? "";
233
+ if (!safeTokenEqual(auth, `Bearer ${MCP_AUTH_TOKEN}`)) {
234
+ res.status(401).json({ error: "Unauthorized" });
235
+ return;
236
+ }
237
+ next();
238
+ }
181
239
  // Health check for Railway / uptime monitors
182
240
  app.get("/health", (_req, res) => {
183
241
  res.json({
@@ -203,7 +261,7 @@ app.get("/.well-known/mcp/server-card.json", (_req, res) => {
203
261
  });
204
262
  });
205
263
  // Stateless StreamableHTTP — new server instance per request (no session state needed)
206
- app.post("/mcp", async (req, res) => {
264
+ app.post("/mcp", mcpRateLimiter, mcpAuthMiddleware, async (req, res) => {
207
265
  const transport = new StreamableHTTPServerTransport({
208
266
  sessionIdGenerator: undefined,
209
267
  });
@@ -215,7 +273,7 @@ app.post("/mcp", async (req, res) => {
215
273
  await transport.handleRequest(req, res, req.body);
216
274
  });
217
275
  // SSE upgrade for clients that prefer streaming
218
- app.get("/mcp", async (req, res) => {
276
+ app.get("/mcp", mcpRateLimiter, mcpAuthMiddleware, async (req, res) => {
219
277
  const transport = new StreamableHTTPServerTransport({
220
278
  sessionIdGenerator: undefined,
221
279
  });
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { BudaClient } from "./client.js";
6
6
  import { cache, CACHE_TTL } from "./cache.js";
7
7
  import { VERSION } from "./version.js";
8
+ import { validateMarketId } from "./validation.js";
8
9
  import * as markets from "./tools/markets.js";
9
10
  import * as ticker from "./tools/ticker.js";
10
11
  import * as orderbook from "./tools/orderbook.js";
@@ -97,7 +98,11 @@ server.resource("buda-markets", "buda://markets", async (uri) => {
97
98
  };
98
99
  });
99
100
  server.resource("buda-ticker", new ResourceTemplate("buda://ticker/{market}", { list: undefined }), async (uri, params) => {
100
- const marketId = params.market.toLowerCase();
101
+ const raw = params.market;
102
+ const validationError = validateMarketId(raw);
103
+ if (validationError)
104
+ throw new Error(validationError);
105
+ const marketId = raw.toLowerCase();
101
106
  const data = await cache.getOrFetch(`ticker:${marketId}`, CACHE_TTL.TICKER, () => client.get(`/markets/${marketId}/ticker`));
102
107
  return {
103
108
  contents: [
@@ -110,9 +115,13 @@ server.resource("buda-ticker", new ResourceTemplate("buda://ticker/{market}", {
110
115
  };
111
116
  });
112
117
  server.resource("buda-summary", new ResourceTemplate("buda://summary/{market}", { list: undefined }), async (uri, params) => {
113
- const marketId = params.market.toUpperCase();
118
+ const raw = params.market;
119
+ const validationError = validateMarketId(raw);
120
+ if (validationError)
121
+ throw new Error(validationError);
122
+ const marketId = raw.toUpperCase();
114
123
  const result = await handleMarketSummary({ market_id: marketId }, client, cache);
115
- const text = result.content[0].text;
124
+ const text = result.content[0]?.text ?? JSON.stringify({ error: "No content returned" });
116
125
  return {
117
126
  contents: [
118
127
  {
@@ -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, path: err.path }
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) }],
@@ -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, path: err.path }
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) }],
@@ -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, path: err.path }
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) }],
@@ -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, path: err.path }
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) }],
@@ -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, path: err.path }
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) }],
@@ -39,6 +39,10 @@ export declare const toolSchema: {
39
39
  required: string[];
40
40
  };
41
41
  };
42
+ max_notional: {
43
+ type: string;
44
+ description: string;
45
+ };
42
46
  confirmation_token: {
43
47
  type: string;
44
48
  description: string;
@@ -63,9 +67,10 @@ declare const orderShape: z.ZodObject<{
63
67
  type SingleOrderInput = z.infer<typeof orderShape>;
64
68
  type BatchOrdersArgs = {
65
69
  orders: SingleOrderInput[];
70
+ max_notional?: number;
66
71
  confirmation_token: string;
67
72
  };
68
- export declare function handlePlaceBatchOrders(args: BatchOrdersArgs, client: BudaClient): Promise<{
73
+ export declare function handlePlaceBatchOrders(args: BatchOrdersArgs, client: BudaClient, transport?: "http" | "stdio"): Promise<{
69
74
  content: Array<{
70
75
  type: "text";
71
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;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCtB,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,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,UAAU,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,CA6GhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBpE"}
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,11 +1,13 @@
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). " +
7
8
  "All orders are pre-validated before any API call — a validation failure stops execution with zero orders placed. " +
8
9
  "Partial API failures do NOT roll back already-placed orders. " +
10
+ "Use max_notional to cap total exposure (computed as sum of amount × limit_price for limit orders; market orders contribute 0). " +
9
11
  "IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
10
12
  "Requires BUDA_API_KEY and BUDA_API_SECRET.",
11
13
  inputSchema: {
@@ -26,6 +28,12 @@ export const toolSchema = {
26
28
  required: ["market_id", "type", "price_type", "amount"],
27
29
  },
28
30
  },
31
+ max_notional: {
32
+ type: "number",
33
+ description: "Optional spending cap: total notional (sum of amount × limit_price for limit orders). " +
34
+ "Batch is rejected before any API call if the sum exceeds this value. " +
35
+ "Market orders contribute 0 to the notional since their execution price is unknown.",
36
+ },
29
37
  confirmation_token: {
30
38
  type: "string",
31
39
  description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute.",
@@ -41,8 +49,8 @@ const orderShape = z.object({
41
49
  amount: z.number().positive(),
42
50
  limit_price: z.number().positive().optional(),
43
51
  });
44
- export async function handlePlaceBatchOrders(args, client) {
45
- const { orders, confirmation_token } = args;
52
+ export async function handlePlaceBatchOrders(args, client, transport = "stdio") {
53
+ const { orders, max_notional, confirmation_token } = args;
46
54
  if (confirmation_token !== "CONFIRM") {
47
55
  return {
48
56
  content: [
@@ -94,6 +102,26 @@ export async function handlePlaceBatchOrders(args, client) {
94
102
  };
95
103
  }
96
104
  }
105
+ // Notional cap check (limit orders only; market orders have unknown execution price)
106
+ if (max_notional !== undefined) {
107
+ const totalNotional = orders.reduce((sum, o) => {
108
+ return sum + (o.price_type === "limit" && o.limit_price ? o.amount * o.limit_price : 0);
109
+ }, 0);
110
+ if (totalNotional > max_notional) {
111
+ return {
112
+ content: [{
113
+ type: "text",
114
+ text: JSON.stringify({
115
+ error: `Total notional ${totalNotional} exceeds max_notional cap of ${max_notional}. No orders were placed.`,
116
+ code: "NOTIONAL_CAP_EXCEEDED",
117
+ total_notional: totalNotional,
118
+ max_notional,
119
+ }),
120
+ }],
121
+ isError: true,
122
+ };
123
+ }
124
+ }
97
125
  // Execute sequentially
98
126
  const results = [];
99
127
  for (let i = 0; i < orders.length; i++) {
@@ -134,9 +162,18 @@ export async function handlePlaceBatchOrders(args, client) {
134
162
  if (failed > 0 && succeeded > 0) {
135
163
  response.warning = "Some orders failed. Already-placed orders were NOT rolled back.";
136
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
+ });
137
174
  return {
138
175
  content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
139
- isError: failed > 0 && succeeded === 0 ? true : undefined,
176
+ isError,
140
177
  };
141
178
  }
142
179
  export function register(server, client) {
@@ -146,6 +183,13 @@ export function register(server, client) {
146
183
  .min(1)
147
184
  .max(20)
148
185
  .describe("Array of 1–20 orders to place."),
186
+ max_notional: z
187
+ .number()
188
+ .positive()
189
+ .optional()
190
+ .describe("Optional spending cap: total notional (sum of amount × limit_price for limit orders). " +
191
+ "Batch is rejected before any API call if the sum exceeds this value. " +
192
+ "Market orders contribute 0 to the notional since their execution price is unknown."),
149
193
  confirmation_token: z
150
194
  .string()
151
195
  .describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute."),
@@ -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;AAIxD,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,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,CAyDhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBpE"}
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
- return {
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, path: err.path }
67
+ ? { error: err.message, code: err.status }
70
68
  : { error: String(err), code: "UNKNOWN" };
71
- return {
72
- content: [{ type: "text", text: JSON.stringify(msg) }],
73
- isError: true,
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;AAGxD,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,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,CAuChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAmBpE"}
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 {
@@ -42,20 +43,19 @@ export async function handleCancelOrder(args, client) {
42
43
  }
43
44
  try {
44
45
  const data = await client.put(`/orders/${order_id}`, {
45
- state: "canceling",
46
+ order: { state: "canceling" },
46
47
  });
47
- return {
48
- content: [{ type: "text", text: JSON.stringify(data.order, null, 2) }],
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, path: err.path }
54
+ ? { error: err.message, code: err.status }
54
55
  : { error: String(err), code: "UNKNOWN" };
55
- return {
56
- content: [{ type: "text", text: JSON.stringify(msg) }],
57
- isError: true,
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;AAIxD,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,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,CAwChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBpE"}
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
- return {
77
- content: [{ type: "text", text: JSON.stringify(normalizeOrder(data.order), null, 2) }],
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, path: err.path }
83
+ ? { error: err.message, code: err.status }
83
84
  : { error: String(err), code: "UNKNOWN" };
84
- return {
85
- content: [{ type: "text", text: JSON.stringify(msg) }],
86
- isError: true,
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;AAGrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAkBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAyExF"}
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"}