@guiie/buda-mcp 1.0.0 → 1.1.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/CHANGELOG.md +96 -0
- package/PUBLISH_CHECKLIST.md +192 -0
- package/README.md +308 -70
- package/dist/cache.d.ts +13 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +25 -0
- package/dist/client.d.ts +9 -8
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +95 -12
- package/dist/http.d.ts +2 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +262 -0
- package/dist/index.js +53 -9
- package/dist/tools/balances.d.ts +4 -0
- package/dist/tools/balances.d.ts.map +1 -0
- package/dist/tools/balances.js +23 -0
- package/dist/tools/cancel_order.d.ts +4 -0
- package/dist/tools/cancel_order.d.ts.map +1 -0
- package/dist/tools/cancel_order.js +53 -0
- package/dist/tools/compare_markets.d.ts +5 -0
- package/dist/tools/compare_markets.d.ts.map +1 -0
- package/dist/tools/compare_markets.js +65 -0
- package/dist/tools/markets.d.ts +2 -1
- package/dist/tools/markets.d.ts.map +1 -1
- package/dist/tools/markets.js +22 -8
- package/dist/tools/orderbook.d.ts +2 -1
- package/dist/tools/orderbook.d.ts.map +1 -1
- package/dist/tools/orderbook.js +27 -13
- package/dist/tools/orders.d.ts +4 -0
- package/dist/tools/orders.d.ts.map +1 -0
- package/dist/tools/orders.js +57 -0
- package/dist/tools/place_order.d.ts +4 -0
- package/dist/tools/place_order.d.ts.map +1 -0
- package/dist/tools/place_order.js +88 -0
- package/dist/tools/price_history.d.ts +5 -0
- package/dist/tools/price_history.d.ts.map +1 -0
- package/dist/tools/price_history.js +97 -0
- package/dist/tools/spread.d.ts +5 -0
- package/dist/tools/spread.d.ts.map +1 -0
- package/dist/tools/spread.js +55 -0
- package/dist/tools/ticker.d.ts +2 -1
- package/dist/tools/ticker.d.ts.map +1 -1
- package/dist/tools/ticker.js +19 -5
- package/dist/tools/trades.d.ts +2 -1
- package/dist/tools/trades.d.ts.map +1 -1
- package/dist/tools/trades.js +22 -10
- package/dist/tools/volume.d.ts +2 -1
- package/dist/tools/volume.d.ts.map +1 -1
- package/dist/tools/volume.js +17 -5
- package/dist/types.d.ts +42 -1
- package/dist/types.d.ts.map +1 -1
- package/marketplace/claude-listing.md +72 -4
- package/marketplace/cursor-mcp.json +1 -1
- package/marketplace/gemini-tools.json +51 -1
- package/marketplace/openapi.yaml +203 -3
- package/package.json +6 -2
- package/railway.json +12 -0
- package/server.json +3 -3
- package/src/cache.ts +34 -0
- package/src/client.ts +107 -12
- package/src/http.ts +305 -0
- package/src/index.ts +77 -9
- package/src/tools/balances.ts +30 -0
- package/src/tools/cancel_order.ts +65 -0
- package/src/tools/compare_markets.ts +82 -0
- package/src/tools/markets.ts +30 -11
- package/src/tools/orderbook.ts +31 -16
- package/src/tools/orders.ts +68 -0
- package/src/tools/place_order.ts +107 -0
- package/src/tools/price_history.ts +124 -0
- package/src/tools/spread.ts +71 -0
- package/src/tools/ticker.ts +23 -8
- package/src/tools/trades.ts +24 -12
- package/src/tools/volume.ts +20 -8
- package/src/types.ts +52 -1
- package/test/run-all.ts +122 -1
- package/tsconfig.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Buda.com Market Data
|
|
2
2
|
|
|
3
3
|
**Category:** Finance / Cryptocurrency
|
|
4
|
-
**Auth:**
|
|
4
|
+
**Auth:** Optional (public mode requires no key; authenticated mode needs `BUDA_API_KEY` + `BUDA_API_SECRET`)
|
|
5
5
|
**Transport:** stdio
|
|
6
6
|
**npm:** `@guiie/buda-mcp`
|
|
7
7
|
**Registry name:** `io.github.gtorreal/buda-mcp`
|
|
@@ -10,14 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
## Description
|
|
12
12
|
|
|
13
|
-
Real-time market data from [Buda.com](https://www.buda.com/), the leading cryptocurrency exchange operating in Chile, Colombia, and Peru. All data is sourced from Buda's public REST API v2 — no API key required.
|
|
13
|
+
Real-time market data from [Buda.com](https://www.buda.com/), the leading cryptocurrency exchange operating in Chile, Colombia, and Peru. All public data is sourced from Buda's public REST API v2 — no API key required.
|
|
14
14
|
|
|
15
|
-
Use this server to query live prices, order books, trade history, and volume for all BTC, ETH, and altcoin markets quoted in CLP, COP, and
|
|
15
|
+
Use this server to query live prices, spreads, order books, OHLCV candles, trade history, and volume for all BTC, ETH, and altcoin markets quoted in CLP, COP, PEN, and USDC. Optional API credentials unlock account tools for balances and order management.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
## Tools
|
|
20
20
|
|
|
21
|
+
### Public tools (no credentials required)
|
|
22
|
+
|
|
21
23
|
### `get_markets`
|
|
22
24
|
List all available trading pairs on Buda.com, or retrieve details for a specific market.
|
|
23
25
|
Returns: base/quote currencies, trading fees, minimum order amounts, fee discount tiers.
|
|
@@ -39,6 +41,46 @@ Recent trade history. Each entry: `[timestamp_ms, amount, price, direction]`.
|
|
|
39
41
|
24h and 7-day transacted volume broken down by buy (bid) and sell (ask) side.
|
|
40
42
|
**Parameters:** `market_id` *(required)*.
|
|
41
43
|
|
|
44
|
+
### `get_spread`
|
|
45
|
+
Bid/ask spread for a market: absolute spread and spread as a percentage of the ask price.
|
|
46
|
+
**Parameters:** `market_id` *(required)*.
|
|
47
|
+
|
|
48
|
+
### `compare_markets`
|
|
49
|
+
Side-by-side ticker data for all trading pairs of a given base currency across all supported quote currencies.
|
|
50
|
+
**Parameters:** `base_currency` *(required)* — e.g. `BTC`, `ETH`, `XRP`.
|
|
51
|
+
|
|
52
|
+
### `get_price_history`
|
|
53
|
+
OHLCV (open/high/low/close/volume) candles derived from recent trade history. Supports `1h`, `4h`, and `1d` periods.
|
|
54
|
+
**Parameters:** `market_id` *(required)*, `period` *(optional: `1h`/`4h`/`1d`, default `1h`)*, `limit` *(optional, max 100 trades)*.
|
|
55
|
+
|
|
56
|
+
### Authenticated tools (require `BUDA_API_KEY` + `BUDA_API_SECRET`)
|
|
57
|
+
|
|
58
|
+
> **Important:** Authenticated instances must run locally only — never expose a server with API credentials publicly.
|
|
59
|
+
|
|
60
|
+
### `get_balances`
|
|
61
|
+
All currency balances: total, available, frozen, and pending withdrawal amounts.
|
|
62
|
+
|
|
63
|
+
### `get_orders`
|
|
64
|
+
Orders for a given market, filterable by state (`pending`, `active`, `traded`, `canceled`).
|
|
65
|
+
**Parameters:** `market_id` *(required)*, `state` *(optional)*, `per` *(optional)*, `page` *(optional)*.
|
|
66
|
+
|
|
67
|
+
### `place_order`
|
|
68
|
+
Place a limit or market order. Requires `confirmation_token="CONFIRM"` to prevent accidental execution.
|
|
69
|
+
**Parameters:** `market_id`, `type` (Bid/Ask), `price_type` (limit/market), `amount`, `limit_price` *(for limit orders)*, `confirmation_token`.
|
|
70
|
+
|
|
71
|
+
### `cancel_order`
|
|
72
|
+
Cancel an open order by ID. Requires `confirmation_token="CONFIRM"`.
|
|
73
|
+
**Parameters:** `order_id`, `confirmation_token`.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## MCP Resources
|
|
78
|
+
|
|
79
|
+
| URI | Description |
|
|
80
|
+
|-----|-------------|
|
|
81
|
+
| `buda://markets` | JSON list of all Buda.com markets |
|
|
82
|
+
| `buda://ticker/{market}` | JSON ticker for a specific market |
|
|
83
|
+
|
|
42
84
|
---
|
|
43
85
|
|
|
44
86
|
## Example prompts
|
|
@@ -48,11 +90,20 @@ Recent trade history. Each entry: `[timestamp_ms, amount, price, direction]`.
|
|
|
48
90
|
- *"How much ETH was traded on Buda in the last 7 days?"*
|
|
49
91
|
- *"List all markets available on Buda.com."*
|
|
50
92
|
- *"What's the spread on BTC-COP right now?"*
|
|
93
|
+
- *"Compare the Bitcoin price across all Buda markets."*
|
|
94
|
+
- *"Show me hourly BTC-CLP candles."*
|
|
95
|
+
- *"What's my available BTC balance?"* *(authenticated)*
|
|
96
|
+
- *"Show my open orders on BTC-CLP."* *(authenticated)*
|
|
51
97
|
|
|
52
98
|
---
|
|
53
99
|
|
|
54
100
|
## Installation
|
|
55
101
|
|
|
102
|
+
**Quick start (npx)**
|
|
103
|
+
```bash
|
|
104
|
+
npx @guiie/buda-mcp
|
|
105
|
+
```
|
|
106
|
+
|
|
56
107
|
**Claude Code (claude CLI)**
|
|
57
108
|
```bash
|
|
58
109
|
claude mcp add buda-mcp -- npx -y @guiie/buda-mcp
|
|
@@ -70,11 +121,27 @@ claude mcp add buda-mcp -- npx -y @guiie/buda-mcp
|
|
|
70
121
|
}
|
|
71
122
|
```
|
|
72
123
|
|
|
124
|
+
**With authentication**
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"mcpServers": {
|
|
128
|
+
"buda-mcp": {
|
|
129
|
+
"command": "npx",
|
|
130
|
+
"args": ["-y", "@guiie/buda-mcp"],
|
|
131
|
+
"env": {
|
|
132
|
+
"BUDA_API_KEY": "your_api_key",
|
|
133
|
+
"BUDA_API_SECRET": "your_api_secret"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
73
140
|
**From source**
|
|
74
141
|
```bash
|
|
75
142
|
git clone https://github.com/gtorreal/buda-mcp.git
|
|
76
143
|
cd buda-mcp && npm install && npm run build
|
|
77
|
-
|
|
144
|
+
node dist/index.js
|
|
78
145
|
```
|
|
79
146
|
|
|
80
147
|
---
|
|
@@ -86,6 +153,7 @@ cd buda-mcp && npm install && npm run build
|
|
|
86
153
|
| CLP | Chile | BTC-CLP, ETH-CLP, XRP-CLP |
|
|
87
154
|
| COP | Colombia | BTC-COP, ETH-COP, XRP-COP |
|
|
88
155
|
| PEN | Peru | BTC-PEN, ETH-PEN |
|
|
156
|
+
| USDC | USD-pegged | BTC-USDC, ETH-USDC |
|
|
89
157
|
| BTC | Cross | ETH-BTC, XRP-BTC, BCH-BTC |
|
|
90
158
|
|
|
91
159
|
---
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"buda-mcp": {
|
|
4
4
|
"command": "npx",
|
|
5
5
|
"args": ["-y", "@guiie/buda-mcp"],
|
|
6
|
-
"description": "Buda.com cryptocurrency exchange — real-time market data for Chile, Colombia, and Peru"
|
|
6
|
+
"description": "Buda.com cryptocurrency exchange — real-time market data, spreads, OHLCV history, and account tools for Chile, Colombia, and Peru"
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "Gemini function declarations for buda-mcp. Pass this array as the `tools[0].functionDeclarations` field when calling the Gemini API. See: https://ai.google.dev/gemini-api/docs/function-calling",
|
|
2
|
+
"_comment": "Gemini function declarations for buda-mcp v1.1.0. Pass this array as the `tools[0].functionDeclarations` field when calling the Gemini API. See: https://ai.google.dev/gemini-api/docs/function-calling",
|
|
3
3
|
"functionDeclarations": [
|
|
4
4
|
{
|
|
5
5
|
"name": "get_markets",
|
|
@@ -82,6 +82,56 @@
|
|
|
82
82
|
},
|
|
83
83
|
"required": ["market_id"]
|
|
84
84
|
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "get_spread",
|
|
88
|
+
"description": "Calculate the bid/ask spread for a Buda.com market. Returns the best bid price, best ask price, absolute spread, and spread as a percentage of the ask price. Useful for assessing market liquidity.",
|
|
89
|
+
"parameters": {
|
|
90
|
+
"type": "OBJECT",
|
|
91
|
+
"properties": {
|
|
92
|
+
"market_id": {
|
|
93
|
+
"type": "STRING",
|
|
94
|
+
"description": "Market identifier such as 'BTC-CLP', 'ETH-COP', or 'ETH-BTC'. Case-insensitive."
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"required": ["market_id"]
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "compare_markets",
|
|
102
|
+
"description": "Compare ticker data side-by-side for all trading pairs of a given base currency across Buda.com's supported quote currencies (CLP, COP, PEN, USDC, BTC, ETH). For example, 'BTC' returns data for BTC-CLP, BTC-COP, BTC-PEN, and BTC-USDC.",
|
|
103
|
+
"parameters": {
|
|
104
|
+
"type": "OBJECT",
|
|
105
|
+
"properties": {
|
|
106
|
+
"base_currency": {
|
|
107
|
+
"type": "STRING",
|
|
108
|
+
"description": "Base currency to compare across all available markets. Examples: 'BTC', 'ETH', 'XRP'. Case-insensitive."
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"required": ["base_currency"]
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "get_price_history",
|
|
116
|
+
"description": "Get OHLCV (open/high/low/close/volume) price history for a Buda.com market, derived from recent trade history. Candles are aggregated client-side from up to 100 raw trades. Supports 1h, 4h, and 1d candle periods.",
|
|
117
|
+
"parameters": {
|
|
118
|
+
"type": "OBJECT",
|
|
119
|
+
"properties": {
|
|
120
|
+
"market_id": {
|
|
121
|
+
"type": "STRING",
|
|
122
|
+
"description": "Market identifier such as 'BTC-CLP' or 'ETH-BTC'. Case-insensitive."
|
|
123
|
+
},
|
|
124
|
+
"period": {
|
|
125
|
+
"type": "STRING",
|
|
126
|
+
"description": "Candle period: '1h' (1 hour), '4h' (4 hours), or '1d' (1 day). Default is '1h'."
|
|
127
|
+
},
|
|
128
|
+
"limit": {
|
|
129
|
+
"type": "INTEGER",
|
|
130
|
+
"description": "Number of raw trades to fetch before aggregation. Default is 100, maximum is 100."
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"required": ["market_id"]
|
|
134
|
+
}
|
|
85
135
|
}
|
|
86
136
|
]
|
|
87
137
|
}
|
package/marketplace/openapi.yaml
CHANGED
|
@@ -4,14 +4,14 @@ info:
|
|
|
4
4
|
description: |
|
|
5
5
|
Real-time cryptocurrency market data from Buda.com — the leading exchange
|
|
6
6
|
in Chile (CLP), Colombia (COP), and Peru (PEN).
|
|
7
|
-
Provides live prices, order books, trade history, and volume for all markets.
|
|
8
|
-
No authentication required.
|
|
7
|
+
Provides live prices, spreads, OHLCV history, order books, trade history, and volume for all markets.
|
|
8
|
+
No authentication required for public tools.
|
|
9
9
|
|
|
10
10
|
**Note:** This spec describes a deployed HTTP wrapper around the buda-mcp
|
|
11
11
|
stdio server. Deploy locally with mcp-proxy:
|
|
12
12
|
mcp-proxy --port 8000 -- npx -y @guiie/buda-mcp
|
|
13
13
|
Or point `servers[0].url` at your hosted instance.
|
|
14
|
-
version: 1.
|
|
14
|
+
version: 1.1.0
|
|
15
15
|
contact:
|
|
16
16
|
url: https://github.com/gtorreal/buda-mcp
|
|
17
17
|
|
|
@@ -175,6 +175,99 @@ paths:
|
|
|
175
175
|
"404":
|
|
176
176
|
$ref: "#/components/responses/NotFound"
|
|
177
177
|
|
|
178
|
+
/get_spread:
|
|
179
|
+
get:
|
|
180
|
+
operationId: getSpread
|
|
181
|
+
summary: Bid/ask spread for a market
|
|
182
|
+
description: |
|
|
183
|
+
Returns the best bid price, best ask price, absolute spread, and spread as a percentage
|
|
184
|
+
of the ask price. Useful for assessing market liquidity.
|
|
185
|
+
parameters:
|
|
186
|
+
- name: market_id
|
|
187
|
+
in: query
|
|
188
|
+
required: true
|
|
189
|
+
description: Market identifier (e.g. "BTC-CLP"). Case-insensitive.
|
|
190
|
+
schema:
|
|
191
|
+
type: string
|
|
192
|
+
example: BTC-CLP
|
|
193
|
+
responses:
|
|
194
|
+
"200":
|
|
195
|
+
description: Spread data
|
|
196
|
+
content:
|
|
197
|
+
application/json:
|
|
198
|
+
schema:
|
|
199
|
+
$ref: "#/components/schemas/SpreadResponse"
|
|
200
|
+
"404":
|
|
201
|
+
$ref: "#/components/responses/NotFound"
|
|
202
|
+
|
|
203
|
+
/compare_markets:
|
|
204
|
+
get:
|
|
205
|
+
operationId: compareMarkets
|
|
206
|
+
summary: Compare all pairs of a base currency side by side
|
|
207
|
+
description: |
|
|
208
|
+
Returns ticker data for all trading pairs of a given base currency across all supported
|
|
209
|
+
quote currencies (CLP, COP, PEN, USDC, BTC, ETH). For example, base_currency=BTC returns
|
|
210
|
+
data for BTC-CLP, BTC-COP, BTC-PEN, and BTC-USDC.
|
|
211
|
+
parameters:
|
|
212
|
+
- name: base_currency
|
|
213
|
+
in: query
|
|
214
|
+
required: true
|
|
215
|
+
description: Base currency to compare (e.g. "BTC", "ETH"). Case-insensitive.
|
|
216
|
+
schema:
|
|
217
|
+
type: string
|
|
218
|
+
example: BTC
|
|
219
|
+
responses:
|
|
220
|
+
"200":
|
|
221
|
+
description: Comparison of all pairs for the given base currency
|
|
222
|
+
content:
|
|
223
|
+
application/json:
|
|
224
|
+
schema:
|
|
225
|
+
$ref: "#/components/schemas/CompareMarketsResponse"
|
|
226
|
+
"404":
|
|
227
|
+
$ref: "#/components/responses/NotFound"
|
|
228
|
+
|
|
229
|
+
/get_price_history:
|
|
230
|
+
get:
|
|
231
|
+
operationId: getPriceHistory
|
|
232
|
+
summary: OHLCV price history derived from trade history
|
|
233
|
+
description: |
|
|
234
|
+
Returns OHLCV (open/high/low/close/volume) candles derived from recent trade history.
|
|
235
|
+
Buda.com has no native candlestick endpoint; candles are aggregated client-side from
|
|
236
|
+
up to 100 raw trades. Supports 1h, 4h, and 1d candle periods.
|
|
237
|
+
parameters:
|
|
238
|
+
- name: market_id
|
|
239
|
+
in: query
|
|
240
|
+
required: true
|
|
241
|
+
description: Market identifier (e.g. "BTC-CLP"). Case-insensitive.
|
|
242
|
+
schema:
|
|
243
|
+
type: string
|
|
244
|
+
example: BTC-CLP
|
|
245
|
+
- name: period
|
|
246
|
+
in: query
|
|
247
|
+
required: false
|
|
248
|
+
description: Candle period. One of "1h", "4h", "1d". Default is "1h".
|
|
249
|
+
schema:
|
|
250
|
+
type: string
|
|
251
|
+
enum: ["1h", "4h", "1d"]
|
|
252
|
+
default: "1h"
|
|
253
|
+
- name: limit
|
|
254
|
+
in: query
|
|
255
|
+
required: false
|
|
256
|
+
description: Number of raw trades to fetch before aggregation (default 100, max 100).
|
|
257
|
+
schema:
|
|
258
|
+
type: integer
|
|
259
|
+
minimum: 1
|
|
260
|
+
maximum: 100
|
|
261
|
+
responses:
|
|
262
|
+
"200":
|
|
263
|
+
description: OHLCV candles
|
|
264
|
+
content:
|
|
265
|
+
application/json:
|
|
266
|
+
schema:
|
|
267
|
+
$ref: "#/components/schemas/PriceHistoryResponse"
|
|
268
|
+
"404":
|
|
269
|
+
$ref: "#/components/responses/NotFound"
|
|
270
|
+
|
|
178
271
|
components:
|
|
179
272
|
schemas:
|
|
180
273
|
Amount:
|
|
@@ -334,11 +427,118 @@ components:
|
|
|
334
427
|
bid_volume_7d:
|
|
335
428
|
$ref: "#/components/schemas/Amount"
|
|
336
429
|
|
|
430
|
+
SpreadResponse:
|
|
431
|
+
type: object
|
|
432
|
+
properties:
|
|
433
|
+
market_id:
|
|
434
|
+
type: string
|
|
435
|
+
example: BTC-CLP
|
|
436
|
+
currency:
|
|
437
|
+
type: string
|
|
438
|
+
example: CLP
|
|
439
|
+
best_bid:
|
|
440
|
+
type: string
|
|
441
|
+
example: "65221128.0"
|
|
442
|
+
best_ask:
|
|
443
|
+
type: string
|
|
444
|
+
example: "65727568.0"
|
|
445
|
+
spread_absolute:
|
|
446
|
+
type: string
|
|
447
|
+
example: "506440.00"
|
|
448
|
+
spread_percentage:
|
|
449
|
+
type: string
|
|
450
|
+
example: "0.7705%"
|
|
451
|
+
last_price:
|
|
452
|
+
type: string
|
|
453
|
+
example: "65221078.43"
|
|
454
|
+
|
|
455
|
+
CompareMarketsResponse:
|
|
456
|
+
type: object
|
|
457
|
+
properties:
|
|
458
|
+
base_currency:
|
|
459
|
+
type: string
|
|
460
|
+
example: BTC
|
|
461
|
+
markets:
|
|
462
|
+
type: array
|
|
463
|
+
items:
|
|
464
|
+
type: object
|
|
465
|
+
properties:
|
|
466
|
+
market_id:
|
|
467
|
+
type: string
|
|
468
|
+
example: BTC-CLP
|
|
469
|
+
last_price:
|
|
470
|
+
type: string
|
|
471
|
+
example: "65221078.43"
|
|
472
|
+
currency:
|
|
473
|
+
type: string
|
|
474
|
+
example: CLP
|
|
475
|
+
best_bid:
|
|
476
|
+
type: string
|
|
477
|
+
best_ask:
|
|
478
|
+
type: string
|
|
479
|
+
volume_24h:
|
|
480
|
+
type: string
|
|
481
|
+
price_change_24h:
|
|
482
|
+
type: string
|
|
483
|
+
example: "0.30%"
|
|
484
|
+
price_change_7d:
|
|
485
|
+
type: string
|
|
486
|
+
example: "-1.20%"
|
|
487
|
+
|
|
488
|
+
OhlcvCandle:
|
|
489
|
+
type: object
|
|
490
|
+
properties:
|
|
491
|
+
time:
|
|
492
|
+
type: string
|
|
493
|
+
format: date-time
|
|
494
|
+
example: "2026-04-10T12:00:00.000Z"
|
|
495
|
+
open:
|
|
496
|
+
type: string
|
|
497
|
+
example: "65221078.43"
|
|
498
|
+
high:
|
|
499
|
+
type: string
|
|
500
|
+
example: "65975364.0"
|
|
501
|
+
low:
|
|
502
|
+
type: string
|
|
503
|
+
example: "65164404.87"
|
|
504
|
+
close:
|
|
505
|
+
type: string
|
|
506
|
+
example: "65386647.0"
|
|
507
|
+
volume:
|
|
508
|
+
type: string
|
|
509
|
+
example: "0.52341200"
|
|
510
|
+
trade_count:
|
|
511
|
+
type: integer
|
|
512
|
+
example: 12
|
|
513
|
+
|
|
514
|
+
PriceHistoryResponse:
|
|
515
|
+
type: object
|
|
516
|
+
properties:
|
|
517
|
+
market_id:
|
|
518
|
+
type: string
|
|
519
|
+
example: BTC-CLP
|
|
520
|
+
period:
|
|
521
|
+
type: string
|
|
522
|
+
example: "1h"
|
|
523
|
+
candle_count:
|
|
524
|
+
type: integer
|
|
525
|
+
example: 6
|
|
526
|
+
note:
|
|
527
|
+
type: string
|
|
528
|
+
candles:
|
|
529
|
+
type: array
|
|
530
|
+
items:
|
|
531
|
+
$ref: "#/components/schemas/OhlcvCandle"
|
|
532
|
+
|
|
337
533
|
Error:
|
|
338
534
|
type: object
|
|
339
535
|
properties:
|
|
340
536
|
error:
|
|
341
537
|
type: string
|
|
538
|
+
code:
|
|
539
|
+
oneOf:
|
|
540
|
+
- type: string
|
|
541
|
+
- type: integer
|
|
342
542
|
|
|
343
543
|
responses:
|
|
344
544
|
NotFound:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guiie/buda-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"mcpName": "io.github.gtorreal/buda-mcp",
|
|
5
5
|
"description": "MCP server for Buda.com's public cryptocurrency exchange API (Chile, Colombia, Peru)",
|
|
6
6
|
"type": "module",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc",
|
|
13
|
-
"start": "node dist/
|
|
13
|
+
"start": "node dist/http.js",
|
|
14
|
+
"start:stdio": "node dist/index.js",
|
|
15
|
+
"dev:http": "tsx src/http.ts",
|
|
14
16
|
"dev": "tsx src/index.ts",
|
|
15
17
|
"test": "tsx test/run-all.ts"
|
|
16
18
|
},
|
|
@@ -43,9 +45,11 @@
|
|
|
43
45
|
"author": "Guille <guillermo@buda.com>",
|
|
44
46
|
"dependencies": {
|
|
45
47
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
+
"express": "^5.2.1",
|
|
46
49
|
"zod": "^4.3.6"
|
|
47
50
|
},
|
|
48
51
|
"devDependencies": {
|
|
52
|
+
"@types/express": "^5.0.6",
|
|
49
53
|
"@types/node": "^25.6.0",
|
|
50
54
|
"tsx": "^4.21.0",
|
|
51
55
|
"typescript": "^6.0.2"
|
package/railway.json
ADDED
package/server.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.gtorreal/buda-mcp",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Buda.com market data: prices, spreads, OHLCV, order books, trades, and volume for CLP, COP, PEN.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/gtorreal/buda-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.1.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@guiie/buda-mcp",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.1.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|
package/src/cache.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface CacheEntry<T> {
|
|
2
|
+
data: T;
|
|
3
|
+
expiry: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export class MemoryCache {
|
|
7
|
+
private store = new Map<string, CacheEntry<unknown>>();
|
|
8
|
+
|
|
9
|
+
async getOrFetch<T>(key: string, ttlMs: number, fetcher: () => Promise<T>): Promise<T> {
|
|
10
|
+
const entry = this.store.get(key) as CacheEntry<T> | undefined;
|
|
11
|
+
if (entry && Date.now() < entry.expiry) {
|
|
12
|
+
return entry.data;
|
|
13
|
+
}
|
|
14
|
+
const data = await fetcher();
|
|
15
|
+
this.store.set(key, { data, expiry: Date.now() + ttlMs });
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
invalidate(key: string): void {
|
|
20
|
+
this.store.delete(key);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
clear(): void {
|
|
24
|
+
this.store.clear();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const CACHE_TTL = {
|
|
29
|
+
MARKETS: 60_000,
|
|
30
|
+
TICKER: 5_000,
|
|
31
|
+
ORDERBOOK: 3_000,
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
export const cache = new MemoryCache();
|
package/src/client.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createHmac } from "crypto";
|
|
2
|
+
|
|
1
3
|
const BASE_URL = "https://www.buda.com/api/v2";
|
|
2
4
|
|
|
3
5
|
export class BudaApiError extends Error {
|
|
@@ -13,18 +15,47 @@ export class BudaApiError extends Error {
|
|
|
13
15
|
|
|
14
16
|
export class BudaClient {
|
|
15
17
|
private readonly baseUrl: string;
|
|
18
|
+
private readonly apiKey: string | undefined;
|
|
19
|
+
private readonly apiSecret: string | undefined;
|
|
16
20
|
|
|
17
|
-
constructor(
|
|
21
|
+
constructor(
|
|
22
|
+
baseUrl: string = BASE_URL,
|
|
23
|
+
apiKey?: string,
|
|
24
|
+
apiSecret?: string,
|
|
25
|
+
) {
|
|
18
26
|
this.baseUrl = baseUrl;
|
|
27
|
+
this.apiKey = apiKey;
|
|
28
|
+
this.apiSecret = apiSecret;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
hasAuth(): boolean {
|
|
32
|
+
return Boolean(this.apiKey && this.apiSecret);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private nonce(): string {
|
|
36
|
+
return String(Math.floor(Date.now() * 1000));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private sign(method: string, pathWithQuery: string, body: string, nonce: string): string {
|
|
40
|
+
const encodedBody = body ? Buffer.from(body).toString("base64") : "";
|
|
41
|
+
const parts = [method, pathWithQuery];
|
|
42
|
+
if (encodedBody) parts.push(encodedBody);
|
|
43
|
+
parts.push(nonce);
|
|
44
|
+
const msg = parts.join(" ");
|
|
45
|
+
return createHmac("sha384", this.apiSecret!).update(msg).digest("hex");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private authHeaders(method: string, path: string, body?: string): Record<string, string> {
|
|
49
|
+
if (!this.hasAuth()) return {};
|
|
50
|
+
const nonce = this.nonce();
|
|
51
|
+
const signature = this.sign(method, path, body ?? "", nonce);
|
|
52
|
+
return {
|
|
53
|
+
"X-SBTC-APIKEY": this.apiKey!,
|
|
54
|
+
"X-SBTC-NONCE": nonce,
|
|
55
|
+
"X-SBTC-SIGNATURE": signature,
|
|
56
|
+
};
|
|
19
57
|
}
|
|
20
58
|
|
|
21
|
-
/**
|
|
22
|
-
* Perform an authenticated GET request.
|
|
23
|
-
*
|
|
24
|
-
* Private endpoints (balances, orders, etc.) require HMAC-SHA2 signing.
|
|
25
|
-
* To add auth later, extend this method with the `apiKey` + `apiSecret`
|
|
26
|
-
* constructor params and sign the nonce/path headers here before fetching.
|
|
27
|
-
*/
|
|
28
59
|
async get<T>(path: string, params?: Record<string, string | number>): Promise<T> {
|
|
29
60
|
const url = new URL(`${this.baseUrl}${path}.json`);
|
|
30
61
|
|
|
@@ -34,11 +65,75 @@ export class BudaClient {
|
|
|
34
65
|
}
|
|
35
66
|
}
|
|
36
67
|
|
|
68
|
+
const urlPath = url.pathname + url.search;
|
|
69
|
+
const headers: Record<string, string> = {
|
|
70
|
+
Accept: "application/json",
|
|
71
|
+
"User-Agent": "buda-mcp/1.1.0",
|
|
72
|
+
...this.authHeaders("GET", urlPath),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const response = await fetch(url.toString(), { headers });
|
|
76
|
+
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
let detail = response.statusText;
|
|
79
|
+
try {
|
|
80
|
+
const body = (await response.json()) as { message?: string };
|
|
81
|
+
if (body.message) detail = body.message;
|
|
82
|
+
} catch {
|
|
83
|
+
// ignore parse error, use statusText
|
|
84
|
+
}
|
|
85
|
+
throw new BudaApiError(response.status, path, `Buda API ${response.status}: ${detail}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return response.json() as Promise<T>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async post<T>(path: string, payload: unknown): Promise<T> {
|
|
92
|
+
const url = new URL(`${this.baseUrl}${path}.json`);
|
|
93
|
+
const bodyStr = JSON.stringify(payload);
|
|
94
|
+
const urlPath = url.pathname + url.search;
|
|
95
|
+
const headers: Record<string, string> = {
|
|
96
|
+
Accept: "application/json",
|
|
97
|
+
"Content-Type": "application/json",
|
|
98
|
+
"User-Agent": "buda-mcp/1.1.0",
|
|
99
|
+
...this.authHeaders("POST", urlPath, bodyStr),
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const response = await fetch(url.toString(), {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers,
|
|
105
|
+
body: bodyStr,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
let detail = response.statusText;
|
|
110
|
+
try {
|
|
111
|
+
const body = (await response.json()) as { message?: string };
|
|
112
|
+
if (body.message) detail = body.message;
|
|
113
|
+
} catch {
|
|
114
|
+
// ignore parse error, use statusText
|
|
115
|
+
}
|
|
116
|
+
throw new BudaApiError(response.status, path, `Buda API ${response.status}: ${detail}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return response.json() as Promise<T>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async put<T>(path: string, payload: unknown): Promise<T> {
|
|
123
|
+
const url = new URL(`${this.baseUrl}${path}.json`);
|
|
124
|
+
const bodyStr = JSON.stringify(payload);
|
|
125
|
+
const urlPath = url.pathname + url.search;
|
|
126
|
+
const headers: Record<string, string> = {
|
|
127
|
+
Accept: "application/json",
|
|
128
|
+
"Content-Type": "application/json",
|
|
129
|
+
"User-Agent": "buda-mcp/1.1.0",
|
|
130
|
+
...this.authHeaders("PUT", urlPath, bodyStr),
|
|
131
|
+
};
|
|
132
|
+
|
|
37
133
|
const response = await fetch(url.toString(), {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
134
|
+
method: "PUT",
|
|
135
|
+
headers,
|
|
136
|
+
body: bodyStr,
|
|
42
137
|
});
|
|
43
138
|
|
|
44
139
|
if (!response.ok) {
|