@michaleffffff/mcp-trading-server 3.0.21 → 3.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.24 - 2026-03-19
4
+
5
+ ### Fixed
6
+ - Hardened LP MCP behavior:
7
+ - `get_pool_metadata(includeLiquidity=true)` now ignores caller-supplied `marketPrice` and derives liquidity depth from a fresh Oracle price only.
8
+ - `get_pool_info` MCP-side market price resolution no longer falls back from fresh Oracle to ticker-derived price.
9
+ - Beta LP router / `PoolManager` fallback mappings were completed for MCP-managed LP and create-market paths.
10
+ - `get_my_lp_holdings` no longer ranks rows by mixed BASE/QUOTE LP raw balances.
11
+
12
+ ### Changed
13
+ - Synced release metadata and operator docs for `v3.0.24`:
14
+ - Updated `README.md`, `TOOL_EXAMPLES.md`, and `trading_best_practices` prompt version strings.
15
+ - Refreshed LP safety docs to reflect Oracle-only liquidity metadata and inventory-only LP holdings semantics.
16
+
17
+ ## 3.0.23 - 2026-03-19
18
+
19
+ ### Changed
20
+ - Upgraded SDK dependency to `@myx-trade/sdk@^1.0.4-beta.4`.
21
+ - Refreshed operator-facing docs and runtime hints to match the new SDK baseline:
22
+ - `README.md` now references `@myx-trade/sdk@^1.0.4-beta.4`.
23
+ - `TOOL_EXAMPLES.md`, `execute_trade`, `close_position`, and `mapTimeInForce` now document the current IOC-only `timeInForce` behavior using `v1.0.4-beta.4`.
24
+ - `trading_best_practices` prompt now aligns with release `v3.0.23`.
25
+
26
+ ### Fixed
27
+ - Hardened LP MCP behavior and synchronized docs:
28
+ - `get_pool_metadata(includeLiquidity=true)` now ignores caller-supplied `marketPrice` and derives liquidity depth from a fresh Oracle price only.
29
+ - `get_pool_info` MCP-side price resolution no longer falls back from fresh Oracle to ticker-derived market price.
30
+ - Beta LP router / `PoolManager` chain mappings were completed for the MCP fallback path.
31
+ - `get_my_lp_holdings` no longer ranks rows by mixed BASE/QUOTE LP raw balances.
32
+ - `README.md`, `TOOL_EXAMPLES.md`, and `mcp_config_guide.md` now document these LP-specific MCP semantics.
33
+
34
+ ## 3.0.22 - 2026-03-19
35
+
36
+ ### Changed
37
+ - Upgraded SDK dependency to `@myx-trade/sdk@^1.0.4-beta.1`.
38
+ - Refreshed operator-facing docs and runtime hints to match the new SDK baseline:
39
+ - `README.md` now references `@myx-trade/sdk@^1.0.4-beta.1`.
40
+ - `TOOL_EXAMPLES.md`, `execute_trade`, `close_position`, and `mapTimeInForce` now document the current IOC-only `timeInForce` behavior using the new SDK version.
41
+ - `trading_best_practices` prompt now aligns with release `v3.0.22`.
42
+
3
43
  ## 3.0.21 - 2026-03-19
4
44
 
5
45
  ### Fixed
@@ -13,6 +53,9 @@
13
53
  - `mcp_config_guide.md` now includes required `BROKER_ADDRESS` configuration and testnet `MYXBroker` references.
14
54
  - `TOOL_EXAMPLES.md` now reflects fresh-Oracle execution, live-direction validation, human-price TP/SL parsing, and trading `slippagePct` conventions.
15
55
  - `trading_best_practices` prompt now aligns with the current MCP safety constraints and testnet broker references.
56
+ - Updated testnet broker defaults:
57
+ - Arbitrum Sepolia `BROKER_ADDRESS` -> `0x895C4ae2A22bB26851011d733A9355f663a1F939`
58
+ - Linea Sepolia `BROKER_ADDRESS` -> `0x634EfDC9dC76D7AbF6E49279875a31B02E9891e2`
16
59
 
17
60
  ## 3.0.19 - 2026-03-19
18
61
 
package/README.md CHANGED
@@ -6,8 +6,8 @@ A production-ready MCP (Model Context Protocol) server for deep integration with
6
6
 
7
7
  # Release Notes
8
8
 
9
- - **Current release: 3.0.20**
10
- - **SDK baseline**: `@myx-trade/sdk@^1.0.2` compatibility completed.
9
+ - **Current release: 3.0.24**
10
+ - **SDK baseline**: `@myx-trade/sdk@^1.0.4-beta.4` compatibility completed.
11
11
  - **Refinement**: Consolidated 40+ specialized tools into ~26 high-level unified tools.
12
12
  - **Improved UX**: Enhanced AI parameter parsing, automated unit conversion, and structured error reporting.
13
13
  - **Safety refresh**: Docs and prompt guidance now reflect Oracle-only execution, exact-approval defaults, notional-based fee checks, TP/SL semantic validation, and LP preview fail-close behavior.
@@ -55,7 +55,7 @@ Use the broker that matches your active RPC and chain configuration.
55
55
  * **`list_pools`**: List all tradable assets on the current chain.
56
56
  * **`search_tools`**: Discover the right MCP tool by keyword, legacy tool name, or intent phrase.
57
57
  * **`get_price`**: Fetch real-time prices (Impact Market Price or Oracle Price).
58
- * **`get_pool_metadata`**: Comprehensive metrics (Fees, Open Interest, Liquidity Depth).
58
+ * **`get_pool_metadata`**: Comprehensive metrics (Fees, Open Interest, Liquidity Depth via fresh Oracle price).
59
59
  * **`get_kline`**: Fetch candlestick data for technical analysis.
60
60
 
61
61
  ### ⚔️ Trading Operations
@@ -93,6 +93,8 @@ Use the broker that matches your active RPC and chain configuration.
93
93
  - **Direction validation**: when a tool operates on an existing `positionId`, the supplied `direction` must match the live position.
94
94
  - **TP/SL semantics**: LONG requires `tpPrice > entryPrice` and `slPrice < entryPrice`; SHORT uses the inverse.
95
95
  - **LP safety**: LP preview failures are fail-close and no longer downgrade to `minAmountOut=0`.
96
+ - **LP metadata safety**: `get_pool_metadata(includeLiquidity=true)` now ignores caller-supplied `marketPrice` and derives liquidity depth from a fresh Oracle price only.
97
+ - **LP holdings semantics**: `get_my_lp_holdings` is an inventory view; returned rows are no longer ranked by mixed BASE/QUOTE LP raw balances.
96
98
 
97
99
  ---
98
100
 
@@ -127,7 +129,7 @@ Use these conventions when generating tool arguments:
127
129
  - `status`: `OPEN` / `HISTORY` / `ALL` are canonical; lowercase is tolerated
128
130
  - `poolType`: `BASE` / `QUOTE` are canonical; lowercase is tolerated
129
131
  - `orderType`: `MARKET` / `LIMIT` / `STOP` / `CONDITIONAL`
130
- - `timeInForce`: SDK `v1.0.2` currently supports `IOC` only, so use `0` or `"IOC"`
132
+ - `timeInForce`: SDK `v1.0.4-beta.4` currently supports `IOC` only, so use `0` or `"IOC"`
131
133
  - `size`: base token quantity, not USD notional; expected order value is usually `collateralAmount * leverage`
132
134
  - `executionFeeToken`: must be a real token address; zero address is rejected. Use the pool `quoteToken`
133
135
  - `slippagePct`: trading tools use 4-decimal raw units where `100 = 1.00%` and `50 = 0.50%`
@@ -156,6 +158,8 @@ Examples:
156
158
  }
157
159
  ```
158
160
 
161
+ For `get_pool_metadata(includeLiquidity=true)`, do not rely on a custom `marketPrice` override. MCP now ignores that field and uses a fresh Oracle price automatically.
162
+
159
163
  ```json
160
164
  {
161
165
  "name": "open_position_simple",
package/TOOL_EXAMPLES.md CHANGED
@@ -1,4 +1,4 @@
1
- # MYX MCP Tool Examples Handbook (v3.0.20)
1
+ # MYX MCP Tool Examples Handbook (v3.0.24)
2
2
 
3
3
  This guide provides practical MCP payload examples for the current unified toolset.
4
4
  All examples use the MCP format:
@@ -120,7 +120,7 @@ Low-level increase-order tool when you want full control.
120
120
  }
121
121
  ```
122
122
 
123
- `timeInForce` should be `0` (or `"IOC"` in string form) for SDK `v1.0.2`.
123
+ `timeInForce` should be `0` (or `"IOC"` in string form) for SDK `v1.0.4-beta.4`.
124
124
  `executionFeeToken` must be a real token address; do not pass the zero address. Use the pool `quoteToken`.
125
125
  If `positionId` is supplied on increase flows, `direction` must remain consistent with the live position.
126
126
 
@@ -249,6 +249,7 @@ Unified pool detail, config, and liquidity info.
249
249
  ```
250
250
 
251
251
  `get_pool_metadata` returns raw values in `poolInfo` and precision-safe human-readable values in `poolInfoFormatted`, including readable funding epoch timestamps, funding-rate `%/秒` and `%/天`, and IO notional-at-entry views.
252
+ When `includeLiquidity=true`, MCP derives liquidity depth from a fresh Oracle price automatically. Any caller-supplied `marketPrice` is now treated as deprecated and ignored.
252
253
 
253
254
  ### `get_kline`
254
255
  Read chart data. Use `limit: 1` for the latest bar.
@@ -330,6 +331,8 @@ Read current LP balances across pools.
330
331
  }
331
332
  ```
332
333
 
334
+ `get_my_lp_holdings` is an inventory view. Results are now stably ordered by symbol / pool id instead of summing BASE LP raw units with QUOTE LP raw units into a misleading mixed-unit ranking.
335
+
333
336
  ---
334
337
 
335
338
  ## Account And Monitoring
@@ -5,10 +5,10 @@ let cached = null;
5
5
  function getDefaultBrokerByChainId(chainId) {
6
6
  // Testnet mappings
7
7
  if (chainId === 421614)
8
- return "0x8f3153C18f698166f5D6124d8ba5B567F5f120f9"; // Arbitrum Sepolia
8
+ return "0x895C4ae2A22bB26851011d733A9355f663a1F939"; // Arbitrum Sepolia
9
9
  if (chainId === 59141)
10
- return "0x0FB08D3A1Ea6bE515fe78D3e0CaEb6990b468Cf3"; // Linea Sepolia
11
- return "0x8f3153C18f698166f5D6124d8ba5B567F5f120f9";
10
+ return "0x634EfDC9dC76D7AbF6E49279875a31B02E9891e2"; // Linea Sepolia
11
+ return "0x895C4ae2A22bB26851011d733A9355f663a1F939";
12
12
  }
13
13
  function getDefaultQuoteTokenByChainId(chainId) {
14
14
  // Testnet mappings
@@ -12,7 +12,7 @@ export const tradingGuidePrompt = {
12
12
  content: {
13
13
  type: "text",
14
14
  text: `
15
- # MYX Trading MCP Best Practices (v3.0.21)
15
+ # MYX Trading MCP Best Practices (v3.0.24)
16
16
 
17
17
  You are an expert crypto trader using the MYX Protocol. To ensure successful execution and safe handling of user funds, follow these patterns:
18
18
 
@@ -30,6 +30,7 @@ You are an expert crypto trader using the MYX Protocol. To ensure successful exe
30
30
  - **Unit Prefixes**: Prefer \`human:\` for readable amounts (e.g., "100" USDC) and \`raw:\` for exact on-chain units.
31
31
  - **Slippage**: Trading tools use 4-decimal raw units where \`100 = 1.00%\` and \`50 = 0.50%\`. Keep it tight unless the market is genuinely illiquid.
32
32
  - **Fees**: Use \`get_pool_metadata\` to view current fee tiers and pool configuration.
33
+ - **Liquidity Metadata**: When calling \`get_pool_metadata(includeLiquidity=true)\`, MCP uses a fresh Oracle price automatically and ignores caller-supplied \`marketPrice\`.
33
34
  - **LP Strategy**: Use \`get_my_lp_holdings\` to monitor liquidity positions. Naming follows \`mBASE.QUOTE\` (e.g., \`mBTC.USDC\`).
34
35
  - **Enum Tolerance**: The server tolerates common lowercase or alias inputs such as \`open\`, \`base\`, \`buy\`, and \`add\`, but canonical forms are still preferred in documentation.
35
36
  - **Oracle Safety**: Execution flows now require a fresh Oracle price. Do not fall back to stale ticker or user-supplied execution prices when the Oracle is unavailable.
@@ -37,6 +38,7 @@ You are an expert crypto trader using the MYX Protocol. To ensure successful exe
37
38
  - **Position Semantics**: \`size\` is BASE quantity, not USD notional. If a \`positionId\` is supplied, \`direction\` must match the live position.
38
39
  - **TP/SL Semantics**: LONG should use \`tpPrice > entryPrice\` and \`slPrice < entryPrice\`; SHORT uses the inverse. Plain integer strings like \`"65000"\` are treated as human prices, not implicit raw 30-decimal values.
39
40
  - **LP Safety**: LP execution requires a fresh price snapshot and preview success; do not continue after preview failure.
41
+ - **LP Read Semantics**: Treat \`get_my_lp_holdings\` as an inventory listing, not a portfolio ranking by economic value.
40
42
 
41
43
  ## 3. Testnet Broker Reference
42
44
  - Arbitrum test: \`0x895C4ae2A22bB26851011d733A9355f663a1F939\`
package/dist/server.js CHANGED
@@ -461,7 +461,7 @@ function zodSchemaToJsonSchema(zodSchema) {
461
461
  };
462
462
  }
463
463
  // ─── MCP Server ───
464
- const server = new Server({ name: "myx-mcp-trading-server", version: "3.0.21" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
464
+ const server = new Server({ name: "myx-mcp-trading-server", version: "3.0.24" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
465
465
  // List tools
466
466
  server.setRequestHandler(ListToolsRequestSchema, async () => {
467
467
  return {
@@ -582,7 +582,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
582
582
  async function main() {
583
583
  const transport = new StdioServerTransport();
584
584
  await server.connect(transport);
585
- logger.info("🚀 MYX Trading MCP Server v3.0.20 running (stdio, pure on-chain, prod ready)");
585
+ logger.info("🚀 MYX Trading MCP Server v3.0.24 running (stdio, pure on-chain, prod ready)");
586
586
  }
587
587
  main().catch((err) => {
588
588
  logger.error("Fatal Server Startup Error", err);
@@ -5,10 +5,19 @@ import { ensureUnits, parseUserUnits } from "../utils/units.js";
5
5
  import { normalizeAddress } from "../utils/address.js";
6
6
  import { Contract } from "ethers";
7
7
  import { logger } from "../utils/logger.js";
8
- import { assertOracleFreshness } from "./marketService.js";
8
+ import { assertOracleFreshness, getFreshOraclePrice } from "./marketService.js";
9
9
  const LP_DECIMALS = 18;
10
10
  const POOL_MANAGER_BY_CHAIN = {
11
11
  421614: "0xf268D9FeD3Bd56fd9aBdb4FeEb993338613678A8",
12
+ 59141: "0x85e869d98216221807A06636541Ec93C9c0a4B0c",
13
+ 97: "0x4F917ef137b573D9790b87e3cF6dfb698cF00c9c",
14
+ 56: "0x13F2130c2F3bfd612BBCBF35FB9E467dd32bAF3A",
15
+ };
16
+ const POOL_MANAGER_BY_CHAIN_BETA = {
17
+ 421614: "0x05314a21Fc97B74f168730153b2B63A870D25dE5",
18
+ 59141: "0xcf51a6895864c6D8E507fC31EF16b9011287c5f4",
19
+ 97: "0x9E84a999e15CCdb2F64a5AF10939c25769dF6b07",
20
+ 56: "0x9E84a999e15CCdb2F64a5AF10939c25769dF6b07",
12
21
  };
13
22
  const POOL_MANAGER_ABI = [
14
23
  "function deployPool((bytes32 marketId,address baseToken))",
@@ -52,6 +61,11 @@ const LP_ROUTER_BY_CHAIN_BETA = {
52
61
  basePool: "0x51B62554a76197d5DF2D5dC4D57FF54d40775938",
53
62
  quotePool: "0x783Ed065a12e1C1D33c2a8d6408385C1843D3084",
54
63
  },
64
+ 56: {
65
+ router: "0x0F4C6f18Fb136DD1eBd6Da3C5d86a86597CF79a3",
66
+ basePool: "0x51B62554a76197d5DF2D5dC4D57FF54d40775938",
67
+ quotePool: "0x783Ed065a12e1C1D33c2a8d6408385C1843D3084",
68
+ },
55
69
  };
56
70
  const PREVIEW_POOL_ABI = [
57
71
  "function previewLpAmountOut(bytes32,uint256,uint256) view returns (uint256)",
@@ -151,9 +165,10 @@ function getPoolManagerAddress(chainId) {
151
165
  if (envAddress) {
152
166
  return normalizeAddress(envAddress, "POOL_MANAGER_ADDRESS");
153
167
  }
154
- const mapped = POOL_MANAGER_BY_CHAIN[chainId];
168
+ const source = isBetaModeEnabled() ? POOL_MANAGER_BY_CHAIN_BETA : POOL_MANAGER_BY_CHAIN;
169
+ const mapped = source[chainId];
155
170
  if (!mapped) {
156
- throw new Error(`Pool manager address is not configured for chainId=${chainId}. Set POOL_MANAGER_ADDRESS env var.`);
171
+ throw new Error(`Pool manager address is not configured for chainId=${chainId} (beta=${isBetaModeEnabled()}). Set POOL_MANAGER_ADDRESS env var.`);
157
172
  }
158
173
  return mapped;
159
174
  }
@@ -353,26 +368,14 @@ async function resolvePositiveMarketPrice30(client, poolId, chainId) {
353
368
  if (!client)
354
369
  return null;
355
370
  try {
356
- const oracle = await client.utils?.getOraclePrice?.(poolId, chainId);
357
- assertOracleFreshness(oracle?.publishTime, poolId);
358
- const byPrice = toPositiveBigint(oracle?.price);
371
+ const oracle = await getFreshOraclePrice(client, poolId, chainId);
372
+ const oraclePrice30 = ensureUnits(String(oracle?.price ?? "").trim(), 30, "oracle price");
373
+ const byPrice = toPositiveBigint(oraclePrice30);
359
374
  if (byPrice)
360
375
  return byPrice;
361
376
  }
362
377
  catch {
363
378
  }
364
- try {
365
- const tickerRes = await client.markets?.getTickerList?.({ chainId, poolIds: [poolId] });
366
- const row = Array.isArray(tickerRes) ? tickerRes[0] : tickerRes?.data?.[0];
367
- if (row?.price) {
368
- const tickerRaw = ensureUnits(row.price, 30, "ticker price");
369
- const byTicker = toPositiveBigint(tickerRaw);
370
- if (byTicker)
371
- return byTicker;
372
- }
373
- }
374
- catch {
375
- }
376
379
  return null;
377
380
  }
378
381
  /**
@@ -473,9 +476,18 @@ export async function getPoolDetail(poolId, chainIdOverride) {
473
476
  /**
474
477
  * 获取流动性信息
475
478
  */
476
- export async function getLiquidityInfo(client, poolId, marketPrice, chainIdOverride) {
479
+ export async function getLiquidityInfo(client, poolId, chainIdOverride) {
477
480
  const chainId = chainIdOverride ?? getChainId();
478
- return client.utils.getLiquidityInfo({ chainId, poolId, marketPrice });
481
+ const oracle = await getFreshOraclePrice(client, poolId, chainId);
482
+ const marketPrice = ensureUnits(String(oracle?.price ?? "").trim(), 30, "oracle price");
483
+ const liquidityInfo = await client.utils.getLiquidityInfo({ chainId, poolId, marketPrice });
484
+ return {
485
+ liquidityInfo,
486
+ marketPrice,
487
+ marketPriceSource: "oracle",
488
+ oraclePublishTime: String(oracle?.publishTime ?? ""),
489
+ oracleType: oracle?.oracleType ?? null,
490
+ };
479
491
  }
480
492
  /**
481
493
  * Quote 池 deposit
@@ -41,7 +41,7 @@ export const closePositionTool = {
41
41
  collateralAmount: z.union([z.string(), z.number()]).describe("Collateral amount (human/raw). Also supports ALL/FULL/MAX to use live position collateral raw."),
42
42
  size: z.union([z.string(), z.number()]).describe("Position size (human/raw). Also supports ALL/FULL/MAX for exact full-close raw size."),
43
43
  price: z.union([z.string(), z.number()]).describe("Price (human or 30-dec raw units)"),
44
- timeInForce: z.union([z.number(), z.string()]).describe("SDK v1.0.2 supports IOC only. Use 0 or 'IOC'."),
44
+ timeInForce: z.union([z.number(), z.string()]).describe("SDK v1.0.4-beta.4 supports IOC only. Use 0 or 'IOC'."),
45
45
  postOnly: z.coerce.boolean().describe("Post-only flag"),
46
46
  slippagePct: z.coerce.string().default("50").describe(SLIPPAGE_PCT_4DP_DESC),
47
47
  executionFeeToken: z.string().describe("Execution fee token address"),
@@ -32,7 +32,7 @@ export const executeTradeTool = {
32
32
  collateralAmount: z.union([z.string(), z.number()]).describe("Collateral. e.g. '100' or 'raw:100000000' (6 decimals for USDC)."),
33
33
  size: z.union([z.string(), z.number()]).describe("Notional size in base tokens. e.g. '0.5' BTC or 'raw:50000000'."),
34
34
  price: z.union([z.string(), z.number()]).describe("Execution or Limit price. e.g. '65000' or 'raw:...'"),
35
- timeInForce: z.union([z.number(), z.string()]).describe("SDK v1.0.2 supports IOC only. Use 0 or 'IOC'."),
35
+ timeInForce: z.union([z.number(), z.string()]).describe("SDK v1.0.4-beta.4 supports IOC only. Use 0 or 'IOC'."),
36
36
  postOnly: z.coerce.boolean().describe("If true, order only executes as Maker."),
37
37
  slippagePct: z.coerce.string().default("50").describe(`${SLIPPAGE_PCT_4DP_DESC}. Default is 50 (0.5%).`),
38
38
  executionFeeToken: z.string().optional().describe("Address of token to pay gas/execution fees (typically USDC). Default is pool quoteToken."),
@@ -121,9 +121,6 @@ function toSymbol(row) {
121
121
  return base;
122
122
  return normalizePoolId(row?.poolId ?? row?.pool_id);
123
123
  }
124
- function sumRaw(baseRaw, quoteRaw) {
125
- return BigInt(baseRaw || "0") + BigInt(quoteRaw || "0");
126
- }
127
124
  async function readErc20Balance(provider, tokenAddress, holder) {
128
125
  const contract = new Contract(tokenAddress, ERC20_BALANCE_ABI, provider);
129
126
  const balance = await contract.balanceOf(holder);
@@ -227,11 +224,10 @@ export const getMyLpHoldingsTool = {
227
224
  });
228
225
  }
229
226
  items.sort((left, right) => {
230
- const leftSum = sumRaw(left.baseLpBalanceRaw, left.quoteLpBalanceRaw);
231
- const rightSum = sumRaw(right.baseLpBalanceRaw, right.quoteLpBalanceRaw);
232
- if (leftSum === rightSum)
233
- return 0;
234
- return rightSum > leftSum ? 1 : -1;
227
+ const symbolCompare = String(left.symbol ?? "").localeCompare(String(right.symbol ?? ""));
228
+ if (symbolCompare !== 0)
229
+ return symbolCompare;
230
+ return String(left.poolId ?? "").localeCompare(String(right.poolId ?? ""));
235
231
  });
236
232
  const payload = {
237
233
  meta: {
@@ -4,21 +4,8 @@ import { resolveClient, getChainId } from "../auth/resolveClient.js";
4
4
  import { getMarketDetail, resolvePool } from "../services/marketService.js";
5
5
  import { getPoolInfo, getLiquidityInfo } from "../services/poolService.js";
6
6
  import { extractErrorMessage } from "../utils/errorMessage.js";
7
- import { parseUserPrice30 } from "../utils/units.js";
8
7
  const INTEGER_RE = /^\d+$/;
9
8
  const SIGNED_INTEGER_RE = /^-?\d+$/;
10
- const DECIMAL_RE = /^\d+(\.\d+)?$/;
11
- function normalizeMarketPrice30Input(value) {
12
- const text = String(value ?? "").trim();
13
- if (!text)
14
- return "";
15
- if (INTEGER_RE.test(text))
16
- return text;
17
- if (!DECIMAL_RE.test(text) && !/^raw:/i.test(text) && !/^human:/i.test(text)) {
18
- throw new Error("marketPrice must be numeric, or prefixed with raw:/human:.");
19
- }
20
- return parseUserPrice30(text, "marketPrice");
21
- }
22
9
  function compactWarning(scope, err) {
23
10
  const raw = extractErrorMessage(err);
24
11
  const flat = raw.replace(/\s+/g, " ").trim();
@@ -211,8 +198,8 @@ export const getPoolMetadataTool = {
211
198
  schema: {
212
199
  poolId: z.string().optional().describe("Pool ID, Token Address, or Keyword"),
213
200
  keyword: z.string().optional().describe("Market keyword (e.g. 'BTC')"),
214
- includeLiquidity: z.boolean().default(false).describe("Whether to include liquidity depth (requires marketPrice)"),
215
- marketPrice: z.union([z.string(), z.number()]).optional().describe("Current price (required if includeLiquidity is true)"),
201
+ includeLiquidity: z.boolean().default(false).describe("Whether to include liquidity depth (uses fresh oracle price automatically)"),
202
+ marketPrice: z.union([z.string(), z.number()]).optional().describe("Deprecated and ignored. MCP now uses fresh oracle price for liquidity depth."),
216
203
  includeConfig: z.boolean().default(false).describe("Whether to include pool level configuration/limits"),
217
204
  chainId: z.number().int().positive().optional().describe("Optional chainId override"),
218
205
  },
@@ -245,10 +232,15 @@ export const getPoolMetadataTool = {
245
232
  // 3. Optional: Liquidity Info
246
233
  if (args.includeLiquidity) {
247
234
  try {
248
- const price = normalizeMarketPrice30Input(args.marketPrice);
249
- if (!price)
250
- throw new Error("marketPrice is required for liquidity info.");
251
- results.liquidityInfo = await getLiquidityInfo(client, poolId, price, chainId);
235
+ const liquidityResult = await getLiquidityInfo(client, poolId, chainId);
236
+ results.liquidityInfo = liquidityResult.liquidityInfo;
237
+ results.liquidityInfoMeta = {
238
+ marketPriceSource: liquidityResult.marketPriceSource,
239
+ marketPrice: liquidityResult.marketPrice,
240
+ oraclePublishTime: liquidityResult.oraclePublishTime,
241
+ oracleType: liquidityResult.oracleType,
242
+ ignoredUserMarketPrice: args.marketPrice !== undefined ? String(args.marketPrice) : null,
243
+ };
252
244
  }
253
245
  catch (err) {
254
246
  errors.push(compactWarning("liquidityInfo", err));
@@ -171,7 +171,7 @@ export const mapTriggerType = (input) => {
171
171
  throw new Error(`Invalid triggerType: ${input}. Use 0/NONE, 1/GTE or 2/LTE.`);
172
172
  };
173
173
  /**
174
- * SDK v1.0.2 currently exposes IOC only.
174
+ * SDK v1.0.4-beta.4 currently exposes IOC only.
175
175
  */
176
176
  export const mapTimeInForce = (input) => {
177
177
  if (input === 0)
@@ -179,5 +179,5 @@ export const mapTimeInForce = (input) => {
179
179
  const s = String(input ?? "").trim().toUpperCase();
180
180
  if (s === "0" || s === "IOC")
181
181
  return 0;
182
- throw new Error(`Invalid timeInForce: ${input}. SDK v1.0.2 currently supports IOC only, use 0/IOC.`);
182
+ throw new Error(`Invalid timeInForce: ${input}. SDK v1.0.4-beta.4 currently supports IOC only, use 0/IOC.`);
183
183
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michaleffffff/mcp-trading-server",
3
- "version": "3.0.21",
3
+ "version": "3.0.24",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "myx-mcp": "dist/server.js"
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@modelcontextprotocol/sdk": "^1.27.1",
24
- "@myx-trade/sdk": "^1.0.2",
24
+ "@myx-trade/sdk": "^1.0.4-beta.4",
25
25
  "dotenv": "^17.3.1",
26
26
  "ethers": "^6.13.1",
27
27
  "zod": "^4.3.6"