@guiie/buda-mcp 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/PUBLISH_CHECKLIST.md +69 -70
  3. package/README.md +4 -4
  4. package/dist/http.js +17 -0
  5. package/dist/index.js +10 -0
  6. package/dist/tools/calculate_position_size.d.ts +48 -0
  7. package/dist/tools/calculate_position_size.d.ts.map +1 -0
  8. package/dist/tools/calculate_position_size.js +111 -0
  9. package/dist/tools/dead_mans_switch.d.ts +84 -0
  10. package/dist/tools/dead_mans_switch.d.ts.map +1 -0
  11. package/dist/tools/dead_mans_switch.js +236 -0
  12. package/dist/tools/market_sentiment.d.ts +30 -0
  13. package/dist/tools/market_sentiment.d.ts.map +1 -0
  14. package/dist/tools/market_sentiment.js +104 -0
  15. package/dist/tools/price_history.d.ts.map +1 -1
  16. package/dist/tools/price_history.js +2 -40
  17. package/dist/tools/simulate_order.d.ts +45 -0
  18. package/dist/tools/simulate_order.d.ts.map +1 -0
  19. package/dist/tools/simulate_order.js +139 -0
  20. package/dist/tools/technical_indicators.d.ts +39 -0
  21. package/dist/tools/technical_indicators.d.ts.map +1 -0
  22. package/dist/tools/technical_indicators.js +223 -0
  23. package/dist/types.d.ts +9 -0
  24. package/dist/types.d.ts.map +1 -1
  25. package/dist/utils.d.ts +7 -1
  26. package/dist/utils.d.ts.map +1 -1
  27. package/dist/utils.js +47 -0
  28. package/marketplace/README.md +1 -1
  29. package/marketplace/claude-listing.md +35 -1
  30. package/marketplace/gemini-tools.json +230 -1
  31. package/marketplace/openapi.yaml +1 -1
  32. package/package.json +1 -1
  33. package/server.json +2 -2
  34. package/src/http.ts +17 -0
  35. package/src/index.ts +10 -0
  36. package/src/tools/calculate_position_size.ts +141 -0
  37. package/src/tools/dead_mans_switch.ts +314 -0
  38. package/src/tools/market_sentiment.ts +141 -0
  39. package/src/tools/price_history.ts +2 -54
  40. package/src/tools/simulate_order.ts +182 -0
  41. package/src/tools/technical_indicators.ts +282 -0
  42. package/src/types.ts +12 -0
  43. package/src/utils.ts +53 -1
  44. package/test/run-all.ts +197 -0
  45. package/test/unit.ts +505 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,47 @@ This project uses [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.4.1] – 2026-04-11
11
+
12
+ ### Fixed
13
+
14
+ - **`simulate_order`**: `taker_fee` returned by Buda API is already expressed as a percentage (`0.8` = 0.8%), not a decimal. Dividing by 100 before use gives correct fee calculations. Previously this caused fee_amount and total_cost to be ~100× too large.
15
+ - Integration test (`test/run-all.ts`): added live checks for all 5 v1.4.0 tools; fixed field name `candles_available` (was `candles_used`).
16
+ - Unit test mocks: updated `taker_fee` mock values from `"0.008"`/`"0.005"` to `"0.8"`/`"0.5"` to match the real Buda API format.
17
+
18
+ ---
19
+
20
+ ## [1.4.0] – 2026-04-11
21
+
22
+ ### Added
23
+
24
+ - **`simulate_order`** (`src/tools/simulate_order.ts`) — public tool that simulates a buy or sell order using live ticker and market data without placing a real order. Inputs: `market_id`, `side` (`buy`|`sell`), `amount`, optional `price` (omit for market order). Fetches ticker (cached) + market info (cached) in parallel to determine fill price, fee rate, and slippage. Uses the actual `taker_fee` from the market (0.8% crypto / 0.5% stablecoin). All responses include `simulation: true`. Exports `handleSimulateOrder` for unit testing.
25
+
26
+ - **`calculate_position_size`** (`src/tools/calculate_position_size.ts`) — public tool for Kelly-style position sizing from capital, risk %, entry price, and stop-loss. Fully client-side — no API calls. Infers `side` (`buy`/`sell`) from the stop vs entry relationship. Validates that stop ≠ entry. Returns `units`, `capital_at_risk`, `position_value`, `fee_impact` (0.8% conservative taker), and a plain-text `risk_reward_note`. Exports `handleCalculatePositionSize` for unit testing.
27
+
28
+ - **`get_market_sentiment`** (`src/tools/market_sentiment.ts`) — public tool computing a composite sentiment score (−100 to +100) from three weighted components: price variation 24h (40%), volume vs 7-day daily average (35%), bid/ask spread vs market-type baseline (25%). Spread baseline: 1.0% for crypto pairs, 0.3% for stablecoin pairs (USDT/USDC/DAI/TUSD). Returns `score`, `label` (`bearish`/`neutral`/`bullish`), `component_breakdown`, `data_timestamp`, and a `disclaimer`. Exports `handleMarketSentiment` for unit testing.
29
+
30
+ - **`get_technical_indicators`** (`src/tools/technical_indicators.ts`) — public tool computing RSI (14), MACD (12/26/9), Bollinger Bands (20, 2σ), SMA 20, and SMA 50 from Buda trade history. No external math libraries — all algorithms implemented inline. Uses at least 500 trades (minimum enforced). Returns signal interpretations: RSI overbought/oversold/neutral, MACD bullish/bearish crossover/neutral, BB above/below/within bands. Returns a structured `{ indicators: null, warning: "insufficient_data" }` object when fewer than 50 candles are available. Includes `disclaimer` field. Exports `handleTechnicalIndicators` for unit testing.
31
+
32
+ - **`schedule_cancel_all` + `renew_cancel_timer` + `disarm_cancel_timer`** (`src/tools/dead_mans_switch.ts`) — three auth-gated tools implementing an in-memory dead man's switch. `schedule_cancel_all` requires `confirmation_token="CONFIRM"`, `ttl_seconds` (10–300), and a `market_id`; arms a `setTimeout` that fetches all pending orders and cancels each one if not renewed. `renew_cancel_timer` resets the countdown for a market (no confirmation). `disarm_cancel_timer` clears the timer without cancelling orders (no confirmation). **WARNING: timer state is lost on server restart — not suitable for hosted deployments (e.g. Railway). Use only on locally-run instances.** Timer state is module-level and persists across HTTP requests within a process. Exports `handleScheduleCancelAll`, `handleRenewCancelTimer`, `handleDisarmCancelTimer` for unit testing.
33
+
34
+ - **`src/utils.ts` — `aggregateTradesToCandles(entries, period)`** — shared utility extracted from `get_price_history` logic. Takes raw Buda trade entries and a period string (`1h`/`4h`/`1d`), returns sorted `OhlcvCandle[]`. Used by both `get_price_history` and `get_technical_indicators`.
35
+
36
+ - **`src/types.ts` — `OhlcvCandle` interface** — exported for use across tools.
37
+
38
+ - **Unit tests (24 new, 59 total)** in `test/unit.ts`:
39
+ - **i. `simulate_order`** (5 tests): market buy fills at min_ask; market sell fills at max_bid; limit order_type_assumed; stablecoin 0.5% fee; invalid market_id.
40
+ - **j. `calculate_position_size`** (4 tests): buy scenario; sell scenario; stop == entry error; invalid market_id.
41
+ - **k. `get_market_sentiment`** (5 tests): disclaimer present; neutral label; bullish on strong positive variation; bearish on strong negative variation; invalid market_id.
42
+ - **l. `get_technical_indicators`** (4 tests): `aggregateTradesToCandles` OHLCV correctness; insufficient candles warning; sufficient candles with correct RSI signal; invalid market_id.
43
+ - **m. `schedule_cancel_all`** (6 tests): CONFIRM guard; invalid market_id; CONFIRM activates + expires_at; renew with no timer; disarm with no timer (no-op); disarm after arm clears timer.
44
+
45
+ ### Changed
46
+
47
+ - **`src/tools/price_history.ts`** — refactored to use the new shared `aggregateTradesToCandles()` from `utils.ts`. Behaviour is identical.
48
+
49
+ ---
50
+
10
51
  ## [1.3.0] – 2026-04-11
11
52
 
12
53
  ### Added
@@ -1,6 +1,8 @@
1
- # Publish Checklist — buda-mcp v1.3.0
1
+ # Publish Checklist — buda-mcp v1.4.0
2
2
 
3
- Steps to publish `v1.3.0` to npm, the MCP registry, and notify community directories.
3
+ Steps to publish `v1.4.0` to npm, the MCP registry, and notify community directories.
4
+
5
+ > **Important for v1.4.0:** The new `schedule_cancel_all` tool uses in-memory timer state that is lost on server restart. This is prominently documented in the tool description, README auth section, and CHANGELOG. Do NOT encourage users to rely on this tool in hosted/Railway deployments.
4
6
 
5
7
  ---
6
8
 
@@ -8,7 +10,7 @@ Steps to publish `v1.3.0` to npm, the MCP registry, and notify community directo
8
10
 
9
11
  ```bash
10
12
  # Confirm version
11
- node -e "console.log(require('./package.json').version)" # should print 1.3.0
13
+ node -e "console.log(require('./package.json').version)" # should print 1.4.0
12
14
 
13
15
  # Build and test
14
16
  npm run build
@@ -39,56 +41,51 @@ Verify: https://www.npmjs.com/package/@guiie/buda-mcp
39
41
 
40
42
  ```bash
41
43
  git add -A
42
- git commit -m "chore: release v1.3.0
43
-
44
- - Flatten all response schemas: all monetary amounts now floats with _currency fields
45
- - get_arbitrage_opportunities: cross-country price discrepancy detection (USDC-normalized)
46
- - get_market_summary: one-call market overview with liquidity_rating
47
- - buda://summary/{market} MCP Resource
48
- - Rewritten tool descriptions with concrete examples and units
49
- - 35 unit tests (12 new: flattenAmount, arbitrage discrepancy, liquidity_rating thresholds)
50
- - src/utils.ts: shared flattenAmount() and getLiquidityRating() helpers"
51
-
52
- git tag v1.3.0
44
+ git commit -m "chore: release v1.4.0
45
+
46
+ - simulate_order: live order cost simulation (no order placed, simulation: true)
47
+ - calculate_position_size: Kelly-style sizing from capital/risk/entry/stop (client-side)
48
+ - get_market_sentiment: composite score -100..+100 from price/volume/spread
49
+ - get_technical_indicators: RSI/MACD/BB/SMA20/SMA50 from trade history (no libs)
50
+ - schedule_cancel_all + renew_cancel_timer + disarm_cancel_timer: in-memory dead man's switch (auth-gated)
51
+ - aggregateTradesToCandles() extracted to utils.ts (shared by price_history + technical_indicators)
52
+ - OhlcvCandle interface moved to types.ts
53
+ - 59 unit tests (24 new)"
54
+
55
+ git tag v1.4.0
53
56
  git push origin main --tags
54
57
  ```
55
58
 
56
- Then create a GitHub Release from the tag with the following release notes:
59
+ Then create a GitHub Release from the tag:
57
60
 
58
61
  ---
59
62
 
60
63
  **Release notes template (GitHub):**
61
64
 
62
65
  ```
63
- ## buda-mcp v1.3.0 — Output Quality
66
+ ## buda-mcp v1.4.0 — Trading Tools
64
67
 
65
- ### What's new
68
+ ### 5 new tools
66
69
 
67
- **Flat, typed response schemas (breaking change for field consumers)**
68
- All tools now return floats instead of `["amount", "currency"]` arrays.
69
- Every monetary Amount is split into a `value` (float) and `_currency` (string) field.
70
- For example, `last_price: ["65000000", "CLP"]` → `last_price: 65000000, last_price_currency: "CLP"`.
71
- Affected tools: get_ticker, get_market_volume, get_orderbook, get_trades, get_spread,
72
- compare_markets, get_price_history, get_balances, get_orders.
70
+ **`simulate_order`** (public)
71
+ Simulates a buy or sell order using live ticker data — no order placed. Returns estimated fill price, fee (actual taker rate from market data: 0.8% crypto / 0.5% stablecoin), total cost, and slippage vs mid. All outputs include simulation: true.
73
72
 
74
- **New tool: `get_market_summary`**
75
- One-call summary: last price, bid/ask, spread %, 24h volume, price change 24h/7d, and
76
- `liquidity_rating` ("high" < 0.3%, "medium" 0.3–1%, "low" > 1%). Best first tool to call.
73
+ **`calculate_position_size`** (public)
74
+ Kelly-style position sizing from capital, risk %, entry, and stop-loss. Fully client-side. Returns units, capital_at_risk, position_value, fee_impact, and a plain-text risk note.
77
75
 
78
- **New tool: `get_arbitrage_opportunities`**
79
- Detects cross-country price discrepancies for an asset across CLP/COP/PEN markets,
80
- normalized to USDC. Includes pairwise discrepancy %, sorted by size.
81
- Fees note: 0.8% taker fee per leg (~1.6% round-trip) included in every response.
76
+ **`get_market_sentiment`** (public)
77
+ Composite sentiment score (−100 to +100) from price variation 24h (40%), volume vs 7d average (35%), and spread vs market-type baseline (25%). Returns score, label, component breakdown, and disclaimer.
82
78
 
83
- **New MCP Resource: `buda://summary/{market}`**
84
- Same data as get_market_summary, served as an MCP Resource in both stdio and HTTP transports.
79
+ **`get_technical_indicators`** (public)
80
+ RSI (14), MACD (12/26/9), Bollinger Bands (20, 2σ), SMA 20, SMA 50 — computed server-side from Buda trade history with no external libraries. Returns signal interpretations and structured warning if insufficient candles.
85
81
 
86
- **Improved tool descriptions**
87
- All 12 tool descriptions rewritten: specific return types, units, and concrete example questions.
82
+ **`schedule_cancel_all` + `renew_cancel_timer` + `disarm_cancel_timer`** (auth-gated)
83
+ In-memory dead man's switch: arms a timer that cancels all open orders if not renewed. WARNING: timer state is lost on server restart. Use only on locally-run instances.
88
84
 
89
- **Test suite: 35 unit tests (was 23)**
90
- New sections: flattenAmount type correctness, arbitrage discrepancy calculation with mock data,
91
- liquidity_rating boundary tests.
85
+ ### Infrastructure
86
+ - `aggregateTradesToCandles()` extracted to `utils.ts` shared by `get_price_history` and `get_technical_indicators`
87
+ - `OhlcvCandle` interface exported from `types.ts`
88
+ - 59 unit tests (was 35)
92
89
 
93
90
  ```bash
94
91
  npx @guiie/buda-mcp
@@ -103,12 +100,6 @@ The GitHub Actions workflow (`.github/workflows/publish.yml`) runs automatically
103
100
 
104
101
  https://registry.modelcontextprotocol.io/servers/io.github.gtorreal/buda-mcp
105
102
 
106
- If the workflow doesn't trigger, run manually:
107
-
108
- ```bash
109
- MCP_REGISTRY_TOKEN=<token> ./mcp-publisher publish
110
- ```
111
-
112
103
  ---
113
104
 
114
105
  ## 5. Smithery
@@ -124,19 +115,19 @@ Verify: https://smithery.ai/server/@guiie/buda-mcp
124
115
  **Email/message template:**
125
116
 
126
117
  ```
127
- Subject: [Update] buda-mcp v1.3.0 — flat schemas, arbitrage tool, market summary tool
118
+ Subject: [Update] buda-mcp v1.4.0 — simulate_order, technical indicators, sentiment, position sizing, dead man's switch
128
119
 
129
120
  Hi mcp.so team,
130
121
 
131
- I've released v1.3.0 of buda-mcp (@guiie/buda-mcp on npm).
122
+ I've released v1.4.0 of buda-mcp (@guiie/buda-mcp on npm).
132
123
 
133
- Key changes:
134
- - All tools now return flat typed objects: floats + _currency fields instead of [amount, currency] arrays
135
- - New tool: get_market_summary — one-call overview with liquidity_rating (high/medium/low)
136
- - New tool: get_arbitrage_opportunities cross-country BTC/ETH/etc price discrepancy detection (USDC-normalized)
137
- - New MCP Resource: buda://summary/{market}
138
- - All tool descriptions rewritten with concrete example questions and units
139
- - 35 unit tests (12 new)
124
+ Key changes (5 new tools + 3 sub-tools):
125
+ - simulate_order: live order cost simulation with actual fee rates (no order placed)
126
+ - calculate_position_size: Kelly-style position sizing (fully client-side)
127
+ - get_market_sentiment: composite score -100..+100 from price/volume/spread microstructure
128
+ - get_technical_indicators: RSI/MACD/Bollinger Bands/SMA (no external libs, from trade history)
129
+ - schedule_cancel_all / renew_cancel_timer / disarm_cancel_timer: in-memory dead man's switch (auth-gated)
130
+ - 59 unit tests (was 35)
140
131
 
141
132
  Links:
142
133
  - npm: https://www.npmjs.com/package/@guiie/buda-mcp
@@ -155,23 +146,23 @@ Thank you!
155
146
  **Message template:**
156
147
 
157
148
  ```
158
- Subject: [Update] buda-mcp v1.3.0
149
+ Subject: [Update] buda-mcp v1.4.0
159
150
 
160
151
  Hi Glama team,
161
152
 
162
- buda-mcp has been updated to v1.3.0.
153
+ buda-mcp has been updated to v1.4.0.
163
154
 
164
155
  Package: @guiie/buda-mcp (npm)
165
156
  Registry: io.github.gtorreal/buda-mcp (MCP Registry)
166
- Version: 1.3.0
157
+ Version: 1.4.0
167
158
 
168
- Changes:
169
- - Flat response schemas: all monetary amounts now floats with _currency fields (LLM-friendly)
170
- - New tool: get_market_summary (one-call overview, liquidity_rating)
171
- - New tool: get_arbitrage_opportunities (cross-country USDC-normalized price discrepancy)
172
- - New MCP Resource: buda://summary/{market}
173
- - Rewritten descriptions with examples and units for all 12 tools
174
- - 35 unit tests
159
+ Changes (5 new tools + 3 sub-tools):
160
+ - simulate_order: order simulation with live data, simulation: true always set
161
+ - calculate_position_size: client-side position sizing
162
+ - get_market_sentiment: composite sentiment score with disclaimers
163
+ - get_technical_indicators: RSI/MACD/BB/SMA from trade history
164
+ - schedule_cancel_all + renew/disarm: in-memory dead man's switch (auth-gated, local use only)
165
+ - 59 unit tests
175
166
 
176
167
  Quick start:
177
168
  npx @guiie/buda-mcp
@@ -186,13 +177,21 @@ Thank you!
186
177
 
187
178
  ## 8. Post-publish verification
188
179
 
189
- - [ ] `npx @guiie/buda-mcp@1.3.0` starts successfully
190
- - [ ] `npm info @guiie/buda-mcp version` returns `1.3.0`
191
- - [ ] GitHub release tag `v1.3.0` is visible
192
- - [ ] MCP Registry entry reflects v1.3.0
193
- - [ ] Smithery server card lists 10 public tools (including get_market_summary, get_arbitrage_opportunities)
194
- - [ ] `GET /health` returns `"version":"1.3.0"` on Railway deployment
195
- - [ ] `GET /.well-known/mcp/server-card.json` returns 3 resources (including buda://summary/{market})
196
- - [ ] get_ticker response has `last_price: <number>` not `last_price: ["...", "CLP"]`
180
+ - [ ] `npx @guiie/buda-mcp@1.4.0` starts successfully
181
+ - [ ] `npm info @guiie/buda-mcp version` returns `1.4.0`
182
+ - [ ] GitHub release tag `v1.4.0` is visible
183
+ - [ ] MCP Registry entry reflects v1.4.0
184
+ - [ ] Smithery server card lists 14 public tools (including 4 new: simulate_order, calculate_position_size, get_market_sentiment, get_technical_indicators)
185
+ - [ ] Smithery server card lists 7 auth tools (including schedule_cancel_all, renew_cancel_timer, disarm_cancel_timer)
186
+ - [ ] `GET /health` returns `"version":"1.4.0"` on Railway deployment
187
+ - [ ] simulate_order response includes `simulation: true`
188
+ - [ ] get_technical_indicators returns `warning: "insufficient_data"` for markets with few trades
189
+ - [ ] schedule_cancel_all requires `confirmation_token="CONFIRM"` (test with wrong token)
197
190
  - [ ] mcp.so listing updated
198
191
  - [ ] Glama.ai listing updated
192
+
193
+ ---
194
+
195
+ ## ARCHIVED: v1.3.0 checklist
196
+
197
+ See git tag `v1.3.0` for the v1.3.0 release notes and verification steps.
package/README.md CHANGED
@@ -285,11 +285,11 @@ Authentication uses HMAC-SHA384 signing per the [Buda API docs](https://api.buda
285
285
 
286
286
  | Quote | Country | Sample pairs |
287
287
  |-------|---------|-------------|
288
- | CLP | Chile | BTC-CLP, ETH-CLP, XRP-CLP |
289
- | COP | Colombia | BTC-COP, ETH-COP, XRP-COP |
288
+ | CLP | Chile | BTC-CLP, ETH-CLP, SOL-CLP |
289
+ | COP | Colombia | BTC-COP, ETH-COP, SOL-COP |
290
290
  | PEN | Peru | BTC-PEN, ETH-PEN |
291
- | USDC | USD-pegged | BTC-USDC, ETH-USDC |
292
- | BTC | Cross | ETH-BTC, XRP-BTC, BCH-BTC |
291
+ | USDC | USD-pegged | BTC-USDC, USDT-USDC |
292
+ | BTC | Cross | ETH-BTC, LTC-BTC, BCH-BTC |
293
293
 
294
294
  ---
295
295
 
package/dist/http.js CHANGED
@@ -18,6 +18,11 @@ import * as balances from "./tools/balances.js";
18
18
  import * as orders from "./tools/orders.js";
19
19
  import * as placeOrder from "./tools/place_order.js";
20
20
  import * as cancelOrder from "./tools/cancel_order.js";
21
+ import * as simulateOrder from "./tools/simulate_order.js";
22
+ import * as positionSize from "./tools/calculate_position_size.js";
23
+ import * as marketSentiment from "./tools/market_sentiment.js";
24
+ import * as technicalIndicators from "./tools/technical_indicators.js";
25
+ import * as deadMansSwitch from "./tools/dead_mans_switch.js";
21
26
  import { handleMarketSummary } from "./tools/market_summary.js";
22
27
  const PORT = parseInt(process.env.PORT ?? "3000", 10);
23
28
  const client = new BudaClient(undefined, process.env.BUDA_API_KEY, process.env.BUDA_API_SECRET);
@@ -35,12 +40,19 @@ const PUBLIC_TOOL_SCHEMAS = [
35
40
  priceHistory.toolSchema,
36
41
  arbitrage.toolSchema,
37
42
  marketSummary.toolSchema,
43
+ simulateOrder.toolSchema,
44
+ positionSize.toolSchema,
45
+ marketSentiment.toolSchema,
46
+ technicalIndicators.toolSchema,
38
47
  ];
39
48
  const AUTH_TOOL_SCHEMAS = [
40
49
  balances.toolSchema,
41
50
  orders.toolSchema,
42
51
  placeOrder.toolSchema,
43
52
  cancelOrder.toolSchema,
53
+ deadMansSwitch.toolSchema,
54
+ deadMansSwitch.renewToolSchema,
55
+ deadMansSwitch.disarmToolSchema,
44
56
  ];
45
57
  function createServer() {
46
58
  const server = new McpServer({ name: "buda-mcp", version: VERSION });
@@ -56,11 +68,16 @@ function createServer() {
56
68
  priceHistory.register(server, client, reqCache);
57
69
  arbitrage.register(server, client, reqCache);
58
70
  marketSummary.register(server, client, reqCache);
71
+ simulateOrder.register(server, client, reqCache);
72
+ positionSize.register(server);
73
+ marketSentiment.register(server, client, reqCache);
74
+ technicalIndicators.register(server, client);
59
75
  if (authEnabled) {
60
76
  balances.register(server, client);
61
77
  orders.register(server, client);
62
78
  placeOrder.register(server, client);
63
79
  cancelOrder.register(server, client);
80
+ deadMansSwitch.register(server, client);
64
81
  }
65
82
  // MCP Resources
66
83
  server.resource("buda-markets", "buda://markets", async (uri) => {
package/dist/index.js CHANGED
@@ -19,6 +19,11 @@ import * as balances from "./tools/balances.js";
19
19
  import * as orders from "./tools/orders.js";
20
20
  import * as placeOrder from "./tools/place_order.js";
21
21
  import * as cancelOrder from "./tools/cancel_order.js";
22
+ import * as simulateOrder from "./tools/simulate_order.js";
23
+ import * as positionSize from "./tools/calculate_position_size.js";
24
+ import * as marketSentiment from "./tools/market_sentiment.js";
25
+ import * as technicalIndicators from "./tools/technical_indicators.js";
26
+ import * as deadMansSwitch from "./tools/dead_mans_switch.js";
22
27
  import { handleMarketSummary } from "./tools/market_summary.js";
23
28
  const client = new BudaClient(undefined, process.env.BUDA_API_KEY, process.env.BUDA_API_SECRET);
24
29
  const server = new McpServer({
@@ -36,12 +41,17 @@ compareMarkets.register(server, client, cache);
36
41
  priceHistory.register(server, client, cache);
37
42
  arbitrage.register(server, client, cache);
38
43
  marketSummary.register(server, client, cache);
44
+ simulateOrder.register(server, client, cache);
45
+ positionSize.register(server);
46
+ marketSentiment.register(server, client, cache);
47
+ technicalIndicators.register(server, client);
39
48
  // Auth-gated tools — only registered when API credentials are present
40
49
  if (client.hasAuth()) {
41
50
  balances.register(server, client);
42
51
  orders.register(server, client);
43
52
  placeOrder.register(server, client);
44
53
  cancelOrder.register(server, client);
54
+ deadMansSwitch.register(server, client);
45
55
  }
46
56
  // MCP Resources
47
57
  server.resource("buda-markets", "buda://markets", async (uri) => {
@@ -0,0 +1,48 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare const toolSchema: {
3
+ name: string;
4
+ description: string;
5
+ inputSchema: {
6
+ type: "object";
7
+ properties: {
8
+ market_id: {
9
+ type: string;
10
+ description: string;
11
+ };
12
+ capital: {
13
+ type: string;
14
+ description: string;
15
+ };
16
+ risk_pct: {
17
+ type: string;
18
+ description: string;
19
+ };
20
+ entry_price: {
21
+ type: string;
22
+ description: string;
23
+ };
24
+ stop_loss_price: {
25
+ type: string;
26
+ description: string;
27
+ };
28
+ };
29
+ required: string[];
30
+ };
31
+ };
32
+ type CalculatePositionSizeArgs = {
33
+ market_id: string;
34
+ capital: number;
35
+ risk_pct: number;
36
+ entry_price: number;
37
+ stop_loss_price: number;
38
+ };
39
+ export declare function handleCalculatePositionSize(args: CalculatePositionSizeArgs): {
40
+ content: Array<{
41
+ type: "text";
42
+ text: string;
43
+ }>;
44
+ isError?: boolean;
45
+ };
46
+ export declare function register(server: McpServer): void;
47
+ export {};
48
+ //# sourceMappingURL=calculate_position_size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calculate_position_size.d.ts","sourceRoot":"","sources":["../../src/tools/calculate_position_size.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCtB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,yBAAyB,GAC9B;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,CA0DvE;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8BhD"}
@@ -0,0 +1,111 @@
1
+ import { z } from "zod";
2
+ import { validateMarketId } from "../validation.js";
3
+ export const toolSchema = {
4
+ name: "calculate_position_size",
5
+ description: "Calculates position size based on your capital, risk tolerance, entry price, and stop-loss. " +
6
+ "Determines how many units to buy or sell so that a stop-loss hit costs exactly risk_pct% of capital. " +
7
+ "Fully client-side — no API call is made. " +
8
+ "Example: 'How many BTC can I buy on BTC-CLP if I have 1,000,000 CLP, risk 2%, entry 80,000,000 CLP, stop at 78,000,000 CLP?'",
9
+ inputSchema: {
10
+ type: "object",
11
+ properties: {
12
+ market_id: {
13
+ type: "string",
14
+ description: "Market ID (e.g. 'BTC-CLP', 'ETH-COP'). Used to derive the quote currency.",
15
+ },
16
+ capital: {
17
+ type: "number",
18
+ description: "Total available capital in the quote currency (e.g. CLP for BTC-CLP).",
19
+ },
20
+ risk_pct: {
21
+ type: "number",
22
+ description: "Percentage of capital to risk on this trade (0.1–10, e.g. 2 = 2%).",
23
+ },
24
+ entry_price: {
25
+ type: "number",
26
+ description: "Planned entry price in quote currency.",
27
+ },
28
+ stop_loss_price: {
29
+ type: "number",
30
+ description: "Stop-loss price in quote currency. Must be below entry for buys, above entry for sells.",
31
+ },
32
+ },
33
+ required: ["market_id", "capital", "risk_pct", "entry_price", "stop_loss_price"],
34
+ },
35
+ };
36
+ export function handleCalculatePositionSize(args) {
37
+ const { market_id, capital, risk_pct, entry_price, stop_loss_price } = args;
38
+ const validationError = validateMarketId(market_id);
39
+ if (validationError) {
40
+ return {
41
+ content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }],
42
+ isError: true,
43
+ };
44
+ }
45
+ if (stop_loss_price === entry_price) {
46
+ return {
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: JSON.stringify({
51
+ error: "stop_loss_price must differ from entry_price.",
52
+ code: "INVALID_STOP_LOSS",
53
+ }),
54
+ },
55
+ ],
56
+ isError: true,
57
+ };
58
+ }
59
+ const quoteCurrency = market_id.split("-")[1].toUpperCase();
60
+ const baseCurrency = market_id.split("-")[0].toUpperCase();
61
+ const side = stop_loss_price < entry_price ? "buy" : "sell";
62
+ const capitalAtRisk = capital * (risk_pct / 100);
63
+ const riskPerUnit = Math.abs(entry_price - stop_loss_price);
64
+ const units = capitalAtRisk / riskPerUnit;
65
+ const positionValue = units * entry_price;
66
+ const feeImpact = parseFloat((positionValue * 0.008).toFixed(8));
67
+ const riskRewardNote = `${side === "buy" ? "Buy" : "Sell"} ${units.toFixed(8)} ${baseCurrency} at ${entry_price} ${quoteCurrency} ` +
68
+ `with stop at ${stop_loss_price} ${quoteCurrency}. ` +
69
+ `Risking ${risk_pct}% of capital (${capitalAtRisk.toFixed(2)} ${quoteCurrency}) ` +
70
+ `on a ${riskPerUnit.toFixed(2)} ${quoteCurrency}/unit move. ` +
71
+ `Estimated entry fee: ${feeImpact.toFixed(2)} ${quoteCurrency} (0.8% taker, conservative estimate).`;
72
+ const result = {
73
+ market_id: market_id.toUpperCase(),
74
+ side,
75
+ units: parseFloat(units.toFixed(8)),
76
+ base_currency: baseCurrency,
77
+ capital_at_risk: parseFloat(capitalAtRisk.toFixed(2)),
78
+ position_value: parseFloat(positionValue.toFixed(2)),
79
+ fee_impact: feeImpact,
80
+ fee_currency: quoteCurrency,
81
+ risk_reward_note: riskRewardNote,
82
+ };
83
+ return {
84
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
85
+ };
86
+ }
87
+ export function register(server) {
88
+ server.tool(toolSchema.name, toolSchema.description, {
89
+ market_id: z
90
+ .string()
91
+ .describe("Market ID (e.g. 'BTC-CLP', 'ETH-COP'). Used to derive the quote currency."),
92
+ capital: z
93
+ .number()
94
+ .positive()
95
+ .describe("Total available capital in the quote currency (e.g. CLP for BTC-CLP)."),
96
+ risk_pct: z
97
+ .number()
98
+ .min(0.1)
99
+ .max(10)
100
+ .describe("Percentage of capital to risk on this trade (0.1–10, e.g. 2 = 2%)."),
101
+ entry_price: z
102
+ .number()
103
+ .positive()
104
+ .describe("Planned entry price in quote currency."),
105
+ stop_loss_price: z
106
+ .number()
107
+ .positive()
108
+ .describe("Stop-loss price in quote currency. Must be below entry for buys, above entry for sells."),
109
+ }, (args) => handleCalculatePositionSize(args));
110
+ }
111
+ //# sourceMappingURL=calculate_position_size.js.map
@@ -0,0 +1,84 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { BudaClient } from "../client.js";
3
+ export declare const toolSchema: {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: {
7
+ type: "object";
8
+ properties: {
9
+ market_id: {
10
+ type: string;
11
+ description: string;
12
+ };
13
+ ttl_seconds: {
14
+ type: string;
15
+ description: string;
16
+ };
17
+ confirmation_token: {
18
+ type: string;
19
+ description: string;
20
+ };
21
+ };
22
+ required: string[];
23
+ };
24
+ };
25
+ export declare const renewToolSchema: {
26
+ name: string;
27
+ description: string;
28
+ inputSchema: {
29
+ type: "object";
30
+ properties: {
31
+ market_id: {
32
+ type: string;
33
+ description: string;
34
+ };
35
+ };
36
+ required: string[];
37
+ };
38
+ };
39
+ export declare const disarmToolSchema: {
40
+ name: string;
41
+ description: string;
42
+ inputSchema: {
43
+ type: "object";
44
+ properties: {
45
+ market_id: {
46
+ type: string;
47
+ description: string;
48
+ };
49
+ };
50
+ required: string[];
51
+ };
52
+ };
53
+ type ScheduleArgs = {
54
+ market_id: string;
55
+ ttl_seconds: number;
56
+ confirmation_token: string;
57
+ };
58
+ export declare function handleScheduleCancelAll(args: ScheduleArgs, client: BudaClient): Promise<{
59
+ content: Array<{
60
+ type: "text";
61
+ text: string;
62
+ }>;
63
+ isError?: boolean;
64
+ }>;
65
+ type MarketOnlyArgs = {
66
+ market_id: string;
67
+ };
68
+ export declare function handleRenewCancelTimer({ market_id }: MarketOnlyArgs, client: BudaClient): {
69
+ content: Array<{
70
+ type: "text";
71
+ text: string;
72
+ }>;
73
+ isError?: boolean;
74
+ };
75
+ export declare function handleDisarmCancelTimer({ market_id }: MarketOnlyArgs): {
76
+ content: Array<{
77
+ type: "text";
78
+ text: string;
79
+ }>;
80
+ isError?: boolean;
81
+ };
82
+ export declare function register(server: McpServer, client: BudaClient): void;
83
+ export {};
84
+ //# sourceMappingURL=dead_mans_switch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead_mans_switch.d.ts","sourceRoot":"","sources":["../../src/tools/dead_mans_switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAiDxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA2BtB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAgB3B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAgB5B,CAAC;AAIF,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA+ChF;AAED,KAAK,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C,wBAAgB,sBAAsB,CACpC,EAAE,SAAS,EAAE,EAAE,cAAc,EAC7B,MAAM,EAAE,UAAU,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CA0CvE;AAED,wBAAgB,uBAAuB,CACrC,EAAE,SAAS,EAAE,EAAE,cAAc,GAC5B;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAwCvE;AAID,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA0CpE"}