hchain-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.env.example +5 -0
  2. package/AGENT-MCP-RULES.md +248 -0
  3. package/OnchainOS-API/345/257/271/346/216/245/350/247/204/350/214/203.md +329 -0
  4. package/README.md +106 -0
  5. package/dist/adapters/onchainos-ws.d.ts +31 -0
  6. package/dist/adapters/onchainos-ws.js +103 -0
  7. package/dist/adapters/onchainos.d.ts +343 -0
  8. package/dist/adapters/onchainos.js +275 -0
  9. package/dist/adapters/shared.d.ts +23 -0
  10. package/dist/adapters/shared.js +107 -0
  11. package/dist/http.d.ts +9 -0
  12. package/dist/http.js +124 -0
  13. package/dist/index.d.ts +6 -0
  14. package/dist/index.js +54 -0
  15. package/dist/tools/balance.d.ts +4 -0
  16. package/dist/tools/balance.js +69 -0
  17. package/dist/tools/defi.d.ts +4 -0
  18. package/dist/tools/defi.js +268 -0
  19. package/dist/tools/gateway.d.ts +4 -0
  20. package/dist/tools/gateway.js +107 -0
  21. package/dist/tools/intent.d.ts +4 -0
  22. package/dist/tools/intent.js +111 -0
  23. package/dist/tools/market.d.ts +4 -0
  24. package/dist/tools/market.js +612 -0
  25. package/dist/tools/payments.d.ts +4 -0
  26. package/dist/tools/payments.js +100 -0
  27. package/dist/tools/skills.d.ts +4 -0
  28. package/dist/tools/skills.js +464 -0
  29. package/dist/tools/trade.d.ts +4 -0
  30. package/dist/tools/trade.js +195 -0
  31. package/dist/tools/txhistory.d.ts +4 -0
  32. package/dist/tools/txhistory.js +49 -0
  33. package/dist/tools/ws.d.ts +4 -0
  34. package/dist/tools/ws.js +64 -0
  35. package/docs/DEFI.md +65 -0
  36. package/docs/GATEWAY.md +45 -0
  37. package/docs/MARKET.md +109 -0
  38. package/docs/PAYMENTS.md +83 -0
  39. package/docs/TRADE.md +103 -0
  40. package/package.json +25 -0
  41. package/src/adapters/onchainos-ws.ts +126 -0
  42. package/src/adapters/onchainos.ts +488 -0
  43. package/src/adapters/shared.ts +100 -0
  44. package/src/http.ts +132 -0
  45. package/src/index.ts +57 -0
  46. package/src/tools/balance.ts +67 -0
  47. package/src/tools/defi.ts +224 -0
  48. package/src/tools/gateway.ts +115 -0
  49. package/src/tools/intent.ts +106 -0
  50. package/src/tools/market.ts +543 -0
  51. package/src/tools/payments.ts +105 -0
  52. package/src/tools/skills.ts +489 -0
  53. package/src/tools/trade.ts +197 -0
  54. package/src/tools/txhistory.ts +51 -0
  55. package/src/tools/ws.ts +72 -0
  56. package/tsconfig.json +18 -0
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Trade 模块 — CAT:[链上-Swap]
3
+ * DEX 聚合器经典兑换: 8 tools, 参数来源官方 API 参考
4
+ */
5
+ import { z } from "zod";
6
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { tradeApi } from "../adapters/onchainos.js";
8
+ import { toResult, toError, AUTH_REQUIRED } from "../adapters/shared.js";
9
+ import type { Auth } from "../adapters/shared.js";
10
+
11
+ export function registerTradeTools(server: McpServer, auth: Auth | null): void {
12
+
13
+ server.tool("onchainos_dex_supported_chain",
14
+ "CAT:[链上-Swap] | ## 功能: 获取 DEX 聚合器支持的链, 返回 chainIndex/chainName/dexTokenApproveAddress\n## 场景: 兑换前确认链 + 获取 DEX Router 授权地址\n## 关键词: DEX, 链列表, chainIndex, router, approve\n## 参数:\n## - chainIndex: 可选过滤\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 微小 ~2KB\n## 关联: dexTokenApproveAddress -> onchainos_dex_approve_transaction",
15
+ { chainIndex: z.string().optional().describe("链索引, 可选过滤。不传返回所有链") },
16
+ { readOnlyHint: true },
17
+ async ({ chainIndex }) => { if(!auth) return AUTH_REQUIRED("READ"); try { return toResult(await tradeApi.supportedChain(auth, chainIndex)); } catch(e) { return toError(e); } },
18
+ );
19
+
20
+ server.tool("onchainos_dex_all_tokens",
21
+ "CAT:[链上-Swap] | ## 功能: 获取链上 DEX 可交易代币列表, 返回 decimals/tokenContractAddress/tokenName/tokenSymbol/tokenLogoUrl\n## 场景: 查找代币合约地址和精度\n## 关键词: 代币列表, tokens, decimals\n## 参数:\n## - chainIndex: 链索引(必填)\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 大 ~100KB\n## 关联: onchainos_dex_supported_chain -> 本工具 -> onchainos_dex_quote",
22
+ { chainIndex: z.string().describe("链索引。'1'=ETH '56'=BSC '137'=Polygon '8453'=Base '501'=Solana '784'=Sui") },
23
+ { readOnlyHint: true },
24
+ async ({ chainIndex }) => { if(!auth) return AUTH_REQUIRED("READ"); try { return toResult(await tradeApi.allTokens(auth, chainIndex)); } catch(e) { return toError(e); } },
25
+ );
26
+
27
+ server.tool("onchainos_dex_liquidity",
28
+ "CAT:[链上-Swap] | ## 功能: 获取链上流动性源列表, 返回 id/name/logo\n## 场景: 了解 DEX 覆盖范围, 用于 quote 的 dexIds/excludeDexIds 参数\n## 关键词: 流动性, liquidity, DEX列表, dexId\n## 参数:\n## - chainIndex: 链索引(必填)\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 中等 ~10KB\n## 关联: 本工具选流动性 -> onchainos_dex_quote (传 dexIds/excludeDexIds)",
29
+ { chainIndex: z.string().describe("链索引") },
30
+ { readOnlyHint: true },
31
+ async ({ chainIndex }) => { if(!auth) return AUTH_REQUIRED("READ"); try { return toResult(await tradeApi.liquidity(auth, chainIndex)); } catch(e) { return toError(e); } },
32
+ );
33
+
34
+ server.tool("onchainos_dex_quote",
35
+ "CAT:[链上-Swap] | ## 功能: 获取最优兑换报价, 返回 toTokenAmount/priceImpactPercent/dexRouterList/estimateGasFee/tradeFee\n## 场景: 交易前比价。返回 fromToken/toToken 含 isHoneyPot(貔貅检测)/taxRate(税率)\n## 关键词: 报价, quote, 价格影响, 路由, swapMode, exactIn, exactOut\n## 参数:\n## - chainIndex/amount/fromTokenAddress/toTokenAddress(必填)\n## - swapMode: exactIn(默认)/exactOut(必填)\n## - dexIds/excludeDexIds: 流动性过滤(可选)\n## - priceImpactProtectionPercent: 价格影响保护(可选, 默认90%)\n## - feePercent/directRoute/singleRouteOnly/singlePoolPerHop/assetAwareRouting(可选)\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 中等 ~10KB\n## 关联: onchainos_dex_all_tokens -> 本工具 -> onchainos_dex_swap / onchainos_dex_approve_transaction",
36
+ {
37
+ chainIndex: z.string().describe("链索引"),
38
+ amount: z.string().describe("交易数量, 含精度(最小单位)。如 1 USDT=1000000, 1 DAI=1000000000000000000"),
39
+ swapMode: z.enum(["exactIn","exactOut"]).optional().default("exactIn").describe("exactIn=按卖出数量报价 exactOut=按买入数量报价。exactOut仅ETH/Base/BSC/Arbitrum支持UniV2/V3"),
40
+ fromTokenAddress: z.string().describe("卖出代币合约地址"),
41
+ toTokenAddress: z.string().describe("买入代币合约地址"),
42
+ dexIds: z.string().optional().describe("限定流动性池 dexId, 逗号分隔。从 onchainos_dex_liquidity 获取"),
43
+ excludeDexIds: z.string().optional().describe("排除流动性池 dexId, 逗号分隔"),
44
+ priceImpactProtectionPercent: z.string().optional().describe("价格影响保护百分比(0-100)。超此值报价被拒。默认90, 设100禁用"),
45
+ feePercent: z.string().optional().describe("分佣百分比。Solana最大10%,其他链最大3%"),
46
+ excludePoolAddresses: z.string().optional().describe("过滤池子地址, 逗号分隔, 最多20个"),
47
+ directRoute: z.boolean().optional().describe("true=限制单一流动性池。仅Solana"),
48
+ singleRouteOnly: z.boolean().optional().describe("true=单路径(允许多跳多池,不并行)"),
49
+ singlePoolPerHop: z.boolean().optional().describe("true=每跳单池"),
50
+ assetAwareRouting: z.boolean().optional().describe("true=仅使用匹配资产类型的路由(U-U/U-Native)"),
51
+ forJitoBundle: z.boolean().optional().describe("true=排除不兼容Jito的DEX"),
52
+ },
53
+ { readOnlyHint: true },
54
+ async (params) => {
55
+ if(!auth) return AUTH_REQUIRED("READ");
56
+ try {
57
+ const q: Record<string, string> = {};
58
+ for (const [k, v] of Object.entries(params)) { if (v !== undefined) q[k] = typeof v === "boolean" ? String(v) : v; }
59
+ return toResult(await tradeApi.quote(auth, q), {
60
+ nextSteps: [
61
+ { action: "如为ERC20, 先授权", tool: "onchainos_dex_approve_transaction", condition: "非原生代币需要" },
62
+ { action: "构建兑换交易", tool: "onchainos_dex_swap" },
63
+ ],
64
+ });
65
+ } catch(e) { return toError(e); }
66
+ },
67
+ );
68
+
69
+ server.tool("onchainos_dex_approve_transaction",
70
+ "CAT:[链上-Swap] | ## 功能: 构建 ERC-20 授权交易 calldata, 返回 data/dexContractAddress/gasLimit/gasPrice\n## 场景: ERC20 Swap 前授权 DEX Router 动用代币\n## 关键词: approve, 授权, ERC20, calldata, dexContractAddress\n## 参数:\n## - chainIndex/tokenContractAddress/approveAmount(必填)\n## 鉴权: 需要 API Key(交易)\n## 风险: WRITE - 返回 calldata\n## 返回量: 微小 ~1KB\n## 关联: onchainos_dex_quote -> 本工具 -> onchainos_gateway_broadcast",
71
+ {
72
+ chainIndex: z.string().describe("链索引"),
73
+ tokenContractAddress: z.string().describe("代币合约地址"),
74
+ approveAmount: z.string().describe("授权数量, 含精度。如授权1 USDT=1000000, 1 DAI=1000000000000000000"),
75
+ },
76
+ { destructiveHint: true, idempotentHint: true },
77
+ async ({ chainIndex, tokenContractAddress, approveAmount }) => {
78
+ if(!auth) return AUTH_REQUIRED("TRADE");
79
+ try {
80
+ return toResult(await tradeApi.approveTransaction(auth, chainIndex, tokenContractAddress, approveAmount), {
81
+ nextSteps: [{ action: "签名后广播", tool: "onchainos_gateway_broadcast" }],
82
+ });
83
+ } catch(e) { return toError(e); }
84
+ },
85
+ );
86
+
87
+ server.tool("onchainos_dex_swap",
88
+ "CAT:[链上-Swap] | ## 功能: 构建兑换交易 calldata, 返回 tx(from/to/data/value/gas/gasPrice/maxPriorityFeePerGas/minReceiveAmount/maxSpendAmount/signatureData)\n## 场景: 授权后构建 swap。approveTransaction=true可一并返回授权calldata省去单独调approve\n## 关键词: swap, 兑换, calldata, 交易构建, MEV, Jito\n## 参数:\n## - chainIndex/amount/fromTokenAddress/toTokenAddress/userWalletAddress/slippagePercent(必填)\n## - swapMode/approveTransaction/approveAmount/feePercent/swapReceiverAddress(可选)\n## - autoSlippage/maxAutoslippagePercent/priceImpactProtectionPercent(可选)\n## - dexIds/excludeDexIds/excludePoolAddresses/disableRFQ/directRoute(可选)\n## - computeUnitPrice/computeUnitLimit/tips: Solana参数(可选)\n## - gaslimit/gasLevel: EVM gas参数(可选)\n## - positiveSlippagePercent/positiveSlippageFeeAddress: 正滑点分佣(可选,白名单)\n## 鉴权: 需要 API Key(交易)\n## 风险: WRITE - 返回 calldata\n## 返回量: 中等 ~5KB\n## 关联: onchainos_dex_quote -> 本工具 -> onchainos_gateway_simulate -> onchainos_gateway_broadcast",
89
+ {
90
+ chainIndex: z.string().describe("链索引"),
91
+ amount: z.string().describe("交易数量, 含精度(最小单位)。如1 USDT=1000000"),
92
+ swapMode: z.enum(["exactIn","exactOut"]).optional().default("exactIn").describe("exactIn=按卖出 exactOut=按买入(仅ETH/Base/BSC/Arbitrum的UniV2/V3支持)"),
93
+ fromTokenAddress: z.string().describe("卖出代币地址"),
94
+ toTokenAddress: z.string().describe("买入代币地址"),
95
+ userWalletAddress: z.string().describe("用户钱包地址"),
96
+ slippagePercent: z.string().describe("滑点百分比。EVM:0-100, Solana:0-<100"),
97
+ approveTransaction: z.boolean().optional().describe("true=一并返回授权calldata(signatureData), 省去单独调approve"),
98
+ approveAmount: z.string().optional().describe("授权数量, 含精度。approveTransaction=true时使用"),
99
+ autoSlippage: z.boolean().optional().describe("true=自动滑点覆盖slippagePercent"),
100
+ maxAutoslippagePercent: z.string().optional().describe("自动滑点上限百分比"),
101
+ feePercent: z.string().optional().describe("分佣百分比。Solana最大10%, 其他链最大3%"),
102
+ fromTokenReferrerWalletAddress: z.string().optional().describe("fromToken分佣地址"),
103
+ toTokenReferrerWalletAddress: z.string().optional().describe("toToken分佣地址"),
104
+ swapReceiverAddress: z.string().optional().describe("接收代币地址, 默认=userWalletAddress"),
105
+ priceImpactProtectionPercent: z.string().optional().describe("价格影响保护(0-100,默认90)"),
106
+ dexIds: z.string().optional().describe("限定流动性池,逗号分隔"),
107
+ excludeDexIds: z.string().optional().describe("排除流动性池,逗号分隔"),
108
+ excludePoolAddresses: z.string().optional().describe("过滤池子地址,逗号分隔,最多20"),
109
+ disableRFQ: z.boolean().optional().describe("true=禁用RFQ"),
110
+ directRoute: z.boolean().optional().describe("true=单跳模式。Solana和EVM均支持"),
111
+ singleRouteOnly: z.boolean().optional().describe("true=单路径(允许多跳多池)"),
112
+ singlePoolPerHop: z.boolean().optional().describe("true=每跳单池"),
113
+ assetAwareRouting: z.boolean().optional().describe("true=仅匹配资产类型的路由"),
114
+ gaslimit: z.string().optional().describe("EVM gas限额(wei)。过低会导致报价失败"),
115
+ gasLevel: z.enum(["average","fast","slow"]).optional().describe("EVM gas等级,默认average"),
116
+ computeUnitPrice: z.string().optional().describe("Solana compute unit price"),
117
+ computeUnitLimit: z.string().optional().describe("Solana compute unit limit"),
118
+ tips: z.string().optional().describe("Jito tips(SOL)。0.0000000001~2。指定后signatureData返回Jito转账calldata"),
119
+ forJitoBundle: z.boolean().optional().describe("true=排除不兼容Jito的DEX"),
120
+ positiveSlippagePercent: z.string().optional().describe("正滑点分佣比例(0-10,白名单)"),
121
+ positiveSlippageFeeAddress: z.string().optional().describe("正滑点分佣地址(白名单)"),
122
+ callDataMemo: z.string().optional().describe("自定义calldata上链数据(64bytes hex,如'0x...')"),
123
+ maxCalldataSize: z.string().optional().describe("最大calldata大小估计值"),
124
+ maxAccounts: z.string().optional().describe("最大账户数估计值"),
125
+ },
126
+ { destructiveHint: true },
127
+ async (params) => {
128
+ if(!auth) return AUTH_REQUIRED("TRADE");
129
+ try {
130
+ const q: Record<string, string> = {};
131
+ for (const [k, v] of Object.entries(params)) { if (v !== undefined) q[k] = typeof v === "boolean" ? String(v) : v; }
132
+ return toResult(await tradeApi.swap(auth, q), {
133
+ nextSteps: [
134
+ { action: "如有 signatureData, 先执行授权 calldata", tool: "onchainos_gateway_broadcast", condition: "signatureData 存在时包含 approveContract+approveTxCalldata" },
135
+ { action: "模拟交易", tool: "onchainos_gateway_simulate", condition: "广播前建议模拟" },
136
+ { action: "签名后广播", tool: "onchainos_gateway_broadcast" },
137
+ { action: "查交易状态", tool: "onchainos_dex_swap_history" },
138
+ ],
139
+ });
140
+ } catch(e) { return toError(e); }
141
+ },
142
+ );
143
+
144
+ server.tool("onchainos_dex_swap_instruction",
145
+ "CAT:[链上-Swap] | ## 功能: 获取 Solana 兑换指令(高级), 返回 instructionLists/addressLookupTableAccount/tx/routerResult\n## 场景: Solana 自定义交易组装, 可加自己的指令\n## 关键词: Solana, swap instruction, 高级, lookup table\n## 参数:\n## - chainIndex/amount/fromTokenAddress/toTokenAddress/userWalletAddress/slippagePercent(必填)\n## - autoSlippage/maxAutoSlippagePercent/feePercent/useTokenLedger/swapReceiverAddress(可选)\n## - priceImpactProtectionPercent/dexIds/excludeDexIds/disableRFQ/directRoute(可选)\n## - computeUnitPrice/computeUnitLimit: Solana gas(可选)\n## - positiveSlippagePercent/positiveSlippageFeeAddress: 正滑点分佣(可选,白名单)\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 大 ~30KB\n## 关联: Solana场景: onchainos_dex_quote -> 本工具 -> 自行签名广播",
146
+ {
147
+ chainIndex: z.string().describe("Solana固定'501'"),
148
+ amount: z.string().describe("卖出数量, 含精度"),
149
+ fromTokenAddress: z.string().describe("卖出代币Mint地址"),
150
+ toTokenAddress: z.string().describe("买入代币Mint地址"),
151
+ userWalletAddress: z.string().describe("Solana钱包地址"),
152
+ slippagePercent: z.string().describe("滑点百分比。Solana:0-<100"),
153
+ autoSlippage: z.boolean().optional().describe("true=自动滑点"),
154
+ maxAutoSlippagePercent: z.string().optional().describe("自动滑点上限"),
155
+ feePercent: z.string().optional().describe("分佣百分比。Solana最大10%"),
156
+ fromTokenReferrerWalletAddress: z.string().optional().describe("fromToken分佣地址"),
157
+ toTokenReferrerWalletAddress: z.string().optional().describe("toToken分佣地址"),
158
+ swapReceiverAddress: z.string().optional().describe("接收代币地址"),
159
+ useTokenLedger: z.boolean().optional().describe("true=执行前记录代币余额"),
160
+ priceImpactProtectionPercent: z.string().optional().describe("价格影响保护(0-100)"),
161
+ dexIds: z.string().optional().describe("限定流动性池,逗号分隔"),
162
+ excludeDexIds: z.string().optional().describe("排除流动性池,逗号分隔"),
163
+ disableRFQ: z.boolean().optional().describe("true=禁用RFQ"),
164
+ directRoute: z.boolean().optional().describe("true=单池路由。仅Solana"),
165
+ computeUnitPrice: z.string().optional().describe("Solana compute unit price"),
166
+ computeUnitLimit: z.string().optional().describe("Solana compute unit limit"),
167
+ positiveSlippagePercent: z.string().optional().describe("正滑点分佣比例(0-10,白名单)"),
168
+ positiveSlippageFeeAddress: z.string().optional().describe("正滑点分佣地址"),
169
+ forJitoBundle: z.boolean().optional().describe("true=排除不兼容Jito的DEX"),
170
+ excludePoolAddresses: z.string().optional().describe("过滤池子地址,逗号分隔,最多20"),
171
+ },
172
+ { readOnlyHint: true },
173
+ async (params) => {
174
+ if(!auth) return AUTH_REQUIRED("READ");
175
+ try {
176
+ const q: Record<string, string> = {};
177
+ for (const [k, v] of Object.entries(params)) { if (v !== undefined) q[k] = typeof v === "boolean" ? String(v) : v; }
178
+ return toResult(await tradeApi.swapInstruction(auth, q));
179
+ } catch(e) { return toError(e); }
180
+ },
181
+ );
182
+
183
+ server.tool("onchainos_dex_swap_history",
184
+ "CAT:[链上-Swap] | ## 功能: 查询兑换交易详情(状态/fromToken/toToken/txFee)\n## 场景: 广播后确认交易状态\n## 关键词: swap history, 交易状态, txHash\n## 参数:\n## - chainIndex: 链索引(必填)\n## - txHash: 交易哈希(必填)\n## - isFromMyProject: 是否本项目(可选)\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 微小 ~2KB\n## 关联: onchainos_gateway_broadcast -> 本工具",
185
+ {
186
+ chainIndex: z.string().describe("链索引"),
187
+ txHash: z.string().describe("交易哈希"),
188
+ isFromMyProject: z.boolean().optional().describe("true=仅查本API Key订单 false=查任意OKX DEX订单"),
189
+ },
190
+ { readOnlyHint: true },
191
+ async ({ chainIndex, txHash, isFromMyProject }) => {
192
+ if(!auth) return AUTH_REQUIRED("READ");
193
+ try { return toResult(await tradeApi.swapHistory(auth, chainIndex, txHash, isFromMyProject)); } catch(e) { return toError(e); }
194
+ },
195
+ );
196
+
197
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * 交易历史模块 — CAT:[链上-账户]
3
+ * 按官方文档逐端点对接
4
+ */
5
+ import { z } from "zod";
6
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { postTxApi } from "../adapters/onchainos.js";
8
+ import { toResult, toError, AUTH_REQUIRED } from "../adapters/shared.js";
9
+ import type { Auth } from "../adapters/shared.js";
10
+
11
+ export function registerTxHistoryTools(server: McpServer, auth: Auth | null): void {
12
+
13
+ server.tool("onchainos_tx_history_supported_chain",
14
+ "CAT:[链上-账户] | ## 功能: 获取交易历史 API 支持的链, 返回 chainIndex(字符串)/name/shortName\n## 场景: 查交易历史前确认目标链是否被支持\n## 关键词: 交易历史, 链列表, tx history, chainIndex\n## 参数: 无\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 微小 ~2KB\n## 关联: 本工具 -> onchainos_transaction_history / onchainos_transaction_detail",
15
+ {}, { readOnlyHint: true },
16
+ async () => { if(!auth) return AUTH_REQUIRED("READ"); try { return toResult(await postTxApi.supportedChain(auth)); } catch(e) { return toError(e); } },
17
+ );
18
+
19
+ server.tool("onchainos_transaction_history",
20
+ "CAT:[链上-账户] | ## 功能: 查询地址6个月内交易历史, 按时间倒序, 支持130+链\n## 场景: 用户想看最近交易记录, 或分析某地址的交易行为\n## 关键词: 交易历史, tx history, 转账, 合约交互\n## 参数:\n## - address: 钱包地址(必填)\n## - chains: 链索引逗号分隔, 最多50个(必填)\n## - tokenContractAddress: 代币筛选(可选)\n## - begin/end: 时间范围 Unix毫秒(可选)\n## - cursor: 分页游标(可选)\n## - limit: 返回条数, 多链最多20, 单链最多100(可选)\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 大 ~100KB\n## 关联: onchainos_tx_history_supported_chain -> 本工具 -> onchainos_transaction_detail(单笔详情)",
21
+ {
22
+ address: z.string().describe("钱包地址"),
23
+ chains: z.string().describe("链索引, 逗号分隔, 最多50个。如 '1'=ETH '56'=BSC。从 onchainos_tx_history_supported_chain 获取"),
24
+ tokenContractAddress: z.string().optional().describe("代币合约地址筛选。不传=查所有代币+主链币, 传空字符串=只查主链币, 传具体地址=查该代币"),
25
+ begin: z.string().optional().describe("开始时间, Unix毫秒时间戳。如 '1700000000000'"),
26
+ end: z.string().optional().describe("结束时间, Unix毫秒时间戳"),
27
+ cursor: z.string().optional().describe("分页游标。首次不传, 后续从返回值取"),
28
+ limit: z.string().optional().describe("返回条数。多链默认20最多20, 单链默认20最多100"),
29
+ },
30
+ { readOnlyHint: true },
31
+ async ({ address, chains, tokenContractAddress, begin, end, cursor, limit }) => {
32
+ if(!auth) return AUTH_REQUIRED("READ");
33
+ try { return toResult(await postTxApi.transactions(auth, address, chains, tokenContractAddress, begin, end, cursor, limit)); } catch(e) { return toError(e); }
34
+ },
35
+ );
36
+
37
+ server.tool("onchainos_transaction_detail",
38
+ "CAT:[链上-账户] | ## 功能: 根据 txHash 查询单笔交易详情, 含 internalTransactionDetails/tokenTransferDetails\n## 场景: 看某笔交易的 gas 消耗、内部交易、代币转移明细\n## 关键词: 交易详情, tx detail, hash, 内部交易, token transfer\n## 参数:\n## - chainIndex: 链索引字符串(必填)\n## - txHash: 交易哈希(必填)\n## - itype: 交易层级类型(可选)\n## 鉴权: 需要 API Key(只读)\n## 风险: READ - 只读查询\n## 返回量: 中等 ~10KB\n## 关联: onchainos_transaction_history -> 本工具 -> onchainos_portfolio_overview(关联地址分析)",
39
+ {
40
+ chainIndex: z.string().describe("链索引(字符串)。如 '1'=ETH '42161'=Arbitrum"),
41
+ txHash: z.string().describe("交易哈希。从 onchainos_transaction_history 返回值或广播返回获取"),
42
+ itype: z.enum(["0","1","2"]).optional().describe("交易层级: '0'=外层主链币转移 '1'=合约内层主链币转移 '2'=token转移。不传查所有"),
43
+ },
44
+ { readOnlyHint: true },
45
+ async ({ chainIndex, txHash, itype }) => {
46
+ if(!auth) return AUTH_REQUIRED("READ");
47
+ try { return toResult(await postTxApi.transactionDetail(auth, chainIndex, txHash, itype)); } catch(e) { return toError(e); }
48
+ },
49
+ );
50
+
51
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * WebSocket 模块 — CAT:[链上-行情]/[链上-Swap]
3
+ * 管理 WS 连接生命周期: connect → subscribe → (数据stderr日志) → unsubscribe → disconnect
4
+ *
5
+ * ⚠️ MCP Tool 限制: WS 是长连接推送, Tool 是请求-响应。
6
+ * subscribe 后数据通过 stderr 日志输出, 供 Agent 读取。
7
+ */
8
+ import { z } from "zod";
9
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import { wsConnect, wsSubscribe, wsUnsubscribe, wsDisconnect } from "../adapters/onchainos-ws.js";
11
+ import { toResult, toError, AUTH_REQUIRED } from "../adapters/shared.js";
12
+ import type { Auth } from "../adapters/shared.js";
13
+
14
+ export function registerWsTools(server: McpServer, auth: Auth | null): void {
15
+
16
+ server.tool("onchainos_ws_connect",
17
+ "CAT:[链上-WS] | ## 功能: 建立 WebSocket 连接并登录\n## 场景: 需要实时推送数据(价格/K线/交易/信号)时先调此工具\n## 关键词: WebSocket, 连接, 实时, 登录\n## 参数: 无(使用 API Key 自动登录)\n## 鉴权: 需要 API Key\n## 风险: READ\n## 返回量: 微小 ~1KB\n## 关联: 本工具 -> onchainos_ws_subscribe -> onchainos_ws_unsubscribe -> onchainos_ws_disconnect",
18
+ {}, { readOnlyHint: true },
19
+ async () => {
20
+ if(!auth) return AUTH_REQUIRED("READ");
21
+ try { const connId = await wsConnect(auth); return toResult({ connId, status: "connected" }); } catch(e) { return toError(e); }
22
+ },
23
+ );
24
+
25
+ server.tool("onchainos_ws_subscribe",
26
+ "CAT:[链上-WS] | ## 功能: 订阅 WebSocket 频道, 数据实时推送到 stderr 日志\n## 场景: 订阅价格/流通/K线/交易/信号/Memepump/地址追踪\n## 关键词: WebSocket, subscribe, 订阅, 实时推送\n## 参数:\n## - channel: 频道名(必填)\n## - chainIndex: 链索引(必填)\n## - tokenContractAddress: 代币地址(价格/流通/K线/交易频道必填)\n## 鉴权: 需先调 onchainos_ws_connect\n## 风险: READ\n## 返回量: 微小 ~1KB\n## 关联: onchainos_ws_connect -> 本工具",
27
+ {
28
+ channel: z.string().describe("频道名: price/price-info/trades/dex-token-candle1m/dex-token-candle1H/dex-market-new-signal-openapi/dex-market-memepump-new-token-openapi/dex-market-memepump-update-metrics-openapi/address-tracker-activity/kol_smartmoney-tracker-activity"),
29
+ chainIndex: z.string().describe("链索引"),
30
+ tokenContractAddress: z.string().optional().describe("代币合约地址(小写)。price/price-info/trades/candle频道必填, 信号/Memepump频道不需要"),
31
+ walletAddress: z.string().optional().describe("钱包地址。仅 address-tracker-activity 频道需要, 最多200个地址"),
32
+ },
33
+ { readOnlyHint: true },
34
+ async ({ channel, chainIndex, tokenContractAddress, walletAddress }) => {
35
+ if(!auth) return AUTH_REQUIRED("READ");
36
+ try {
37
+ const ch: Record<string, string> = { channel, chainIndex };
38
+ if (tokenContractAddress) ch.tokenContractAddress = tokenContractAddress;
39
+ if (walletAddress) ch.walletAddress = walletAddress;
40
+ await wsSubscribe(ch as any);
41
+ return toResult({ channel, chainIndex, status: "subscribed" }, {
42
+ warnings: ["数据将通过 stderr 日志实时推送, 标签 [WS-DATA]"],
43
+ });
44
+ } catch(e) { return toError(e); }
45
+ },
46
+ );
47
+
48
+ server.tool("onchainos_ws_unsubscribe",
49
+ "CAT:[链上-WS] | ## 功能: 取消订阅 WebSocket 频道\n## 场景: 不再需要某个频道的实时数据\n## 关键词: WebSocket, unsubscribe, 取消订阅\n## 参数:\n## - channel/chainIndex/tokenContractAddress: 同 subscribe\n## 鉴权: 需已连接\n## 风险: READ\n## 返回量: 微小 ~1KB\n## 关联: onchainos_ws_subscribe -> 本工具",
50
+ {
51
+ channel: z.string().describe("频道名"),
52
+ chainIndex: z.string().describe("链索引"),
53
+ tokenContractAddress: z.string().optional().describe("代币地址"),
54
+ },
55
+ { readOnlyHint: true },
56
+ async ({ channel, chainIndex, tokenContractAddress }) => {
57
+ try {
58
+ const ch: Record<string, string> = { channel, chainIndex };
59
+ if (tokenContractAddress) ch.tokenContractAddress = tokenContractAddress;
60
+ await wsUnsubscribe(ch as any);
61
+ return toResult({ channel, status: "unsubscribed" });
62
+ } catch(e) { return toError(e); }
63
+ },
64
+ );
65
+
66
+ server.tool("onchainos_ws_disconnect",
67
+ "CAT:[链上-WS] | ## 功能: 断开 WebSocket 连接\n## 场景: 不再需要实时数据时关闭连接\n## 关键词: WebSocket, disconnect, 断开\n## 参数: 无\n## 鉴权: 无\n## 风险: READ\n## 返回量: 微小 ~1KB\n## 关联: 关闭所有订阅并断开",
68
+ {}, { readOnlyHint: true },
69
+ async () => { wsDisconnect(); return toResult({ status: "disconnected" }); },
70
+ );
71
+
72
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "rootDir": "src",
7
+ "outDir": "dist",
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "sourceMap": true,
11
+ "strict": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true
15
+ },
16
+ "include": ["src/**/*.ts"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }