@michaleffffff/mcp-trading-server 2.2.2 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -67,7 +67,7 @@ function zodSchemaToJsonSchema(zodSchema) {
67
67
  };
68
68
  }
69
69
  // ─── MCP Server ───
70
- const server = new Server({ name: "myx-mcp-trading-server", version: "2.2.2" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
70
+ const server = new Server({ name: "myx-mcp-trading-server", version: "2.3.1" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
71
71
  // List tools
72
72
  server.setRequestHandler(ListToolsRequestSchema, async () => {
73
73
  return {
@@ -167,7 +167,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
167
167
  async function main() {
168
168
  const transport = new StdioServerTransport();
169
169
  await server.connect(transport);
170
- logger.info("🚀 MYX Trading MCP Server v2.2.2 running (stdio, pure on-chain, prod ready)");
170
+ logger.info("🚀 MYX Trading MCP Server v2.3.1 running (stdio, pure on-chain, prod ready)");
171
171
  }
172
172
  main().catch((err) => {
173
173
  logger.error("Fatal Server Startup Error", err);
@@ -1,4 +1,5 @@
1
1
  import { getChainId } from "../auth/resolveClient.js";
2
+ import { getMarketStateDesc } from "../utils/mappings.js";
2
3
  export async function getMarketPrice(client, poolId) {
3
4
  const chainId = getChainId();
4
5
  const ticker = await client.markets.getTickerList({
@@ -51,11 +52,29 @@ export async function searchMarket(client, keyword, limit = 100) {
51
52
  price: ticker ? ticker.price : "0",
52
53
  change24h: ticker ? ticker.change : "0",
53
54
  tvl: m.tvl || "0",
54
- state: m.state
55
+ state: m.state,
56
+ stateDescription: getMarketStateDesc(m.state)
55
57
  };
56
58
  });
57
59
  }
58
60
  export async function getMarketDetail(client, poolId) {
59
61
  const chainId = getChainId();
60
- return client.markets.getMarketDetail({ chainId, poolId });
62
+ const res = await client.markets.getMarketDetail({ chainId, poolId });
63
+ // Ensure it's returned as { data: ... } for consistency with other services if needed,
64
+ // but looking at existing tools, they often stringify the whole result.
65
+ // Let's just normalize it to always have the data if it's missing.
66
+ return res?.marketId ? { data: res } : res;
67
+ }
68
+ /**
69
+ * 获取所有池子列表
70
+ */
71
+ export async function getPoolList(client) {
72
+ return client.api.getPoolList();
73
+ }
74
+ /**
75
+ * 获取池子分级配置
76
+ */
77
+ export async function getPoolLevelConfig(client, poolId) {
78
+ const chainId = getChainId();
79
+ return client.api.getPoolLevelConfig({ poolId, chainId });
61
80
  }
@@ -1,4 +1,4 @@
1
- import { Direction, OrderType, TriggerType, OracleType } from "@myx-trade/sdk";
1
+ import { Direction, OrderType, TriggerType } from "@myx-trade/sdk";
2
2
  import { parseUnits } from "ethers";
3
3
  import { getChainId, getQuoteToken, getQuoteDecimals } from "../auth/resolveClient.js";
4
4
  import { ensureUnits, parseHumanUnits } from "../utils/units.js";
@@ -87,11 +87,13 @@ export async function openPosition(client, address, args) {
87
87
  }
88
88
  // tradingFee: SDK 第二个参数
89
89
  const tradingFeeStr = (args.tradingFee || "0").toString();
90
- console.error("=== [DEBUG] ORDER PARAMS TO SDK ===");
91
- console.error(JSON.stringify(orderParams, (k, v) => typeof v === 'bigint' ? v.toString() : v, 2));
92
- console.error("tradingFeeStr:", tradingFeeStr);
93
- console.error("===========================");
94
- return client.order.createIncreaseOrder(orderParams, tradingFeeStr);
90
+ // 获取 marketId,SDK 0.1.267 要求 as 3rd parameter
91
+ const marketDetailRes = await client.markets.getMarketDetail({ chainId, poolId: args.poolId });
92
+ const marketId = marketDetailRes?.marketId || marketDetailRes?.data?.marketId;
93
+ if (!marketId) {
94
+ throw new Error(`Could not find marketId for poolId: ${args.poolId}`);
95
+ }
96
+ return client.order.createIncreaseOrder(orderParams, tradingFeeStr, marketId);
95
97
  }
96
98
  /**
97
99
  * 平仓 / 减仓
@@ -165,7 +167,6 @@ export async function adjustMargin(client, address, args) {
165
167
  positionId: args.positionId,
166
168
  adjustAmount: parseHumanUnits(args.adjustAmount, quoteDecimals, "adjustAmount"),
167
169
  quoteToken,
168
- poolOracleType: OracleType.Pyth,
169
170
  chainId,
170
171
  address,
171
172
  });
@@ -217,3 +218,22 @@ export async function closeAllPositions(client, address) {
217
218
  }
218
219
  return { status: "success", data: results };
219
220
  }
221
+ /**
222
+ * 更新止盈止损订单
223
+ */
224
+ export async function updateOrderTpSl(client, address, args) {
225
+ const chainId = getChainId();
226
+ const quoteToken = args.quoteToken || getQuoteToken();
227
+ const params = {
228
+ orderId: args.orderId,
229
+ tpSize: args.tpSize || "0",
230
+ tpPrice: args.tpPrice ? parseHumanUnits(args.tpPrice, 30, "tpPrice") : "0",
231
+ slSize: args.slSize || "0",
232
+ slPrice: args.slPrice ? parseHumanUnits(args.slPrice, 30, "slPrice") : "0",
233
+ useOrderCollateral: args.useOrderCollateral ?? true,
234
+ executionFeeToken: quoteToken,
235
+ size: args.size || "0",
236
+ price: args.price || "0",
237
+ };
238
+ return client.order.updateOrderTpSl(params, quoteToken, chainId, address, args.marketId, args.isTpSlOrder ?? true);
239
+ }
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { resolveClient, getChainId } from "../auth/resolveClient.js";
3
+ import { getTradeFlowTypeDesc } from "../utils/mappings.js";
3
4
  export const getAccountInfoTool = {
4
5
  name: "get_account_info",
5
6
  description: "Get full account information for a pool (freeMargin, quoteProfit, etc.). Essential for risk management.",
@@ -11,7 +12,24 @@ export const getAccountInfoTool = {
11
12
  const { client, address } = await resolveClient();
12
13
  const chainId = getChainId();
13
14
  const result = await client.account.getAccountInfo(chainId, address, args.poolId);
14
- return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
15
+ // Map the raw array to a structured object for better usability
16
+ let structuredData = result;
17
+ if (result && result.code === 0 && Array.isArray(result.data)) {
18
+ const d = result.data;
19
+ structuredData = {
20
+ ...result,
21
+ data: {
22
+ marginBalance: d[0],
23
+ availableMargin: d[1],
24
+ unrealizedPnL: d[2],
25
+ initialMargin: d[3],
26
+ maintenanceMargin: d[4],
27
+ positionMargin: d[5],
28
+ lastUpdateTime: d[6]
29
+ }
30
+ };
31
+ }
32
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: structuredData }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
15
33
  }
16
34
  catch (error) {
17
35
  return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
@@ -30,7 +48,11 @@ export const getTradeFlowTool = {
30
48
  const { client, address } = await resolveClient();
31
49
  const chainId = getChainId();
32
50
  const result = await client.account.getTradeFlow({ chainId, limit: args.limit || 20 }, address);
33
- return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
51
+ const enhancedData = (result?.data || []).map((flow) => ({
52
+ ...flow,
53
+ typeDesc: getTradeFlowTypeDesc(flow.type)
54
+ }));
55
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: { ...result, data: enhancedData } }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
34
56
  }
35
57
  catch (error) {
36
58
  return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
@@ -2,7 +2,7 @@ import { resolveClient } from "../auth/resolveClient.js";
2
2
  import { searchMarket } from "../services/marketService.js";
3
3
  export const getMarketListTool = {
4
4
  name: "get_market_list",
5
- description: "Get the complete list of all available tradable markets/pools. Automatically filters for active and tradable markets.",
5
+ description: "Get the complete list of all available tradable markets/pools. Automatically filters for active and tradable markets. The 'state' field indicates market status: 0=Created, 1=WaitOracle, 2=Active, 3=PreDelisting, 4=Delisted.",
6
6
  schema: {},
7
7
  handler: async () => {
8
8
  try {
@@ -0,0 +1,17 @@
1
+ import { resolveClient } from "../auth/resolveClient.js";
2
+ import { getPoolList } from "../services/marketService.js";
3
+ export const getPoolListTool = {
4
+ name: "get_pool_list",
5
+ description: "Get the complete list of all available tradable pools directly from the SDK.",
6
+ schema: {},
7
+ handler: async () => {
8
+ try {
9
+ const { client } = await resolveClient();
10
+ const result = await getPoolList(client);
11
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
12
+ }
13
+ catch (error) {
14
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
15
+ }
16
+ },
17
+ };
@@ -1,5 +1,6 @@
1
1
  import { resolveClient } from "../auth/resolveClient.js";
2
2
  import { getPositions } from "../services/positionService.js";
3
+ import { getDirectionDesc } from "../utils/mappings.js";
3
4
  export const getPositionsTool = {
4
5
  name: "get_positions",
5
6
  description: "Get all open positions for the current account.",
@@ -8,7 +9,11 @@ export const getPositionsTool = {
8
9
  try {
9
10
  const { client, address } = await resolveClient();
10
11
  const data = await getPositions(client, address);
11
- return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
12
+ const enhancedData = (data || []).map((pos) => ({
13
+ ...pos,
14
+ directionDesc: getDirectionDesc(pos.direction)
15
+ }));
16
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: enhancedData }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
12
17
  }
13
18
  catch (error) {
14
19
  return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
@@ -3,6 +3,7 @@ export { executeTradeTool } from "./executeTrade.js";
3
3
  export { cancelOrderTool } from "./cancelOrder.js";
4
4
  export { closePositionTool } from "./closePosition.js";
5
5
  export { setTpSlTool } from "./setTpSl.js";
6
+ export { updateOrderTpSlTool } from "./updateOrderTpSl.js";
6
7
  export { adjustMarginTool } from "./adjustMargin.js";
7
8
  export { closeAllPositionsTool } from "./closeAllPositions.js";
8
9
  export { checkApprovalTool } from "./checkApproval.js";
@@ -12,6 +13,8 @@ export { getOraclePriceTool } from "./getOraclePrice.js";
12
13
  export { searchMarketTool } from "./searchMarket.js";
13
14
  export { getKlineTool } from "./getKline.js";
14
15
  export { getMarketDetailTool, getPoolInfoTool, getLiquidityInfoTool } from "./marketInfo.js";
16
+ export { getPoolListTool } from "./getPoolList.js";
17
+ export { getPoolLevelConfigTool } from "./poolConfig.js";
15
18
  // Tools — 池子 & 流动性
16
19
  export { createPerpMarketTool } from "./createPerpMarket.js";
17
20
  export { manageLiquidityTool, getLpPriceTool } from "./manageLiquidity.js";
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { resolveClient, getChainId } from "../auth/resolveClient.js";
3
+ import { getOrderTypeDesc, getOrderStatusDesc, getDirectionDesc, getHistoryOrderStatusDesc, getExecTypeDesc } from "../utils/mappings.js";
3
4
  export const getOpenOrdersTool = {
4
5
  name: "get_open_orders",
5
6
  description: "List all currently open/pending orders.",
@@ -8,7 +9,13 @@ export const getOpenOrdersTool = {
8
9
  try {
9
10
  const { client, address } = await resolveClient();
10
11
  const result = await client.order.getOrders(address);
11
- return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
12
+ const enhancedData = (result?.data || []).map((order) => ({
13
+ ...order,
14
+ orderTypeDesc: getOrderTypeDesc(order.orderType),
15
+ statusDesc: getOrderStatusDesc(order.status),
16
+ directionDesc: getDirectionDesc(order.direction)
17
+ }));
18
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: enhancedData }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
12
19
  }
13
20
  catch (error) {
14
21
  return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
@@ -28,7 +35,14 @@ export const getOrderHistoryTool = {
28
35
  const { client, address } = await resolveClient();
29
36
  const chainId = getChainId();
30
37
  const result = await client.order.getOrderHistory({ chainId, poolId: args.poolId, limit: args.limit || 20 }, address);
31
- return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
38
+ const enhancedData = (result?.data || []).map((order) => ({
39
+ ...order,
40
+ orderTypeDesc: getOrderTypeDesc(order.orderType),
41
+ orderStatusDesc: getHistoryOrderStatusDesc(order.orderStatus),
42
+ directionDesc: getDirectionDesc(order.direction),
43
+ execTypeDesc: getExecTypeDesc(order.execType)
44
+ }));
45
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: { ...result, data: enhancedData } }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
32
46
  }
33
47
  catch (error) {
34
48
  return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ import { resolveClient } from "../auth/resolveClient.js";
3
+ import { getPoolLevelConfig } from "../services/marketService.js";
4
+ export const getPoolLevelConfigTool = {
5
+ name: "get_pool_level_config",
6
+ description: "Get the level configuration and trading limits for a specific pool.",
7
+ schema: {
8
+ poolId: z.string().describe("Pool ID"),
9
+ },
10
+ handler: async (args) => {
11
+ try {
12
+ const { client } = await resolveClient();
13
+ const result = await getPoolLevelConfig(client, args.poolId);
14
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
15
+ }
16
+ catch (error) {
17
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
18
+ }
19
+ },
20
+ };
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { resolveClient, getChainId } from "../auth/resolveClient.js";
3
+ import { getDirectionDesc, getCloseTypeDesc } from "../utils/mappings.js";
3
4
  export const getPositionHistoryTool = {
4
5
  name: "get_position_history",
5
6
  description: "Get historical closed positions with optional pool filter and pagination.",
@@ -13,7 +14,12 @@ export const getPositionHistoryTool = {
13
14
  const { client, address } = await resolveClient();
14
15
  const chainId = getChainId();
15
16
  const result = await client.position.getPositionHistory({ chainId, poolId: args.poolId, limit: args.limit || 20 }, address);
16
- return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
17
+ const enhancedData = (result?.data || []).map((pos) => ({
18
+ ...pos,
19
+ directionDesc: getDirectionDesc(pos.direction),
20
+ closeTypeDesc: getCloseTypeDesc(pos.closeType)
21
+ }));
22
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: { ...result, data: enhancedData } }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
17
23
  }
18
24
  catch (error) {
19
25
  return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import { resolveClient } from "../auth/resolveClient.js";
3
+ import { updateOrderTpSl } from "../services/tradeService.js";
4
+ export const updateOrderTpSlTool = {
5
+ name: "update_order_tp_sl",
6
+ description: "Update an existing take profit or stop loss order.",
7
+ schema: {
8
+ orderId: z.string().describe("The ID of the order to update"),
9
+ marketId: z.string().describe("The market ID (config hash) for the order"),
10
+ tpPrice: z.string().optional().describe("New take-profit trigger price (human-readable)"),
11
+ tpSize: z.string().optional().describe("New TP size (18 decimals). Omit or '0' for full position."),
12
+ slPrice: z.string().optional().describe("New stop-loss trigger price (human-readable)"),
13
+ slSize: z.string().optional().describe("New SL size (18 decimals). Omit or '0' for full position."),
14
+ isTpSlOrder: z.boolean().optional().describe("Whether this is a TP/SL order (default true)"),
15
+ quoteToken: z.string().optional().describe("Quote token address"),
16
+ },
17
+ handler: async (args) => {
18
+ try {
19
+ const { client, address } = await resolveClient();
20
+ const result = await updateOrderTpSl(client, address, args);
21
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
22
+ }
23
+ catch (error) {
24
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
25
+ }
26
+ },
27
+ };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Direction: LONG=0, SHORT=1
3
+ */
4
+ export const getDirectionDesc = (direction) => {
5
+ switch (direction) {
6
+ case 0: return "Long";
7
+ case 1: return "Short";
8
+ default: return `Unknown(${direction})`;
9
+ }
10
+ };
11
+ /**
12
+ * OrderType: MARKET=0, LIMIT=1, STOP=2, CONDITIONAL=3
13
+ */
14
+ export const getOrderTypeDesc = (type) => {
15
+ switch (type) {
16
+ case 0: return "Market";
17
+ case 1: return "Limit";
18
+ case 2: return "Stop";
19
+ case 3: return "Conditional";
20
+ default: return `Unknown(${type})`;
21
+ }
22
+ };
23
+ /**
24
+ * OrderStatus: PENDING=0, PARTIAL=1, FILLED=2, CANCELLED=3, REJECTED=4, EXPIRED=5
25
+ */
26
+ export const getOrderStatusDesc = (status) => {
27
+ switch (status) {
28
+ case 0: return "Pending";
29
+ case 1: return "Partial";
30
+ case 2: return "Filled";
31
+ case 3: return "Cancelled";
32
+ case 4: return "Rejected";
33
+ case 5: return "Expired";
34
+ default: return `Unknown(${status})`;
35
+ }
36
+ };
37
+ /**
38
+ * OrderStatusEnum (Historical): Cancelled=1, Expired=2, Successful=9, PartialFilled=8
39
+ */
40
+ export const getHistoryOrderStatusDesc = (status) => {
41
+ switch (status) {
42
+ case 1: return "Cancelled";
43
+ case 2: return "Expired";
44
+ case 9: return "Successful";
45
+ case 8: return "PartialFilled";
46
+ default: return `Unknown(${status})`;
47
+ }
48
+ };
49
+ /**
50
+ * MarketPoolState
51
+ */
52
+ export const getMarketStateDesc = (state) => {
53
+ switch (state) {
54
+ case 0: return "Created";
55
+ case 1: return "WaitOracle";
56
+ case 2: return "Active";
57
+ case 3: return "PreDelisting";
58
+ case 4: return "Delisted";
59
+ default: return `Unknown(${state})`;
60
+ }
61
+ };
62
+ /**
63
+ * TradeFlowTypeEnum
64
+ */
65
+ export const getTradeFlowTypeDesc = (type) => {
66
+ const types = {
67
+ 0: "Increase",
68
+ 1: "Decrease",
69
+ 2: "AddMargin",
70
+ 3: "RemoveMargin",
71
+ 4: "CancelOrder",
72
+ 5: "ADL",
73
+ 6: "Liquidation",
74
+ 7: "MarketClose",
75
+ 8: "EarlyClose",
76
+ 9: "AddTPSL",
77
+ 10: "SecurityDeposit",
78
+ 11: "TransferToWallet",
79
+ 12: "MarginAccountDeposit",
80
+ 13: "ReferralReward",
81
+ 14: "ReferralRewardClaim"
82
+ };
83
+ return types[type] || `Unknown(${type})`;
84
+ };
85
+ /**
86
+ * ExecTypeEnum
87
+ */
88
+ export const getExecTypeDesc = (type) => {
89
+ const types = {
90
+ 1: "Market",
91
+ 2: "Limit",
92
+ 3: "TP",
93
+ 4: "SL",
94
+ 5: "ADL",
95
+ 6: "ADLTrigger",
96
+ 7: "Liquidation",
97
+ 8: "EarlyClose",
98
+ 9: "MarketClose"
99
+ };
100
+ return types[type] || `Unknown(${type})`;
101
+ };
102
+ /**
103
+ * CloseTypeEnum
104
+ */
105
+ export const getCloseTypeDesc = (type) => {
106
+ const types = {
107
+ 0: "Open",
108
+ 1: "PartialClose",
109
+ 2: "FullClose",
110
+ 3: "Liquidation",
111
+ 4: "EarlyClose",
112
+ 5: "MarketClose",
113
+ 6: "ADL",
114
+ 7: "TP",
115
+ 8: "SL",
116
+ 9: "Increase"
117
+ };
118
+ return types[type] || `Unknown(${type})`;
119
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michaleffffff/mcp-trading-server",
3
- "version": "2.2.2",
3
+ "version": "2.3.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "myx-mcp": "dist/server.js"
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@modelcontextprotocol/sdk": "^0.5.0",
19
- "@myx-trade/sdk": "0.1.267",
19
+ "@myx-trade/sdk": "^0.1.269",
20
20
  "dotenv": "^16.4.5",
21
21
  "ethers": "^6.13.1",
22
22
  "zod": "^3.23.8"