@okx_ai/okx-trade-mcp 1.3.8-beta.3 → 1.3.8-beta.4

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/dist/index.js CHANGED
@@ -2374,7 +2374,7 @@ function registerIndicatorTools() {
2374
2374
  params: {
2375
2375
  type: "array",
2376
2376
  items: { type: "number" },
2377
- description: "Indicator-specific parameters as a number array. Examples: MA/EMA [14] (period), MACD [12,26,9] (fast,slow,signal), BB [20,2] (period,stdDev), RSI [14] (period). For period-based indicators a parameter is required; the CLI applies a sensible default when omitted."
2377
+ description: "Indicator-specific parameters as a number array. Examples: MA/EMA [14] (period), MACD [12,26,9] (fast,slow,signal), BB [20,2] (period,stdDev), RSI [14] (period). Omit to use server defaults."
2378
2378
  },
2379
2379
  returnList: {
2380
2380
  type: "boolean",
@@ -2480,6 +2480,203 @@ var MODULES = [
2480
2480
  "skills"
2481
2481
  ];
2482
2482
  var DEFAULT_MODULES = ["spot", "swap", "option", "account", ...BOT_DEFAULT_SUB_MODULES, "skills"];
2483
+ var AGGREGATE_ENDPOINT = "/api/v5/aigc/forward/balance-aggregate";
2484
+ var TRADING_ENDPOINT = "/api/v5/account/balance";
2485
+ var FUNDING_ENDPOINT = "/api/v5/asset/balances";
2486
+ var VALUATION_ENDPOINT = "/api/v5/asset/asset-valuation";
2487
+ function parseParams(rawArgs) {
2488
+ const args = asRecord(rawArgs);
2489
+ const accounts = readString(args, "accounts") ?? "trading,funding";
2490
+ return {
2491
+ ccy: readString(args, "ccy"),
2492
+ accounts,
2493
+ requestedAccounts: accounts.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean),
2494
+ showValuation: readBoolean(args, "showValuation") ?? true,
2495
+ valuationCcy: readString(args, "valuationCcy") ?? "USDT",
2496
+ preferParallel: readBoolean(args, "preferParallel") ?? false
2497
+ };
2498
+ }
2499
+ function normalizeSubError(error) {
2500
+ if (!error || typeof error !== "object") {
2501
+ return void 0;
2502
+ }
2503
+ const e = error;
2504
+ return {
2505
+ code: e["code"] === void 0 || e["code"] === null ? "UNKNOWN" : String(e["code"]),
2506
+ msg: typeof e["msg"] === "string" ? e["msg"] : String(e["msg"] ?? "")
2507
+ };
2508
+ }
2509
+ function toIsoTimestamp(value, fallbackMs) {
2510
+ if (typeof value === "number" && Number.isFinite(value)) {
2511
+ return new Date(value).toISOString();
2512
+ }
2513
+ if (typeof value === "string" && value.trim() !== "") {
2514
+ return value;
2515
+ }
2516
+ return new Date(fallbackMs).toISOString();
2517
+ }
2518
+ function normalizeAggregate(agg, params, startTime) {
2519
+ const result = {};
2520
+ const trading = agg["trading"];
2521
+ if (trading) {
2522
+ result.trading = compactObject({
2523
+ available: trading["available"] ?? false,
2524
+ totalEq: trading["totalEq"],
2525
+ adjEq: trading["adjEq"],
2526
+ details: Array.isArray(trading["details"]) ? trading["details"] : [],
2527
+ error: normalizeSubError(trading["error"])
2528
+ });
2529
+ }
2530
+ const funding = agg["funding"];
2531
+ if (funding) {
2532
+ result.funding = compactObject({
2533
+ available: funding["available"] ?? false,
2534
+ details: Array.isArray(funding["details"]) ? funding["details"] : [],
2535
+ error: normalizeSubError(funding["error"])
2536
+ });
2537
+ }
2538
+ const valuation = agg["valuation"];
2539
+ if (valuation) {
2540
+ result.valuation = compactObject({
2541
+ available: valuation["available"] ?? false,
2542
+ valuationCcy: valuation["valuationCcy"] ?? params.valuationCcy,
2543
+ totalBal: valuation["totalBal"] ?? "0",
2544
+ details: Array.isArray(valuation["details"]) ? valuation["details"] : [],
2545
+ error: normalizeSubError(valuation["error"])
2546
+ });
2547
+ }
2548
+ const meta = agg["meta"] ?? {};
2549
+ result.meta = compactObject({
2550
+ requestedAt: toIsoTimestamp(meta["requestedAt"], startTime),
2551
+ elapsedMs: typeof meta["elapsedMs"] === "number" ? meta["elapsedMs"] : Date.now() - startTime,
2552
+ partialFailure: Boolean(meta["partialFailure"]),
2553
+ site: typeof meta["site"] === "string" ? meta["site"] : void 0,
2554
+ source: "aggregate"
2555
+ });
2556
+ return result;
2557
+ }
2558
+ async function queryAggregate(context, params, startTime) {
2559
+ const resp = await context.client.privateGet(
2560
+ AGGREGATE_ENDPOINT,
2561
+ compactObject({
2562
+ ccy: params.ccy,
2563
+ accounts: params.accounts,
2564
+ showValuation: params.showValuation,
2565
+ valuationCcy: params.valuationCcy
2566
+ }),
2567
+ privateRateLimit("account_get_balance_all", 5)
2568
+ );
2569
+ const data = resp.data;
2570
+ const agg = Array.isArray(data) ? data[0] : void 0;
2571
+ if (!agg || agg["trading"] === void 0 && agg["funding"] === void 0) {
2572
+ throw new OkxApiError("Aggregate endpoint returned no usable data", {
2573
+ code: "AGG_EMPTY",
2574
+ endpoint: `GET ${AGGREGATE_ENDPOINT}`
2575
+ });
2576
+ }
2577
+ return normalizeAggregate(agg, params, startTime);
2578
+ }
2579
+ var REQUESTED_KEYS = /* @__PURE__ */ new Set(["trading", "funding"]);
2580
+ function buildBalanceTasks(context, params) {
2581
+ const { ccy, requestedAccounts, showValuation, valuationCcy } = params;
2582
+ const tasks = [];
2583
+ if (requestedAccounts.includes("trading")) {
2584
+ tasks.push({
2585
+ key: "trading",
2586
+ run: () => context.client.privateGet(TRADING_ENDPOINT, compactObject({ ccy }), privateRateLimit("account_get_balance", 10)).then((resp) => resp.data)
2587
+ });
2588
+ }
2589
+ if (requestedAccounts.includes("funding")) {
2590
+ tasks.push({
2591
+ key: "funding",
2592
+ run: () => context.client.privateGet(FUNDING_ENDPOINT, compactObject({ ccy }), privateRateLimit("account_get_asset_balance", 6)).then((resp) => resp.data)
2593
+ });
2594
+ }
2595
+ if (showValuation) {
2596
+ tasks.push({
2597
+ key: "valuation",
2598
+ run: () => context.client.privateGet(VALUATION_ENDPOINT, { ccy: valuationCcy }, privateRateLimit("account_get_asset_valuation", 1)).then((resp) => resp.data)
2599
+ });
2600
+ }
2601
+ return tasks;
2602
+ }
2603
+ async function settleBalanceTasks(tasks) {
2604
+ return Promise.all(
2605
+ tasks.map(async (task) => {
2606
+ try {
2607
+ return { key: task.key, data: await task.run() };
2608
+ } catch (error) {
2609
+ return { key: task.key, error };
2610
+ }
2611
+ })
2612
+ );
2613
+ }
2614
+ function buildSuccessSection(key, data, valuationCcy) {
2615
+ const rows = Array.isArray(data) ? data : [];
2616
+ const first = rows[0];
2617
+ if (key === "funding") {
2618
+ return { available: true, details: rows };
2619
+ }
2620
+ if (key === "valuation") {
2621
+ return { available: true, valuationCcy, totalBal: first?.["totalBal"] ?? "0", details: rows };
2622
+ }
2623
+ return {
2624
+ available: true,
2625
+ totalEq: first?.["totalEq"] ?? "0",
2626
+ adjEq: first?.["adjEq"] ?? "0",
2627
+ details: first && Array.isArray(first["details"]) ? first["details"] : []
2628
+ };
2629
+ }
2630
+ function buildErrorSection(error) {
2631
+ return {
2632
+ available: false,
2633
+ error: {
2634
+ code: error instanceof OkxApiError ? error.code ?? "UNKNOWN" : "UNKNOWN",
2635
+ msg: error.message
2636
+ }
2637
+ };
2638
+ }
2639
+ async function queryParallel(context, params, startTime) {
2640
+ const tasks = buildBalanceTasks(context, params);
2641
+ const outcomes = await settleBalanceTasks(tasks);
2642
+ const authFailure = outcomes.find((o) => o.error instanceof AuthenticationError);
2643
+ if (authFailure?.error) {
2644
+ throw authFailure.error;
2645
+ }
2646
+ const result = {};
2647
+ for (const outcome of outcomes) {
2648
+ result[outcome.key] = outcome.error ? buildErrorSection(outcome.error) : buildSuccessSection(outcome.key, outcome.data, params.valuationCcy);
2649
+ }
2650
+ const requestedCount = tasks.filter((t) => REQUESTED_KEYS.has(t.key)).length;
2651
+ const requestedFailures = outcomes.filter((o) => o.error && REQUESTED_KEYS.has(o.key)).length;
2652
+ if (requestedCount > 0 && requestedFailures >= requestedCount) {
2653
+ throw new OkxApiError("Both balance queries failed", { code: "-30001" });
2654
+ }
2655
+ const site = typeof context.config?.site === "string" ? context.config.site : void 0;
2656
+ result.meta = compactObject({
2657
+ requestedAt: new Date(startTime).toISOString(),
2658
+ elapsedMs: Date.now() - startTime,
2659
+ partialFailure: requestedFailures > 0,
2660
+ site,
2661
+ source: "fallback"
2662
+ });
2663
+ return result;
2664
+ }
2665
+ async function buildBalanceAll(rawArgs, context) {
2666
+ const params = parseParams(rawArgs);
2667
+ const startTime = Date.now();
2668
+ if (params.preferParallel) {
2669
+ return queryParallel(context, params, startTime);
2670
+ }
2671
+ try {
2672
+ return await queryAggregate(context, params, startTime);
2673
+ } catch (error) {
2674
+ if (error instanceof AuthenticationError) {
2675
+ throw error;
2676
+ }
2677
+ return queryParallel(context, params, startTime);
2678
+ }
2679
+ }
2483
2680
  function registerAccountTools() {
2484
2681
  return [
2485
2682
  {
@@ -3059,6 +3256,39 @@ function registerAccountTools() {
3059
3256
  );
3060
3257
  return normalizeResponse(response);
3061
3258
  }
3259
+ },
3260
+ {
3261
+ name: "account_get_balance_all",
3262
+ title: "Get Aggregate Balance Snapshot",
3263
+ module: "account",
3264
+ description: "One-shot snapshot of all OKX assets: trading-account equity + funding-account balances + optional cross-account valuation. Use when the user asks for total assets / net worth / \u603B\u8D44\u4EA7 / all balances. Prefer this over calling account_get_balance + account_get_asset_balance separately. Returns {trading, funding, valuation, meta} with per-section error so partial failures don't block the rest.",
3265
+ isWrite: false,
3266
+ inputSchema: {
3267
+ type: "object",
3268
+ properties: {
3269
+ ccy: {
3270
+ type: "string",
3271
+ description: "Filter by currency, comma-separated (e.g. BTC,ETH). Omit for all. Applied to trading + funding queries only."
3272
+ },
3273
+ accounts: {
3274
+ type: "string",
3275
+ description: "Comma-separated accounts to query: 'trading','funding'. Default 'trading,funding'."
3276
+ },
3277
+ showValuation: {
3278
+ type: "boolean",
3279
+ description: "Include cross-account asset valuation. Default true."
3280
+ },
3281
+ valuationCcy: {
3282
+ type: "string",
3283
+ description: "Currency for valuation (e.g. USDT, BTC). Default USDT. Only effective when showValuation=true."
3284
+ },
3285
+ preferParallel: {
3286
+ type: "boolean",
3287
+ description: "Skip the server-side aggregate endpoint and query trading/funding/valuation directly in parallel. Default false. Use when you need the per-account valuation breakdown or a non-USD valuation currency."
3288
+ }
3289
+ }
3290
+ },
3291
+ handler: (rawArgs, context) => buildBalanceAll(rawArgs, context)
3062
3292
  }
3063
3293
  ];
3064
3294
  }
@@ -12397,7 +12627,7 @@ var _require = createRequire(import.meta.url);
12397
12627
  var pkg = _require("../package.json");
12398
12628
  var SERVER_NAME = "okx-trade-mcp";
12399
12629
  var SERVER_VERSION = pkg.version;
12400
- var GIT_HASH = true ? "52f6524c" : "dev";
12630
+ var GIT_HASH = true ? "9beb3ee8" : "dev";
12401
12631
 
12402
12632
  // src/server.ts
12403
12633
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";