@guiie/buda-mcp 1.2.1 → 1.3.0

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 (56) hide show
  1. package/.cursor/rules/release-workflow.mdc +54 -0
  2. package/CHANGELOG.md +37 -0
  3. package/PUBLISH_CHECKLIST.md +62 -53
  4. package/dist/http.js +22 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +20 -0
  7. package/dist/tools/arbitrage.d.ts +35 -0
  8. package/dist/tools/arbitrage.d.ts.map +1 -0
  9. package/dist/tools/arbitrage.js +142 -0
  10. package/dist/tools/balances.d.ts.map +1 -1
  11. package/dist/tools/balances.js +24 -4
  12. package/dist/tools/compare_markets.d.ts.map +1 -1
  13. package/dist/tools/compare_markets.js +11 -10
  14. package/dist/tools/market_summary.d.ts +43 -0
  15. package/dist/tools/market_summary.d.ts.map +1 -0
  16. package/dist/tools/market_summary.js +81 -0
  17. package/dist/tools/markets.d.ts.map +1 -1
  18. package/dist/tools/markets.js +4 -2
  19. package/dist/tools/orderbook.d.ts.map +1 -1
  20. package/dist/tools/orderbook.js +14 -4
  21. package/dist/tools/orders.d.ts.map +1 -1
  22. package/dist/tools/orders.js +41 -3
  23. package/dist/tools/price_history.js +14 -14
  24. package/dist/tools/spread.d.ts.map +1 -1
  25. package/dist/tools/spread.js +10 -8
  26. package/dist/tools/ticker.d.ts.map +1 -1
  27. package/dist/tools/ticker.js +24 -3
  28. package/dist/tools/trades.d.ts.map +1 -1
  29. package/dist/tools/trades.js +17 -3
  30. package/dist/tools/volume.d.ts.map +1 -1
  31. package/dist/tools/volume.js +21 -3
  32. package/dist/utils.d.ts +17 -0
  33. package/dist/utils.d.ts.map +1 -0
  34. package/dist/utils.js +21 -0
  35. package/marketplace/README.md +1 -1
  36. package/marketplace/claude-listing.md +26 -14
  37. package/marketplace/gemini-tools.json +41 -9
  38. package/marketplace/openapi.yaml +335 -119
  39. package/package.json +1 -1
  40. package/server.json +2 -2
  41. package/src/http.ts +27 -0
  42. package/src/index.ts +25 -0
  43. package/src/tools/arbitrage.ts +202 -0
  44. package/src/tools/balances.ts +27 -4
  45. package/src/tools/compare_markets.ts +11 -10
  46. package/src/tools/market_summary.ts +124 -0
  47. package/src/tools/markets.ts +4 -2
  48. package/src/tools/orderbook.ts +15 -4
  49. package/src/tools/orders.ts +45 -4
  50. package/src/tools/price_history.ts +17 -17
  51. package/src/tools/spread.ts +10 -8
  52. package/src/tools/ticker.ts +27 -3
  53. package/src/tools/trades.ts +18 -3
  54. package/src/tools/volume.ts +24 -3
  55. package/src/utils.ts +21 -0
  56. package/test/unit.ts +254 -0
@@ -3,9 +3,10 @@ import { BudaApiError } from "../client.js";
3
3
  import { CACHE_TTL } from "../cache.js";
4
4
  export const toolSchema = {
5
5
  name: "compare_markets",
6
- description: "Compare ticker data for all trading pairs of a given base currency across Buda.com's " +
7
- "supported quote currencies (CLP, COP, PEN, BTC, USDC, ETH). " +
8
- "For example, passing 'BTC' returns side-by-side data for BTC-CLP, BTC-COP, BTC-PEN, etc.",
6
+ description: "Returns side-by-side ticker data for all trading pairs of a given base currency across Buda.com's " +
7
+ "supported quote currencies (CLP, COP, PEN, BTC, USDC, ETH). All prices are floats; " +
8
+ "price_change_24h and price_change_7d are floats in percent (e.g. 1.23 means +1.23%). " +
9
+ "Example: 'In which country is Bitcoin currently most expensive on Buda?'",
9
10
  inputSchema: {
10
11
  type: "object",
11
12
  properties: {
@@ -48,16 +49,16 @@ export function register(server, client, cache) {
48
49
  base_currency: base,
49
50
  markets: matching.map((t) => ({
50
51
  market_id: t.market_id,
51
- last_price: t.last_price[0],
52
- currency: t.last_price[1],
53
- best_bid: t.max_bid ? t.max_bid[0] : null,
54
- best_ask: t.min_ask ? t.min_ask[0] : null,
55
- volume_24h: t.volume ? t.volume[0] : null,
52
+ last_price: parseFloat(t.last_price[0]),
53
+ last_price_currency: t.last_price[1],
54
+ best_bid: t.max_bid ? parseFloat(t.max_bid[0]) : null,
55
+ best_ask: t.min_ask ? parseFloat(t.min_ask[0]) : null,
56
+ volume_24h: t.volume ? parseFloat(t.volume[0]) : null,
56
57
  price_change_24h: t.price_variation_24h
57
- ? (parseFloat(t.price_variation_24h) * 100).toFixed(2) + "%"
58
+ ? parseFloat((parseFloat(t.price_variation_24h) * 100).toFixed(4))
58
59
  : null,
59
60
  price_change_7d: t.price_variation_7d
60
- ? (parseFloat(t.price_variation_7d) * 100).toFixed(2) + "%"
61
+ ? parseFloat((parseFloat(t.price_variation_7d) * 100).toFixed(4))
61
62
  : null,
62
63
  })),
63
64
  };
@@ -0,0 +1,43 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { BudaClient } from "../client.js";
3
+ import { MemoryCache } from "../cache.js";
4
+ export declare const toolSchema: {
5
+ name: string;
6
+ description: string;
7
+ inputSchema: {
8
+ type: "object";
9
+ properties: {
10
+ market_id: {
11
+ type: string;
12
+ description: string;
13
+ };
14
+ };
15
+ required: string[];
16
+ };
17
+ };
18
+ export interface MarketSummaryResult {
19
+ market_id: string;
20
+ last_price: number;
21
+ last_price_currency: string;
22
+ bid: number;
23
+ ask: number;
24
+ spread_pct: number;
25
+ volume_24h: number;
26
+ volume_24h_currency: string;
27
+ price_change_24h: number;
28
+ price_change_7d: number;
29
+ liquidity_rating: "high" | "medium" | "low";
30
+ }
31
+ interface MarketSummaryInput {
32
+ market_id: string;
33
+ }
34
+ export declare function handleMarketSummary({ market_id }: MarketSummaryInput, client: BudaClient, cache: MemoryCache): Promise<{
35
+ content: Array<{
36
+ type: "text";
37
+ text: string;
38
+ }>;
39
+ isError?: boolean;
40
+ }>;
41
+ export declare function register(server: McpServer, client: BudaClient, cache: MemoryCache): void;
42
+ export {};
43
+ //# sourceMappingURL=market_summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"market_summary.d.ts","sourceRoot":"","sources":["../../src/tools/market_summary.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;AAKrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAkBtB,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CAC7C;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,mBAAmB,CACvC,EAAE,SAAS,EAAE,EAAE,kBAAkB,EACjC,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,CA4DhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAWxF"}
@@ -0,0 +1,81 @@
1
+ import { z } from "zod";
2
+ import { BudaApiError } from "../client.js";
3
+ import { CACHE_TTL } from "../cache.js";
4
+ import { validateMarketId } from "../validation.js";
5
+ import { flattenAmount, getLiquidityRating } from "../utils.js";
6
+ export const toolSchema = {
7
+ name: "get_market_summary",
8
+ description: "One-call summary of everything relevant about a market: last price, best bid/ask, spread %, " +
9
+ "24h volume, 24h and 7d price change, and a liquidity_rating ('high' / 'medium' / 'low' based on " +
10
+ "spread thresholds: < 0.3% = high, 0.3–1% = medium, > 1% = low). All prices and volumes are floats. " +
11
+ "Best first tool to call when a user asks about any specific market. " +
12
+ "Example: 'Give me a complete overview of the BTC-CLP market right now.'",
13
+ inputSchema: {
14
+ type: "object",
15
+ properties: {
16
+ market_id: {
17
+ type: "string",
18
+ description: "Market ID (e.g. 'BTC-CLP', 'ETH-COP', 'BTC-PEN').",
19
+ },
20
+ },
21
+ required: ["market_id"],
22
+ },
23
+ };
24
+ export async function handleMarketSummary({ market_id }, client, cache) {
25
+ try {
26
+ const validationError = validateMarketId(market_id);
27
+ if (validationError) {
28
+ return {
29
+ content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }],
30
+ isError: true,
31
+ };
32
+ }
33
+ const id = market_id.toLowerCase();
34
+ // Fetch ticker and volume in parallel
35
+ const [tickerData, volumeData] = await Promise.all([
36
+ cache.getOrFetch(`ticker:${id}`, CACHE_TTL.TICKER, () => client.get(`/markets/${id}/ticker`)),
37
+ client.get(`/markets/${id}/volume`),
38
+ ]);
39
+ const t = tickerData.ticker;
40
+ const v = volumeData.volume;
41
+ const lastPrice = flattenAmount(t.last_price);
42
+ const bid = parseFloat(t.max_bid[0]);
43
+ const ask = parseFloat(t.min_ask[0]);
44
+ const volume24h = flattenAmount(v.ask_volume_24h);
45
+ const spreadAbs = ask - bid;
46
+ const spreadPct = ask > 0 ? parseFloat(((spreadAbs / ask) * 100).toFixed(4)) : 0;
47
+ const result = {
48
+ market_id: t.market_id,
49
+ last_price: lastPrice.value,
50
+ last_price_currency: lastPrice.currency,
51
+ bid,
52
+ ask,
53
+ spread_pct: spreadPct,
54
+ volume_24h: volume24h.value,
55
+ volume_24h_currency: volume24h.currency,
56
+ price_change_24h: parseFloat((parseFloat(t.price_variation_24h) * 100).toFixed(4)),
57
+ price_change_7d: parseFloat((parseFloat(t.price_variation_7d) * 100).toFixed(4)),
58
+ liquidity_rating: getLiquidityRating(spreadPct),
59
+ };
60
+ return {
61
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
62
+ };
63
+ }
64
+ catch (err) {
65
+ const msg = err instanceof BudaApiError
66
+ ? { error: err.message, code: err.status, path: err.path }
67
+ : { error: String(err), code: "UNKNOWN" };
68
+ return {
69
+ content: [{ type: "text", text: JSON.stringify(msg) }],
70
+ isError: true,
71
+ };
72
+ }
73
+ }
74
+ export function register(server, client, cache) {
75
+ server.tool(toolSchema.name, toolSchema.description, {
76
+ market_id: z
77
+ .string()
78
+ .describe("Market ID (e.g. 'BTC-CLP', 'ETH-COP', 'BTC-PEN')."),
79
+ }, (args) => handleMarketSummary(args, client, cache));
80
+ }
81
+ //# sourceMappingURL=market_summary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markets.d.ts","sourceRoot":"","sources":["../../src/tools/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;;;;;;;;;;;;CActB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAsDxF"}
1
+ {"version":3,"file":"markets.d.ts","sourceRoot":"","sources":["../../src/tools/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;;;;;;;;;;;;CAgBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAsDxF"}
@@ -4,8 +4,10 @@ import { CACHE_TTL } from "../cache.js";
4
4
  import { validateMarketId } from "../validation.js";
5
5
  export const toolSchema = {
6
6
  name: "get_markets",
7
- description: "List all available trading pairs on Buda.com, or get details for a specific market. " +
8
- "Returns base/quote currencies, fees, and minimum order sizes.",
7
+ description: "Lists all available trading pairs on Buda.com, or returns details for a specific market " +
8
+ "(base/quote currencies, taker/maker fees as decimals, minimum order size in base currency, " +
9
+ "and fee discount tiers). Omit market_id to get all ~26 markets at once. " +
10
+ "Example: 'What is the taker fee and minimum order size for BTC-CLP?'",
9
11
  inputSchema: {
10
12
  type: "object",
11
13
  properties: {
@@ -1 +1 @@
1
- {"version":3,"file":"orderbook.d.ts","sourceRoot":"","sources":["../../src/tools/orderbook.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;;;;;;;;;;;;;;;;;CAmBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAuDxF"}
1
+ {"version":3,"file":"orderbook.d.ts","sourceRoot":"","sources":["../../src/tools/orderbook.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;;;;;;;;;;;;;;;;;CAqBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAgExF"}
@@ -4,8 +4,10 @@ import { CACHE_TTL } from "../cache.js";
4
4
  import { validateMarketId } from "../validation.js";
5
5
  export const toolSchema = {
6
6
  name: "get_orderbook",
7
- description: "Get the current order book (bids and asks) for a Buda.com market. Returns sorted arrays of " +
8
- "bids (buy orders) and asks (sell orders), each as [price, amount] pairs.",
7
+ description: "Returns the current order book for a Buda.com market as typed objects with float price and amount fields. " +
8
+ "Bids are sorted highest-price first; asks lowest-price first. " +
9
+ "Prices are in the quote currency; amounts are in the base currency. " +
10
+ "Example: 'What are the top 5 buy and sell orders for BTC-CLP right now?'",
9
11
  inputSchema: {
10
12
  type: "object",
11
13
  properties: {
@@ -44,9 +46,17 @@ export function register(server, client, cache) {
44
46
  const id = market_id.toLowerCase();
45
47
  const data = await cache.getOrFetch(`orderbook:${id}`, CACHE_TTL.ORDERBOOK, () => client.get(`/markets/${id}/order_book`));
46
48
  const book = data.order_book;
49
+ const bids = limit ? book.bids.slice(0, limit) : book.bids;
50
+ const asks = limit ? book.asks.slice(0, limit) : book.asks;
47
51
  const result = {
48
- bids: limit ? book.bids.slice(0, limit) : book.bids,
49
- asks: limit ? book.asks.slice(0, limit) : book.asks,
52
+ bids: bids.map(([price, amount]) => ({
53
+ price: parseFloat(price),
54
+ amount: parseFloat(amount),
55
+ })),
56
+ asks: asks.map(([price, amount]) => ({
57
+ price: parseFloat(price),
58
+ amount: parseFloat(amount),
59
+ })),
50
60
  bid_count: book.bids.length,
51
61
  ask_count: book.asks.length,
52
62
  };
@@ -1 +1 @@
1
- {"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../../src/tools/orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;CA4BtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAqEpE"}
1
+ {"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../../src/tools/orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;CA+BtB,CAAC;AAMF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAsGpE"}
@@ -1,10 +1,14 @@
1
1
  import { z } from "zod";
2
2
  import { BudaApiError } from "../client.js";
3
3
  import { validateMarketId } from "../validation.js";
4
+ import { flattenAmount } from "../utils.js";
4
5
  export const toolSchema = {
5
6
  name: "get_orders",
6
- description: "Get orders for a given Buda.com market. Filter by state (pending, active, traded, canceled). " +
7
- "Requires BUDA_API_KEY and BUDA_API_SECRET environment variables.",
7
+ description: "Returns orders for a given Buda.com market as flat typed objects. All monetary amounts are floats " +
8
+ "with separate _currency fields (e.g. amount + amount_currency). Filterable by state: pending, " +
9
+ "active, traded, canceled. Supports pagination via per and page. " +
10
+ "Requires BUDA_API_KEY and BUDA_API_SECRET. " +
11
+ "Example: 'Show my open limit orders on BTC-CLP.'",
8
12
  inputSchema: {
9
13
  type: "object",
10
14
  properties: {
@@ -28,6 +32,9 @@ export const toolSchema = {
28
32
  required: ["market_id"],
29
33
  },
30
34
  };
35
+ function flattenAmountField(amount) {
36
+ return flattenAmount(amount);
37
+ }
31
38
  export function register(server, client) {
32
39
  server.tool(toolSchema.name, toolSchema.description, {
33
40
  market_id: z
@@ -68,11 +75,42 @@ export function register(server, client) {
68
75
  if (page !== undefined)
69
76
  params.page = page;
70
77
  const data = await client.get(`/markets/${market_id.toLowerCase()}/orders`, Object.keys(params).length > 0 ? params : undefined);
78
+ const orders = data.orders.map((o) => {
79
+ const amount = flattenAmountField(o.amount);
80
+ const originalAmount = flattenAmountField(o.original_amount);
81
+ const tradedAmount = flattenAmountField(o.traded_amount);
82
+ const totalExchanged = flattenAmountField(o.total_exchanged);
83
+ const paidFee = flattenAmountField(o.paid_fee);
84
+ const limitPrice = o.limit ? flattenAmountField(o.limit) : null;
85
+ return {
86
+ id: o.id,
87
+ type: o.type,
88
+ state: o.state,
89
+ created_at: o.created_at,
90
+ market_id: o.market_id,
91
+ fee_currency: o.fee_currency,
92
+ price_type: o.price_type,
93
+ order_type: o.order_type,
94
+ client_id: o.client_id,
95
+ limit_price: limitPrice ? limitPrice.value : null,
96
+ limit_price_currency: limitPrice ? limitPrice.currency : null,
97
+ amount: amount.value,
98
+ amount_currency: amount.currency,
99
+ original_amount: originalAmount.value,
100
+ original_amount_currency: originalAmount.currency,
101
+ traded_amount: tradedAmount.value,
102
+ traded_amount_currency: tradedAmount.currency,
103
+ total_exchanged: totalExchanged.value,
104
+ total_exchanged_currency: totalExchanged.currency,
105
+ paid_fee: paidFee.value,
106
+ paid_fee_currency: paidFee.currency,
107
+ };
108
+ });
71
109
  return {
72
110
  content: [
73
111
  {
74
112
  type: "text",
75
- text: JSON.stringify({ orders: data.orders, meta: data.meta }, null, 2),
113
+ text: JSON.stringify({ orders, meta: data.meta }, null, 2),
76
114
  },
77
115
  ],
78
116
  };
@@ -10,9 +10,9 @@ export const toolSchema = {
10
10
  name: "get_price_history",
11
11
  description: "IMPORTANT: Candles are aggregated client-side from raw trades (Buda has no native candlestick " +
12
12
  "endpoint) — fetching more trades via the 'limit' parameter gives deeper history but slower " +
13
- "responses. Returns OHLCV (open/high/low/close/volume) price history for a Buda.com market. " +
14
- "Candle timestamps are UTC bucket boundaries (e.g. '2026-04-10T12:00:00.000Z' for 1h). " +
15
- "Supports 1h, 4h, and 1d candle periods.",
13
+ "responses. Returns OHLCV candles (open/high/low/close as floats in quote currency; volume as float " +
14
+ "in base currency) for periods 1h, 4h, or 1d. Candle timestamps are UTC bucket boundaries. " +
15
+ "Example: 'Show me the hourly BTC-CLP price chart for the past 24 hours.'",
16
16
  inputSchema: {
17
17
  type: "object",
18
18
  properties: {
@@ -86,22 +86,22 @@ export function register(server, client, _cache) {
86
86
  if (!buckets.has(bucketStart)) {
87
87
  buckets.set(bucketStart, {
88
88
  time: new Date(bucketStart).toISOString(),
89
- open: price,
90
- high: price,
91
- low: price,
92
- close: price,
93
- volume: amount,
89
+ open: p,
90
+ high: p,
91
+ low: p,
92
+ close: p,
93
+ volume: v,
94
94
  trade_count: 1,
95
95
  });
96
96
  }
97
97
  else {
98
98
  const candle = buckets.get(bucketStart);
99
- if (p > parseFloat(candle.high))
100
- candle.high = price;
101
- if (p < parseFloat(candle.low))
102
- candle.low = price;
103
- candle.close = price;
104
- candle.volume = (parseFloat(candle.volume) + v).toFixed(8);
99
+ if (p > candle.high)
100
+ candle.high = p;
101
+ if (p < candle.low)
102
+ candle.low = p;
103
+ candle.close = p;
104
+ candle.volume = parseFloat((candle.volume + v).toFixed(8));
105
105
  candle.trade_count++;
106
106
  }
107
107
  }
@@ -1 +1 @@
1
- {"version":3,"file":"spread.d.ts","sourceRoot":"","sources":["../../src/tools/spread.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;;;;;;;;;;;;;CAetB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAuExF"}
1
+ {"version":3,"file":"spread.d.ts","sourceRoot":"","sources":["../../src/tools/spread.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;;;;;;;;;;;;;CAiBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAuExF"}
@@ -4,8 +4,10 @@ import { CACHE_TTL } from "../cache.js";
4
4
  import { validateMarketId } from "../validation.js";
5
5
  export const toolSchema = {
6
6
  name: "get_spread",
7
- description: "Calculate the bid/ask spread for a Buda.com market. " +
8
- "Returns the best bid, best ask, absolute spread, and spread as a percentage of the ask price.",
7
+ description: "Returns the best bid, best ask, absolute spread, and spread percentage for a Buda.com market. " +
8
+ "All prices are floats in the quote currency (e.g. CLP). spread_percentage is a float in percent " +
9
+ "(e.g. 0.15 means 0.15%). Use this to evaluate liquidity before placing a large order. " +
10
+ "Example: 'Is BTC-CLP liquid enough to buy 10M CLP without significant slippage?'",
9
11
  inputSchema: {
10
12
  type: "object",
11
13
  properties: {
@@ -52,12 +54,12 @@ export function register(server, client, cache) {
52
54
  const spreadPct = (spreadAbs / ask) * 100;
53
55
  const result = {
54
56
  market_id: ticker.market_id,
55
- currency,
56
- best_bid: bid.toString(),
57
- best_ask: ask.toString(),
58
- spread_absolute: spreadAbs.toFixed(2),
59
- spread_percentage: spreadPct.toFixed(4) + "%",
60
- last_price: ticker.last_price[0],
57
+ price_currency: currency,
58
+ best_bid: bid,
59
+ best_ask: ask,
60
+ spread_absolute: parseFloat(spreadAbs.toFixed(2)),
61
+ spread_percentage: parseFloat(spreadPct.toFixed(4)),
62
+ last_price: parseFloat(ticker.last_price[0]),
61
63
  };
62
64
  return {
63
65
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
@@ -1 +1 @@
1
- {"version":3,"file":"ticker.d.ts","sourceRoot":"","sources":["../../src/tools/ticker.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;;;;;;;;;;;;;CAetB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAwCxF"}
1
+ {"version":3,"file":"ticker.d.ts","sourceRoot":"","sources":["../../src/tools/ticker.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;AAKrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAiBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CA6DxF"}
@@ -2,10 +2,13 @@ import { z } from "zod";
2
2
  import { BudaApiError } from "../client.js";
3
3
  import { CACHE_TTL } from "../cache.js";
4
4
  import { validateMarketId } from "../validation.js";
5
+ import { flattenAmount } from "../utils.js";
5
6
  export const toolSchema = {
6
7
  name: "get_ticker",
7
- description: "Get the current ticker for a Buda.com market: last traded price, best bid/ask, " +
8
- "24h volume, and price change over 24h and 7d.",
8
+ description: "Returns the current market snapshot for a Buda.com market: last traded price, best bid, " +
9
+ "best ask, 24h volume, and price change over 24h and 7d. All prices are floats in the quote " +
10
+ "currency (e.g. CLP for BTC-CLP). price_variation_24h is a decimal fraction (0.012 = +1.2%). " +
11
+ "Example: 'What is the current Bitcoin price in Chilean pesos?'",
9
12
  inputSchema: {
10
13
  type: "object",
11
14
  properties: {
@@ -33,8 +36,26 @@ export function register(server, client, cache) {
33
36
  }
34
37
  const id = market_id.toLowerCase();
35
38
  const data = await cache.getOrFetch(`ticker:${id}`, CACHE_TTL.TICKER, () => client.get(`/markets/${id}/ticker`));
39
+ const t = data.ticker;
40
+ const lastPrice = flattenAmount(t.last_price);
41
+ const minAsk = flattenAmount(t.min_ask);
42
+ const maxBid = flattenAmount(t.max_bid);
43
+ const volume = flattenAmount(t.volume);
44
+ const result = {
45
+ market_id: t.market_id,
46
+ last_price: lastPrice.value,
47
+ last_price_currency: lastPrice.currency,
48
+ min_ask: minAsk.value,
49
+ min_ask_currency: minAsk.currency,
50
+ max_bid: maxBid.value,
51
+ max_bid_currency: maxBid.currency,
52
+ volume: volume.value,
53
+ volume_currency: volume.currency,
54
+ price_variation_24h: parseFloat(t.price_variation_24h),
55
+ price_variation_7d: parseFloat(t.price_variation_7d),
56
+ };
36
57
  return {
37
- content: [{ type: "text", text: JSON.stringify(data.ticker, null, 2) }],
58
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
38
59
  };
39
60
  }
40
61
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"trades.d.ts","sourceRoot":"","sources":["../../src/tools/trades.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CAwBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAyDzF"}
1
+ {"version":3,"file":"trades.d.ts","sourceRoot":"","sources":["../../src/tools/trades.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA0BtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAsEzF"}
@@ -3,8 +3,10 @@ import { BudaApiError } from "../client.js";
3
3
  import { validateMarketId } from "../validation.js";
4
4
  export const toolSchema = {
5
5
  name: "get_trades",
6
- description: "Get recent trade history for a Buda.com market. Each entry contains " +
7
- "[timestamp_ms, amount, price, direction]. Direction is 'buy' or 'sell'.",
6
+ description: "Returns recent trade history for a Buda.com market as typed objects. Each entry has " +
7
+ "timestamp_ms (integer), amount (float, base currency), price (float, quote currency), " +
8
+ "and direction ('buy' or 'sell'). " +
9
+ "Example: 'What was the last executed price for BTC-CLP and was it a buy or sell?'",
8
10
  inputSchema: {
9
11
  type: "object",
10
12
  properties: {
@@ -56,8 +58,20 @@ export function register(server, client, _cache) {
56
58
  if (timestamp !== undefined)
57
59
  params.timestamp = timestamp;
58
60
  const data = await client.get(`/markets/${market_id.toLowerCase()}/trades`, Object.keys(params).length > 0 ? params : undefined);
61
+ const t = data.trades;
62
+ const result = {
63
+ timestamp: t.timestamp,
64
+ last_timestamp: t.last_timestamp,
65
+ market_id: t.market_id,
66
+ entries: t.entries.map(([tsMs, amount, price, direction]) => ({
67
+ timestamp_ms: parseInt(tsMs, 10),
68
+ amount: parseFloat(amount),
69
+ price: parseFloat(price),
70
+ direction,
71
+ })),
72
+ };
59
73
  return {
60
- content: [{ type: "text", text: JSON.stringify(data.trades, null, 2) }],
74
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
61
75
  };
62
76
  }
63
77
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"volume.d.ts","sourceRoot":"","sources":["../../src/tools/volume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAetB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAqCzF"}
1
+ {"version":3,"file":"volume.d.ts","sourceRoot":"","sources":["../../src/tools/volume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAgBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAwDzF"}
@@ -1,10 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import { BudaApiError } from "../client.js";
3
3
  import { validateMarketId } from "../validation.js";
4
+ import { flattenAmount } from "../utils.js";
4
5
  export const toolSchema = {
5
6
  name: "get_market_volume",
6
- description: "Get 24h and 7-day transacted volume for a Buda.com market. " +
7
- "Returns ask (sell) and bid (buy) volumes in the market's base currency.",
7
+ description: "Returns 24h and 7-day transacted volume for a Buda.com market, split by buy (bid) and sell (ask) side. " +
8
+ "All volume values are floats in the base currency (e.g. BTC for BTC-CLP). " +
9
+ "Example: 'How much Bitcoin was sold on BTC-CLP in the last 24 hours?'",
8
10
  inputSchema: {
9
11
  type: "object",
10
12
  properties: {
@@ -31,8 +33,24 @@ export function register(server, client, _cache) {
31
33
  };
32
34
  }
33
35
  const data = await client.get(`/markets/${market_id.toLowerCase()}/volume`);
36
+ const v = data.volume;
37
+ const ask24 = flattenAmount(v.ask_volume_24h);
38
+ const ask7d = flattenAmount(v.ask_volume_7d);
39
+ const bid24 = flattenAmount(v.bid_volume_24h);
40
+ const bid7d = flattenAmount(v.bid_volume_7d);
41
+ const result = {
42
+ market_id: v.market_id,
43
+ ask_volume_24h: ask24.value,
44
+ ask_volume_24h_currency: ask24.currency,
45
+ ask_volume_7d: ask7d.value,
46
+ ask_volume_7d_currency: ask7d.currency,
47
+ bid_volume_24h: bid24.value,
48
+ bid_volume_24h_currency: bid24.currency,
49
+ bid_volume_7d: bid7d.value,
50
+ bid_volume_7d_currency: bid7d.currency,
51
+ };
34
52
  return {
35
- content: [{ type: "text", text: JSON.stringify(data.volume, null, 2) }],
53
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
36
54
  };
37
55
  }
38
56
  catch (err) {
@@ -0,0 +1,17 @@
1
+ import type { Amount } from "./types.js";
2
+ /**
3
+ * Flattens a Buda API Amount tuple [value_string, currency] into a typed object.
4
+ * All numeric strings are cast to float via parseFloat.
5
+ */
6
+ export declare function flattenAmount(amount: Amount): {
7
+ value: number;
8
+ currency: string;
9
+ };
10
+ /**
11
+ * Returns a liquidity rating based on the bid/ask spread percentage.
12
+ * < 0.3% → "high"
13
+ * 0.3–1% → "medium"
14
+ * > 1% → "low"
15
+ */
16
+ export declare function getLiquidityRating(spreadPct: number): "high" | "medium" | "low";
17
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAEjF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAI/E"}
package/dist/utils.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Flattens a Buda API Amount tuple [value_string, currency] into a typed object.
3
+ * All numeric strings are cast to float via parseFloat.
4
+ */
5
+ export function flattenAmount(amount) {
6
+ return { value: parseFloat(amount[0]), currency: amount[1] };
7
+ }
8
+ /**
9
+ * Returns a liquidity rating based on the bid/ask spread percentage.
10
+ * < 0.3% → "high"
11
+ * 0.3–1% → "medium"
12
+ * > 1% → "low"
13
+ */
14
+ export function getLiquidityRating(spreadPct) {
15
+ if (spreadPct < 0.3)
16
+ return "high";
17
+ if (spreadPct <= 1.0)
18
+ return "medium";
19
+ return "low";
20
+ }
21
+ //# sourceMappingURL=utils.js.map
@@ -1,4 +1,4 @@
1
- # Marketplace Submission Assets — v1.2.0
1
+ # Marketplace Submission Assets — v1.3.0
2
2
 
3
3
  Ready-to-use assets for submitting buda-mcp to every major AI marketplace.
4
4
  Replace `gtorreal` / `gtorreal` with your actual handles before submitting.