@guiie/buda-mcp 1.5.0 → 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.
- package/.cursor/rules/marketplace-docs-sync.mdc +32 -0
- package/CHANGELOG.md +40 -0
- package/PUBLISH_CHECKLIST.md +40 -88
- package/README.md +446 -78
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/http.js +42 -6
- package/dist/index.js +12 -3
- package/dist/tools/batch_orders.d.ts +5 -0
- package/dist/tools/batch_orders.d.ts.map +1 -1
- package/dist/tools/batch_orders.js +35 -1
- package/dist/tools/cancel_order.js +1 -1
- 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 +33 -3
- package/dist/tools/lightning.d.ts.map +1 -1
- package/dist/tools/lightning.js +15 -1
- package/dist/tools/place_order.d.ts.map +1 -1
- package/dist/tools/place_order.js +31 -0
- package/dist/tools/receive_addresses.d.ts +5 -0
- package/dist/tools/receive_addresses.d.ts.map +1 -1
- package/dist/tools/receive_addresses.js +26 -2
- package/dist/tools/remittances.d.ts +5 -0
- package/dist/tools/remittances.d.ts.map +1 -1
- package/dist/tools/remittances.js +27 -3
- package/dist/tools/technical_indicators.d.ts.map +1 -1
- package/dist/tools/technical_indicators.js +2 -1
- package/dist/tools/withdrawals.d.ts.map +1 -1
- package/dist/tools/withdrawals.js +11 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +4 -1
- package/dist/validation.d.ts +6 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +26 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +8 -1
- package/marketplace/README.md +1 -1
- package/marketplace/claude-listing.md +75 -4
- package/marketplace/gemini-tools.json +325 -2
- package/marketplace/openapi.yaml +160 -1
- package/package.json +2 -1
- package/server.json +2 -2
- package/src/client.ts +3 -1
- package/src/http.ts +50 -6
- package/src/index.ts +10 -3
- package/src/tools/batch_orders.ts +40 -1
- package/src/tools/cancel_order.ts +1 -1
- package/src/tools/dead_mans_switch.ts +39 -3
- package/src/tools/lightning.ts +17 -1
- package/src/tools/place_order.ts +32 -0
- package/src/tools/receive_addresses.ts +29 -3
- package/src/tools/remittances.ts +30 -4
- package/src/tools/technical_indicators.ts +2 -1
- package/src/tools/withdrawals.ts +12 -1
- package/src/utils.ts +3 -1
- package/src/validation.ts +29 -0
- package/src/version.ts +11 -3
- package/test/unit.ts +261 -18
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,qBAAa,YAAa,SAAQ,KAAK;aAEnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;aAEZ,YAAY,CAAC,EAAE,MAAM;gBAHrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,YAAY,CAAC,EAAE,MAAM,YAAA;CAKxC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;gBAG7C,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM;IAOpB,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,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(
|
|
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,11 @@
|
|
|
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";
|
|
6
7
|
import { VERSION } from "./version.js";
|
|
8
|
+
import { validateMarketId } from "./validation.js";
|
|
7
9
|
import * as markets from "./tools/markets.js";
|
|
8
10
|
import * as ticker from "./tools/ticker.js";
|
|
9
11
|
import * as orderbook from "./tools/orderbook.js";
|
|
@@ -119,7 +121,7 @@ function createServer() {
|
|
|
119
121
|
orders.register(server, client);
|
|
120
122
|
placeOrder.register(server, client);
|
|
121
123
|
cancelOrder.register(server, client);
|
|
122
|
-
deadMansSwitch.register(server, client);
|
|
124
|
+
deadMansSwitch.register(server, client, "http");
|
|
123
125
|
account.register(server, client);
|
|
124
126
|
balance.register(server, client);
|
|
125
127
|
orderLookup.register(server, client);
|
|
@@ -148,7 +150,11 @@ function createServer() {
|
|
|
148
150
|
};
|
|
149
151
|
});
|
|
150
152
|
server.resource("buda-ticker", new ResourceTemplate("buda://ticker/{market}", { list: undefined }), async (uri, params) => {
|
|
151
|
-
const
|
|
153
|
+
const raw = params.market;
|
|
154
|
+
const validationError = validateMarketId(raw);
|
|
155
|
+
if (validationError)
|
|
156
|
+
throw new Error(validationError);
|
|
157
|
+
const marketId = raw.toLowerCase();
|
|
152
158
|
const data = await reqCache.getOrFetch(`ticker:${marketId}`, CACHE_TTL.TICKER, () => client.get(`/markets/${marketId}/ticker`));
|
|
153
159
|
return {
|
|
154
160
|
contents: [
|
|
@@ -161,9 +167,13 @@ function createServer() {
|
|
|
161
167
|
};
|
|
162
168
|
});
|
|
163
169
|
server.resource("buda-summary", new ResourceTemplate("buda://summary/{market}", { list: undefined }), async (uri, params) => {
|
|
164
|
-
const
|
|
170
|
+
const raw = params.market;
|
|
171
|
+
const validationError = validateMarketId(raw);
|
|
172
|
+
if (validationError)
|
|
173
|
+
throw new Error(validationError);
|
|
174
|
+
const marketId = raw.toUpperCase();
|
|
165
175
|
const result = await handleMarketSummary({ market_id: marketId }, client, reqCache);
|
|
166
|
-
const text = result.content[0].
|
|
176
|
+
const text = result.content[0]?.text ?? JSON.stringify({ error: "No content returned" });
|
|
167
177
|
return {
|
|
168
178
|
contents: [
|
|
169
179
|
{
|
|
@@ -178,6 +188,32 @@ function createServer() {
|
|
|
178
188
|
}
|
|
179
189
|
const app = express();
|
|
180
190
|
app.use(express.json());
|
|
191
|
+
const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
|
|
192
|
+
if (authEnabled && !MCP_AUTH_TOKEN) {
|
|
193
|
+
console.error("[buda-mcp] FATAL: BUDA_API_KEY/BUDA_API_SECRET are set but MCP_AUTH_TOKEN is not.\n" +
|
|
194
|
+
" The /mcp endpoint would be publicly accessible with full account access.\n" +
|
|
195
|
+
" Set MCP_AUTH_TOKEN to a long random secret, or run in stdio mode instead.");
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
const mcpRateLimiter = rateLimit({
|
|
199
|
+
windowMs: 60_000,
|
|
200
|
+
max: parseInt(process.env.MCP_RATE_LIMIT ?? "120", 10),
|
|
201
|
+
standardHeaders: true,
|
|
202
|
+
legacyHeaders: false,
|
|
203
|
+
message: { error: "Too many requests. Retry after 60 seconds.", code: "RATE_LIMITED" },
|
|
204
|
+
});
|
|
205
|
+
function mcpAuthMiddleware(req, res, next) {
|
|
206
|
+
if (!MCP_AUTH_TOKEN) {
|
|
207
|
+
next();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const auth = req.headers.authorization ?? "";
|
|
211
|
+
if (auth !== `Bearer ${MCP_AUTH_TOKEN}`) {
|
|
212
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
next();
|
|
216
|
+
}
|
|
181
217
|
// Health check for Railway / uptime monitors
|
|
182
218
|
app.get("/health", (_req, res) => {
|
|
183
219
|
res.json({
|
|
@@ -203,7 +239,7 @@ app.get("/.well-known/mcp/server-card.json", (_req, res) => {
|
|
|
203
239
|
});
|
|
204
240
|
});
|
|
205
241
|
// Stateless StreamableHTTP — new server instance per request (no session state needed)
|
|
206
|
-
app.post("/mcp", async (req, res) => {
|
|
242
|
+
app.post("/mcp", mcpRateLimiter, mcpAuthMiddleware, async (req, res) => {
|
|
207
243
|
const transport = new StreamableHTTPServerTransport({
|
|
208
244
|
sessionIdGenerator: undefined,
|
|
209
245
|
});
|
|
@@ -215,7 +251,7 @@ app.post("/mcp", async (req, res) => {
|
|
|
215
251
|
await transport.handleRequest(req, res, req.body);
|
|
216
252
|
});
|
|
217
253
|
// SSE upgrade for clients that prefer streaming
|
|
218
|
-
app.get("/mcp", async (req, res) => {
|
|
254
|
+
app.get("/mcp", mcpRateLimiter, mcpAuthMiddleware, async (req, res) => {
|
|
219
255
|
const transport = new StreamableHTTPServerTransport({
|
|
220
256
|
sessionIdGenerator: undefined,
|
|
221
257
|
});
|
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
|
|
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
|
|
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].
|
|
124
|
+
const text = result.content[0]?.text ?? JSON.stringify({ error: "No content returned" });
|
|
116
125
|
return {
|
|
117
126
|
contents: [
|
|
118
127
|
{
|
|
@@ -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,6 +67,7 @@ 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
73
|
export declare function handlePlaceBatchOrders(args: BatchOrdersArgs, client: BudaClient): Promise<{
|
|
@@ -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
|
|
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"}
|
|
@@ -6,6 +6,7 @@ export const toolSchema = {
|
|
|
6
6
|
description: "Place multiple orders sequentially on Buda.com (up to 20). " +
|
|
7
7
|
"All orders are pre-validated before any API call — a validation failure stops execution with zero orders placed. " +
|
|
8
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). " +
|
|
9
10
|
"IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
|
|
10
11
|
"Requires BUDA_API_KEY and BUDA_API_SECRET.",
|
|
11
12
|
inputSchema: {
|
|
@@ -26,6 +27,12 @@ export const toolSchema = {
|
|
|
26
27
|
required: ["market_id", "type", "price_type", "amount"],
|
|
27
28
|
},
|
|
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
|
+
},
|
|
29
36
|
confirmation_token: {
|
|
30
37
|
type: "string",
|
|
31
38
|
description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute.",
|
|
@@ -42,7 +49,7 @@ const orderShape = z.object({
|
|
|
42
49
|
limit_price: z.number().positive().optional(),
|
|
43
50
|
});
|
|
44
51
|
export async function handlePlaceBatchOrders(args, client) {
|
|
45
|
-
const { orders, confirmation_token } = args;
|
|
52
|
+
const { orders, max_notional, confirmation_token } = args;
|
|
46
53
|
if (confirmation_token !== "CONFIRM") {
|
|
47
54
|
return {
|
|
48
55
|
content: [
|
|
@@ -94,6 +101,26 @@ export async function handlePlaceBatchOrders(args, client) {
|
|
|
94
101
|
};
|
|
95
102
|
}
|
|
96
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
|
+
}
|
|
97
124
|
// Execute sequentially
|
|
98
125
|
const results = [];
|
|
99
126
|
for (let i = 0; i < orders.length; i++) {
|
|
@@ -146,6 +173,13 @@ export function register(server, client) {
|
|
|
146
173
|
.min(1)
|
|
147
174
|
.max(20)
|
|
148
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."),
|
|
149
183
|
confirmation_token: z
|
|
150
184
|
.string()
|
|
151
185
|
.describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute."),
|
|
@@ -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) }],
|
|
@@ -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,
|
|
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) =>
|
|
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()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lightning.d.ts","sourceRoot":"","sources":["../../src/tools/lightning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;CAuBzC,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;CAwB5C,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,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+
|
|
1
|
+
{"version":3,"file":"lightning.d.ts","sourceRoot":"","sources":["../../src/tools/lightning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;CAuBzC,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;CAwB5C,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,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+EhF;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,0BAA0B,EAChC,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,CA8ChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2CpE"}
|
package/dist/tools/lightning.js
CHANGED
|
@@ -66,6 +66,20 @@ export async function handleLightningWithdrawal(args, client) {
|
|
|
66
66
|
isError: true,
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
const BOLT11_RE = /^ln(bc|tb|bcrt)\d/i;
|
|
70
|
+
if (!BOLT11_RE.test(invoice)) {
|
|
71
|
+
return {
|
|
72
|
+
content: [{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: JSON.stringify({
|
|
75
|
+
error: "Invalid Lightning invoice format. " +
|
|
76
|
+
"Expected a BOLT-11 string starting with 'lnbc', 'lntb', or 'lnbcrt'.",
|
|
77
|
+
code: "INVALID_INVOICE",
|
|
78
|
+
}),
|
|
79
|
+
}],
|
|
80
|
+
isError: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
69
83
|
try {
|
|
70
84
|
const data = await client.post(`/reserves/ln-btc/withdrawals`, { invoice });
|
|
71
85
|
const lw = data.lightning_withdrawal;
|
|
@@ -141,7 +155,7 @@ export function register(server, client) {
|
|
|
141
155
|
server.tool(lightningWithdrawalToolSchema.name, lightningWithdrawalToolSchema.description, {
|
|
142
156
|
invoice: z
|
|
143
157
|
.string()
|
|
144
|
-
.min(
|
|
158
|
+
.min(50)
|
|
145
159
|
.describe("BOLT-11 Lightning invoice string (starts with 'lnbc', 'lntb', etc.)."),
|
|
146
160
|
confirmation_token: z
|
|
147
161
|
.string()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"place_order.d.ts","sourceRoot":"","sources":["../../src/tools/place_order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEtB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,cAAc,EACpB,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,
|
|
1
|
+
{"version":3,"file":"place_order.d.ts","sourceRoot":"","sources":["../../src/tools/place_order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEtB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,cAAc,EACpB,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,CAqKhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA4DpE"}
|
|
@@ -145,6 +145,37 @@ export async function handlePlaceOrder(args, client) {
|
|
|
145
145
|
isError: true,
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
|
+
if (gtd_timestamp !== undefined) {
|
|
149
|
+
const ts = new Date(gtd_timestamp).getTime();
|
|
150
|
+
if (isNaN(ts)) {
|
|
151
|
+
return {
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: "text",
|
|
155
|
+
text: JSON.stringify({
|
|
156
|
+
error: "gtd_timestamp must be a valid ISO 8601 datetime string.",
|
|
157
|
+
code: "VALIDATION_ERROR",
|
|
158
|
+
}),
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
isError: true,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (ts <= Date.now()) {
|
|
165
|
+
return {
|
|
166
|
+
content: [
|
|
167
|
+
{
|
|
168
|
+
type: "text",
|
|
169
|
+
text: JSON.stringify({
|
|
170
|
+
error: "gtd_timestamp must be a future datetime.",
|
|
171
|
+
code: "VALIDATION_ERROR",
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
isError: true,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
148
179
|
let limitType = "gtc";
|
|
149
180
|
if (ioc)
|
|
150
181
|
limitType = "ioc";
|
|
@@ -10,6 +10,10 @@ export declare const createReceiveAddressToolSchema: {
|
|
|
10
10
|
type: string;
|
|
11
11
|
description: string;
|
|
12
12
|
};
|
|
13
|
+
confirmation_token: {
|
|
14
|
+
type: string;
|
|
15
|
+
description: string;
|
|
16
|
+
};
|
|
13
17
|
};
|
|
14
18
|
required: string[];
|
|
15
19
|
};
|
|
@@ -67,6 +71,7 @@ export declare function handleGetReceiveAddress(args: {
|
|
|
67
71
|
}>;
|
|
68
72
|
export declare function handleCreateReceiveAddress(args: {
|
|
69
73
|
currency: string;
|
|
74
|
+
confirmation_token: string;
|
|
70
75
|
}, client: BudaClient): Promise<{
|
|
71
76
|
content: Array<{
|
|
72
77
|
type: "text";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receive_addresses.d.ts","sourceRoot":"","sources":["../../src/tools/receive_addresses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,8BAA8B
|
|
1
|
+
{"version":3,"file":"receive_addresses.d.ts","sourceRoot":"","sources":["../../src/tools/receive_addresses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;CAwB1C,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;CAiB1C,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;CAoBvC,CAAC;AAYF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC1B,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,CAqChF;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACtC,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,CA4BhF;AAED,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,EACtD,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,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA+BpE"}
|
|
@@ -6,6 +6,7 @@ export const createReceiveAddressToolSchema = {
|
|
|
6
6
|
description: "Generates a new receive address for a crypto currency. " +
|
|
7
7
|
"Creates a new blockchain deposit address for the given currency. " +
|
|
8
8
|
"Each call generates a distinct address. Not idempotent. " +
|
|
9
|
+
"IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
|
|
9
10
|
"Only applicable to crypto currencies (BTC, ETH, etc.). " +
|
|
10
11
|
"Requires BUDA_API_KEY and BUDA_API_SECRET. " +
|
|
11
12
|
"Example: 'Give me a fresh Bitcoin deposit address.'",
|
|
@@ -16,8 +17,12 @@ export const createReceiveAddressToolSchema = {
|
|
|
16
17
|
type: "string",
|
|
17
18
|
description: "Currency code (e.g. 'BTC', 'ETH').",
|
|
18
19
|
},
|
|
20
|
+
confirmation_token: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to generate a new address.",
|
|
23
|
+
},
|
|
19
24
|
},
|
|
20
|
-
required: ["currency"],
|
|
25
|
+
required: ["currency", "confirmation_token"],
|
|
21
26
|
},
|
|
22
27
|
};
|
|
23
28
|
export const listReceiveAddressesToolSchema = {
|
|
@@ -122,7 +127,23 @@ export async function handleGetReceiveAddress(args, client) {
|
|
|
122
127
|
}
|
|
123
128
|
}
|
|
124
129
|
export async function handleCreateReceiveAddress(args, client) {
|
|
125
|
-
const { currency } = args;
|
|
130
|
+
const { currency, confirmation_token } = args;
|
|
131
|
+
if (confirmation_token !== "CONFIRM") {
|
|
132
|
+
return {
|
|
133
|
+
content: [
|
|
134
|
+
{
|
|
135
|
+
type: "text",
|
|
136
|
+
text: JSON.stringify({
|
|
137
|
+
error: "Address not generated. confirmation_token must equal 'CONFIRM' to execute. " +
|
|
138
|
+
"Each call creates a distinct address — review and set confirmation_token='CONFIRM' to proceed.",
|
|
139
|
+
code: "CONFIRMATION_REQUIRED",
|
|
140
|
+
preview: { currency },
|
|
141
|
+
}),
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
isError: true,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
126
147
|
const validationError = validateCurrency(currency);
|
|
127
148
|
if (validationError) {
|
|
128
149
|
return {
|
|
@@ -156,6 +177,9 @@ export function register(server, client) {
|
|
|
156
177
|
}, (args) => handleGetReceiveAddress(args, client));
|
|
157
178
|
server.tool(createReceiveAddressToolSchema.name, createReceiveAddressToolSchema.description, {
|
|
158
179
|
currency: z.string().min(2).max(10).describe("Currency code (e.g. 'BTC', 'ETH')."),
|
|
180
|
+
confirmation_token: z
|
|
181
|
+
.string()
|
|
182
|
+
.describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to generate a new address."),
|
|
159
183
|
}, (args) => handleCreateReceiveAddress(args, client));
|
|
160
184
|
}
|
|
161
185
|
//# sourceMappingURL=receive_addresses.js.map
|
|
@@ -35,6 +35,10 @@ export declare const quoteRemittanceToolSchema: {
|
|
|
35
35
|
type: string;
|
|
36
36
|
description: string;
|
|
37
37
|
};
|
|
38
|
+
confirmation_token: {
|
|
39
|
+
type: string;
|
|
40
|
+
description: string;
|
|
41
|
+
};
|
|
38
42
|
};
|
|
39
43
|
required: string[];
|
|
40
44
|
};
|
|
@@ -94,6 +98,7 @@ export declare function handleQuoteRemittance(args: {
|
|
|
94
98
|
currency: string;
|
|
95
99
|
amount: number;
|
|
96
100
|
recipient_id: number;
|
|
101
|
+
confirmation_token: string;
|
|
97
102
|
}, client: BudaClient): Promise<{
|
|
98
103
|
content: Array<{
|
|
99
104
|
type: "text";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remittances.d.ts","sourceRoot":"","sources":["../../src/tools/remittances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;CAoBrC,CAAC;AAEF,eAAO,MAAM,yBAAyB
|
|
1
|
+
{"version":3,"file":"remittances.d.ts","sourceRoot":"","sources":["../../src/tools/remittances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;CAoBrC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CAiCrC,CAAC;AAEF,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;CAuB3C,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;CAiBnC,CAAC;AAgBF,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACrC,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,CAoChF;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACpB,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,CAgBhF;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,EAC5F,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,CAkDhF;AAED,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,EAChD,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,CAqChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2CpE"}
|
|
@@ -28,7 +28,8 @@ export const quoteRemittanceToolSchema = {
|
|
|
28
28
|
"Requests a price quote for a fiat remittance to a saved recipient. " +
|
|
29
29
|
"Returns a remittance object in 'quoted' state with an expiry timestamp. " +
|
|
30
30
|
"NOT idempotent — creates a new remittance record each call. " +
|
|
31
|
-
"
|
|
31
|
+
"IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
|
|
32
|
+
"To execute the transfer, call accept_remittance_quote with the returned ID before it expires. " +
|
|
32
33
|
"Requires BUDA_API_KEY and BUDA_API_SECRET. " +
|
|
33
34
|
"Example: 'Get a remittance quote to send 100000 CLP to recipient 5.'",
|
|
34
35
|
inputSchema: {
|
|
@@ -46,8 +47,12 @@ export const quoteRemittanceToolSchema = {
|
|
|
46
47
|
type: "number",
|
|
47
48
|
description: "ID of the saved remittance recipient.",
|
|
48
49
|
},
|
|
50
|
+
confirmation_token: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to create the quote.",
|
|
53
|
+
},
|
|
49
54
|
},
|
|
50
|
-
required: ["currency", "amount", "recipient_id"],
|
|
55
|
+
required: ["currency", "amount", "recipient_id", "confirmation_token"],
|
|
51
56
|
},
|
|
52
57
|
};
|
|
53
58
|
export const acceptRemittanceQuoteToolSchema = {
|
|
@@ -151,7 +156,23 @@ export async function handleGetRemittance(args, client) {
|
|
|
151
156
|
}
|
|
152
157
|
}
|
|
153
158
|
export async function handleQuoteRemittance(args, client) {
|
|
154
|
-
const { currency, amount, recipient_id } = args;
|
|
159
|
+
const { currency, amount, recipient_id, confirmation_token } = args;
|
|
160
|
+
if (confirmation_token !== "CONFIRM") {
|
|
161
|
+
return {
|
|
162
|
+
content: [
|
|
163
|
+
{
|
|
164
|
+
type: "text",
|
|
165
|
+
text: JSON.stringify({
|
|
166
|
+
error: "Remittance quote not created. confirmation_token must equal 'CONFIRM' to execute. " +
|
|
167
|
+
"Review the details and set confirmation_token='CONFIRM' to proceed.",
|
|
168
|
+
code: "CONFIRMATION_REQUIRED",
|
|
169
|
+
preview: { currency, amount, recipient_id },
|
|
170
|
+
}),
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
isError: true,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
155
176
|
const validationError = validateCurrency(currency);
|
|
156
177
|
if (validationError) {
|
|
157
178
|
return {
|
|
@@ -228,6 +249,9 @@ export function register(server, client) {
|
|
|
228
249
|
currency: z.string().min(2).max(10).describe("Fiat currency code (e.g. 'CLP', 'COP')."),
|
|
229
250
|
amount: z.number().positive().describe("Amount to remit (positive number)."),
|
|
230
251
|
recipient_id: z.number().int().positive().describe("ID of the saved remittance recipient."),
|
|
252
|
+
confirmation_token: z
|
|
253
|
+
.string()
|
|
254
|
+
.describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to create the quote."),
|
|
231
255
|
}, (args) => handleQuoteRemittance(args, client));
|
|
232
256
|
server.tool(acceptRemittanceQuoteToolSchema.name, acceptRemittanceQuoteToolSchema.description, {
|
|
233
257
|
id: z.number().int().positive().describe("The numeric ID of the remittance quote to accept."),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"technical_indicators.d.ts","sourceRoot":"","sources":["../../src/tools/technical_indicators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA8BtB,CAAC;AAsGF,KAAK,uBAAuB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,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,
|
|
1
|
+
{"version":3,"file":"technical_indicators.d.ts","sourceRoot":"","sources":["../../src/tools/technical_indicators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA8BtB,CAAC;AAsGF,KAAK,uBAAuB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,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,CA4GhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAyBpE"}
|
|
@@ -146,7 +146,7 @@ export async function handleTechnicalIndicators(args, client) {
|
|
|
146
146
|
const macdResult = macd(closes, 12, 26, 9);
|
|
147
147
|
const bbResult = bollingerBands(closes, 20, 2);
|
|
148
148
|
const sma20 = parseFloat(sma(closes, 20).toFixed(2));
|
|
149
|
-
const sma50 = parseFloat(sma(closes, 50).toFixed(2));
|
|
149
|
+
const sma50 = closes.length >= 50 ? parseFloat(sma(closes, 50).toFixed(2)) : null;
|
|
150
150
|
const lastClose = closes[closes.length - 1];
|
|
151
151
|
// Signal interpretations
|
|
152
152
|
const rsiSignal = rsiValue !== null && rsiValue > 70
|
|
@@ -180,6 +180,7 @@ export async function handleTechnicalIndicators(args, client) {
|
|
|
180
180
|
bollinger_bands: bbResult,
|
|
181
181
|
sma_20: sma20,
|
|
182
182
|
sma_50: sma50,
|
|
183
|
+
sma_50_warning: sma50 === null ? `insufficient data (need 50 candles, have ${closes.length})` : undefined,
|
|
183
184
|
},
|
|
184
185
|
signals: {
|
|
185
186
|
rsi_signal: rsiSignal,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withdrawals.d.ts","sourceRoot":"","sources":["../../src/tools/withdrawals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;CA8B1C,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAqBF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,wBAAwB,EAC9B,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,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"withdrawals.d.ts","sourceRoot":"","sources":["../../src/tools/withdrawals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;CA8B1C,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAqBF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,wBAAwB,EAC9B,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,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBtC,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,oBAAoB,EAC1B,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,CAmGhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA+BpE"}
|