@okx_ai/okx-trade-mcp 1.3.5 → 1.3.6

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
@@ -5,6 +5,7 @@ import { parseArgs } from "util";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
 
7
7
  // ../core/dist/index.js
8
+ import { EnvHttpProxyAgent, setGlobalDispatcher } from "undici";
8
9
  import { ProxyAgent } from "undici";
9
10
  import { isIP } from "net";
10
11
  import { lookup as dnsLookup } from "dns";
@@ -35,10 +36,10 @@ import { writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync
35
36
  import { join as join4, resolve, basename, sep } from "path";
36
37
  import { randomUUID } from "crypto";
37
38
  import yauzl from "yauzl";
38
- import { join as join6, dirname as dirname3 } from "path";
39
+ import { join as join8, dirname as dirname3 } from "path";
39
40
  import { homedir as homedir4 } from "os";
40
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
41
- import { join as join7, dirname as dirname4 } from "path";
41
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
42
+ import { join as join9, dirname as dirname4 } from "path";
42
43
  import { homedir as homedir5 } from "os";
43
44
 
44
45
  // ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
@@ -727,8 +728,8 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
727
728
  }
728
729
 
729
730
  // ../core/dist/index.js
730
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
731
- import { join as join8 } from "path";
731
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
732
+ import { join as join10 } from "path";
732
733
  import { homedir as homedir6 } from "os";
733
734
  import fs2 from "fs";
734
735
  import path2 from "path";
@@ -737,8 +738,21 @@ import * as fs3 from "fs";
737
738
  import * as path3 from "path";
738
739
  import * as os3 from "os";
739
740
  import { execFileSync } from "child_process";
740
- import { join as join12 } from "path";
741
+ import { join as join14 } from "path";
741
742
  import { homedir as homedir10 } from "os";
743
+ function hasProxyEnv(env = process.env) {
744
+ return Boolean(
745
+ env.HTTPS_PROXY || env.https_proxy || env.HTTP_PROXY || env.http_proxy
746
+ );
747
+ }
748
+ function installEnvProxyDispatcher(deps = {}) {
749
+ const env = deps.env ?? process.env;
750
+ if (!hasProxyEnv(env)) return false;
751
+ const register = deps.register ?? (() => setGlobalDispatcher(new EnvHttpProxyAgent()));
752
+ register();
753
+ return true;
754
+ }
755
+ installEnvProxyDispatcher();
742
756
  var EXEC_TIMEOUT_MS = 3e4;
743
757
  var ALLOWED_DOMAIN_RE = /^[\w.-]+\.okx\.com$/;
744
758
  var PILOT_BIN_DIR = join(homedir(), ".okx", "bin");
@@ -761,25 +775,25 @@ function execPilotBinary(domain, exclude = [], userAgent) {
761
775
  if (userAgent) {
762
776
  args.push("--user-agent", userAgent);
763
777
  }
764
- return new Promise((resolve3) => {
778
+ return new Promise((resolve4) => {
765
779
  execFile(
766
780
  binPath,
767
781
  args,
768
782
  { timeout: EXEC_TIMEOUT_MS, encoding: "utf-8" },
769
783
  (error, stdout) => {
770
784
  if (error) {
771
- resolve3(null);
785
+ resolve4(null);
772
786
  return;
773
787
  }
774
788
  try {
775
789
  const result = JSON.parse(stdout);
776
790
  if (result.code === 0 && result.data) {
777
- resolve3(result.data);
791
+ resolve4(result.data);
778
792
  } else {
779
- resolve3(null);
793
+ resolve4(null);
780
794
  }
781
795
  } catch {
782
- resolve3(null);
796
+ resolve4(null);
783
797
  }
784
798
  }
785
799
  );
@@ -1113,7 +1127,7 @@ var EXIT_CODES = {
1113
1127
  NOT_LOGGED_IN: 2,
1114
1128
  REFRESH_FAILED: 3
1115
1129
  };
1116
- function finalizeToken(code, token, resolve3, reject) {
1130
+ function finalizeToken(code, token, resolve4, reject) {
1117
1131
  if (code === EXIT_CODES.SUCCESS) {
1118
1132
  if (!token) {
1119
1133
  reject(new AuthenticationError(
@@ -1122,7 +1136,7 @@ function finalizeToken(code, token, resolve3, reject) {
1122
1136
  ));
1123
1137
  return;
1124
1138
  }
1125
- resolve3(token);
1139
+ resolve4(token);
1126
1140
  return;
1127
1141
  }
1128
1142
  if (code === EXIT_CODES.NOT_LOGGED_IN) {
@@ -1159,7 +1173,7 @@ function defaultWindowsPipeName() {
1159
1173
  return WIN_PIPE_PREFIX + randomBytes(32).toString("hex");
1160
1174
  }
1161
1175
  function execAuthTokenWindows(binPath, makePipeName = defaultWindowsPipeName) {
1162
- return new Promise((resolve3, reject) => {
1176
+ return new Promise((resolve4, reject) => {
1163
1177
  const pipeName = makePipeName();
1164
1178
  const server = createServer();
1165
1179
  const chunks = [];
@@ -1179,7 +1193,7 @@ function execAuthTokenWindows(binPath, makePipeName = defaultWindowsPipeName) {
1179
1193
  const tryFinalize = () => {
1180
1194
  if (!pipeClosed || exitCode === void 0) return;
1181
1195
  const token = Buffer.concat(chunks).toString("utf-8").trim();
1182
- settle(() => finalizeToken(exitCode, token, resolve3, reject));
1196
+ settle(() => finalizeToken(exitCode, token, resolve4, reject));
1183
1197
  };
1184
1198
  server.on("connection", (socket) => {
1185
1199
  connectionMade = true;
@@ -1226,7 +1240,7 @@ function execAuthToken() {
1226
1240
  return process.platform === "win32" ? execAuthTokenWindows(binPath) : execAuthTokenUnix(binPath);
1227
1241
  }
1228
1242
  function execAuthTokenUnix(binPath) {
1229
- return new Promise((resolve3, reject) => {
1243
+ return new Promise((resolve4, reject) => {
1230
1244
  const child = spawn2(binPath, ["token"], {
1231
1245
  stdio: ["ignore", "ignore", "inherit", "pipe"]
1232
1246
  // stdin stdout stderr fd3 (pipe)
@@ -1239,35 +1253,35 @@ function execAuthTokenUnix(binPath) {
1239
1253
  });
1240
1254
  child.on("close", (code) => {
1241
1255
  const token = Buffer.concat(chunks).toString("utf-8").trim();
1242
- finalizeToken(code, token, resolve3, reject);
1256
+ finalizeToken(code, token, resolve4, reject);
1243
1257
  });
1244
1258
  });
1245
1259
  }
1246
1260
  function execAuthStatus() {
1247
1261
  const binPath = getAuthBinaryPath();
1248
- return new Promise((resolve3) => {
1262
+ return new Promise((resolve4) => {
1249
1263
  execFile2(
1250
1264
  binPath,
1251
1265
  ["status", "--json"],
1252
1266
  { timeout: EXEC_TIMEOUT_MS2, encoding: "utf-8" },
1253
1267
  (error, stdout) => {
1254
1268
  if (error) {
1255
- resolve3(null);
1269
+ resolve4(null);
1256
1270
  return;
1257
1271
  }
1258
1272
  try {
1259
1273
  const result = JSON.parse(stdout);
1260
- resolve3(result);
1274
+ resolve4(result);
1261
1275
  } catch {
1262
- resolve3(null);
1276
+ resolve4(null);
1263
1277
  }
1264
1278
  }
1265
1279
  );
1266
1280
  });
1267
1281
  }
1268
1282
  function sleep(ms) {
1269
- return new Promise((resolve3) => {
1270
- setTimeout(resolve3, ms);
1283
+ return new Promise((resolve4) => {
1284
+ setTimeout(resolve4, ms);
1271
1285
  });
1272
1286
  }
1273
1287
  var RateLimiter = class {
@@ -2337,6 +2351,7 @@ function registerIndicatorTools() {
2337
2351
  return [
2338
2352
  {
2339
2353
  name: "market_get_indicator",
2354
+ title: "Get Technical Indicator",
2340
2355
  module: "market",
2341
2356
  description: "Get technical indicator values for an instrument. Common indicators: ma, ema, rsi, macd, bb (Bollinger), kdj, supertrend, ahr999. Call market_list_indicators first to see all valid names. No credentials required.",
2342
2357
  isWrite: false,
@@ -2410,6 +2425,7 @@ function registerIndicatorTools() {
2410
2425
  },
2411
2426
  {
2412
2427
  name: "market_list_indicators",
2428
+ title: "List Technical Indicators",
2413
2429
  module: "market",
2414
2430
  description: "List all supported technical indicator names and descriptions. Call this before market_get_indicator to discover valid indicator names. No credentials required.",
2415
2431
  isWrite: false,
@@ -2468,6 +2484,7 @@ function registerAccountTools() {
2468
2484
  return [
2469
2485
  {
2470
2486
  name: "account_get_balance",
2487
+ title: "Get Trading Account Balance",
2471
2488
  module: "account",
2472
2489
  description: "Get account balance for trading account. Returns balances for all currencies or a specific one.",
2473
2490
  isWrite: false,
@@ -2492,9 +2509,11 @@ function registerAccountTools() {
2492
2509
  },
2493
2510
  {
2494
2511
  name: "account_transfer",
2512
+ title: "Transfer Between Accounts",
2495
2513
  module: "account",
2496
2514
  description: "Transfer funds between accounts (trading, funding, etc.). [CAUTION] Moves real funds.",
2497
2515
  isWrite: true,
2516
+ destructiveHint: false,
2498
2517
  inputSchema: {
2499
2518
  type: "object",
2500
2519
  properties: {
@@ -2549,6 +2568,7 @@ function registerAccountTools() {
2549
2568
  },
2550
2569
  {
2551
2570
  name: "account_get_max_size",
2571
+ title: "Get Max Order Size",
2552
2572
  module: "account",
2553
2573
  description: "Get max buy/sell order size for a SWAP/FUTURES instrument given current balance and leverage. Useful before placing orders.",
2554
2574
  isWrite: false,
@@ -2596,6 +2616,7 @@ function registerAccountTools() {
2596
2616
  },
2597
2617
  {
2598
2618
  name: "account_get_asset_balance",
2619
+ title: "Get Funding Account Balance",
2599
2620
  module: "account",
2600
2621
  description: "Get funding account balance (asset account). Different from account_get_balance which queries the trading account. Optionally includes total asset valuation across all account types (trading, funding, earn, etc.).",
2601
2622
  isWrite: false,
@@ -2659,6 +2680,7 @@ function registerAccountTools() {
2659
2680
  },
2660
2681
  {
2661
2682
  name: "account_get_bills",
2683
+ title: "Get Account Bills",
2662
2684
  module: "account",
2663
2685
  description: "Get account ledger: fees paid, funding charges, realized PnL, transfers, etc. Default 20 records (last 7 days), max 100.",
2664
2686
  isWrite: false,
@@ -2725,6 +2747,7 @@ function registerAccountTools() {
2725
2747
  },
2726
2748
  {
2727
2749
  name: "account_get_positions_history",
2750
+ title: "Get Closed Positions History",
2728
2751
  module: "account",
2729
2752
  description: "Get closed position history for SWAP or FUTURES. Default 20 records, max 100.",
2730
2753
  isWrite: false,
@@ -2786,6 +2809,7 @@ function registerAccountTools() {
2786
2809
  },
2787
2810
  {
2788
2811
  name: "account_get_trade_fee",
2812
+ title: "Get Trade Fee Tier",
2789
2813
  module: "account",
2790
2814
  description: "Get maker/taker fee rates for the account. Useful to understand your fee tier before trading.",
2791
2815
  isWrite: false,
@@ -2818,6 +2842,7 @@ function registerAccountTools() {
2818
2842
  },
2819
2843
  {
2820
2844
  name: "account_get_config",
2845
+ title: "Get Account Configuration",
2821
2846
  module: "account",
2822
2847
  description: "Get account configuration: position mode (net vs hedge), account level, auto-loan settings, etc. Note: `settleCcy` is the current settlement currency for USDS-margined contracts. `settleCcyList` is the list of available settlement currencies to choose from. These fields only apply to USDS-margined contracts and can be ignored for standard USDT/coin-margined trading.",
2823
2848
  isWrite: false,
@@ -2836,6 +2861,7 @@ function registerAccountTools() {
2836
2861
  },
2837
2862
  {
2838
2863
  name: "account_get_max_withdrawal",
2864
+ title: "Get Max Withdrawable Amount",
2839
2865
  module: "account",
2840
2866
  description: "Get maximum withdrawable amount for a currency from the trading account. Useful before initiating a transfer or withdrawal.",
2841
2867
  isWrite: false,
@@ -2860,6 +2886,7 @@ function registerAccountTools() {
2860
2886
  },
2861
2887
  {
2862
2888
  name: "account_get_max_avail_size",
2889
+ title: "Get Max Available Position Size",
2863
2890
  module: "account",
2864
2891
  description: "Get maximum available size for opening or reducing a position. Different from account_get_max_size which calculates new order size.",
2865
2892
  isWrite: false,
@@ -2904,6 +2931,7 @@ function registerAccountTools() {
2904
2931
  },
2905
2932
  {
2906
2933
  name: "account_get_positions",
2934
+ title: "Get Current Positions",
2907
2935
  module: "account",
2908
2936
  description: "Get current open positions across all instrument types (MARGIN, SWAP, FUTURES, OPTION, EVENTS). Use swap_get_positions for SWAP/FUTURES-only queries.",
2909
2937
  isWrite: false,
@@ -2939,6 +2967,7 @@ function registerAccountTools() {
2939
2967
  },
2940
2968
  {
2941
2969
  name: "account_get_bills_archive",
2970
+ title: "Get Archived Account Bills",
2942
2971
  module: "account",
2943
2972
  description: "Get archived account ledger (bills older than 7 days, up to 3 months). Use account_get_bills for recent 7-day records. Default 20 records, max 100.",
2944
2973
  isWrite: false,
@@ -3005,9 +3034,11 @@ function registerAccountTools() {
3005
3034
  },
3006
3035
  {
3007
3036
  name: "account_set_position_mode",
3037
+ title: "Set Position Mode",
3008
3038
  module: "account",
3009
3039
  description: "Switch between net position mode and long/short hedge mode. net: one position per instrument (default). long_short_mode: separate long and short positions. [CAUTION] Requires no open positions or pending orders.",
3010
3040
  isWrite: true,
3041
+ idempotentHint: true,
3011
3042
  inputSchema: {
3012
3043
  type: "object",
3013
3044
  properties: {
@@ -3147,6 +3178,8 @@ function registerAlgoTradeTools() {
3147
3178
  return [
3148
3179
  {
3149
3180
  name: "swap_place_algo_order",
3181
+ title: "Perpetual Futures Place Algo Order",
3182
+ destructiveHint: false,
3150
3183
  module: "swap",
3151
3184
  description: "Place a SWAP/FUTURES algo order. [CAUTION] Executes real trades. conditional: single TP, single SL, or both on one order. oco: TP+SL simultaneously - first trigger cancels the other. move_order_stop: trailing stop (callbackRatio or callbackSpread). trigger: pending order activated when triggerPx is hit (provide triggerPx + orderPx). chase: smart-follow best bid/ask. iceberg: split large order into child orders at intervals. twap: time-weighted average price order splitting.",
3152
3185
  isWrite: true,
@@ -3295,6 +3328,8 @@ function registerAlgoTradeTools() {
3295
3328
  },
3296
3329
  {
3297
3330
  name: "swap_place_move_stop_order",
3331
+ title: "Perpetual Futures Place Move-Stop Order",
3332
+ destructiveHint: false,
3298
3333
  module: "swap",
3299
3334
  description: "[DEPRECATED] Use swap_place_algo_order with ordType='move_order_stop' instead. Place a SWAP/FUTURES trailing stop order. [CAUTION] Executes real trades. Specify callbackRatio (e.g. '0.01'=1%) or callbackSpread (fixed price distance), not both. Optionally set activePx so tracking starts once market reaches that price.",
3300
3335
  isWrite: true,
@@ -3372,6 +3407,8 @@ function registerAlgoTradeTools() {
3372
3407
  },
3373
3408
  {
3374
3409
  name: "swap_cancel_algo_orders",
3410
+ title: "Perpetual Futures Cancel Algo Orders",
3411
+ idempotentHint: true,
3375
3412
  module: "swap",
3376
3413
  description: "Cancel one or more pending SWAP/FUTURES algo orders (TP/SL). Accepts a list of {algoId, instId} objects.",
3377
3414
  isWrite: true,
@@ -3415,6 +3452,7 @@ function registerAlgoTradeTools() {
3415
3452
  },
3416
3453
  {
3417
3454
  name: "swap_get_algo_orders",
3455
+ title: "Perpetual Futures Get Algo Orders",
3418
3456
  module: "swap",
3419
3457
  description: "Query pending or completed SWAP/FUTURES algo orders (TP/SL, OCO, trailing stop).",
3420
3458
  isWrite: false,
@@ -3507,6 +3545,8 @@ function registerFuturesAlgoTools() {
3507
3545
  return [
3508
3546
  {
3509
3547
  name: "futures_place_algo_order",
3548
+ title: "Futures Place Algo Order",
3549
+ destructiveHint: false,
3510
3550
  module: "futures",
3511
3551
  description: "Place a FUTURES delivery algo order. [CAUTION] Executes real trades. conditional: single TP, single SL, or both on one order. oco: TP+SL simultaneously - first trigger cancels the other. move_order_stop: trailing stop (callbackRatio or callbackSpread). trigger: pending order activated when triggerPx is hit (provide triggerPx + orderPx). chase: smart-follow best bid/ask. iceberg: split large order into child orders at intervals. twap: time-weighted average price order splitting.",
3512
3552
  isWrite: true,
@@ -3655,6 +3695,8 @@ function registerFuturesAlgoTools() {
3655
3695
  },
3656
3696
  {
3657
3697
  name: "futures_place_move_stop_order",
3698
+ title: "Futures Place Move-Stop Order",
3699
+ destructiveHint: false,
3658
3700
  module: "futures",
3659
3701
  description: "[DEPRECATED] Use futures_place_algo_order with ordType='move_order_stop' instead. Place a FUTURES delivery trailing stop order. [CAUTION] Executes real trades.",
3660
3702
  isWrite: true,
@@ -3732,6 +3774,8 @@ function registerFuturesAlgoTools() {
3732
3774
  },
3733
3775
  {
3734
3776
  name: "futures_amend_algo_order",
3777
+ title: "Futures Amend Algo Order",
3778
+ idempotentHint: true,
3735
3779
  module: "futures",
3736
3780
  description: "Amend a pending FUTURES delivery algo order (modify TP/SL prices or size). Also covers TP/SL orders attached when placing the main order - look up algoId via futures_get_algo_orders first.",
3737
3781
  isWrite: true,
@@ -3768,6 +3812,8 @@ function registerFuturesAlgoTools() {
3768
3812
  },
3769
3813
  {
3770
3814
  name: "futures_cancel_algo_orders",
3815
+ title: "Futures Cancel Algo Orders",
3816
+ idempotentHint: true,
3771
3817
  module: "futures",
3772
3818
  description: "Cancel one or more pending FUTURES delivery algo orders (TP/SL). Accepts a list of {algoId, instId} objects.",
3773
3819
  isWrite: true,
@@ -3805,6 +3851,7 @@ function registerFuturesAlgoTools() {
3805
3851
  },
3806
3852
  {
3807
3853
  name: "futures_get_algo_orders",
3854
+ title: "Futures Get Algo Orders",
3808
3855
  module: "futures",
3809
3856
  description: "Query pending or completed FUTURES delivery algo orders (TP/SL, OCO, trailing stop).",
3810
3857
  isWrite: false,
@@ -3926,6 +3973,7 @@ function registerAuditTools() {
3926
3973
  {
3927
3974
  name: "trade_get_history",
3928
3975
  module: "account",
3976
+ title: "Get Tool-Call Audit Log",
3929
3977
  description: "Query local audit log of tool calls made through this MCP server. Returns recent operations with timestamps, duration, params, and results. Use to review what trades or queries were executed in this session or past sessions.",
3930
3978
  isWrite: false,
3931
3979
  inputSchema: {
@@ -4023,13 +4071,15 @@ async function downloadSkillZip(client, name, targetDir, format = "zip") {
4023
4071
  const filePath = safeWriteFile(targetDir, fileName, result.data);
4024
4072
  return filePath;
4025
4073
  }
4074
+ var ED25519_SPKI_HEADER = Buffer.from("302a300506032b6570032100", "hex");
4026
4075
  var DEFAULT_MAX_TOTAL_BYTES = 100 * 1024 * 1024;
4027
- var DEFAULT_REGISTRY_PATH = join6(homedir4(), ".okx", "skills", "registry.json");
4076
+ var DEFAULT_REGISTRY_PATH = join8(homedir4(), ".okx", "skills", "registry.json");
4028
4077
  function registerSkillsTools() {
4029
4078
  return [
4030
4079
  {
4031
4080
  name: "skills_get_categories",
4032
4081
  module: "skills",
4082
+ title: "Skills Marketplace List Categories",
4033
4083
  description: "List all available skill categories in OKX Skills Marketplace. Use the returned categoryId as input to skills_search for category filtering. Do NOT use for searching or downloading skills - use skills_search or skills_download.",
4034
4084
  inputSchema: {
4035
4085
  type: "object",
@@ -4042,6 +4092,7 @@ function registerSkillsTools() {
4042
4092
  {
4043
4093
  name: "skills_search",
4044
4094
  module: "skills",
4095
+ title: "Skills Marketplace Search",
4045
4096
  description: "Search for skills in OKX Skills Marketplace by keyword or category. To get valid category IDs, call skills_get_categories first. Returns skill names for use with skills_download. Do NOT use for downloading - use skills_download.",
4046
4097
  inputSchema: {
4047
4098
  type: "object",
@@ -4071,6 +4122,7 @@ function registerSkillsTools() {
4071
4122
  {
4072
4123
  name: "skills_download",
4073
4124
  module: "skills",
4125
+ title: "Skills Marketplace Download",
4074
4126
  description: "Download a skill package from OKX Skills Marketplace to a local directory. Always call skills_search first to confirm the skill name exists. Downloads the latest approved version. NOTE: Downloads third-party developer content - does NOT install to agents. For full installation use CLI: okx skill add <name>. Use when the user wants to inspect or manually install a skill package.",
4075
4127
  inputSchema: {
4076
4128
  type: "object",
@@ -4093,6 +4145,8 @@ function registerSkillsTools() {
4093
4145
  additionalProperties: false
4094
4146
  },
4095
4147
  isWrite: true,
4148
+ destructiveHint: false,
4149
+ idempotentHint: true,
4096
4150
  handler: handleDownload
4097
4151
  }
4098
4152
  ];
@@ -4156,6 +4210,7 @@ function registerGridTools() {
4156
4210
  return [
4157
4211
  {
4158
4212
  name: "grid_get_orders",
4213
+ title: "Grid Bot List Orders",
4159
4214
  module: "bot.grid",
4160
4215
  description: "List grid bots. status='active' for running; 'history' for stopped.",
4161
4216
  isWrite: false,
@@ -4202,6 +4257,7 @@ function registerGridTools() {
4202
4257
  },
4203
4258
  {
4204
4259
  name: "grid_get_order_details",
4260
+ title: "Grid Bot Get Detail",
4205
4261
  module: "bot.grid",
4206
4262
  description: "Get grid bot detail by algo ID. Returns config, status, PnL, and position.",
4207
4263
  isWrite: false,
@@ -4232,6 +4288,7 @@ function registerGridTools() {
4232
4288
  },
4233
4289
  {
4234
4290
  name: "grid_get_sub_orders",
4291
+ title: "Grid Bot Get Sub-Orders",
4235
4292
  module: "bot.grid",
4236
4293
  description: "Query sub-orders (grid trades) of a bot. type='filled' for executed; 'live' for pending.",
4237
4294
  isWrite: false,
@@ -4276,9 +4333,11 @@ function registerGridTools() {
4276
4333
  },
4277
4334
  {
4278
4335
  name: "grid_create_order",
4336
+ title: "Grid Bot Create",
4279
4337
  module: "bot.grid",
4280
4338
  description: "Create grid bot (spot, USDT-margined, or coin-margined contract). [CAUTION] Locks funds. Spot: quoteSz|baseSz. Contract: direction+lever+sz.",
4281
4339
  isWrite: true,
4340
+ destructiveHint: false,
4282
4341
  inputSchema: {
4283
4342
  type: "object",
4284
4343
  properties: {
@@ -4351,7 +4410,9 @@ function registerGridTools() {
4351
4410
  },
4352
4411
  {
4353
4412
  name: "grid_amend_order",
4413
+ title: "Grid Bot Amend",
4354
4414
  module: "bot.grid",
4415
+ idempotentHint: true,
4355
4416
  description: "Amend a running grid bot. [CAUTION] Modifies a running bot. Use grid_list_orders to confirm the bot is running and obtain the algoId before calling.\nSupports two modes, which can be combined in a single call:\n\u2022 Price-range mode (maxPx+minPx+gridNum): change upper/lower price boundary and grid count. Contract grid: if new range requires more margin, pass topUpAmt; omit to auto-use the minimum required. Spot grid: topUpAmt is not supported.\n\u2022 TP/SL mode (instId + any of tpTriggerPx/slTriggerPx/tpRatio/slRatio): update take-profit and/or stop-loss. Pass '-1' to explicitly clear an existing TP or SL. tpTriggerPx/slTriggerPx are absolute prices; tpRatio/slRatio are profit ratios (e.g. '0.1' = 10%).\nWhen both sets of params are provided, both APIs are called sequentially.\nDo NOT use to create a new grid bot - use grid_create_order instead. Do NOT use to stop a grid bot - use grid_stop_order instead.",
4356
4417
  isWrite: true,
4357
4418
  inputSchema: {
@@ -4474,7 +4535,9 @@ function registerGridTools() {
4474
4535
  },
4475
4536
  {
4476
4537
  name: "grid_stop_order",
4538
+ title: "Grid Bot Stop",
4477
4539
  module: "bot.grid",
4540
+ idempotentHint: true,
4478
4541
  description: "[CAUTION] Stop a grid bot or close its remaining open position \u2014 real trades, irreversible. Workflow: (1) If the user has not specified which bot to stop, call grid_get_orders first and ask the user to confirm which bot before proceeding. (2) Call grid_get_order_details to check the current 'state' field. (3) If state='running' \u2192 call this tool: stopType='1' (default, clean exit) \u2014 spot grid sells all base assets back to quote; contract grid market-closes all positions. stopType='2' (keep assets) \u2014 spot grid keeps base assets as-is; contract grid cancels grid orders but leaves the position open. (4) If state='no_close_position' \u2192 call this tool with stopType='1' to close the remaining open position.",
4479
4542
  isWrite: true,
4480
4543
  inputSchema: {
@@ -4574,9 +4637,11 @@ function registerDcaTools() {
4574
4637
  return [
4575
4638
  {
4576
4639
  name: "dca_create_order",
4640
+ title: "Martingale Bot Create",
4577
4641
  module: "bot.dca",
4578
4642
  description: "Create a DCA (Martingale) bot. [CAUTION] Real trades. contract_dca requires lever; spot_dca must be long. If maxSafetyOrds>0: need safetyOrdAmt, pxSteps.",
4579
4643
  isWrite: true,
4644
+ destructiveHint: false,
4580
4645
  inputSchema: {
4581
4646
  type: "object",
4582
4647
  properties: {
@@ -4652,7 +4717,9 @@ function registerDcaTools() {
4652
4717
  },
4653
4718
  {
4654
4719
  name: "dca_stop_order",
4720
+ title: "Martingale Bot Stop",
4655
4721
  module: "bot.dca",
4722
+ idempotentHint: true,
4656
4723
  description: "[CAUTION] Stop a DCA bot or close its remaining open position \u2014 real trades, irreversible. Workflow: (1) If the user has not specified which bot to stop, call dca_get_orders first and ask the user to confirm which bot before proceeding. (2) Call dca_get_order_details to check the current 'state' field. (3) If state='running' \u2192 call this tool. (4) If state='no_close_position' \u2192 call this tool with stopType='1' to close the remaining open position. spot_dca requires stopType: 1=sell all tokens, 2=keep tokens.",
4657
4724
  isWrite: true,
4658
4725
  inputSchema: {
@@ -4685,6 +4752,7 @@ function registerDcaTools() {
4685
4752
  },
4686
4753
  {
4687
4754
  name: "dca_get_orders",
4755
+ title: "Martingale Bot List Orders",
4688
4756
  module: "bot.dca",
4689
4757
  description: "List DCA bots. Default: active (running). Use status=history for stopped.",
4690
4758
  isWrite: false,
@@ -4723,6 +4791,7 @@ function registerDcaTools() {
4723
4791
  },
4724
4792
  {
4725
4793
  name: "dca_get_order_details",
4794
+ title: "Martingale Bot Get Detail",
4726
4795
  module: "bot.dca",
4727
4796
  description: "Get DCA bot position details (avgPx, upl, liqPx, etc).",
4728
4797
  isWrite: false,
@@ -4748,6 +4817,7 @@ function registerDcaTools() {
4748
4817
  },
4749
4818
  {
4750
4819
  name: "dca_get_sub_orders",
4820
+ title: "Martingale Bot Get Sub-Orders",
4751
4821
  module: "bot.dca",
4752
4822
  description: "Get DCA cycles or orders in a cycle. Omit cycleId=cycle list; with cycleId=orders.",
4753
4823
  isWrite: false,
@@ -4807,8 +4877,9 @@ function registerEarnTools() {
4807
4877
  return [
4808
4878
  {
4809
4879
  name: "earn_get_savings_balance",
4880
+ title: "Get Simple Earn Balance",
4810
4881
  module: "earn.savings",
4811
- description: "Get Simple Earn (savings/flexible earn) balance. Returns current holdings for all currencies or a specific one. To show market rates alongside balance (\u5E02\u573A\u5747\u5229\u7387), call earn_get_lending_rate_history. earn_get_lending_rate_history also returns fixed-term (\u5B9A\u671F) product offers, so one call gives a complete view of both flexible and fixed options. Do NOT use for fixed-term (\u5B9A\u671F) order queries - use earn_get_fixed_order_list instead.",
4882
+ description: "Get Simple Earn (savings/flexible earn) balance. Returns current holdings for all currencies or a specific one. To show market rates alongside balance, call earn_get_lending_rate_history. To browse available fixed-term products with quota info, use earn_get_fixed_earn_products. Do NOT use for fixed-term order queries \u2014 use earn_get_fixed_order_list instead.",
4812
4883
  isWrite: false,
4813
4884
  inputSchema: {
4814
4885
  type: "object",
@@ -4831,6 +4902,7 @@ function registerEarnTools() {
4831
4902
  },
4832
4903
  {
4833
4904
  name: "earn_get_fixed_order_list",
4905
+ title: "Get Fixed-Term Earn Orders",
4834
4906
  module: "earn.savings",
4835
4907
  description: "Get Simple Earn Fixed (\u5B9A\u671F\u8D5A\u5E01) lending order list. Returns orders sorted by creation time descending. Use this to check status of fixed-term lending orders (pending/earning/expired/settled/cancelled). Do NOT use for flexible earn balance - use earn_get_savings_balance instead. If the result is empty, do NOT display any fixed-term section in the output.",
4836
4908
  isWrite: false,
@@ -4868,9 +4940,11 @@ function registerEarnTools() {
4868
4940
  },
4869
4941
  {
4870
4942
  name: "earn_savings_purchase",
4943
+ title: "Subscribe Simple Earn",
4871
4944
  module: "earn.savings",
4872
4945
  description: "Purchase Simple Earn (savings/flexible earn). [CAUTION] Moves real funds into earn product.",
4873
4946
  isWrite: true,
4947
+ destructiveHint: false,
4874
4948
  inputSchema: {
4875
4949
  type: "object",
4876
4950
  properties: {
@@ -4906,9 +4980,11 @@ function registerEarnTools() {
4906
4980
  },
4907
4981
  {
4908
4982
  name: "earn_savings_redeem",
4983
+ title: "Redeem Simple Earn",
4909
4984
  module: "earn.savings",
4910
4985
  description: "Redeem Simple Earn (savings/flexible earn). [CAUTION] Withdraws funds from earn product.",
4911
4986
  isWrite: true,
4987
+ destructiveHint: false,
4912
4988
  inputSchema: {
4913
4989
  type: "object",
4914
4990
  properties: {
@@ -4939,9 +5015,11 @@ function registerEarnTools() {
4939
5015
  },
4940
5016
  {
4941
5017
  name: "earn_set_lending_rate",
5018
+ title: "Set Lending Rate",
4942
5019
  module: "earn.savings",
4943
5020
  description: "Set lending rate for Simple Earn. [CAUTION] Changes your lending rate preference.",
4944
5021
  isWrite: true,
5022
+ idempotentHint: true,
4945
5023
  inputSchema: {
4946
5024
  type: "object",
4947
5025
  properties: {
@@ -4971,6 +5049,7 @@ function registerEarnTools() {
4971
5049
  },
4972
5050
  {
4973
5051
  name: "earn_get_lending_history",
5052
+ title: "Get Lending History",
4974
5053
  module: "earn.savings",
4975
5054
  description: "Get personal lending records for Simple Earn (your own lending history). NOT for market rate queries. Returns your lending records with amount, rate, and earnings data.",
4976
5055
  isWrite: false,
@@ -5012,9 +5091,11 @@ function registerEarnTools() {
5012
5091
  },
5013
5092
  {
5014
5093
  name: "earn_fixed_purchase",
5094
+ title: "Subscribe Fixed-Term Earn",
5015
5095
  module: "earn.savings",
5016
- description: "Purchase Simple Earn Fixed (\u5B9A\u671F) product, two-step flow. First call (confirm omitted or false): returns purchase preview with product details and risk warning. Preview offer fields: lendQuota = remaining quota (\u5269\u4F59\u989D\u5EA6), soldOut = whether product is sold out (lendQuota is 0). YOU MUST display the 'warning' field from the preview response to the user VERBATIM before asking for confirmation - do NOT omit or summarize it. Second call (confirm=true): executes the purchase. Only proceed after the user explicitly confirms. IMPORTANT: Orders in 'pending' (\u5339\u914D\u4E2D) state can still be cancelled via earn_fixed_redeem; once the status changes to 'earning' (\u8D5A\u5E01\u4E2D), funds are LOCKED until maturity - no early redemption allowed.",
5096
+ description: "Purchase Simple Earn Fixed (\u5B9A\u671F) product, two-step flow. First call (confirm omitted or false): returns purchase preview with product details and risk warning. Preview offer fields: lendQuota = remaining quota, soldOut = whether product is sold out (lendQuota is 0). YOU MUST display the 'warning' field from the preview response to the user VERBATIM before asking for confirmation \u2014 do NOT omit or summarize it. Second call (confirm=true): executes the purchase. Only proceed after the user explicitly confirms. IMPORTANT: Orders in 'pending' (\u5339\u914D\u4E2D) state can still be cancelled via earn_fixed_redeem; once the status changes to 'earning' (\u8D5A\u5E01\u4E2D), funds are LOCKED until maturity - no early redemption allowed.",
5017
5097
  isWrite: true,
5098
+ destructiveHint: false,
5018
5099
  inputSchema: {
5019
5100
  type: "object",
5020
5101
  properties: {
@@ -5086,9 +5167,11 @@ function registerEarnTools() {
5086
5167
  },
5087
5168
  {
5088
5169
  name: "earn_fixed_redeem",
5170
+ title: "Redeem Fixed-Term Earn",
5089
5171
  module: "earn.savings",
5090
5172
  description: "Redeem Simple Earn Fixed (\u5B9A\u671F\u8D5A\u5E01) order. [CAUTION] Redeems a fixed-term lending order. Always redeems the full order amount. Only orders in 'pending' (\u5339\u914D\u4E2D) state can be redeemed - orders in 'earning' state are locked until maturity and cannot be redeemed early. Do NOT use for flexible earn redemption - use earn_savings_redeem instead.",
5091
5173
  isWrite: true,
5174
+ destructiveHint: false,
5092
5175
  inputSchema: {
5093
5176
  type: "object",
5094
5177
  properties: {
@@ -5114,8 +5197,9 @@ function registerEarnTools() {
5114
5197
  },
5115
5198
  {
5116
5199
  name: "earn_get_lending_rate_history",
5200
+ title: "Get Lending Rates & Offers",
5117
5201
  module: "earn.savings",
5118
- description: "Query Simple Earn lending rates and fixed-term offers. Use this tool when the user asks about Simple Earn products, current or historical lending rates, or when displaying savings balance with market rate context (\u5E02\u573A\u5747\u5229\u7387). Returns lending rate history (lendingRate field, newest-first) AND available fixed-term (\u5B9A\u671F) offers with APR, term, min amount, and quota - one call gives a complete view of both flexible and fixed options. In fixedOffers: lendQuota = remaining quota (\u5269\u4F59\u989D\u5EA6), soldOut = whether product is sold out (lendQuota is 0). To get current flexible APY: use limit=1 and read lendingRate.",
5202
+ description: "Query Simple Earn lending rates and fixed-term offers. Use this tool when the user asks about Simple Earn products, current or historical lending rates, or when displaying savings balance with market rate context (\u5E02\u573A\u5747\u5229\u7387). Returns lending rate history (lendingRate field, newest-first) AND available fixed-term (\u5B9A\u671F) offers with APR, term, min amount, and quota \u2014 one call gives a complete view of both flexible and fixed options. In fixedOffers: lendQuota = remaining quota, soldOut = whether product is sold out (lendQuota is 0). For dedicated fixed-term product queries, use earn_get_fixed_earn_products. To get current flexible APY: use limit=1 and read lendingRate.",
5119
5203
  isWrite: false,
5120
5204
  inputSchema: {
5121
5205
  type: "object",
@@ -5174,6 +5258,37 @@ function registerEarnTools() {
5174
5258
  fixedOffers
5175
5259
  };
5176
5260
  }
5261
+ },
5262
+ {
5263
+ name: "earn_get_fixed_earn_products",
5264
+ title: "Get Fixed-Term Earn Products",
5265
+ module: "earn.savings",
5266
+ description: "Query available Simple Earn Fixed-term products. Returns fixed-term offers with APR, term, min investment, and remaining quota. Use to check available products and quota before purchasing. Do NOT use for querying your own orders \u2014 use earn_get_fixed_order_list instead. Do NOT use just for current flexible APY -- use earn_get_lending_rate_history with limit=1 instead.",
5267
+ isWrite: false,
5268
+ inputSchema: {
5269
+ type: "object",
5270
+ properties: {
5271
+ ccy: {
5272
+ type: "string",
5273
+ description: "e.g. USDT. Omit for all currencies."
5274
+ }
5275
+ }
5276
+ },
5277
+ handler: async (rawArgs, context) => {
5278
+ const args = asRecord(rawArgs);
5279
+ const response = await context.client.privateGet(
5280
+ "/api/v5/finance/simple-earn-fixed/offers",
5281
+ compactObject({ ccy: readString(args, "ccy") }),
5282
+ privateRateLimit("earn_get_fixed_earn_products", 2)
5283
+ );
5284
+ const result = normalizeResponse(response);
5285
+ const allOffers = Array.isArray(result["data"]) ? result["data"] : [];
5286
+ result["data"] = allOffers.map(({ borrowingOrderQuota: _, ...rest }) => ({
5287
+ ...rest,
5288
+ soldOut: rest["lendQuota"] === "0"
5289
+ }));
5290
+ return result;
5291
+ }
5177
5292
  }
5178
5293
  ];
5179
5294
  }
@@ -5184,6 +5299,7 @@ function registerOnchainEarnTools() {
5184
5299
  // -------------------------------------------------------------------------
5185
5300
  {
5186
5301
  name: "onchain_earn_get_offers",
5302
+ title: "On-chain Earn List Offers",
5187
5303
  module: "earn.onchain",
5188
5304
  description: "List staking/DeFi products with APY, terms, and limits. Always show protocol name (protocol field) and earnings currency (earningData[].ccy) when presenting results.",
5189
5305
  isWrite: false,
@@ -5223,9 +5339,11 @@ function registerOnchainEarnTools() {
5223
5339
  // -------------------------------------------------------------------------
5224
5340
  {
5225
5341
  name: "onchain_earn_purchase",
5342
+ title: "On-chain Earn Subscribe",
5226
5343
  module: "earn.onchain",
5227
5344
  description: "Invest in a staking/DeFi product. [CAUTION] Moves real funds.",
5228
5345
  isWrite: true,
5346
+ destructiveHint: false,
5229
5347
  inputSchema: {
5230
5348
  type: "object",
5231
5349
  properties: {
@@ -5276,9 +5394,11 @@ function registerOnchainEarnTools() {
5276
5394
  // -------------------------------------------------------------------------
5277
5395
  {
5278
5396
  name: "onchain_earn_redeem",
5397
+ title: "On-chain Earn Redeem",
5279
5398
  module: "earn.onchain",
5280
5399
  description: "Redeem a staking/DeFi investment. [CAUTION] Some products have lock periods, early redemption may incur penalties.",
5281
5400
  isWrite: true,
5401
+ destructiveHint: false,
5282
5402
  inputSchema: {
5283
5403
  type: "object",
5284
5404
  properties: {
@@ -5316,9 +5436,11 @@ function registerOnchainEarnTools() {
5316
5436
  // -------------------------------------------------------------------------
5317
5437
  {
5318
5438
  name: "onchain_earn_cancel",
5439
+ title: "On-chain Earn Cancel Order",
5319
5440
  module: "earn.onchain",
5320
5441
  description: "Cancel a pending staking/DeFi purchase order. [CAUTION]",
5321
5442
  isWrite: true,
5443
+ idempotentHint: true,
5322
5444
  inputSchema: {
5323
5445
  type: "object",
5324
5446
  properties: {
@@ -5351,6 +5473,7 @@ function registerOnchainEarnTools() {
5351
5473
  // -------------------------------------------------------------------------
5352
5474
  {
5353
5475
  name: "onchain_earn_get_active_orders",
5476
+ title: "On-chain Earn Active Orders",
5354
5477
  module: "earn.onchain",
5355
5478
  description: "List current active staking/DeFi investments.",
5356
5479
  isWrite: false,
@@ -5395,6 +5518,7 @@ function registerOnchainEarnTools() {
5395
5518
  // -------------------------------------------------------------------------
5396
5519
  {
5397
5520
  name: "onchain_earn_get_order_history",
5521
+ title: "On-chain Earn Order History",
5398
5522
  module: "earn.onchain",
5399
5523
  description: "List past staking/DeFi orders including redeemed ones.",
5400
5524
  isWrite: false,
@@ -5493,6 +5617,7 @@ function registerDcdTools() {
5493
5617
  return [
5494
5618
  {
5495
5619
  name: "dcd_get_currency_pairs",
5620
+ title: "Dual Investment List Currency Pairs",
5496
5621
  module: "earn.dcd",
5497
5622
  description: "Get available DCD currency pairs.",
5498
5623
  isWrite: false,
@@ -5510,6 +5635,7 @@ function registerDcdTools() {
5510
5635
  },
5511
5636
  {
5512
5637
  name: "dcd_get_products",
5638
+ title: "Dual Investment List Products",
5513
5639
  module: "earn.dcd",
5514
5640
  description: "Get DCD products with yield and quota info. Yields in response are decimal fractions, not percentages.",
5515
5641
  isWrite: false,
@@ -5540,6 +5666,7 @@ function registerDcdTools() {
5540
5666
  },
5541
5667
  {
5542
5668
  name: "dcd_get_order_state",
5669
+ title: "Dual Investment Get Order State",
5543
5670
  module: "earn.dcd",
5544
5671
  description: "Check DCD order state after subscription (returns ordId + state only). For full order details (productId, strike, yield, settlement info), use dcd_get_orders instead.",
5545
5672
  isWrite: false,
@@ -5564,6 +5691,7 @@ function registerDcdTools() {
5564
5691
  },
5565
5692
  {
5566
5693
  name: "dcd_get_orders",
5694
+ title: "Dual Investment Get Order History",
5567
5695
  module: "earn.dcd",
5568
5696
  description: "Get DCD order history. Yields in response are decimal fractions, not percentages.",
5569
5697
  isWrite: false,
@@ -5608,9 +5736,11 @@ function registerDcdTools() {
5608
5736
  },
5609
5737
  {
5610
5738
  name: "dcd_subscribe",
5739
+ title: "Dual Investment Subscribe",
5611
5740
  module: "earn.dcd",
5612
5741
  description: "Subscribe to a DCD product: get quote and execute atomically. Confirm product, amount, and currency with user before calling. Optional minAnnualizedYield rejects the order if quote yield falls below threshold. Returns order result with quote snapshot (minAnnualizedYield is in percent; response yields are decimal fractions).",
5613
5742
  isWrite: true,
5743
+ destructiveHint: false,
5614
5744
  inputSchema: {
5615
5745
  type: "object",
5616
5746
  properties: {
@@ -5693,9 +5823,11 @@ function registerDcdTools() {
5693
5823
  },
5694
5824
  {
5695
5825
  name: "dcd_redeem",
5826
+ title: "Dual Investment Redeem",
5696
5827
  module: "earn.dcd",
5697
5828
  description: "Early redemption of a DCD order, two-step flow. First call (no quoteId): returns redemption quote for user confirmation. Second call (with quoteId): executes redemption. If the quote expired, auto-refreshes and executes; response includes autoRefreshedQuote: true.",
5698
5829
  isWrite: true,
5830
+ destructiveHint: false,
5699
5831
  inputSchema: {
5700
5832
  type: "object",
5701
5833
  properties: {
@@ -5770,9 +5902,11 @@ function registerAutoEarnTools() {
5770
5902
  return [
5771
5903
  {
5772
5904
  name: "earn_auto_set",
5905
+ title: "Set Auto-Earn Configuration",
5773
5906
  module: "earn.autoearn",
5774
5907
  description: "Enable or disable auto-earn for a currency. earnType='0' for auto-lend+stake (most currencies); earnType='1' for USDG earn (USDG, BUIDL). Use account_get_balance first: if autoLendStatus or autoStakingStatus != 'unsupported', use earnType='0'; for USDG/BUIDL use earnType='1'. [CAUTION] Cannot disable within 24h of enabling.",
5775
5908
  isWrite: true,
5909
+ idempotentHint: true,
5776
5910
  inputSchema: {
5777
5911
  type: "object",
5778
5912
  properties: {
@@ -5822,6 +5956,7 @@ function registerFlashEarnTools() {
5822
5956
  return [
5823
5957
  {
5824
5958
  name: "earn_get_flash_earn_projects",
5959
+ title: "Flash Earn List Projects",
5825
5960
  module: "earn.flash",
5826
5961
  description: "Get Flash Earn projects. Use this to browse upcoming or in-progress Flash Earn opportunities. Do NOT use for purchase or redeem actions - Flash Earn is query-only in this module.",
5827
5962
  isWrite: false,
@@ -6244,6 +6379,7 @@ function registerEventContractTools() {
6244
6379
  // -----------------------------------------------------------------------
6245
6380
  {
6246
6381
  name: "event_browse",
6382
+ title: "Event Contracts Browse Active",
6247
6383
  module: "event",
6248
6384
  description: "Browse currently active (in-progress) event contracts. Call when user asks what event contracts are available to trade. Returns only in-progress contracts (floorStrike set). If a live quote field px is present, it is the event contract price (0.01-0.99), not the underlying asset price; it reflects the market-implied probability when actively trading. Grouped by settlement type and underlying. Do NOT use for querying contracts within a specific series - use event_get_markets with seriesId instead.",
6249
6385
  isWrite: false,
@@ -6284,6 +6420,7 @@ function registerEventContractTools() {
6284
6420
  },
6285
6421
  {
6286
6422
  name: "event_get_series",
6423
+ title: "Event Contracts List Series",
6287
6424
  module: "event",
6288
6425
  description: "List event contract series. Returns all available series with settlement type and underlying. Use event_browse to see currently active contracts.",
6289
6426
  isWrite: false,
@@ -6308,6 +6445,7 @@ function registerEventContractTools() {
6308
6445
  },
6309
6446
  {
6310
6447
  name: "event_get_events",
6448
+ title: "Event Contracts List Events",
6311
6449
  module: "event",
6312
6450
  description: "List expiry periods within a series. state: preopen|live|settling|expired. expTime is pre-formatted UTC+8.",
6313
6451
  isWrite: false,
@@ -6363,6 +6501,7 @@ function registerEventContractTools() {
6363
6501
  },
6364
6502
  {
6365
6503
  name: "event_get_markets",
6504
+ title: "Event Contracts List Markets",
6366
6505
  module: "event",
6367
6506
  description: "List tradeable contracts within a series. state=live for active contracts, state=expired for settlement results. floorStrike=strike price; px (when present) is the event contract price (0.01-0.99), not the underlying asset price - reflects the market-implied probability when actively trading; outcome pre-translated (pending/YES/NO/UP/DOWN); timestamps UTC+8. Do NOT use for discovering what series are available across all underlyings - use event_browse instead.",
6368
6507
  isWrite: false,
@@ -6444,6 +6583,7 @@ function registerEventContractTools() {
6444
6583
  },
6445
6584
  {
6446
6585
  name: "event_get_orders",
6586
+ title: "Event Contracts Get Orders",
6447
6587
  module: "event",
6448
6588
  description: "Query event contract orders (open, 7d history, or 3-month archive). outcome pre-translated (YES/NO/UP/DOWN). Do NOT use for trade executions - use event_get_fills for fill records and settlement outcomes.",
6449
6589
  isWrite: false,
@@ -6502,6 +6642,7 @@ function registerEventContractTools() {
6502
6642
  },
6503
6643
  {
6504
6644
  name: "event_get_fills",
6645
+ title: "Event Contracts Get Fills",
6505
6646
  module: "event",
6506
6647
  description: "Get event contract fill history (trade executions and settlement payouts). archive=true for up to 3mo, false (default) for last 3d. outcome pre-translated (YES/NO/UP/DOWN). Each record includes a 'type' field: 'fill' (opening trade) or 'settlement' (expiry payout with settlementResult win/loss and pnl). Do NOT use for order status - use event_get_orders instead.",
6507
6648
  isWrite: false,
@@ -6549,6 +6690,8 @@ function registerEventContractTools() {
6549
6690
  // -----------------------------------------------------------------------
6550
6691
  {
6551
6692
  name: "event_place_order",
6693
+ title: "Event Contracts Place Order",
6694
+ destructiveHint: false,
6552
6695
  module: "event",
6553
6696
  description: `Place an event contract order. [CAUTION] Places a real order. Before placing, call event_get_markets(seriesId, state=live) to obtain the instId of the target contract.
6554
6697
  - outcome: UP/YES (bet price goes up/condition met) or DOWN/NO (bet price goes down/condition not met)
@@ -6624,6 +6767,8 @@ function registerEventContractTools() {
6624
6767
  },
6625
6768
  {
6626
6769
  name: "event_amend_order",
6770
+ title: "Event Contracts Amend Order",
6771
+ idempotentHint: true,
6627
6772
  module: "event",
6628
6773
  description: "Amend a pending event contract order (change price or size). [CAUTION] Modifies a real order. Before amending, call event_get_orders(status=open) to obtain the ordId and confirm the order is still pending. Only limit/post_only orders can be amended.",
6629
6774
  isWrite: true,
@@ -6655,6 +6800,8 @@ function registerEventContractTools() {
6655
6800
  },
6656
6801
  {
6657
6802
  name: "event_cancel_order",
6803
+ title: "Event Contracts Cancel Order",
6804
+ idempotentHint: true,
6658
6805
  module: "event",
6659
6806
  description: "Cancel a pending event contract order. [CAUTION] Cancels a real order. Before cancelling, call event_get_orders(status=open) to obtain the ordId and confirm the order is still pending. instId must be the full event contract instrument ID (e.g. BTC-ABOVE-DAILY-260224-1600-69700), NOT a spot trading pair.",
6660
6807
  isWrite: true,
@@ -7063,6 +7210,7 @@ function registerSmartmoneyTools() {
7063
7210
  /* ---------- T1. Top traders (leaderboard rank) ---------- */
7064
7211
  {
7065
7212
  name: "smartmoney_get_traders_by_filter",
7213
+ title: "Smart Money Leaderboard",
7066
7214
  module: "smartmoney",
7067
7215
  description: "Leaderboard ranking of OKX smart-money traders, filtered by pool conditions and ranked by `sortBy`. Use when: discovering top performers by criteria (PnL / win-rate / drawdown / AUM). See also: `smartmoney_get_performance_by_trader` (lookup by ID), `smartmoney_search_trader` (lookup by nickname). Note: `updateTime` is 12-digit `yyyyMMddHHmm` UTC+8, different from signal tools' 10-digit UTC `asOfTime`/`dataVersion` - do not cross-pass.",
7068
7216
  isWrite: false,
@@ -7129,6 +7277,7 @@ function registerSmartmoneyTools() {
7129
7277
  /* ---------- T2. Trader performance (by authorIds) ---------- */
7130
7278
  {
7131
7279
  name: "smartmoney_get_performance_by_trader",
7280
+ title: "Smart Money Trader Performance",
7132
7281
  module: "smartmoney",
7133
7282
  description: "PnL / win-rate / drawdown profile for one or more traders looked up by `authorIds`. Use when: caller already has trader IDs and needs their performance metrics. See also: `smartmoney_search_trader` (resolve nickname -> authorId), `smartmoney_get_traders_by_filter` (criteria-based discovery). Note: response `updateTime` is 12-digit `yyyyMMddHHmm` UTC+8 - do not pass to signal-side tools' `asOfTime` (10-digit UTC).",
7134
7283
  isWrite: false,
@@ -7199,6 +7348,7 @@ function registerSmartmoneyTools() {
7199
7348
  /* ---------- T3. Trader current positions ---------- */
7200
7349
  {
7201
7350
  name: "smartmoney_get_trader_positions",
7351
+ title: "Smart Money Trader Current Positions",
7202
7352
  module: "smartmoney",
7203
7353
  description: "Currently-open positions held by a single trader (direction, size, leverage, entry, conviction). Use when: inspecting what a top trader is holding RIGHT NOW. See also: `smartmoney_get_trader_positions_history` (closed positions), `smartmoney_search_trader` (nickname -> authorId), `smartmoney_get_traders_by_filter` (discover trader).",
7204
7354
  isWrite: false,
@@ -7280,6 +7430,7 @@ function registerSmartmoneyTools() {
7280
7430
  /* ---------- T4. Trader closed-position history ---------- */
7281
7431
  {
7282
7432
  name: "smartmoney_get_trader_positions_history",
7433
+ title: "Smart Money Trader Position History",
7283
7434
  module: "smartmoney",
7284
7435
  description: "Closed-position history of a single trader, paginated by `posId` cursor. Use when: studying realized PnL pattern, holding duration, win/loss streaks, or how positions ended (closed vs liquidated). See also: `smartmoney_get_trader_positions` (currently-open), `smartmoney_search_trader` (nickname -> authorId), `smartmoney_get_traders_by_filter` (discover trader).",
7285
7436
  isWrite: false,
@@ -7417,6 +7568,7 @@ function registerSmartmoneyTools() {
7417
7568
  /* ---------- T5. Trader order history ---------- */
7418
7569
  {
7419
7570
  name: "smartmoney_get_trader_orders_history",
7571
+ title: "Smart Money Trader Order History",
7420
7572
  module: "smartmoney",
7421
7573
  description: "Recent orders/fills placed by a single trader (direction, size, price, leverage), paginated by `ordId` cursor. Aligned with the cross-module `*_get_orders` family. Use when: tracking a top trader's latest trade activity. See also: `smartmoney_search_trader` (nickname -> authorId), `smartmoney_get_traders_by_filter` (discover trader).",
7422
7574
  isWrite: false,
@@ -7535,6 +7687,7 @@ function registerSmartmoneyTools() {
7535
7687
  /* ---------- T6. Search top traders by nickname keyword ---------- */
7536
7688
  {
7537
7689
  name: "smartmoney_search_trader",
7690
+ title: "Search Smart Money Top Traders",
7538
7691
  module: "smartmoney",
7539
7692
  description: "Search Top Traders by nickname keyword, ranked by OKX-platform follower count DESC. Returns up to 10 matches; intersects KOL full-text recall with the Top Trader set. Use when: resolving a nickname or partial name to `authorId`(s) before calling other `smartmoney_get_trader_*` tools. See also: `smartmoney_get_traders_by_filter` (discover top performers by criteria), `smartmoney_get_performance_by_trader` (lookup by known authorId).",
7540
7693
  isWrite: false,
@@ -7585,6 +7738,7 @@ function registerSmartmoneyTools() {
7585
7738
  /* ---------- S1. Signal overview by filter (multi-asset, tier-filtered pool) ---------- */
7586
7739
  {
7587
7740
  name: "smartmoney_get_signal_overview_by_filter",
7741
+ title: "Smart Money Consensus Signals by Filter",
7588
7742
  module: "smartmoney",
7589
7743
  description: "Multi-asset smart-money consensus signals (long/short ratio, weighted entry, capital flow, deltas vs 1h/24h/7d), aggregated over a tier-filtered trader pool (PnL / win-rate / drawdown / AUM). Pick instruments via `topInstruments` OR `instCcyList` - exactly one. Snapshot time auto-resolved to current hour. **Linear (USDT/USDS-margined) contracts only - coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions are excluded by upstream and silently omitted from the aggregation.** Use when: latest cross-asset consensus from a criteria-defined pool. See also: `smartmoney_get_signal_overview_by_trader` (restrict pool to specific traders), `smartmoney_get_signal_trend_by_filter` (time-series instead of latest snapshot).",
7590
7744
  isWrite: false,
@@ -7645,6 +7799,7 @@ function registerSmartmoneyTools() {
7645
7799
  /* ---------- S2. Signal overview by trader (multi-asset, authorIds-restricted) ---------- */
7646
7800
  {
7647
7801
  name: "smartmoney_get_signal_overview_by_trader",
7802
+ title: "Smart Money Consensus Signals by Trader",
7648
7803
  module: "smartmoney",
7649
7804
  description: "Multi-asset smart-money signals aggregated over a hand-picked set of traders (`authorIds`). Pick instruments via `topInstruments` OR `instCcyList`. Capability tier filters (pnlTier / winRateTier / etc.) not exposed - backend uses defaults for direct-lookup scenarios. **Linear (USDT/USDS-margined) contracts only - a trader's coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions are silently excluded from the aggregation, even when those positions are large.** Use `smartmoney_get_trader_positions` if the full position book is needed. Use when: caller already knows which traders to follow and wants their cross-asset consensus at the latest hour. See also: `smartmoney_get_signal_overview_by_filter` (criteria-defined pool), `smartmoney_get_signal_trend_by_trader` (time-series), `smartmoney_get_traders_by_filter` / `smartmoney_search_trader` (discover authorIds).",
7650
7805
  isWrite: false,
@@ -7727,6 +7882,7 @@ function registerSmartmoneyTools() {
7727
7882
  /* ---------- S3. Signal trend by filter (single-asset, tier-filtered pool, asOfTime anchor) ---------- */
7728
7883
  {
7729
7884
  name: "smartmoney_get_signal_trend_by_filter",
7885
+ title: "Smart Money Signal Trend by Filter",
7730
7886
  module: "smartmoney",
7731
7887
  description: "Time-series of single-asset smart-money signal across hourly/daily buckets, aggregated over a tier-filtered trader pool. Returns the latest `limit` buckets ending at `asOfTime` (defaults to current UTC hour). **Linear (USDT/USDS-margined) contracts only - coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions are excluded by upstream and silently omitted.** Use when: tracking how long/short conviction and capital evolve over time (smart money adding exposure or retreating). See also: `smartmoney_get_signal_overview_by_filter` (latest snapshot only), `smartmoney_get_signal_trend_by_trader` (restrict to specific traders). Note: `asOfTime` is 10-digit `yyyyMMddHH` UTC, different from leaderboard tools' 12-digit UTC+8 `updateTime` - do not cross-pass.",
7732
7888
  isWrite: false,
@@ -7799,6 +7955,7 @@ function registerSmartmoneyTools() {
7799
7955
  /* ---------- S4. Signal trend by trader (single-asset, authorIds-restricted) ---------- */
7800
7956
  {
7801
7957
  name: "smartmoney_get_signal_trend_by_trader",
7958
+ title: "Smart Money Signal Trend by Trader",
7802
7959
  module: "smartmoney",
7803
7960
  description: "Time-series of single-asset smart-money signal aggregated over a hand-picked set of traders (`authorIds`). Returns the latest `limit` buckets ending at `asOfTime` (defaults to current UTC hour). Capability tier filters (pnlTier / winRateTier / etc.) not exposed - backend uses defaults for direct-lookup scenarios. **Linear (USDT/USDS-margined) contracts only - a trader's coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions on the requested base ccy are silently excluded from each bucket.** Use `smartmoney_get_trader_positions` to inspect the full position book. Use when: tracking how a specific group of traders has evolved their long/short consensus over time on one coin. See also: `smartmoney_get_signal_trend_by_filter` (criteria-defined pool), `smartmoney_get_signal_overview_by_trader` (latest snapshot only), `smartmoney_get_traders_by_filter` / `smartmoney_search_trader` (discover authorIds). Note: `asOfTime` is 10-digit `yyyyMMddHH` UTC, different from leaderboard tools' 12-digit UTC+8 `updateTime` - do not cross-pass.",
7804
7961
  isWrite: false,
@@ -7893,7 +8050,7 @@ function registerSmartmoneyTools() {
7893
8050
  return tools;
7894
8051
  }
7895
8052
  function buildContractTradeTools(cfg) {
7896
- const { prefix, module, label, instTypes, instIdExample } = cfg;
8053
+ const { prefix, module, label, instTypes, instIdExample, titleLabel } = cfg;
7897
8054
  const [defaultType, otherType] = instTypes;
7898
8055
  const instTypeDesc = `${defaultType} (default) or ${otherType}`;
7899
8056
  const n = (suffix) => `${prefix}_${suffix}`;
@@ -7901,6 +8058,8 @@ function buildContractTradeTools(cfg) {
7901
8058
  // ── place_order ──────────────────────────────────────────────────────────
7902
8059
  {
7903
8060
  name: n("place_order"),
8061
+ title: `${titleLabel} Place Order`,
8062
+ destructiveHint: false,
7904
8063
  module,
7905
8064
  description: `Place ${label} order. Attach TP/SL via tpTriggerPx/slTriggerPx. Before placing, use market_get_instruments to get ctVal (contract face value) - do NOT assume contract sizes. [CAUTION] Executes real trades.`,
7906
8065
  isWrite: true,
@@ -7997,6 +8156,8 @@ function buildContractTradeTools(cfg) {
7997
8156
  // ── cancel_order ─────────────────────────────────────────────────────────
7998
8157
  {
7999
8158
  name: n("cancel_order"),
8159
+ title: `${titleLabel} Cancel Order`,
8160
+ idempotentHint: true,
8000
8161
  module,
8001
8162
  description: `Cancel an unfilled ${label} order.`,
8002
8163
  isWrite: true,
@@ -8026,6 +8187,7 @@ function buildContractTradeTools(cfg) {
8026
8187
  // ── get_order ─────────────────────────────────────────────────────────────
8027
8188
  {
8028
8189
  name: n("get_order"),
8190
+ title: `${titleLabel} Get Order`,
8029
8191
  module,
8030
8192
  description: `Get details of a single ${label} order by ordId or clOrdId.`,
8031
8193
  isWrite: false,
@@ -8055,6 +8217,7 @@ function buildContractTradeTools(cfg) {
8055
8217
  // ── get_orders ───────────────────────────────────────────────────────────
8056
8218
  {
8057
8219
  name: n("get_orders"),
8220
+ title: `${titleLabel} Get Orders`,
8058
8221
  module,
8059
8222
  description: `Query ${label} open orders, history (last 7 days), or archive (up to 3 months).`,
8060
8223
  isWrite: false,
@@ -8113,6 +8276,7 @@ function buildContractTradeTools(cfg) {
8113
8276
  // ── get_positions ────────────────────────────────────────────────────────
8114
8277
  {
8115
8278
  name: n("get_positions"),
8279
+ title: `${titleLabel} Get Positions`,
8116
8280
  module,
8117
8281
  description: `Get current ${label} positions.`,
8118
8282
  isWrite: false,
@@ -8147,6 +8311,7 @@ function buildContractTradeTools(cfg) {
8147
8311
  // ── get_fills ────────────────────────────────────────────────────────────
8148
8312
  {
8149
8313
  name: n("get_fills"),
8314
+ title: `${titleLabel} Get Fills`,
8150
8315
  module,
8151
8316
  description: `Get ${label} fill details. archive=false (default): last 3 days; archive=true: up to 3 months.`,
8152
8317
  isWrite: false,
@@ -8197,6 +8362,8 @@ function buildContractTradeTools(cfg) {
8197
8362
  // ── close_position ───────────────────────────────────────────────────────
8198
8363
  {
8199
8364
  name: n("close_position"),
8365
+ title: `${titleLabel} Close Position`,
8366
+ idempotentHint: true,
8200
8367
  module,
8201
8368
  description: `[CAUTION] Close entire ${label} position at market.`,
8202
8369
  isWrite: true,
@@ -8239,6 +8406,8 @@ function buildContractTradeTools(cfg) {
8239
8406
  // ── set_leverage ─────────────────────────────────────────────────────────
8240
8407
  {
8241
8408
  name: n("set_leverage"),
8409
+ title: `${titleLabel} Set Leverage`,
8410
+ idempotentHint: true,
8242
8411
  module,
8243
8412
  description: `Set leverage for a ${label} instrument or position. [CAUTION] Changes risk parameters.
8244
8413
  Scenarios (SWAP/FUTURES only):
@@ -8301,6 +8470,7 @@ Not supported: PORTFOLIO MARGIN accounts cannot adjust cross leverage for SWAP/F
8301
8470
  // ── get_leverage ─────────────────────────────────────────────────────────
8302
8471
  {
8303
8472
  name: n("get_leverage"),
8473
+ title: `${titleLabel} Get Leverage`,
8304
8474
  module,
8305
8475
  description: `Get current leverage for a ${label} instrument.`,
8306
8476
  isWrite: false,
@@ -8328,6 +8498,8 @@ Not supported: PORTFOLIO MARGIN accounts cannot adjust cross leverage for SWAP/F
8328
8498
  // ── batch_amend ──────────────────────────────────────────────────────────
8329
8499
  {
8330
8500
  name: n("batch_amend"),
8501
+ title: `${titleLabel} Batch Amend Orders`,
8502
+ idempotentHint: true,
8331
8503
  module,
8332
8504
  description: `[CAUTION] Batch amend up to 20 unfilled ${label} orders.`,
8333
8505
  isWrite: true,
@@ -8359,6 +8531,8 @@ Not supported: PORTFOLIO MARGIN accounts cannot adjust cross leverage for SWAP/F
8359
8531
  // ── batch_cancel ─────────────────────────────────────────────────────────
8360
8532
  {
8361
8533
  name: n("batch_cancel"),
8534
+ title: `${titleLabel} Batch Cancel Orders`,
8535
+ idempotentHint: true,
8362
8536
  module,
8363
8537
  description: `[CAUTION] Batch cancel up to 20 ${label} orders.`,
8364
8538
  isWrite: true,
@@ -8394,6 +8568,7 @@ function registerFuturesTools() {
8394
8568
  prefix: "futures",
8395
8569
  module: "futures",
8396
8570
  label: "FUTURES delivery",
8571
+ titleLabel: "Futures",
8397
8572
  instTypes: ["FUTURES", "SWAP"],
8398
8573
  instIdExample: "e.g. BTC-USDT-240329"
8399
8574
  });
@@ -8403,6 +8578,8 @@ function registerFuturesTools() {
8403
8578
  // Unique to futures: amend a regular (non-algo) unfilled order.
8404
8579
  {
8405
8580
  name: "futures_amend_order",
8581
+ title: "Futures Amend Order",
8582
+ idempotentHint: true,
8406
8583
  module: "futures",
8407
8584
  description: "Amend an unfilled FUTURES delivery order (modify price and/or size). To modify attached TP/SL, use futures_amend_algo_order with the algoId from futures_get_algo_orders.",
8408
8585
  isWrite: true,
@@ -8437,6 +8614,8 @@ function registerFuturesTools() {
8437
8614
  // Unique to futures: batch place only (no cancel/amend action dispatch).
8438
8615
  {
8439
8616
  name: "futures_batch_orders",
8617
+ title: "Futures Batch Place Orders",
8618
+ destructiveHint: false,
8440
8619
  module: "futures",
8441
8620
  description: "[CAUTION] Batch place up to 20 FUTURES delivery orders.",
8442
8621
  isWrite: true,
@@ -8496,6 +8675,7 @@ function registerMarketTools() {
8496
8675
  return [
8497
8676
  {
8498
8677
  name: "market_get_ticker",
8678
+ title: "Get Ticker",
8499
8679
  module: "market",
8500
8680
  description: "Get ticker data for a single instrument.",
8501
8681
  isWrite: false,
@@ -8523,6 +8703,7 @@ function registerMarketTools() {
8523
8703
  },
8524
8704
  {
8525
8705
  name: "market_get_tickers",
8706
+ title: "Get All Tickers",
8526
8707
  module: "market",
8527
8708
  description: "Get ticker data for all instruments of a given type.",
8528
8709
  isWrite: false,
@@ -8562,6 +8743,7 @@ function registerMarketTools() {
8562
8743
  },
8563
8744
  {
8564
8745
  name: "market_get_orderbook",
8746
+ title: "Get Order Book",
8565
8747
  module: "market",
8566
8748
  description: "Get the order book (bids/asks) for an instrument.",
8567
8749
  isWrite: false,
@@ -8596,6 +8778,7 @@ function registerMarketTools() {
8596
8778
  },
8597
8779
  {
8598
8780
  name: "market_get_candles",
8781
+ title: "Get Candlesticks",
8599
8782
  module: "market",
8600
8783
  description: "Get candlestick (OHLCV) data for an instrument. Automatically retrieves historical data (back to 2021) when requesting older time ranges. Use the `after` parameter to paginate back in time (the old `history` parameter has been removed). IMPORTANT: Before fetching with `after`/`before`, estimate the number of candles: time_range_ms / bar_interval_ms. If the estimate exceeds ~500 candles, inform the user of the estimated count and ask for confirmation before proceeding.",
8601
8784
  isWrite: false,
@@ -8652,6 +8835,7 @@ function registerMarketTools() {
8652
8835
  },
8653
8836
  {
8654
8837
  name: "market_get_instruments",
8838
+ title: "List Instruments",
8655
8839
  module: "market",
8656
8840
  description: "Get tradable instruments for a given type. Returns contract specs: min order size, lot size, tick size, contract value, settlement currency, listing/expiry time. Essential before placing orders.",
8657
8841
  isWrite: false,
@@ -8696,6 +8880,7 @@ function registerMarketTools() {
8696
8880
  },
8697
8881
  {
8698
8882
  name: "market_get_funding_rate",
8883
+ title: "Get Funding Rate",
8699
8884
  module: "market",
8700
8885
  description: "Get funding rate for a perpetual SWAP instrument. IMPORTANT: instId must end with -SWAP (e.g. BTC-USDT-SWAP). Spot IDs like BTC-USDT are NOT valid. history=false (default): current rate + next estimated rate; history=true: historical rates.",
8701
8886
  isWrite: false,
@@ -8757,6 +8942,7 @@ function registerMarketTools() {
8757
8942
  },
8758
8943
  {
8759
8944
  name: "market_get_mark_price",
8945
+ title: "Get Mark Price",
8760
8946
  module: "market",
8761
8947
  description: "Get mark price for SWAP, FUTURES, or MARGIN instruments. Used for liquidation calculations and unrealized PnL.",
8762
8948
  isWrite: false,
@@ -8800,6 +8986,7 @@ function registerMarketTools() {
8800
8986
  },
8801
8987
  {
8802
8988
  name: "market_get_trades",
8989
+ title: "Get Recent Trades",
8803
8990
  module: "market",
8804
8991
  description: "Get recent trades for an instrument. Default 20 records, max 500.",
8805
8992
  isWrite: false,
@@ -8834,6 +9021,7 @@ function registerMarketTools() {
8834
9021
  },
8835
9022
  {
8836
9023
  name: "market_get_index_ticker",
9024
+ title: "Get Index Ticker",
8837
9025
  module: "market",
8838
9026
  description: "Get index ticker data (e.g. BTC-USD, ETH-USD index prices). Independent of any single exchange.",
8839
9027
  isWrite: false,
@@ -8867,6 +9055,7 @@ function registerMarketTools() {
8867
9055
  },
8868
9056
  {
8869
9057
  name: "market_get_index_candles",
9058
+ title: "Get Index Candlesticks",
8870
9059
  module: "market",
8871
9060
  description: "Get candlestick data for an index (e.g. BTC-USD index). history=false: recent up to 1440 bars; history=true: older data.",
8872
9061
  isWrite: false,
@@ -8923,6 +9112,7 @@ function registerMarketTools() {
8923
9112
  },
8924
9113
  {
8925
9114
  name: "market_get_price_limit",
9115
+ title: "Get Price Limit",
8926
9116
  module: "market",
8927
9117
  description: "Get the current price limit (upper and lower bands) for a SWAP or FUTURES instrument. Orders outside these limits will be rejected.",
8928
9118
  isWrite: false,
@@ -8950,6 +9140,7 @@ function registerMarketTools() {
8950
9140
  },
8951
9141
  {
8952
9142
  name: "market_get_open_interest",
9143
+ title: "Get Open Interest",
8953
9144
  module: "market",
8954
9145
  description: "Get open interest for SWAP, FUTURES, or OPTION instruments. Useful for gauging market sentiment and positioning.",
8955
9146
  isWrite: false,
@@ -8993,6 +9184,7 @@ function registerMarketTools() {
8993
9184
  },
8994
9185
  {
8995
9186
  name: "market_get_stock_tokens",
9187
+ title: "List Stock Tokens",
8996
9188
  module: "market",
8997
9189
  description: '[Deprecated: use market_get_instruments_by_category with instCategory="3" instead] Get all stock token instruments (instCategory=3). Stock tokens track real-world stock prices on OKX (e.g. AAPL-USDT-SWAP).',
8998
9190
  isWrite: false,
@@ -9029,6 +9221,7 @@ function registerMarketTools() {
9029
9221
  },
9030
9222
  {
9031
9223
  name: "market_get_instruments_by_category",
9224
+ title: "List Instruments by Category",
9032
9225
  module: "market",
9033
9226
  description: "Discover tradeable instruments by asset category. Stock tokens (instCategory=3, e.g. AAPL-USDT-SWAP, TSLA-USDT-SWAP), Metals (4, e.g. XAUUSDT-USDT-SWAP for gold), Commodities (5, e.g. OIL-USDT-SWAP for crude oil), Forex (6, e.g. EURUSDT-USDT-SWAP for EUR/USD), Bonds (7, e.g. US30Y-USDT-SWAP for crude oil). Use this to find instIds before querying prices or placing orders. Filters client-side by instCategory.",
9034
9227
  isWrite: false,
@@ -9079,6 +9272,7 @@ function registerMarketFilterTools() {
9079
9272
  // ─────────────────────────────────────────────────────────────────────────
9080
9273
  {
9081
9274
  name: "market_filter",
9275
+ title: "Screen Instruments",
9082
9276
  module: "market",
9083
9277
  description: "Screen / rank instruments across SPOT, SWAP, or FUTURES by multi-dimensional criteria: price range, 24h change %, market cap, 24h volume (USD), funding rate (SWAP), open interest (USD), listing time. Returns ranked rows with full ticker snapshot. Use to find top movers, high-OI contracts, newly listed tokens, etc. No credentials required. Do NOT use to get OI change rankings across contracts - use market_filter_oi_change instead. Do NOT use to get OI time series for a single instrument - use market_get_oi_history instead.",
9084
9278
  isWrite: false,
@@ -9216,6 +9410,7 @@ function registerMarketFilterTools() {
9216
9410
  // ─────────────────────────────────────────────────────────────────────────
9217
9411
  {
9218
9412
  name: "market_get_oi_history",
9413
+ title: "Get Open Interest History",
9219
9414
  module: "market",
9220
9415
  description: "Get open interest (OI) history time series for a single SWAP or FUTURES instrument. Returns per-bar OI in contracts, base currency and USD, plus bar-over-bar delta and delta %. Useful for tracking how OI evolves around price moves. No credentials required. Do NOT use to compare OI changes across multiple contracts - use market_filter_oi_change instead. Do NOT use to screen instruments by current OI level - use market_filter instead.",
9221
9416
  isWrite: false,
@@ -9263,6 +9458,7 @@ function registerMarketFilterTools() {
9263
9458
  // ─────────────────────────────────────────────────────────────────────────
9264
9459
  {
9265
9460
  name: "market_filter_oi_change",
9461
+ title: "Find Open Interest Change Instruments",
9266
9462
  module: "market",
9267
9463
  description: "Find SWAP or FUTURES instruments with significant open interest changes over a given bar window. Returns ranked rows with current OI (USD), previous OI (USD), OI delta (USD and %), price change %, 24h volume and funding rate. Ideal for spotting unusual accumulation/distribution or confirming trend momentum. No credentials required. Do NOT use to get OI time series for a single instrument - use market_get_oi_history instead. Do NOT use to screen by current OI absolute level or other non-OI metrics - use market_filter instead.",
9268
9464
  isWrite: false,
@@ -9335,6 +9531,7 @@ function registerMarketFilterTools() {
9335
9531
  // ─────────────────────────────────────────────────────────────────────────
9336
9532
  {
9337
9533
  name: "market_get_pair_spread",
9534
+ title: "Get Pair Spread",
9338
9535
  module: "market",
9339
9536
  description: "Compute spread statistics between two instruments over a lookback window. Returns absolute and ratio spread (mean / stdDev / median / min / max) plus an optional realtime spread snapshot. Use to size pairs trades, detect mean-reversion setups, or compare cross-listed contracts. Results are cached ~60s per (pair, bar, window) tuple. Read-only, no credentials required.\nDo NOT use to fetch raw candles (use market_get_candles) or single-instrument OI/funding (use market_get_oi_history / market_filter_oi_change).",
9340
9537
  isWrite: false,
@@ -9627,6 +9824,7 @@ function registerNewsTools() {
9627
9824
  // -----------------------------------------------------------------------
9628
9825
  {
9629
9826
  name: "news_get_latest",
9827
+ title: "Get Latest Crypto News",
9630
9828
  module: "news",
9631
9829
  description: "Get crypto news sorted by time. For broad browsing ('what happened recently', 'latest news', 'any big news today'), pass importance='low' to include both high and low importance. Server default (when importance omitted) returns only high-importance news. For coin-specific news, use news_get_by_coin instead.",
9632
9830
  isWrite: false,
@@ -9672,6 +9870,7 @@ function registerNewsTools() {
9672
9870
  },
9673
9871
  {
9674
9872
  name: "news_get_by_coin",
9873
+ title: "Get News by Coin",
9675
9874
  module: "news",
9676
9875
  description: "Get news for specific coins or tokens. Use when user mentions a coin: 'BTC news', 'any SOL updates'. Supports multiple coins (comma-separated). For general browsing without a coin filter, use news_get_latest.",
9677
9876
  isWrite: false,
@@ -9715,6 +9914,7 @@ function registerNewsTools() {
9715
9914
  },
9716
9915
  {
9717
9916
  name: "news_search",
9917
+ title: "Search News",
9718
9918
  module: "news",
9719
9919
  description: "Search crypto news by keyword with optional filters. Use when user provides specific search terms: 'SEC ETF news', 'stablecoin regulation'. Keyword is optional - pass sentiment alone to browse by sentiment direction. For coin-only queries prefer news_get_by_coin.",
9720
9920
  isWrite: false,
@@ -9772,6 +9972,7 @@ function registerNewsTools() {
9772
9972
  },
9773
9973
  {
9774
9974
  name: "news_get_detail",
9975
+ title: "Get News Article",
9775
9976
  module: "news",
9776
9977
  description: "Get full article content by news ID (returns title + summary + full original text). Use when user says 'show full article', 'read more', or provides a specific news ID from a previous result.",
9777
9978
  isWrite: false,
@@ -9803,6 +10004,7 @@ function registerNewsTools() {
9803
10004
  },
9804
10005
  {
9805
10006
  name: "news_get_domains",
10007
+ title: "List News Sources",
9806
10008
  module: "news",
9807
10009
  description: "List available news source domains (e.g. coindesk, cointelegraph). Use when user asks what news sources are available or which platforms are covered.",
9808
10010
  isWrite: false,
@@ -9825,6 +10027,7 @@ function registerNewsTools() {
9825
10027
  // -----------------------------------------------------------------------
9826
10028
  {
9827
10029
  name: "news_get_coin_sentiment",
10030
+ title: "Get Coin Sentiment",
9828
10031
  module: "news",
9829
10032
  description: "Get sentiment snapshot or time-series trend for coins. Returns bullish/bearish ratios and mention counts. Pass trendPoints for trend data (1h->24 points, 4h->6, 24h->7). Use when user asks about coin sentiment, sentiment trend, or how bullish/bearish a coin is. For ranking all coins by sentiment, use news_get_sentiment_ranking instead.",
9830
10033
  isWrite: false,
@@ -9866,6 +10069,7 @@ function registerNewsTools() {
9866
10069
  },
9867
10070
  {
9868
10071
  name: "news_get_sentiment_ranking",
10072
+ title: "Get Sentiment Ranking",
9869
10073
  module: "news",
9870
10074
  description: "Get coin ranking by social hotness or sentiment direction. Use when user asks which coins are trending, most bullish/bearish coins. Sort by hot (mention count), bullish, or bearish. For sentiment data on a specific coin, use news_get_coin_sentiment instead.",
9871
10075
  isWrite: false,
@@ -9905,6 +10109,7 @@ function registerNewsTools() {
9905
10109
  // -----------------------------------------------------------------------
9906
10110
  {
9907
10111
  name: "news_list_calendar_regions",
10112
+ title: "List Calendar Regions",
9908
10113
  module: "news",
9909
10114
  description: "List all valid region values for the economic calendar. Returns a string array of snake_case region codes. Call this when economic-calendar returns empty results to verify the region value, or to help the user pick a valid region. Do NOT use to list news source platforms - use news_get_domains instead.",
9910
10115
  isWrite: false,
@@ -9913,6 +10118,7 @@ function registerNewsTools() {
9913
10118
  },
9914
10119
  {
9915
10120
  name: "news_get_economic_calendar",
10121
+ title: "Get Economic Calendar",
9916
10122
  module: "news",
9917
10123
  description: "Get macro-economic calendar data (GDP, CPI, NFP, interest rate decisions, PMI, etc.). Returns scheduled and released economic events with forecast, previous, and actual values. Use when user asks about economic calendar, macro data, or specific indicators like NFP/CPI/GDP/FOMC. Do NOT use for news articles or sentiment - use news_get_latest or news_search instead.",
9918
10124
  isWrite: false,
@@ -9973,6 +10179,8 @@ function registerOptionAlgoTools() {
9973
10179
  return [
9974
10180
  {
9975
10181
  name: "option_place_algo_order",
10182
+ title: "Option Place Algo Order",
10183
+ destructiveHint: false,
9976
10184
  module: "option",
9977
10185
  description: "Place OPTION TP/SL algo order (conditional/oco). [CAUTION] Executes real trades. conditional=single TP/SL; oco=TP+SL pair. -1=market.",
9978
10186
  isWrite: true,
@@ -10079,6 +10287,8 @@ function registerOptionAlgoTools() {
10079
10287
  },
10080
10288
  {
10081
10289
  name: "option_amend_algo_order",
10290
+ title: "Option Amend Algo Order",
10291
+ idempotentHint: true,
10082
10292
  module: "option",
10083
10293
  description: "Amend a pending OPTION algo order (modify TP/SL prices or size). Also covers TP/SL orders attached when placing the main order - look up algoId via option_get_algo_orders first.",
10084
10294
  isWrite: true,
@@ -10115,6 +10325,8 @@ function registerOptionAlgoTools() {
10115
10325
  },
10116
10326
  {
10117
10327
  name: "option_cancel_algo_orders",
10328
+ title: "Option Cancel Algo Orders",
10329
+ idempotentHint: true,
10118
10330
  module: "option",
10119
10331
  description: "Cancel OPTION algo orders (TP/SL). Each item: {algoId, instId}.",
10120
10332
  isWrite: true,
@@ -10158,6 +10370,7 @@ function registerOptionAlgoTools() {
10158
10370
  },
10159
10371
  {
10160
10372
  name: "option_get_algo_orders",
10373
+ title: "Option Get Algo Orders",
10161
10374
  module: "option",
10162
10375
  description: "Query pending or completed OPTION algo orders (TP/SL, OCO).",
10163
10376
  isWrite: false,
@@ -10242,6 +10455,8 @@ function registerOptionTools() {
10242
10455
  return [
10243
10456
  {
10244
10457
  name: "option_place_order",
10458
+ title: "Option Place Order",
10459
+ destructiveHint: false,
10245
10460
  module: "option",
10246
10461
  description: "Place OPTION order. instId: {uly}-{expiry}-{strike}-C/P, e.g. BTC-USD-241227-50000-C. Before placing, use market_get_instruments to get ctVal (contract face value) - do NOT assume contract sizes. [CAUTION] Executes real trades.",
10247
10462
  isWrite: true,
@@ -10345,6 +10560,8 @@ function registerOptionTools() {
10345
10560
  },
10346
10561
  {
10347
10562
  name: "option_cancel_order",
10563
+ title: "Option Cancel Order",
10564
+ idempotentHint: true,
10348
10565
  module: "option",
10349
10566
  description: "Cancel an unfilled OPTION order. Provide ordId or clOrdId.",
10350
10567
  isWrite: true,
@@ -10373,6 +10590,8 @@ function registerOptionTools() {
10373
10590
  },
10374
10591
  {
10375
10592
  name: "option_batch_cancel",
10593
+ title: "Option Batch Cancel Orders",
10594
+ idempotentHint: true,
10376
10595
  module: "option",
10377
10596
  description: "[CAUTION] Batch cancel up to 20 OPTION orders.",
10378
10597
  isWrite: true,
@@ -10403,6 +10622,8 @@ function registerOptionTools() {
10403
10622
  },
10404
10623
  {
10405
10624
  name: "option_amend_order",
10625
+ title: "Option Amend Order",
10626
+ idempotentHint: true,
10406
10627
  module: "option",
10407
10628
  description: "Amend an unfilled OPTION order (price and/or size). Provide ordId or clOrdId. To modify attached TP/SL, use option_amend_algo_order with the algoId from option_get_algo_orders.",
10408
10629
  isWrite: true,
@@ -10435,6 +10656,7 @@ function registerOptionTools() {
10435
10656
  },
10436
10657
  {
10437
10658
  name: "option_get_order",
10659
+ title: "Option Get Order",
10438
10660
  module: "option",
10439
10661
  description: "Get details of a single OPTION order by ordId or clOrdId.",
10440
10662
  isWrite: false,
@@ -10463,6 +10685,7 @@ function registerOptionTools() {
10463
10685
  },
10464
10686
  {
10465
10687
  name: "option_get_orders",
10688
+ title: "Option Get Orders",
10466
10689
  module: "option",
10467
10690
  description: "List OPTION orders. status: live=pending (default), history=7d, archive=3mo.",
10468
10691
  isWrite: false,
@@ -10517,6 +10740,7 @@ function registerOptionTools() {
10517
10740
  },
10518
10741
  {
10519
10742
  name: "option_get_positions",
10743
+ title: "Option Get Positions with Greeks",
10520
10744
  module: "option",
10521
10745
  description: "Get current OPTION positions including Greeks (delta, gamma, theta, vega).",
10522
10746
  isWrite: false,
@@ -10543,6 +10767,7 @@ function registerOptionTools() {
10543
10767
  },
10544
10768
  {
10545
10769
  name: "option_get_fills",
10770
+ title: "Option Get Fills",
10546
10771
  module: "option",
10547
10772
  description: "Get OPTION fill history. archive=false: last 3 days (default); archive=true: up to 3 months.",
10548
10773
  isWrite: false,
@@ -10585,6 +10810,7 @@ function registerOptionTools() {
10585
10810
  },
10586
10811
  {
10587
10812
  name: "option_get_instruments",
10813
+ title: "Option List Instruments (Chain)",
10588
10814
  module: "option",
10589
10815
  description: "List available OPTION contracts for a given underlying (option chain). Use to find valid instIds before placing orders.",
10590
10816
  isWrite: false,
@@ -10618,6 +10844,7 @@ function registerOptionTools() {
10618
10844
  },
10619
10845
  {
10620
10846
  name: "option_get_greeks",
10847
+ title: "Option Get Greeks",
10621
10848
  module: "option",
10622
10849
  description: "Get implied volatility and Greeks (delta, gamma, theta, vega) for OPTION contracts by underlying.",
10623
10850
  isWrite: false,
@@ -10654,6 +10881,8 @@ function registerSpotTradeTools() {
10654
10881
  return [
10655
10882
  {
10656
10883
  name: "spot_place_order",
10884
+ title: "Spot Place Order",
10885
+ destructiveHint: false,
10657
10886
  module: "spot",
10658
10887
  description: "Place a spot order. Attach TP/SL via tpTriggerPx/slTriggerPx. [CAUTION] Executes real trades.",
10659
10888
  isWrite: true,
@@ -10748,6 +10977,8 @@ function registerSpotTradeTools() {
10748
10977
  },
10749
10978
  {
10750
10979
  name: "spot_cancel_order",
10980
+ title: "Spot Cancel Order",
10981
+ idempotentHint: true,
10751
10982
  module: "spot",
10752
10983
  description: "Cancel an unfilled spot order.",
10753
10984
  isWrite: true,
@@ -10783,6 +11014,8 @@ function registerSpotTradeTools() {
10783
11014
  },
10784
11015
  {
10785
11016
  name: "spot_amend_order",
11017
+ title: "Spot Amend Order",
11018
+ idempotentHint: true,
10786
11019
  module: "spot",
10787
11020
  description: "Amend an unfilled spot order (modify price or size). To modify attached TP/SL, use the corresponding algo amend tool: spot_amend_algo_order (spot), swap_amend_algo_order (swap), futures_amend_algo_order (futures), option_amend_algo_order (option). Use spot_get_algo_orders to find the algoId for spot orders.",
10788
11021
  isWrite: true,
@@ -10833,6 +11066,7 @@ function registerSpotTradeTools() {
10833
11066
  },
10834
11067
  {
10835
11068
  name: "spot_get_orders",
11069
+ title: "Spot Get Orders",
10836
11070
  module: "spot",
10837
11071
  description: "Query spot orders. status: open(active)|history(7d)|archive(3mo).",
10838
11072
  isWrite: false,
@@ -10901,6 +11135,8 @@ function registerSpotTradeTools() {
10901
11135
  },
10902
11136
  {
10903
11137
  name: "spot_place_algo_order",
11138
+ title: "Spot Place Algo Order",
11139
+ destructiveHint: false,
10904
11140
  module: "spot",
10905
11141
  description: "Place a spot algo order. [CAUTION] Executes real trades. conditional: single TP/SL. oco: TP+SL pair. move_order_stop: trailing stop. trigger: pending order at triggerPx. chase: follow best bid/ask. iceberg: split large order into child orders. twap: time-weighted split.",
10906
11142
  isWrite: true,
@@ -11016,6 +11252,8 @@ function registerSpotTradeTools() {
11016
11252
  },
11017
11253
  {
11018
11254
  name: "spot_amend_algo_order",
11255
+ title: "Spot Amend Algo Order",
11256
+ idempotentHint: true,
11019
11257
  module: "spot",
11020
11258
  description: "Amend a pending spot algo order (modify TP/SL prices or size). Also covers TP/SL orders attached when placing the main order - look up algoId via spot_get_algo_orders first.",
11021
11259
  isWrite: true,
@@ -11052,6 +11290,8 @@ function registerSpotTradeTools() {
11052
11290
  },
11053
11291
  {
11054
11292
  name: "spot_cancel_algo_order",
11293
+ title: "Spot Cancel Algo Order",
11294
+ idempotentHint: true,
11055
11295
  module: "spot",
11056
11296
  description: "Cancel a spot algo order (TP/SL).",
11057
11297
  isWrite: true,
@@ -11085,6 +11325,7 @@ function registerSpotTradeTools() {
11085
11325
  },
11086
11326
  {
11087
11327
  name: "spot_get_algo_orders",
11328
+ title: "Spot Get Algo Orders",
11088
11329
  module: "spot",
11089
11330
  description: "Query spot algo orders (TP/SL) - pending or history.",
11090
11331
  isWrite: false,
@@ -11162,6 +11403,7 @@ function registerSpotTradeTools() {
11162
11403
  },
11163
11404
  {
11164
11405
  name: "spot_get_fills",
11406
+ title: "Spot Get Fills",
11165
11407
  module: "spot",
11166
11408
  description: "Get spot transaction fills. archive=false(3d, default)|true(up to 3mo).",
11167
11409
  isWrite: false,
@@ -11225,6 +11467,7 @@ function registerSpotTradeTools() {
11225
11467
  },
11226
11468
  {
11227
11469
  name: "spot_batch_orders",
11470
+ title: "Spot Batch Orders",
11228
11471
  module: "spot",
11229
11472
  description: "[CAUTION] Batch place/cancel/amend up to 20 spot orders. action: place|cancel|amend.",
11230
11473
  isWrite: true,
@@ -11283,6 +11526,7 @@ function registerSpotTradeTools() {
11283
11526
  },
11284
11527
  {
11285
11528
  name: "spot_get_order",
11529
+ title: "Spot Get Order",
11286
11530
  module: "spot",
11287
11531
  description: "Get details of a single spot order.",
11288
11532
  isWrite: false,
@@ -11320,6 +11564,8 @@ function registerSpotTradeTools() {
11320
11564
  },
11321
11565
  {
11322
11566
  name: "spot_batch_amend",
11567
+ title: "Spot Batch Amend Orders",
11568
+ idempotentHint: true,
11323
11569
  module: "spot",
11324
11570
  description: "[CAUTION] Batch amend up to 20 unfilled spot orders.",
11325
11571
  isWrite: true,
@@ -11350,6 +11596,8 @@ function registerSpotTradeTools() {
11350
11596
  },
11351
11597
  {
11352
11598
  name: "spot_batch_cancel",
11599
+ title: "Spot Batch Cancel Orders",
11600
+ idempotentHint: true,
11353
11601
  module: "spot",
11354
11602
  description: "[CAUTION] Batch cancel up to 20 spot orders.",
11355
11603
  isWrite: true,
@@ -11387,6 +11635,8 @@ function registerSpotTradeTools() {
11387
11635
  // Not applicable: posSide (spot has no long/short hedge).
11388
11636
  {
11389
11637
  name: "spot_set_leverage",
11638
+ title: "Spot Set Leverage",
11639
+ idempotentHint: true,
11390
11640
  module: "spot",
11391
11641
  description: "Set leverage for SPOT margin trading. Provide exactly ONE of instId (pair-level) or ccy (currency-level cross, requires borrow-enabled account / multi-ccy / portfolio margin). [CAUTION] Changes risk parameters.\nScenarios:\n \u2022 instId + mgnMode=isolated -> pair-level isolated margin\n \u2022 instId + mgnMode=cross -> pair-level cross margin (contract-mode account)\n \u2022 ccy + mgnMode=cross -> currency-level cross margin (spot-with-borrow / multi-ccy / portfolio margin)\nWhen ccy is supplied, mgnMode MUST be cross. posSide is never applicable to spot margin.",
11392
11642
  isWrite: true,
@@ -11461,6 +11711,7 @@ function registerSwapTradeTools() {
11461
11711
  prefix: "swap",
11462
11712
  module: "swap",
11463
11713
  label: "SWAP/FUTURES",
11714
+ titleLabel: "Perpetual Futures",
11464
11715
  instTypes: ["SWAP", "FUTURES"],
11465
11716
  instIdExample: "e.g. BTC-USDT-SWAP"
11466
11717
  });
@@ -11470,6 +11721,8 @@ function registerSwapTradeTools() {
11470
11721
  // Unique to swap: amend a pending TP/SL algo order attached to a position.
11471
11722
  {
11472
11723
  name: "swap_amend_algo_order",
11724
+ title: "Perpetual Futures Amend Algo Order",
11725
+ idempotentHint: true,
11473
11726
  module: "swap",
11474
11727
  description: "Amend a pending SWAP/FUTURES algo order (modify TP/SL prices or size). Also covers TP/SL orders attached when placing the main order - look up algoId via swap_get_algo_orders first.",
11475
11728
  isWrite: true,
@@ -11508,6 +11761,7 @@ function registerSwapTradeTools() {
11508
11761
  // Unique to swap: 3-in-1 batch tool (place / cancel / amend via action param).
11509
11762
  {
11510
11763
  name: "swap_batch_orders",
11764
+ title: "Perpetual Futures Batch Orders",
11511
11765
  module: "swap",
11512
11766
  description: "[CAUTION] Batch place/cancel/amend SWAP/FUTURES orders (max 20). action=place|cancel|amend.",
11513
11767
  isWrite: true,
@@ -11598,26 +11852,30 @@ function buildTools(config) {
11598
11852
  return tools.filter((tool) => !tool.isWrite);
11599
11853
  }
11600
11854
  function toMcpTool(tool) {
11855
+ const destructive = tool.destructiveHint ?? tool.isWrite;
11856
+ const idempotent = tool.idempotentHint ?? !tool.isWrite;
11601
11857
  return {
11602
11858
  name: tool.name,
11859
+ title: tool.title,
11603
11860
  description: tool.description,
11604
11861
  inputSchema: tool.inputSchema,
11605
11862
  ...tool.outputSchema ? { outputSchema: tool.outputSchema } : {},
11606
11863
  annotations: {
11864
+ title: tool.title,
11607
11865
  readOnlyHint: !tool.isWrite,
11608
- destructiveHint: tool.isWrite,
11609
- idempotentHint: !tool.isWrite,
11866
+ destructiveHint: destructive,
11867
+ idempotentHint: idempotent,
11610
11868
  openWorldHint: true
11611
11869
  }
11612
11870
  };
11613
11871
  }
11614
11872
  function configFilePath() {
11615
- return join7(homedir5(), ".okx", "config.toml");
11873
+ return join9(homedir5(), ".okx", "config.toml");
11616
11874
  }
11617
11875
  function readFullConfig() {
11618
11876
  const path4 = configFilePath();
11619
11877
  if (!existsSync3(path4)) return { profiles: {} };
11620
- const raw = readFileSync4(path4, "utf-8");
11878
+ const raw = readFileSync6(path4, "utf-8");
11621
11879
  try {
11622
11880
  return parse(raw);
11623
11881
  } catch (err) {
@@ -11752,7 +12010,7 @@ async function loadConfig(cli) {
11752
12010
  verbose: cli.verbose ?? false
11753
12011
  };
11754
12012
  }
11755
- var CACHE_FILE = join8(homedir6(), ".okx", "update-check.json");
12013
+ var CACHE_FILE = join10(homedir6(), ".okx", "update-check.json");
11756
12014
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
11757
12015
  var NEGATIVE_CHECK_INTERVAL_MS = 60 * 60 * 1e3;
11758
12016
  var DEFAULT_REGISTRY = "https://registry.npmjs.org/";
@@ -11760,7 +12018,7 @@ var FETCH_TIMEOUT_MS = 3e3;
11760
12018
  function readCache2() {
11761
12019
  try {
11762
12020
  if (existsSync4(CACHE_FILE)) {
11763
- return JSON.parse(readFileSync5(CACHE_FILE, "utf-8"));
12021
+ return JSON.parse(readFileSync7(CACHE_FILE, "utf-8"));
11764
12022
  }
11765
12023
  } catch {
11766
12024
  }
@@ -11768,7 +12026,7 @@ function readCache2() {
11768
12026
  }
11769
12027
  function writeCache2(cache) {
11770
12028
  try {
11771
- mkdirSync6(join8(homedir6(), ".okx"), { recursive: true });
12029
+ mkdirSync6(join10(homedir6(), ".okx"), { recursive: true });
11772
12030
  writeFileSync5(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
11773
12031
  } catch {
11774
12032
  }
@@ -11798,13 +12056,13 @@ function buildNpmrcCandidates() {
11798
12056
  let dir = process.cwd();
11799
12057
  const root = dir.startsWith("/") ? "/" : dir.slice(0, 3);
11800
12058
  while (true) {
11801
- add(join8(dir, ".npmrc"));
12059
+ add(join10(dir, ".npmrc"));
11802
12060
  if (dir === root) break;
11803
- const parent = join8(dir, "..");
12061
+ const parent = join10(dir, "..");
11804
12062
  if (parent === dir) break;
11805
12063
  dir = parent;
11806
12064
  }
11807
- add(join8(homedir6(), ".npmrc"));
12065
+ add(join10(homedir6(), ".npmrc"));
11808
12066
  if (process.platform !== "win32") {
11809
12067
  add("/etc/npmrc");
11810
12068
  }
@@ -11813,7 +12071,7 @@ function buildNpmrcCandidates() {
11813
12071
  function readNpmrcRegistry(filePath) {
11814
12072
  try {
11815
12073
  if (!existsSync4(filePath)) return null;
11816
- const lines = readFileSync5(filePath, "utf-8").split(/\r?\n/);
12074
+ const lines = readFileSync7(filePath, "utf-8").split(/\r?\n/);
11817
12075
  for (const line of lines) {
11818
12076
  const trimmed = line.trim();
11819
12077
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -12130,7 +12388,7 @@ function runSetup(options) {
12130
12388
  `);
12131
12389
  }
12132
12390
  }
12133
- var CACHE_PATH = join12(homedir10(), ".okx", "auth-binary-check.json");
12391
+ var CACHE_PATH = join14(homedir10(), ".okx", "auth-binary-check.json");
12134
12392
  var CHECK_INTERVAL_MS2 = 2 * 60 * 60 * 1e3;
12135
12393
 
12136
12394
  // src/constants.ts
@@ -12139,7 +12397,7 @@ var _require = createRequire(import.meta.url);
12139
12397
  var pkg = _require("../package.json");
12140
12398
  var SERVER_NAME = "okx-trade-mcp";
12141
12399
  var SERVER_VERSION = pkg.version;
12142
- var GIT_HASH = true ? "c34b282c" : "dev";
12400
+ var GIT_HASH = true ? "92abfa77" : "dev";
12143
12401
 
12144
12402
  // src/server.ts
12145
12403
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -12150,12 +12408,14 @@ import {
12150
12408
  var SYSTEM_CAPABILITIES_TOOL_NAME = "system_get_capabilities";
12151
12409
  var SYSTEM_CAPABILITIES_TOOL = {
12152
12410
  name: SYSTEM_CAPABILITIES_TOOL_NAME,
12411
+ title: "Server Capabilities Snapshot",
12153
12412
  description: "Return machine-readable server capabilities and module availability for agent planning.",
12154
12413
  inputSchema: {
12155
12414
  type: "object",
12156
12415
  additionalProperties: false
12157
12416
  },
12158
12417
  annotations: {
12418
+ title: "Server Capabilities Snapshot",
12159
12419
  readOnlyHint: true,
12160
12420
  destructiveHint: false,
12161
12421
  idempotentHint: true,