@guiie/buda-mcp 1.4.2 → 1.5.1

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 (113) hide show
  1. package/.cursor/rules/marketplace-docs-sync.mdc +32 -0
  2. package/CHANGELOG.md +79 -0
  3. package/PUBLISH_CHECKLIST.md +40 -88
  4. package/README.md +446 -78
  5. package/dist/cache.d.ts +1 -0
  6. package/dist/cache.d.ts.map +1 -1
  7. package/dist/cache.js +1 -0
  8. package/dist/client.d.ts +2 -0
  9. package/dist/client.d.ts.map +1 -1
  10. package/dist/client.js +18 -1
  11. package/dist/http.js +97 -6
  12. package/dist/index.js +42 -3
  13. package/dist/tools/account.d.ts +19 -0
  14. package/dist/tools/account.d.ts.map +1 -0
  15. package/dist/tools/account.js +49 -0
  16. package/dist/tools/balance.d.ts +29 -0
  17. package/dist/tools/balance.d.ts.map +1 -0
  18. package/dist/tools/balance.js +72 -0
  19. package/dist/tools/banks.d.ts +28 -0
  20. package/dist/tools/banks.d.ts.map +1 -0
  21. package/dist/tools/banks.js +68 -0
  22. package/dist/tools/batch_orders.d.ts +82 -0
  23. package/dist/tools/batch_orders.d.ts.map +1 -0
  24. package/dist/tools/batch_orders.js +188 -0
  25. package/dist/tools/cancel_all_orders.d.ts +34 -0
  26. package/dist/tools/cancel_all_orders.d.ts.map +1 -0
  27. package/dist/tools/cancel_all_orders.js +89 -0
  28. package/dist/tools/cancel_order.js +1 -1
  29. package/dist/tools/cancel_order_by_client_id.d.ts +34 -0
  30. package/dist/tools/cancel_order_by_client_id.d.ts.map +1 -0
  31. package/dist/tools/cancel_order_by_client_id.js +102 -0
  32. package/dist/tools/dead_mans_switch.d.ts +1 -1
  33. package/dist/tools/dead_mans_switch.d.ts.map +1 -1
  34. package/dist/tools/dead_mans_switch.js +33 -3
  35. package/dist/tools/deposits.d.ts +83 -0
  36. package/dist/tools/deposits.d.ts.map +1 -0
  37. package/dist/tools/deposits.js +174 -0
  38. package/dist/tools/fees.d.ts +34 -0
  39. package/dist/tools/fees.d.ts.map +1 -0
  40. package/dist/tools/fees.js +72 -0
  41. package/dist/tools/lightning.d.ts +68 -0
  42. package/dist/tools/lightning.d.ts.map +1 -0
  43. package/dist/tools/lightning.js +185 -0
  44. package/dist/tools/order_lookup.d.ts +50 -0
  45. package/dist/tools/order_lookup.d.ts.map +1 -0
  46. package/dist/tools/order_lookup.js +112 -0
  47. package/dist/tools/place_order.d.ts +30 -0
  48. package/dist/tools/place_order.d.ts.map +1 -1
  49. package/dist/tools/place_order.js +131 -2
  50. package/dist/tools/quotation.d.ts +44 -0
  51. package/dist/tools/quotation.d.ts.map +1 -0
  52. package/dist/tools/quotation.js +99 -0
  53. package/dist/tools/receive_addresses.d.ts +83 -0
  54. package/dist/tools/receive_addresses.d.ts.map +1 -0
  55. package/dist/tools/receive_addresses.js +185 -0
  56. package/dist/tools/remittance_recipients.d.ts +54 -0
  57. package/dist/tools/remittance_recipients.d.ts.map +1 -0
  58. package/dist/tools/remittance_recipients.js +106 -0
  59. package/dist/tools/remittances.d.ts +120 -0
  60. package/dist/tools/remittances.d.ts.map +1 -0
  61. package/dist/tools/remittances.js +261 -0
  62. package/dist/tools/simulate_order.d.ts.map +1 -1
  63. package/dist/tools/simulate_order.js +2 -1
  64. package/dist/tools/technical_indicators.d.ts.map +1 -1
  65. package/dist/tools/technical_indicators.js +2 -1
  66. package/dist/tools/withdrawals.d.ts +93 -0
  67. package/dist/tools/withdrawals.d.ts.map +1 -0
  68. package/dist/tools/withdrawals.js +225 -0
  69. package/dist/types.d.ts +155 -0
  70. package/dist/types.d.ts.map +1 -1
  71. package/dist/utils.d.ts.map +1 -1
  72. package/dist/utils.js +4 -1
  73. package/dist/validation.d.ts +11 -0
  74. package/dist/validation.d.ts.map +1 -1
  75. package/dist/validation.js +38 -0
  76. package/dist/version.d.ts.map +1 -1
  77. package/dist/version.js +8 -1
  78. package/marketplace/README.md +1 -1
  79. package/marketplace/claude-listing.md +101 -2
  80. package/marketplace/gemini-tools.json +478 -1
  81. package/marketplace/openapi.yaml +160 -1
  82. package/package.json +2 -1
  83. package/server.json +2 -2
  84. package/src/cache.ts +1 -0
  85. package/src/client.ts +23 -1
  86. package/src/http.ts +105 -6
  87. package/src/index.ts +40 -3
  88. package/src/tools/account.ts +66 -0
  89. package/src/tools/balance.ts +94 -0
  90. package/src/tools/banks.ts +94 -0
  91. package/src/tools/batch_orders.ts +238 -0
  92. package/src/tools/cancel_all_orders.ts +117 -0
  93. package/src/tools/cancel_order.ts +1 -1
  94. package/src/tools/cancel_order_by_client_id.ts +132 -0
  95. package/src/tools/dead_mans_switch.ts +39 -3
  96. package/src/tools/deposits.ts +230 -0
  97. package/src/tools/fees.ts +91 -0
  98. package/src/tools/lightning.ts +247 -0
  99. package/src/tools/order_lookup.ts +139 -0
  100. package/src/tools/place_order.ts +151 -2
  101. package/src/tools/quotation.ts +124 -0
  102. package/src/tools/receive_addresses.ts +242 -0
  103. package/src/tools/remittance_recipients.ts +139 -0
  104. package/src/tools/remittances.ts +325 -0
  105. package/src/tools/simulate_order.ts +1 -0
  106. package/src/tools/technical_indicators.ts +2 -1
  107. package/src/tools/withdrawals.ts +287 -0
  108. package/src/types.ts +210 -0
  109. package/src/utils.ts +3 -1
  110. package/src/validation.ts +45 -0
  111. package/src/version.ts +11 -3
  112. package/test/run-all.ts +16 -0
  113. package/test/unit.ts +2149 -1
@@ -0,0 +1,82 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { BudaClient } from "../client.js";
4
+ export declare const toolSchema: {
5
+ name: string;
6
+ description: string;
7
+ inputSchema: {
8
+ type: "object";
9
+ properties: {
10
+ orders: {
11
+ type: string;
12
+ description: string;
13
+ items: {
14
+ type: string;
15
+ properties: {
16
+ market_id: {
17
+ type: string;
18
+ description: string;
19
+ };
20
+ type: {
21
+ type: string;
22
+ enum: string[];
23
+ description: string;
24
+ };
25
+ price_type: {
26
+ type: string;
27
+ enum: string[];
28
+ description: string;
29
+ };
30
+ amount: {
31
+ type: string;
32
+ description: string;
33
+ };
34
+ limit_price: {
35
+ type: string;
36
+ description: string;
37
+ };
38
+ };
39
+ required: string[];
40
+ };
41
+ };
42
+ max_notional: {
43
+ type: string;
44
+ description: string;
45
+ };
46
+ confirmation_token: {
47
+ type: string;
48
+ description: string;
49
+ };
50
+ };
51
+ required: string[];
52
+ };
53
+ };
54
+ declare const orderShape: z.ZodObject<{
55
+ market_id: z.ZodString;
56
+ type: z.ZodEnum<{
57
+ Bid: "Bid";
58
+ Ask: "Ask";
59
+ }>;
60
+ price_type: z.ZodEnum<{
61
+ limit: "limit";
62
+ market: "market";
63
+ }>;
64
+ amount: z.ZodNumber;
65
+ limit_price: z.ZodOptional<z.ZodNumber>;
66
+ }, z.core.$strip>;
67
+ type SingleOrderInput = z.infer<typeof orderShape>;
68
+ type BatchOrdersArgs = {
69
+ orders: SingleOrderInput[];
70
+ max_notional?: number;
71
+ confirmation_token: string;
72
+ };
73
+ export declare function handlePlaceBatchOrders(args: BatchOrdersArgs, client: BudaClient): Promise<{
74
+ content: Array<{
75
+ type: "text";
76
+ text: string;
77
+ }>;
78
+ isError?: boolean;
79
+ }>;
80
+ export declare function register(server: McpServer, client: BudaClient): void;
81
+ export {};
82
+ //# sourceMappingURL=batch_orders.d.ts.map
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,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,CAkIhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2BpE"}
@@ -0,0 +1,188 @@
1
+ import { z } from "zod";
2
+ import { BudaApiError } from "../client.js";
3
+ import { validateMarketId } from "../validation.js";
4
+ export const toolSchema = {
5
+ name: "place_batch_orders",
6
+ description: "Place multiple orders sequentially on Buda.com (up to 20). " +
7
+ "All orders are pre-validated before any API call — a validation failure stops execution with zero orders placed. " +
8
+ "Partial API failures do NOT roll back already-placed orders. " +
9
+ "Use max_notional to cap total exposure (computed as sum of amount × limit_price for limit orders; market orders contribute 0). " +
10
+ "IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
11
+ "Requires BUDA_API_KEY and BUDA_API_SECRET.",
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {
15
+ orders: {
16
+ type: "array",
17
+ description: "Array of 1–20 orders to place.",
18
+ items: {
19
+ type: "object",
20
+ properties: {
21
+ market_id: { type: "string", description: "Market ID (e.g. 'BTC-CLP')." },
22
+ type: { type: "string", enum: ["Bid", "Ask"], description: "Order side." },
23
+ price_type: { type: "string", enum: ["limit", "market"], description: "Order type." },
24
+ amount: { type: "number", description: "Order size in base currency." },
25
+ limit_price: { type: "number", description: "Required when price_type is 'limit'." },
26
+ },
27
+ required: ["market_id", "type", "price_type", "amount"],
28
+ },
29
+ },
30
+ max_notional: {
31
+ type: "number",
32
+ description: "Optional spending cap: total notional (sum of amount × limit_price for limit orders). " +
33
+ "Batch is rejected before any API call if the sum exceeds this value. " +
34
+ "Market orders contribute 0 to the notional since their execution price is unknown.",
35
+ },
36
+ confirmation_token: {
37
+ type: "string",
38
+ description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute.",
39
+ },
40
+ },
41
+ required: ["orders", "confirmation_token"],
42
+ },
43
+ };
44
+ const orderShape = z.object({
45
+ market_id: z.string(),
46
+ type: z.enum(["Bid", "Ask"]),
47
+ price_type: z.enum(["limit", "market"]),
48
+ amount: z.number().positive(),
49
+ limit_price: z.number().positive().optional(),
50
+ });
51
+ export async function handlePlaceBatchOrders(args, client) {
52
+ const { orders, max_notional, confirmation_token } = args;
53
+ if (confirmation_token !== "CONFIRM") {
54
+ return {
55
+ content: [
56
+ {
57
+ type: "text",
58
+ text: JSON.stringify({
59
+ error: "Orders not placed. confirmation_token must equal 'CONFIRM' to execute. " +
60
+ "Review all orders and set confirmation_token='CONFIRM' to proceed.",
61
+ code: "CONFIRMATION_REQUIRED",
62
+ preview: { order_count: orders.length },
63
+ }),
64
+ },
65
+ ],
66
+ isError: true,
67
+ };
68
+ }
69
+ // Pre-validate ALL orders before any API call
70
+ for (let i = 0; i < orders.length; i++) {
71
+ const order = orders[i];
72
+ const marketError = validateMarketId(order.market_id);
73
+ if (marketError) {
74
+ return {
75
+ content: [
76
+ {
77
+ type: "text",
78
+ text: JSON.stringify({
79
+ error: `Order at index ${i}: ${marketError}`,
80
+ code: "INVALID_MARKET_ID",
81
+ index: i,
82
+ }),
83
+ },
84
+ ],
85
+ isError: true,
86
+ };
87
+ }
88
+ if (order.price_type === "limit" && order.limit_price === undefined) {
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: JSON.stringify({
94
+ error: `Order at index ${i}: limit_price is required when price_type is 'limit'.`,
95
+ code: "VALIDATION_ERROR",
96
+ index: i,
97
+ }),
98
+ },
99
+ ],
100
+ isError: true,
101
+ };
102
+ }
103
+ }
104
+ // Notional cap check (limit orders only; market orders have unknown execution price)
105
+ if (max_notional !== undefined) {
106
+ const totalNotional = orders.reduce((sum, o) => {
107
+ return sum + (o.price_type === "limit" && o.limit_price ? o.amount * o.limit_price : 0);
108
+ }, 0);
109
+ if (totalNotional > max_notional) {
110
+ return {
111
+ content: [{
112
+ type: "text",
113
+ text: JSON.stringify({
114
+ error: `Total notional ${totalNotional} exceeds max_notional cap of ${max_notional}. No orders were placed.`,
115
+ code: "NOTIONAL_CAP_EXCEEDED",
116
+ total_notional: totalNotional,
117
+ max_notional,
118
+ }),
119
+ }],
120
+ isError: true,
121
+ };
122
+ }
123
+ }
124
+ // Execute sequentially
125
+ const results = [];
126
+ for (let i = 0; i < orders.length; i++) {
127
+ const order = orders[i];
128
+ try {
129
+ const payload = {
130
+ type: order.type,
131
+ price_type: order.price_type,
132
+ amount: order.amount,
133
+ };
134
+ if (order.price_type === "limit") {
135
+ payload.limit = { price: order.limit_price, type: "gtc" };
136
+ }
137
+ const data = await client.post(`/markets/${order.market_id.toLowerCase()}/orders`, payload);
138
+ results.push({ index: i, market_id: order.market_id, success: true, order: data.order });
139
+ }
140
+ catch (err) {
141
+ const errInfo = err instanceof BudaApiError
142
+ ? { error: err.message, code: err.status }
143
+ : { error: String(err), code: "UNKNOWN" };
144
+ results.push({
145
+ index: i,
146
+ market_id: order.market_id,
147
+ success: false,
148
+ error: errInfo.error,
149
+ code: errInfo.code,
150
+ });
151
+ }
152
+ }
153
+ const succeeded = results.filter((r) => r.success).length;
154
+ const failed = results.filter((r) => !r.success).length;
155
+ const response = {
156
+ results,
157
+ total: orders.length,
158
+ succeeded,
159
+ failed,
160
+ };
161
+ if (failed > 0 && succeeded > 0) {
162
+ response.warning = "Some orders failed. Already-placed orders were NOT rolled back.";
163
+ }
164
+ return {
165
+ content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
166
+ isError: failed > 0 && succeeded === 0 ? true : undefined,
167
+ };
168
+ }
169
+ export function register(server, client) {
170
+ server.tool(toolSchema.name, toolSchema.description, {
171
+ orders: z
172
+ .array(orderShape)
173
+ .min(1)
174
+ .max(20)
175
+ .describe("Array of 1–20 orders to place."),
176
+ max_notional: z
177
+ .number()
178
+ .positive()
179
+ .optional()
180
+ .describe("Optional spending cap: total notional (sum of amount × limit_price for limit orders). " +
181
+ "Batch is rejected before any API call if the sum exceeds this value. " +
182
+ "Market orders contribute 0 to the notional since their execution price is unknown."),
183
+ confirmation_token: z
184
+ .string()
185
+ .describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute."),
186
+ }, (args) => handlePlaceBatchOrders(args, client));
187
+ }
188
+ //# sourceMappingURL=batch_orders.js.map
@@ -0,0 +1,34 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { BudaClient } from "../client.js";
3
+ export declare const toolSchema: {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: {
7
+ type: "object";
8
+ properties: {
9
+ market_id: {
10
+ type: string;
11
+ description: string;
12
+ };
13
+ confirmation_token: {
14
+ type: string;
15
+ description: string;
16
+ };
17
+ };
18
+ required: string[];
19
+ };
20
+ };
21
+ type CancelAllOrdersArgs = {
22
+ market_id: string;
23
+ confirmation_token: string;
24
+ };
25
+ export declare function handleCancelAllOrders(args: CancelAllOrdersArgs, client: BudaClient): Promise<{
26
+ content: Array<{
27
+ type: "text";
28
+ text: string;
29
+ }>;
30
+ isError?: boolean;
31
+ }>;
32
+ export declare function register(server: McpServer, client: BudaClient): void;
33
+ export {};
34
+ //# sourceMappingURL=cancel_all_orders.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,89 @@
1
+ import { z } from "zod";
2
+ import { BudaApiError } from "../client.js";
3
+ import { validateMarketId } from "../validation.js";
4
+ export const toolSchema = {
5
+ name: "cancel_all_orders",
6
+ description: "Cancel all open orders on Buda.com, optionally filtered by a specific market. " +
7
+ "Pass market_id='*' to cancel across all markets, or a specific market ID (e.g. 'BTC-CLP'). " +
8
+ "IMPORTANT: This action is irreversible. Pass confirmation_token='CONFIRM' to execute. " +
9
+ "Requires BUDA_API_KEY and BUDA_API_SECRET.",
10
+ inputSchema: {
11
+ type: "object",
12
+ properties: {
13
+ market_id: {
14
+ type: "string",
15
+ description: "Market ID (e.g. 'BTC-CLP') or '*' to cancel orders across all markets.",
16
+ },
17
+ confirmation_token: {
18
+ type: "string",
19
+ description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute. " +
20
+ "Any other value will reject the request without canceling.",
21
+ },
22
+ },
23
+ required: ["market_id", "confirmation_token"],
24
+ },
25
+ };
26
+ export async function handleCancelAllOrders(args, client) {
27
+ const { market_id, confirmation_token } = args;
28
+ if (confirmation_token !== "CONFIRM") {
29
+ return {
30
+ content: [
31
+ {
32
+ type: "text",
33
+ text: JSON.stringify({
34
+ error: "Orders not canceled. confirmation_token must equal 'CONFIRM' to execute. " +
35
+ "Review and set confirmation_token='CONFIRM' to proceed.",
36
+ code: "CONFIRMATION_REQUIRED",
37
+ preview: { market_id },
38
+ }),
39
+ },
40
+ ],
41
+ isError: true,
42
+ };
43
+ }
44
+ if (market_id !== "*") {
45
+ const validationError = validateMarketId(market_id);
46
+ if (validationError) {
47
+ return {
48
+ content: [
49
+ { type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) },
50
+ ],
51
+ isError: true,
52
+ };
53
+ }
54
+ }
55
+ try {
56
+ const params = market_id !== "*" ? { market_id: market_id.toLowerCase() } : undefined;
57
+ 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
+ ],
65
+ };
66
+ }
67
+ catch (err) {
68
+ const msg = err instanceof BudaApiError
69
+ ? { error: err.message, code: err.status, path: err.path }
70
+ : { error: String(err), code: "UNKNOWN" };
71
+ return {
72
+ content: [{ type: "text", text: JSON.stringify(msg) }],
73
+ isError: true,
74
+ };
75
+ }
76
+ }
77
+ export function register(server, client) {
78
+ server.tool(toolSchema.name, toolSchema.description, {
79
+ market_id: z
80
+ .string()
81
+ .min(1)
82
+ .describe("Market ID (e.g. 'BTC-CLP') or '*' to cancel orders across all markets."),
83
+ confirmation_token: z
84
+ .string()
85
+ .describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute. " +
86
+ "Any other value will reject the request without canceling."),
87
+ }, (args) => handleCancelAllOrders(args, client));
88
+ }
89
+ //# sourceMappingURL=cancel_all_orders.js.map
@@ -42,7 +42,7 @@ export async function handleCancelOrder(args, client) {
42
42
  }
43
43
  try {
44
44
  const data = await client.put(`/orders/${order_id}`, {
45
- state: "canceling",
45
+ order: { state: "canceling" },
46
46
  });
47
47
  return {
48
48
  content: [{ type: "text", text: JSON.stringify(data.order, null, 2) }],
@@ -0,0 +1,34 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { BudaClient } from "../client.js";
3
+ export declare const toolSchema: {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: {
7
+ type: "object";
8
+ properties: {
9
+ client_id: {
10
+ type: string;
11
+ description: string;
12
+ };
13
+ confirmation_token: {
14
+ type: string;
15
+ description: string;
16
+ };
17
+ };
18
+ required: string[];
19
+ };
20
+ };
21
+ type CancelOrderByClientIdArgs = {
22
+ client_id: string;
23
+ confirmation_token: string;
24
+ };
25
+ export declare function handleCancelOrderByClientId(args: CancelOrderByClientIdArgs, client: BudaClient): Promise<{
26
+ content: Array<{
27
+ type: "text";
28
+ text: string;
29
+ }>;
30
+ isError?: boolean;
31
+ }>;
32
+ export declare function register(server: McpServer, client: BudaClient): void;
33
+ export {};
34
+ //# sourceMappingURL=cancel_order_by_client_id.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,102 @@
1
+ import { z } from "zod";
2
+ import { BudaApiError } from "../client.js";
3
+ import { flattenAmount } from "../utils.js";
4
+ export const toolSchema = {
5
+ name: "cancel_order_by_client_id",
6
+ description: "Cancel an open order by its client-assigned ID on Buda.com. " +
7
+ "IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
8
+ "Requires BUDA_API_KEY and BUDA_API_SECRET.",
9
+ inputSchema: {
10
+ type: "object",
11
+ properties: {
12
+ client_id: {
13
+ type: "string",
14
+ description: "The client ID string assigned when placing the order.",
15
+ },
16
+ confirmation_token: {
17
+ type: "string",
18
+ description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute. " +
19
+ "Any other value will reject the request without canceling.",
20
+ },
21
+ },
22
+ required: ["client_id", "confirmation_token"],
23
+ },
24
+ };
25
+ function normalizeOrder(o) {
26
+ const amount = flattenAmount(o.amount);
27
+ const originalAmount = flattenAmount(o.original_amount);
28
+ const tradedAmount = flattenAmount(o.traded_amount);
29
+ const totalExchanged = flattenAmount(o.total_exchanged);
30
+ const paidFee = flattenAmount(o.paid_fee);
31
+ const limitPrice = o.limit ? flattenAmount(o.limit) : null;
32
+ return {
33
+ id: o.id,
34
+ type: o.type,
35
+ state: o.state,
36
+ created_at: o.created_at,
37
+ market_id: o.market_id,
38
+ fee_currency: o.fee_currency,
39
+ price_type: o.price_type,
40
+ order_type: o.order_type,
41
+ client_id: o.client_id,
42
+ limit_price: limitPrice ? limitPrice.value : null,
43
+ limit_price_currency: limitPrice ? limitPrice.currency : null,
44
+ amount: amount.value,
45
+ amount_currency: amount.currency,
46
+ original_amount: originalAmount.value,
47
+ original_amount_currency: originalAmount.currency,
48
+ traded_amount: tradedAmount.value,
49
+ traded_amount_currency: tradedAmount.currency,
50
+ total_exchanged: totalExchanged.value,
51
+ total_exchanged_currency: totalExchanged.currency,
52
+ paid_fee: paidFee.value,
53
+ paid_fee_currency: paidFee.currency,
54
+ };
55
+ }
56
+ export async function handleCancelOrderByClientId(args, client) {
57
+ const { client_id, confirmation_token } = args;
58
+ if (confirmation_token !== "CONFIRM") {
59
+ return {
60
+ content: [
61
+ {
62
+ type: "text",
63
+ text: JSON.stringify({
64
+ error: "Order not canceled. confirmation_token must equal 'CONFIRM' to execute. " +
65
+ "Verify the client ID and set confirmation_token='CONFIRM' to proceed.",
66
+ code: "CONFIRMATION_REQUIRED",
67
+ client_id,
68
+ }),
69
+ },
70
+ ],
71
+ isError: true,
72
+ };
73
+ }
74
+ try {
75
+ 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
+ };
79
+ }
80
+ catch (err) {
81
+ const msg = err instanceof BudaApiError
82
+ ? { error: err.message, code: err.status, path: err.path }
83
+ : { error: String(err), code: "UNKNOWN" };
84
+ return {
85
+ content: [{ type: "text", text: JSON.stringify(msg) }],
86
+ isError: true,
87
+ };
88
+ }
89
+ }
90
+ export function register(server, client) {
91
+ server.tool(toolSchema.name, toolSchema.description, {
92
+ client_id: z
93
+ .string()
94
+ .min(1)
95
+ .describe("The client ID string assigned when placing the order."),
96
+ confirmation_token: z
97
+ .string()
98
+ .describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute. " +
99
+ "Any other value will reject the request without canceling."),
100
+ }, (args) => handleCancelOrderByClientId(args, client));
101
+ }
102
+ //# sourceMappingURL=cancel_order_by_client_id.js.map
@@ -79,6 +79,6 @@ export declare function handleDisarmCancelTimer({ market_id }: MarketOnlyArgs):
79
79
  }>;
80
80
  isError?: boolean;
81
81
  };
82
- export declare function register(server: McpServer, client: BudaClient): void;
82
+ export declare function register(server: McpServer, client: BudaClient, transport?: "stdio" | "http"): void;
83
83
  export {};
84
84
  //# sourceMappingURL=dead_mans_switch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dead_mans_switch.d.ts","sourceRoot":"","sources":["../../src/tools/dead_mans_switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAiDxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA2BtB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAgB3B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAgB5B,CAAC;AAIF,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,YAAY,EAClB,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,CA+ChF;AAED,KAAK,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C,wBAAgB,sBAAsB,CACpC,EAAE,SAAS,EAAE,EAAE,cAAc,EAC7B,MAAM,EAAE,UAAU,GACjB;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,CA0CvE;AAED,wBAAgB,uBAAuB,CACrC,EAAE,SAAS,EAAE,EAAE,cAAc,GAC5B;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,CAwCvE;AAID,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA0CpE"}
1
+ {"version":3,"file":"dead_mans_switch.d.ts","sourceRoot":"","sources":["../../src/tools/dead_mans_switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAiDxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA2BtB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAgB3B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAgB5B,CAAC;AAIF,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,YAAY,EAClB,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,CA8DhF;AAED,KAAK,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C,wBAAgB,sBAAsB,CACpC,EAAE,SAAS,EAAE,EAAE,cAAc,EAC7B,MAAM,EAAE,UAAU,GACjB;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,CA0CvE;AAED,wBAAgB,uBAAuB,CACrC,EAAE,SAAS,EAAE,EAAE,cAAc,GAC5B;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,CAwCvE;AAID,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,GAAE,OAAO,GAAG,MAAgB,GACpC,IAAI,CA2DN"}
@@ -5,7 +5,7 @@ async function cancelAllOrdersForMarket(marketId, client) {
5
5
  try {
6
6
  const data = await client.get(`/markets/${marketId}/orders`, { state: "pending", per: 300 });
7
7
  const orders = data.orders ?? [];
8
- await Promise.allSettled(orders.map((order) => client.put(`/orders/${order.id}`, { state: "canceling" })));
8
+ await Promise.allSettled(orders.map((order) => client.put(`/orders/${order.id}`, { order: { state: "canceling" } })));
9
9
  timers.delete(marketId);
10
10
  }
11
11
  catch {
@@ -111,6 +111,20 @@ export async function handleScheduleCancelAll(args, client) {
111
111
  isError: true,
112
112
  };
113
113
  }
114
+ if (!Number.isInteger(ttl_seconds) || ttl_seconds < 10 || ttl_seconds > 300) {
115
+ return {
116
+ content: [
117
+ {
118
+ type: "text",
119
+ text: JSON.stringify({
120
+ error: "ttl_seconds must be an integer between 10 and 300.",
121
+ code: "VALIDATION_ERROR",
122
+ }),
123
+ },
124
+ ],
125
+ isError: true,
126
+ };
127
+ }
114
128
  const id = market_id.toLowerCase();
115
129
  const entry = armTimer(id, ttl_seconds, client);
116
130
  return {
@@ -207,7 +221,7 @@ export function handleDisarmCancelTimer({ market_id }) {
207
221
  };
208
222
  }
209
223
  // ---- Registration ----
210
- export function register(server, client) {
224
+ export function register(server, client, transport = "stdio") {
211
225
  server.tool(toolSchema.name, toolSchema.description, {
212
226
  market_id: z
213
227
  .string()
@@ -221,7 +235,23 @@ export function register(server, client) {
221
235
  confirmation_token: z
222
236
  .string()
223
237
  .describe("Must equal exactly 'CONFIRM' (case-sensitive) to arm the switch."),
224
- }, (args) => handleScheduleCancelAll(args, client));
238
+ }, (args) => {
239
+ if (transport === "http") {
240
+ return Promise.resolve({
241
+ content: [{
242
+ type: "text",
243
+ text: JSON.stringify({
244
+ error: "schedule_cancel_all is not available on the HTTP transport. " +
245
+ "Timer state is lost on every server restart or deploy. " +
246
+ "Run buda-mcp in stdio mode on a persistent local process to use this feature.",
247
+ code: "TRANSPORT_NOT_SUPPORTED",
248
+ }),
249
+ }],
250
+ isError: true,
251
+ });
252
+ }
253
+ return handleScheduleCancelAll(args, client);
254
+ });
225
255
  server.tool(renewToolSchema.name, renewToolSchema.description, {
226
256
  market_id: z
227
257
  .string()