hvip-mcp-server 0.2.49 → 0.2.51

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 (2) hide show
  1. package/dist/index.js +1180 -364
  2. package/package.json +64 -64
package/dist/index.js CHANGED
@@ -6,9 +6,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __esm = (fn, res) => function __init() {
10
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
- };
12
9
  var __commonJS = (cb, mod) => function __require() {
13
10
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
14
11
  };
@@ -33,6 +30,410 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
30
  mod
34
31
  ));
35
32
 
33
+ // node_modules/dotenv/package.json
34
+ var require_package = __commonJS({
35
+ "node_modules/dotenv/package.json"(exports2, module2) {
36
+ module2.exports = {
37
+ name: "dotenv",
38
+ version: "16.6.1",
39
+ description: "Loads environment variables from .env file",
40
+ main: "lib/main.js",
41
+ types: "lib/main.d.ts",
42
+ exports: {
43
+ ".": {
44
+ types: "./lib/main.d.ts",
45
+ require: "./lib/main.js",
46
+ default: "./lib/main.js"
47
+ },
48
+ "./config": "./config.js",
49
+ "./config.js": "./config.js",
50
+ "./lib/env-options": "./lib/env-options.js",
51
+ "./lib/env-options.js": "./lib/env-options.js",
52
+ "./lib/cli-options": "./lib/cli-options.js",
53
+ "./lib/cli-options.js": "./lib/cli-options.js",
54
+ "./package.json": "./package.json"
55
+ },
56
+ scripts: {
57
+ "dts-check": "tsc --project tests/types/tsconfig.json",
58
+ lint: "standard",
59
+ pretest: "npm run lint && npm run dts-check",
60
+ test: "tap run --allow-empty-coverage --disable-coverage --timeout=60000",
61
+ "test:coverage": "tap run --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
62
+ prerelease: "npm test",
63
+ release: "standard-version"
64
+ },
65
+ repository: {
66
+ type: "git",
67
+ url: "git://github.com/motdotla/dotenv.git"
68
+ },
69
+ homepage: "https://github.com/motdotla/dotenv#readme",
70
+ funding: "https://dotenvx.com",
71
+ keywords: [
72
+ "dotenv",
73
+ "env",
74
+ ".env",
75
+ "environment",
76
+ "variables",
77
+ "config",
78
+ "settings"
79
+ ],
80
+ readmeFilename: "README.md",
81
+ license: "BSD-2-Clause",
82
+ devDependencies: {
83
+ "@types/node": "^18.11.3",
84
+ decache: "^4.6.2",
85
+ sinon: "^14.0.1",
86
+ standard: "^17.0.0",
87
+ "standard-version": "^9.5.0",
88
+ tap: "^19.2.0",
89
+ typescript: "^4.8.4"
90
+ },
91
+ engines: {
92
+ node: ">=12"
93
+ },
94
+ browser: {
95
+ fs: false
96
+ }
97
+ };
98
+ }
99
+ });
100
+
101
+ // node_modules/dotenv/lib/main.js
102
+ var require_main = __commonJS({
103
+ "node_modules/dotenv/lib/main.js"(exports2, module2) {
104
+ var fs3 = require("fs");
105
+ var path3 = require("path");
106
+ var os2 = require("os");
107
+ var crypto5 = require("crypto");
108
+ var packageJson = require_package();
109
+ var version2 = packageJson.version;
110
+ var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
111
+ function parse3(src) {
112
+ const obj = {};
113
+ let lines = src.toString();
114
+ lines = lines.replace(/\r\n?/mg, "\n");
115
+ let match;
116
+ while ((match = LINE.exec(lines)) != null) {
117
+ const key = match[1];
118
+ let value = match[2] || "";
119
+ value = value.trim();
120
+ const maybeQuote = value[0];
121
+ value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
122
+ if (maybeQuote === '"') {
123
+ value = value.replace(/\\n/g, "\n");
124
+ value = value.replace(/\\r/g, "\r");
125
+ }
126
+ obj[key] = value;
127
+ }
128
+ return obj;
129
+ }
130
+ function _parseVault(options) {
131
+ options = options || {};
132
+ const vaultPath = _vaultPath(options);
133
+ options.path = vaultPath;
134
+ const result = DotenvModule.configDotenv(options);
135
+ if (!result.parsed) {
136
+ const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
137
+ err.code = "MISSING_DATA";
138
+ throw err;
139
+ }
140
+ const keys = _dotenvKey(options).split(",");
141
+ const length = keys.length;
142
+ let decrypted;
143
+ for (let i = 0; i < length; i++) {
144
+ try {
145
+ const key = keys[i].trim();
146
+ const attrs = _instructions(result, key);
147
+ decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
148
+ break;
149
+ } catch (error2) {
150
+ if (i + 1 >= length) {
151
+ throw error2;
152
+ }
153
+ }
154
+ }
155
+ return DotenvModule.parse(decrypted);
156
+ }
157
+ function _warn(message) {
158
+ console.log(`[dotenv@${version2}][WARN] ${message}`);
159
+ }
160
+ function _debug(message) {
161
+ console.log(`[dotenv@${version2}][DEBUG] ${message}`);
162
+ }
163
+ function _log(message) {
164
+ console.log(`[dotenv@${version2}] ${message}`);
165
+ }
166
+ function _dotenvKey(options) {
167
+ if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
168
+ return options.DOTENV_KEY;
169
+ }
170
+ if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
171
+ return process.env.DOTENV_KEY;
172
+ }
173
+ return "";
174
+ }
175
+ function _instructions(result, dotenvKey) {
176
+ let uri;
177
+ try {
178
+ uri = new URL(dotenvKey);
179
+ } catch (error2) {
180
+ if (error2.code === "ERR_INVALID_URL") {
181
+ const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
182
+ err.code = "INVALID_DOTENV_KEY";
183
+ throw err;
184
+ }
185
+ throw error2;
186
+ }
187
+ const key = uri.password;
188
+ if (!key) {
189
+ const err = new Error("INVALID_DOTENV_KEY: Missing key part");
190
+ err.code = "INVALID_DOTENV_KEY";
191
+ throw err;
192
+ }
193
+ const environment = uri.searchParams.get("environment");
194
+ if (!environment) {
195
+ const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
196
+ err.code = "INVALID_DOTENV_KEY";
197
+ throw err;
198
+ }
199
+ const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
200
+ const ciphertext = result.parsed[environmentKey];
201
+ if (!ciphertext) {
202
+ const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
203
+ err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
204
+ throw err;
205
+ }
206
+ return { ciphertext, key };
207
+ }
208
+ function _vaultPath(options) {
209
+ let possibleVaultPath = null;
210
+ if (options && options.path && options.path.length > 0) {
211
+ if (Array.isArray(options.path)) {
212
+ for (const filepath of options.path) {
213
+ if (fs3.existsSync(filepath)) {
214
+ possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
215
+ }
216
+ }
217
+ } else {
218
+ possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
219
+ }
220
+ } else {
221
+ possibleVaultPath = path3.resolve(process.cwd(), ".env.vault");
222
+ }
223
+ if (fs3.existsSync(possibleVaultPath)) {
224
+ return possibleVaultPath;
225
+ }
226
+ return null;
227
+ }
228
+ function _resolveHome(envPath) {
229
+ return envPath[0] === "~" ? path3.join(os2.homedir(), envPath.slice(1)) : envPath;
230
+ }
231
+ function _configVault(options) {
232
+ const debug = Boolean(options && options.debug);
233
+ const quiet = options && "quiet" in options ? options.quiet : true;
234
+ if (debug || !quiet) {
235
+ _log("Loading env from encrypted .env.vault");
236
+ }
237
+ const parsed = DotenvModule._parseVault(options);
238
+ let processEnv = process.env;
239
+ if (options && options.processEnv != null) {
240
+ processEnv = options.processEnv;
241
+ }
242
+ DotenvModule.populate(processEnv, parsed, options);
243
+ return { parsed };
244
+ }
245
+ function configDotenv(options) {
246
+ const dotenvPath = path3.resolve(process.cwd(), ".env");
247
+ let encoding = "utf8";
248
+ const debug = Boolean(options && options.debug);
249
+ const quiet = options && "quiet" in options ? options.quiet : true;
250
+ if (options && options.encoding) {
251
+ encoding = options.encoding;
252
+ } else {
253
+ if (debug) {
254
+ _debug("No encoding is specified. UTF-8 is used by default");
255
+ }
256
+ }
257
+ let optionPaths = [dotenvPath];
258
+ if (options && options.path) {
259
+ if (!Array.isArray(options.path)) {
260
+ optionPaths = [_resolveHome(options.path)];
261
+ } else {
262
+ optionPaths = [];
263
+ for (const filepath of options.path) {
264
+ optionPaths.push(_resolveHome(filepath));
265
+ }
266
+ }
267
+ }
268
+ let lastError;
269
+ const parsedAll = {};
270
+ for (const path4 of optionPaths) {
271
+ try {
272
+ const parsed = DotenvModule.parse(fs3.readFileSync(path4, { encoding }));
273
+ DotenvModule.populate(parsedAll, parsed, options);
274
+ } catch (e) {
275
+ if (debug) {
276
+ _debug(`Failed to load ${path4} ${e.message}`);
277
+ }
278
+ lastError = e;
279
+ }
280
+ }
281
+ let processEnv = process.env;
282
+ if (options && options.processEnv != null) {
283
+ processEnv = options.processEnv;
284
+ }
285
+ DotenvModule.populate(processEnv, parsedAll, options);
286
+ if (debug || !quiet) {
287
+ const keysCount = Object.keys(parsedAll).length;
288
+ const shortPaths = [];
289
+ for (const filePath of optionPaths) {
290
+ try {
291
+ const relative = path3.relative(process.cwd(), filePath);
292
+ shortPaths.push(relative);
293
+ } catch (e) {
294
+ if (debug) {
295
+ _debug(`Failed to load ${filePath} ${e.message}`);
296
+ }
297
+ lastError = e;
298
+ }
299
+ }
300
+ _log(`injecting env (${keysCount}) from ${shortPaths.join(",")}`);
301
+ }
302
+ if (lastError) {
303
+ return { parsed: parsedAll, error: lastError };
304
+ } else {
305
+ return { parsed: parsedAll };
306
+ }
307
+ }
308
+ function config2(options) {
309
+ if (_dotenvKey(options).length === 0) {
310
+ return DotenvModule.configDotenv(options);
311
+ }
312
+ const vaultPath = _vaultPath(options);
313
+ if (!vaultPath) {
314
+ _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
315
+ return DotenvModule.configDotenv(options);
316
+ }
317
+ return DotenvModule._configVault(options);
318
+ }
319
+ function decrypt(encrypted, keyStr) {
320
+ const key = Buffer.from(keyStr.slice(-64), "hex");
321
+ let ciphertext = Buffer.from(encrypted, "base64");
322
+ const nonce = ciphertext.subarray(0, 12);
323
+ const authTag = ciphertext.subarray(-16);
324
+ ciphertext = ciphertext.subarray(12, -16);
325
+ try {
326
+ const aesgcm = crypto5.createDecipheriv("aes-256-gcm", key, nonce);
327
+ aesgcm.setAuthTag(authTag);
328
+ return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
329
+ } catch (error2) {
330
+ const isRange = error2 instanceof RangeError;
331
+ const invalidKeyLength = error2.message === "Invalid key length";
332
+ const decryptionFailed = error2.message === "Unsupported state or unable to authenticate data";
333
+ if (isRange || invalidKeyLength) {
334
+ const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
335
+ err.code = "INVALID_DOTENV_KEY";
336
+ throw err;
337
+ } else if (decryptionFailed) {
338
+ const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
339
+ err.code = "DECRYPTION_FAILED";
340
+ throw err;
341
+ } else {
342
+ throw error2;
343
+ }
344
+ }
345
+ }
346
+ function populate(processEnv, parsed, options = {}) {
347
+ const debug = Boolean(options && options.debug);
348
+ const override = Boolean(options && options.override);
349
+ if (typeof parsed !== "object") {
350
+ const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
351
+ err.code = "OBJECT_REQUIRED";
352
+ throw err;
353
+ }
354
+ for (const key of Object.keys(parsed)) {
355
+ if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
356
+ if (override === true) {
357
+ processEnv[key] = parsed[key];
358
+ }
359
+ if (debug) {
360
+ if (override === true) {
361
+ _debug(`"${key}" is already defined and WAS overwritten`);
362
+ } else {
363
+ _debug(`"${key}" is already defined and was NOT overwritten`);
364
+ }
365
+ }
366
+ } else {
367
+ processEnv[key] = parsed[key];
368
+ }
369
+ }
370
+ }
371
+ var DotenvModule = {
372
+ configDotenv,
373
+ _configVault,
374
+ _parseVault,
375
+ config: config2,
376
+ decrypt,
377
+ parse: parse3,
378
+ populate
379
+ };
380
+ module2.exports.configDotenv = DotenvModule.configDotenv;
381
+ module2.exports._configVault = DotenvModule._configVault;
382
+ module2.exports._parseVault = DotenvModule._parseVault;
383
+ module2.exports.config = DotenvModule.config;
384
+ module2.exports.decrypt = DotenvModule.decrypt;
385
+ module2.exports.parse = DotenvModule.parse;
386
+ module2.exports.populate = DotenvModule.populate;
387
+ module2.exports = DotenvModule;
388
+ }
389
+ });
390
+
391
+ // node_modules/dotenv/lib/env-options.js
392
+ var require_env_options = __commonJS({
393
+ "node_modules/dotenv/lib/env-options.js"(exports2, module2) {
394
+ var options = {};
395
+ if (process.env.DOTENV_CONFIG_ENCODING != null) {
396
+ options.encoding = process.env.DOTENV_CONFIG_ENCODING;
397
+ }
398
+ if (process.env.DOTENV_CONFIG_PATH != null) {
399
+ options.path = process.env.DOTENV_CONFIG_PATH;
400
+ }
401
+ if (process.env.DOTENV_CONFIG_QUIET != null) {
402
+ options.quiet = process.env.DOTENV_CONFIG_QUIET;
403
+ }
404
+ if (process.env.DOTENV_CONFIG_DEBUG != null) {
405
+ options.debug = process.env.DOTENV_CONFIG_DEBUG;
406
+ }
407
+ if (process.env.DOTENV_CONFIG_OVERRIDE != null) {
408
+ options.override = process.env.DOTENV_CONFIG_OVERRIDE;
409
+ }
410
+ if (process.env.DOTENV_CONFIG_DOTENV_KEY != null) {
411
+ options.DOTENV_KEY = process.env.DOTENV_CONFIG_DOTENV_KEY;
412
+ }
413
+ module2.exports = options;
414
+ }
415
+ });
416
+
417
+ // node_modules/dotenv/lib/cli-options.js
418
+ var require_cli_options = __commonJS({
419
+ "node_modules/dotenv/lib/cli-options.js"(exports2, module2) {
420
+ var re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/;
421
+ module2.exports = function optionMatcher(args) {
422
+ const options = args.reduce(function(acc, cur) {
423
+ const matches = cur.match(re);
424
+ if (matches) {
425
+ acc[matches[1]] = matches[2];
426
+ }
427
+ return acc;
428
+ }, {});
429
+ if (!("quiet" in options)) {
430
+ options.quiet = "true";
431
+ }
432
+ return options;
433
+ };
434
+ }
435
+ });
436
+
36
437
  // node_modules/ajv/dist/compile/codegen/code.js
37
438
  var require_code = __commonJS({
38
439
  "node_modules/ajv/dist/compile/codegen/code.js"(exports2) {
@@ -10568,33 +10969,16 @@ var require_websocket_server = __commonJS({
10568
10969
  }
10569
10970
  });
10570
10971
 
10571
- // node_modules/ws/wrapper.mjs
10572
- var wrapper_exports = {};
10573
- __export(wrapper_exports, {
10574
- PerMessageDeflate: () => import_permessage_deflate.default,
10575
- Receiver: () => import_receiver.default,
10576
- Sender: () => import_sender.default,
10577
- WebSocket: () => import_websocket.default,
10578
- WebSocketServer: () => import_websocket_server.default,
10579
- createWebSocketStream: () => import_stream2.default,
10580
- default: () => wrapper_default,
10581
- extension: () => import_extension.default,
10582
- subprotocol: () => import_subprotocol.default
10583
- });
10584
- var import_stream2, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
10585
- var init_wrapper = __esm({
10586
- "node_modules/ws/wrapper.mjs"() {
10587
- import_stream2 = __toESM(require_stream(), 1);
10588
- import_extension = __toESM(require_extension(), 1);
10589
- import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
10590
- import_receiver = __toESM(require_receiver(), 1);
10591
- import_sender = __toESM(require_sender(), 1);
10592
- import_subprotocol = __toESM(require_subprotocol(), 1);
10593
- import_websocket = __toESM(require_websocket(), 1);
10594
- import_websocket_server = __toESM(require_websocket_server(), 1);
10595
- wrapper_default = import_websocket.default;
10596
- }
10597
- });
10972
+ // node_modules/dotenv/config.js
10973
+ (function() {
10974
+ require_main().config(
10975
+ Object.assign(
10976
+ {},
10977
+ require_env_options(),
10978
+ require_cli_options()(process.argv)
10979
+ )
10980
+ );
10981
+ })();
10598
10982
 
10599
10983
  // src/index.ts
10600
10984
  var import_node_http = require("node:http");
@@ -26665,24 +27049,181 @@ function toResult(data) {
26665
27049
  }
26666
27050
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
26667
27051
  }
27052
+ var OKX_ERROR_MESSAGES = {
27053
+ // 公共 / 系统
27054
+ 5e4: "\u7CFB\u7EDF\u5185\u90E8\u9519\u8BEF",
27055
+ 50001: "\u7CFB\u7EDF\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
27056
+ 50002: "\u7CFB\u7EDF\u5347\u7EA7\u7EF4\u62A4\u4E2D",
27057
+ 50004: "\u8BF7\u6C42\u8D85\u65F6",
27058
+ 50005: "\u63A5\u53E3\u5DF2\u88AB\u51BB\u7ED3\uFF0C\u8BF7\u8054\u7CFB\u5BA2\u670D",
27059
+ 50006: "OK-ACCESS-KEY \u65E0\u6548",
27060
+ 50007: "OK-ACCESS-SIGN \u7B7E\u540D\u9519\u8BEF",
27061
+ 50008: "OK-ACCESS-TIMESTAMP \u65F6\u95F4\u6233\u65E0\u6548",
27062
+ 50009: "OK-ACCESS-PASSPHRASE \u5BC6\u7801\u77ED\u8BED\u9519\u8BEF",
27063
+ 50010: "\u5F53\u524D IP \u4E0D\u5728 API Key \u767D\u540D\u5355\u4E2D",
27064
+ 50011: "\u8BF7\u6C42\u9891\u7387\u8FC7\u5FEB\uFF0C\u5DF2\u89E6\u53D1\u9650\u6D41\u3002\u8BF7\u964D\u4F4E\u8BF7\u6C42\u901F\u7387",
27065
+ 50012: "\u7CFB\u7EDF\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
27066
+ 50013: "\u7CFB\u7EDF\u9519\u8BEF",
27067
+ 50014: "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5FC5\u586B\u5B57\u6BB5\u548C\u683C\u5F0F",
27068
+ 50015: "\u4ED3\u4F4D\u5DF2\u88AB\u51BB\u7ED3",
27069
+ 50016: "\u8D26\u6237\u5DF2\u88AB\u51BB\u7ED3",
27070
+ 50017: "\u8D26\u6237\u5DF2\u88AB\u6682\u505C",
27071
+ 50018: "\u8D26\u6237\u7B49\u7EA7\u4E0D\u8DB3",
27072
+ 50019: "\u5408\u7EA6\u5DF2\u5230\u671F",
27073
+ 50020: "\u4F59\u989D\u4E0D\u8DB3",
27074
+ 50021: "\u4FDD\u8BC1\u91D1\u4E0D\u8DB3",
27075
+ 50022: "\u4E0B\u5355\u6570\u91CF\u5C0F\u4E8E\u6700\u5C0F\u9650\u5236",
27076
+ 50023: "\u4E0B\u5355\u6570\u91CF\u8D85\u8FC7\u6700\u5927\u9650\u5236",
27077
+ 50024: "\u6301\u4ED3\u6570\u91CF\u5DF2\u8FBE\u4E0A\u9650",
27078
+ 50025: "\u6302\u5355\u6570\u91CF\u5DF2\u8FBE\u4E0A\u9650",
27079
+ 50026: "\u4E0B\u5355\u4EF7\u683C\u8D85\u51FA\u9650\u4EF7\u8303\u56F4",
27080
+ 50027: "\u4EF7\u683C\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27081
+ 50028: "\u6570\u91CF\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27082
+ 50029: "\u8BE5\u5408\u7EA6\u6682\u4E0D\u53EF\u7528",
27083
+ 50030: "API Key \u65E0\u6B64\u64CD\u4F5C\u6743\u9650",
27084
+ 50031: "API Key \u5DF2\u8FC7\u671F",
27085
+ 50032: "API Key \u672A\u627E\u5230",
27086
+ 50033: "API Key \u672A\u6FC0\u6D3B",
27087
+ 50035: "\u89E6\u53D1\u98CE\u63A7\u89C4\u5219\uFF0C\u4EA4\u6613\u88AB\u62D2\u7EDD",
27088
+ 50036: "\u65E0\u4EA4\u6613\u6743\u9650",
27089
+ 50044: "\u8BA2\u5355\u4E0D\u5B58\u5728",
27090
+ 50045: "\u8BE5\u8BA2\u5355\u4E0D\u53EF\u64A4\u9500",
27091
+ 50046: "\u8BA2\u5355\u5DF2\u5168\u90E8\u6210\u4EA4",
27092
+ 50047: "\u8BA2\u5355\u5DF2\u88AB\u64A4\u9500",
27093
+ 50050: "\u6301\u4ED3\u4E0D\u5B58\u5728",
27094
+ 50051: "\u4ED3\u4F4D\u5DF2\u5E73\u4ED3",
27095
+ 50053: "\u4ED3\u4F4D\u4FDD\u8BC1\u91D1\u4E0D\u8DB3",
27096
+ 50056: "\u4E0B\u5355\u8FC7\u4E8E\u9891\u7E41",
27097
+ 50058: "\u8BE5\u5E01\u79CD\u6682\u4E0D\u652F\u6301",
27098
+ 50059: "\u53C2\u6570\u89E3\u6790\u5931\u8D25",
27099
+ 50060: "\u8D26\u6237\u6A21\u5F0F\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C",
27100
+ 50061: "\u5B50\u8D26\u6237\u8BF7\u6C42\u9891\u7387\u8D85\u9650",
27101
+ 50064: "\u8BE5\u5408\u7EA6\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C",
27102
+ 50068: "\u7CFB\u7EDF\u5347\u7EA7\u4E2D\uFF0C\u6682\u4E0D\u53EF\u7528",
27103
+ 50070: "\u6301\u4ED3\u6A21\u5F0F\u4E0D\u5339\u914D",
27104
+ 50071: "\u4FDD\u8BC1\u91D1\u6A21\u5F0F\u4E0D\u5339\u914D",
27105
+ 50072: "\u6760\u6746\u500D\u6570\u8D85\u51FA\u5141\u8BB8\u8303\u56F4",
27106
+ 50074: "\u89E6\u53D1\u4EF7\u683C\u65E0\u6548",
27107
+ 50080: "\u4E0B\u5355\u4EF7\u683C\u504F\u79BB\u5E02\u573A\u4EF7\u8FC7\u5927",
27108
+ 50082: "\u8D26\u6237\u6743\u76CA\u4E0D\u8DB3",
27109
+ // API Key 相关
27110
+ 50100: "API Key \u5DF2\u88AB\u51BB\u7ED3",
27111
+ 50101: "API Key \u5DF2\u8FC7\u671F",
27112
+ 50102: "\u8BF7\u6C42\u65F6\u95F4\u6233\u4E0E\u670D\u52A1\u5668\u65F6\u95F4\u504F\u5DEE\u8D85\u8FC7 30 \u79D2",
27113
+ 50103: "\u8BF7\u6C42\u5934 OK-ACCESS-KEY \u4E0D\u80FD\u4E3A\u7A7A",
27114
+ 50104: "\u8BF7\u6C42\u5934 OK-ACCESS-SIGN \u7B7E\u540D\u4E0D\u80FD\u4E3A\u7A7A",
27115
+ 50105: "\u8BF7\u6C42\u5934 OK-ACCESS-TIMESTAMP \u4E0D\u80FD\u4E3A\u7A7A",
27116
+ 50106: "\u8BF7\u6C42\u5934 OK-ACCESS-PASSPHRASE \u4E0D\u80FD\u4E3A\u7A7A",
27117
+ 50107: "API Key \u5BF9\u5E94\u7684\u8D26\u6237\u4E0D\u5B58\u5728",
27118
+ 50108: "\u8D26\u6237\u4F59\u989D\u4E0D\u8DB3",
27119
+ 50109: "\u5212\u8F6C\u91D1\u989D\u8D85\u8FC7\u9650\u989D",
27120
+ 50110: "\u5212\u8F6C\u5E01\u79CD\u4E0D\u652F\u6301",
27121
+ 50111: "\u5212\u8F6C\u5931\u8D25",
27122
+ 50120: "API Key \u6743\u9650\u4E0D\u8DB3\uFF0C\u8BF7\u68C0\u67E5\u662F\u5426\u5F00\u901A\u4E86\u6240\u9700\u6743\u9650\uFF08\u8BFB\u53D6/\u4EA4\u6613/\u63D0\u73B0\uFF09",
27123
+ 50121: "API Key \u5DF2\u8FC7\u671F",
27124
+ 50122: "API Key \u672A\u627E\u5230",
27125
+ 50123: "API Key \u672A\u6FC0\u6D3B",
27126
+ 50124: "API Key \u5DF2\u88AB\u5220\u9664",
27127
+ 50125: "API Key \u5DF2\u88AB\u51BB\u7ED3",
27128
+ 50126: "API Key \u5DF2\u88AB\u7981\u7528",
27129
+ // 交易
27130
+ 51e3: "\u53C2\u6570\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u5FC5\u586B\u53C2\u6570",
27131
+ 51001: "\u8BA2\u5355\u7C7B\u578B\u4E0D\u652F\u6301",
27132
+ 51002: "\u8BA2\u5355\u65B9\u5411\u4E0D\u652F\u6301",
27133
+ 51003: "\u8BA2\u5355\u6570\u91CF\u4E0D\u80FD\u4E3A 0 \u6216\u8D1F\u6570",
27134
+ 51004: "\u8BA2\u5355\u4EF7\u683C\u4E0D\u80FD\u4E3A 0 \u6216\u8D1F\u6570",
27135
+ 51005: "\u4FDD\u8BC1\u91D1\u6A21\u5F0F\u4E0D\u652F\u6301",
27136
+ 51006: "\u8BA2\u5355\u4EF7\u683C\u8D85\u51FA\u9650\u4EF7\u8303\u56F4",
27137
+ 51007: "\u8BA2\u5355\u6570\u91CF\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27138
+ 51008: "\u8BA2\u5355\u4EF7\u683C\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27139
+ 51009: "\u8BA2\u5355\u6570\u91CF\u8D85\u51FA\u6700\u5927\u9650\u5236",
27140
+ 51010: "\u8BA2\u5355\u6570\u91CF\u4F4E\u4E8E\u6700\u5C0F\u9650\u5236",
27141
+ 51011: "\u8BE5\u4EA7\u54C1\u4E0D\u652F\u6301\u6B64\u8BA2\u5355\u7C7B\u578B",
27142
+ 51012: "\u8BE5\u4EA7\u54C1\u4E0D\u652F\u6301\u6B64\u4FDD\u8BC1\u91D1\u6A21\u5F0F",
27143
+ 51013: "\u8BE5\u4EA7\u54C1\u4E0D\u652F\u6301\u6B64\u6301\u4ED3\u6A21\u5F0F",
27144
+ 51014: "\u5F53\u524D\u6301\u4ED3\u6A21\u5F0F\u4E0D\u5141\u8BB8\u6B64\u64CD\u4F5C",
27145
+ 51015: "\u5F53\u524D\u8D26\u6237\u6A21\u5F0F\u4E0D\u5141\u8BB8\u6B64\u64CD\u4F5C",
27146
+ 51020: "\u6279\u91CF\u4E0B\u5355\u6570\u91CF\u8D85\u8FC7\u4E0A\u9650",
27147
+ 51021: "\u6279\u91CF\u64CD\u4F5C\u4E2D\u5305\u542B\u91CD\u590D\u8BA2\u5355",
27148
+ 51026: "\u8BA2\u5355\u4EF7\u683C\u8D85\u51FA\u6ED1\u70B9\u4FDD\u62A4\u8303\u56F4",
27149
+ 51027: "\u8BA2\u5355\u5DF2\u8FC7\u671F",
27150
+ 51100: "\u8BE5\u4EA7\u54C1\u4E0D\u5728\u53EF\u4EA4\u6613\u5217\u8868",
27151
+ 51102: "\u6301\u4ED3\u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u65E0\u6CD5\u5E73\u4ED3",
27152
+ 51103: "\u4FDD\u8BC1\u91D1\u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u65E0\u6CD5\u5E73\u4ED3",
27153
+ 51104: "\u6760\u6746\u500D\u6570\u4E0D\u5339\u914D",
27154
+ 51107: "\u5E02\u4EF7\u5355\u5F53\u524D\u4E0D\u53EF\u7528",
27155
+ 51108: "\u6B62\u635F\u5355\u5F53\u524D\u4E0D\u53EF\u7528",
27156
+ // 资金
27157
+ 52e3: "\u5212\u8F6C\u5931\u8D25",
27158
+ 52001: "\u63D0\u73B0\u91D1\u989D\u8D85\u8FC7\u9650\u989D",
27159
+ 52002: "\u63D0\u73B0\u5730\u5740\u65E0\u6548",
27160
+ 52003: "\u63D0\u73B0\u94FE\u4E0D\u652F\u6301",
27161
+ 52004: "\u63D0\u73B0\u7F51\u7EDC\u8D39\u4E0D\u8DB3",
27162
+ 52005: "\u63D0\u73B0\u5DF2\u51BB\u7ED3",
27163
+ 52006: "\u5145\u503C\u5730\u5740\u751F\u6210\u5931\u8D25",
27164
+ 52007: "\u8BE5\u5E01\u79CD\u4E0D\u652F\u6301\u5145\u503C",
27165
+ 52008: "\u8BE5\u5E01\u79CD\u4E0D\u652F\u6301\u63D0\u73B0",
27166
+ // 跟单交易
27167
+ 52100: "\u4EA4\u6613\u5458\u4E0D\u5B58\u5728",
27168
+ 52101: "\u4EA4\u6613\u5458\u4E0D\u5BF9\u5916\u516C\u5F00",
27169
+ 52102: "\u8DDF\u5355\u91D1\u989D\u8D85\u51FA\u9650\u5236",
27170
+ 52103: "\u8DDF\u5355\u4EBA\u6570\u5DF2\u8FBE\u4E0A\u9650",
27171
+ 52104: "\u5F53\u524D\u4E0D\u652F\u6301\u8DDF\u5355\u8BE5\u4EA4\u6613\u5458",
27172
+ 52105: "\u8BE5\u4EA4\u6613\u5458\u5DF2\u505C\u6B62\u5E26\u5355",
27173
+ // 策略 / 网格
27174
+ 53e3: "\u7B56\u7565\u59D4\u6258\u521B\u5EFA\u5931\u8D25",
27175
+ 53001: "\u7B56\u7565\u59D4\u6258\u4FEE\u6539\u5931\u8D25",
27176
+ 53002: "\u7B56\u7565\u59D4\u6258\u64A4\u9500\u5931\u8D25",
27177
+ 53003: "\u7B56\u7565\u59D4\u6258\u4E0D\u5B58\u5728",
27178
+ 53004: "\u7B56\u7565\u59D4\u6258\u5DF2\u89E6\u53D1",
27179
+ 53005: "\u7F51\u683C\u7B56\u7565\u521B\u5EFA\u5931\u8D25",
27180
+ 53006: "\u7F51\u683C\u7B56\u7565\u4E0D\u5B58\u5728",
27181
+ 53007: "\u7F51\u683C\u7B56\u7565\u5DF2\u505C\u6B62",
27182
+ 53008: "\u7F51\u683C\u53C2\u6570\u65E0\u6548",
27183
+ // WebSocket
27184
+ 60001: "\u8BA2\u9605\u9891\u9053\u4E0D\u5B58\u5728\u6216\u53C2\u6570\u9519\u8BEF",
27185
+ 60002: "WebSocket \u767B\u5F55\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 API Key",
27186
+ 60003: "WebSocket \u8BA2\u9605\u53C2\u6570\u65E0\u6548",
27187
+ 60004: "WebSocket \u8BF7\u6C42\u9891\u7387\u8FC7\u9AD8",
27188
+ 60005: "WebSocket \u8FDE\u63A5\u6570\u5DF2\u8FBE\u4E0A\u9650",
27189
+ 60006: "WebSocket \u8FDE\u63A5\u88AB\u670D\u52A1\u7AEF\u5173\u95ED",
27190
+ 60007: "WebSocket \u8BE5\u9891\u9053\u9700\u8981\u767B\u5F55",
27191
+ 60008: "WebSocket \u8BE5\u9891\u9053\u4E0D\u9700\u8981\u767B\u5F55",
27192
+ 60009: "WebSocket \u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55",
27193
+ 64008: "\u670D\u52A1\u5347\u7EA7\u4E2D\uFF0C\u8FDE\u63A5\u5373\u5C06\u5173\u95ED\uFF0C\u8BF7\u91CD\u8FDE"
27194
+ };
27195
+ function translateError(code, rawMsg) {
27196
+ const translated = OKX_ERROR_MESSAGES[code];
27197
+ if (translated) return translated;
27198
+ if (code >= 5e4 && code < 50100) return `\u7CFB\u7EDF/\u8BA4\u8BC1\u9519\u8BEF (${code}): ${rawMsg}`;
27199
+ if (code >= 50100 && code < 50200) return `API Key \u9519\u8BEF (${code}): ${rawMsg}`;
27200
+ if (code >= 51e3 && code < 51200) return `\u4EA4\u6613\u53C2\u6570\u9519\u8BEF (${code}): ${rawMsg}`;
27201
+ if (code >= 52e3 && code < 52200) return `\u8D44\u91D1/\u8DDF\u5355\u9519\u8BEF (${code}): ${rawMsg}`;
27202
+ if (code >= 53e3 && code < 54e3) return `\u7B56\u7565\u59D4\u6258\u9519\u8BEF (${code}): ${rawMsg}`;
27203
+ if (code >= 6e4 && code < 65e3) return `WebSocket \u9519\u8BEF (${code}): ${rawMsg}`;
27204
+ return rawMsg;
27205
+ }
26668
27206
  function classifyError(msg) {
26669
27207
  const okxMatch = msg.match(/OKX (\d+):/);
26670
27208
  if (okxMatch && okxMatch[1]) {
26671
27209
  const code = parseInt(okxMatch[1]);
26672
- if (code >= 5e4 && code < 50100) return { errorCode: `OKX_${code}`, errorCategory: "AUTH" };
26673
- if (code >= 51e3) return { errorCode: `OKX_${code}`, errorCategory: "BUSINESS" };
26674
- if (code >= 50004 && code <= 50014) return { errorCode: `OKX_${code}`, errorCategory: "VALIDATION" };
26675
- return { errorCode: `OKX_${code}`, errorCategory: "BUSINESS" };
27210
+ const rawMsg = msg.replace(/^OKX \d+: /, "");
27211
+ const translated = translateError(code, rawMsg);
27212
+ if (code >= 5e4 && code < 50100) return { errorCode: `OKX_${code}`, errorCategory: "AUTH", errorMessage: translated };
27213
+ if (code === 50100 || code === 50101 || code === 50120) return { errorCode: `OKX_${code}`, errorCategory: "AUTH", errorMessage: translated };
27214
+ if (code >= 50004 && code <= 50014) return { errorCode: `OKX_${code}`, errorCategory: "VALIDATION", errorMessage: translated };
27215
+ if (code >= 51e3 && code < 51200) return { errorCode: `OKX_${code}`, errorCategory: "VALIDATION", errorMessage: translated };
27216
+ return { errorCode: `OKX_${code}`, errorCategory: "BUSINESS", errorMessage: translated };
26676
27217
  }
26677
27218
  if (msg.startsWith("HTTP ")) {
26678
27219
  const httpMatch = msg.match(/HTTP (\d+)/);
26679
27220
  const status = httpMatch && httpMatch[1] ? parseInt(httpMatch[1]) : 0;
26680
- if (status === 401 || status === 403) return { errorCode: "HTTP_401", errorCategory: "AUTH" };
26681
- if (status === 429) return { errorCode: "HTTP_429", errorCategory: "RATE_LIMIT" };
26682
- return { errorCode: "NETWORK_ERROR", errorCategory: "NETWORK" };
27221
+ if (status === 401 || status === 403) return { errorCode: "HTTP_401", errorCategory: "AUTH", errorMessage: "API Key \u8BA4\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5BC6\u94A5\u662F\u5426\u6B63\u786E\u914D\u7F6E" };
27222
+ if (status === 429) return { errorCode: "HTTP_429", errorCategory: "RATE_LIMIT", errorMessage: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u5DF2\u89E6\u53D1\u9650\u6D41\u3002\u8BF7\u7A0D\u7B49\u540E\u91CD\u8BD5" };
27223
+ return { errorCode: "NETWORK_ERROR", errorCategory: "NETWORK", errorMessage: `\u7F51\u7EDC\u9519\u8BEF HTTP ${status}` };
26683
27224
  }
26684
- if (msg.includes("API Key")) return { errorCode: "AUTH_REQUIRED", errorCategory: "AUTH" };
26685
- return { errorCode: "UNKNOWN_ERROR", errorCategory: "BUSINESS" };
27225
+ if (msg.includes("API Key")) return { errorCode: "AUTH_REQUIRED", errorCategory: "AUTH", errorMessage: msg };
27226
+ return { errorCode: "UNKNOWN_ERROR", errorCategory: "BUSINESS", errorMessage: msg };
26686
27227
  }
26687
27228
  function classifyRisk(toolName) {
26688
27229
  const admin = ["okx_set_account_mode", "okx_set_position_mode", "okx_set_settle_currency"];
@@ -26737,12 +27278,13 @@ function classifyRisk(toolName) {
26737
27278
  }
26738
27279
  function toError(e) {
26739
27280
  const msg = e instanceof Error ? e.message : String(e);
26740
- const { errorCode, errorCategory } = classifyError(msg);
27281
+ const { errorCode, errorCategory, errorMessage } = classifyError(msg);
26741
27282
  return {
26742
- content: [{ type: "text", text: msg }],
27283
+ content: [{ type: "text", text: errorMessage }],
26743
27284
  isError: true,
26744
27285
  errorCode,
26745
- errorCategory
27286
+ errorCategory,
27287
+ errorMessage
26746
27288
  };
26747
27289
  }
26748
27290
 
@@ -33757,12 +34299,13 @@ function registerAgentUtils(server, auth) {
33757
34299
  },
33758
34300
  {
33759
34301
  domain: "WebSocket \u5B9E\u65F6",
33760
- what: "\u5B9E\u65F6\u884C\u60C5\u63A8\u9001\u3001\u6210\u4EA4\u63A8\u9001",
33761
- when: ["\u5B9E\u65F6", "\u8BA2\u9605", "\u63A8\u9001", "websocket", "ws", "\u76D1\u542C"],
34302
+ what: "\u5B9E\u65F6\u884C\u60C5\u3001\u8D26\u6237\u3001\u8BA2\u5355\u3001\u7206\u4ED3\u3001\u4EF7\u5DEE\u3001\u5927\u5B97\u63A8\u9001\uFF0855 \u9891\u9053\uFF09",
34303
+ when: ["\u5B9E\u65F6", "\u8BA2\u9605", "\u63A8\u9001", "websocket", "ws", "\u76D1\u542C", "\u7206\u4ED3", "\u5B9E\u65F6\u8BA2\u5355"],
33762
34304
  go_to: "okx_ws_subscribe",
33763
34305
  also: [
33764
- "okx_ws_events \u2014 \u83B7\u53D6\u63A8\u9001\u4E8B\u4EF6",
33765
- "okx_ws_status \u2014 \u8BA2\u9605\u72B6\u6001",
34306
+ "okx_ws_subscribe_private \u2014 \u79C1\u6709\u9891\u9053\uFF08\u8D26\u6237/\u6301\u4ED3/\u8BA2\u5355\uFF0C\u9700Key\uFF09",
34307
+ "okx_ws_events \u2014 \u62C9\u53D6\u7F13\u51B2\u4E8B\u4EF6",
34308
+ "okx_ws_status \u2014 \u67E5\u770B\u8BA2\u9605\u72B6\u6001",
33766
34309
  "okx_ws_close \u2014 \u5173\u95ED\u8BA2\u9605"
33767
34310
  ],
33768
34311
  risk: "READ"
@@ -33854,7 +34397,8 @@ function registerAgentUtils(server, auth) {
33854
34397
  "agent_get_preference": "key? (\u4E0D\u586B\u8FD4\u56DE\u5168\u90E8)",
33855
34398
  "agent_set_preference": "key, value",
33856
34399
  "okx_event_instruments": "eventType? (\u4E0D\u586B\u8FD4\u56DE\u5168\u90E8)",
33857
- "okx_ws_subscribe": "channels (JSON\u6570\u7EC4)",
34400
+ "okx_ws_subscribe": "instId (\u4EA7\u54C1ID), channel (33\u4E2A\u516C\u5F00\u9891\u9053)",
34401
+ "okx_ws_subscribe_private": "instId? (\u4EA7\u54C1ID), channel (22\u4E2A\u79C1\u6709\u9891\u9053\uFF0C\u9700Key)",
33858
34402
  "okx_get_grid_ai_param": "instType, algoOrdType"
33859
34403
  };
33860
34404
  const enrichedDomains = CATALOG.domains.map((d) => ({
@@ -34055,12 +34599,13 @@ function registerAgentUtils(server, auth) {
34055
34599
  ]
34056
34600
  },
34057
34601
  "WebSocket \u5B9E\u65F6": {
34058
- workflow: "okx_ws_subscribe \u8BA2\u9605\u9891\u9053 \u2192 okx_ws_events \u62C9\u53D6\u4E8B\u4EF6",
34602
+ workflow: "okx_ws_subscribe \u516C\u5F00\u9891\u9053 \u2192 okx_ws_subscribe_private \u79C1\u6709\u9891\u9053\uFF08\u9700Key\uFF09\u2192 okx_ws_events \u62C9\u53D6 \u2192 okx_ws_status \u7BA1\u7406",
34059
34603
  tools: [
34060
- { name: "okx_ws_subscribe", auth: "\u516C\u5F00", params: "channels[]", what: "\u8BA2\u9605\u5B9E\u65F6\u9891\u9053\uFF08tickers/trades/books/candles/fundingRate \u7B49\uFF09" },
34061
- { name: "okx_ws_events", auth: "\u516C\u5F00", params: "channel?", what: "\u6536\u53D6\u8BA2\u9605\u7684\u5B9E\u65F6\u63A8\u9001\u4E8B\u4EF6" },
34062
- { name: "okx_ws_status", auth: "\u516C\u5F00", params: "\u65E0", what: "\u5F53\u524D\u8BA2\u9605\u72B6\u6001" },
34063
- { name: "okx_ws_close", auth: "\u516C\u5F00", params: "channel?", what: "\u53D6\u6D88\u8BA2\u9605" }
34604
+ { name: "okx_ws_subscribe", auth: "\u516C\u5F00", params: "instId, channel (33\u516C\u5F00\u9891\u9053)", what: "\u8BA2\u9605\u516C\u5F00\u9891\u9053\uFF1A\u884C\u60C5/\u6DF1\u5EA6/\u7206\u4ED3/\u4EF7\u5DEE/\u5927\u5B97/\u8D44\u91D1\u8D39\u7387\u7B49" },
34605
+ { name: "okx_ws_subscribe_private", auth: "API Key", params: "instId?, channel (22\u79C1\u6709\u9891\u9053)", what: "\u8BA2\u9605\u79C1\u6709\u9891\u9053\uFF1A\u8D26\u6237/\u6301\u4ED3/\u8BA2\u5355/\u7F51\u683C/\u8DDF\u5355\u7B49\u5B9E\u65F6\u63A8\u9001" },
34606
+ { name: "okx_ws_events", auth: "\u516C\u5F00", params: "subscriptionId?, limit?, filter?", what: "\u62C9\u53D6\u7F13\u51B2\u7684\u5B9E\u65F6\u4E8B\u4EF6" },
34607
+ { name: "okx_ws_status", auth: "\u516C\u5F00", params: "\u65E0", what: "\u5F53\u524D\u6240\u6709\u8BA2\u9605+\u7F13\u51B2\u79EF\u538B" },
34608
+ { name: "okx_ws_close", auth: "\u516C\u5F00", params: "subscriptionId?", what: "\u5173\u95ED\u8BA2\u9605" }
34064
34609
  ]
34065
34610
  },
34066
34611
  "\u6A21\u62DF\u4F30\u7B97": {
@@ -35009,8 +35554,18 @@ function registerSmartMoneyTools(server, auth) {
35009
35554
  );
35010
35555
  }
35011
35556
 
35557
+ // node_modules/ws/wrapper.mjs
35558
+ var import_stream2 = __toESM(require_stream(), 1);
35559
+ var import_extension = __toESM(require_extension(), 1);
35560
+ var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
35561
+ var import_receiver = __toESM(require_receiver(), 1);
35562
+ var import_sender = __toESM(require_sender(), 1);
35563
+ var import_subprotocol = __toESM(require_subprotocol(), 1);
35564
+ var import_websocket = __toESM(require_websocket(), 1);
35565
+ var import_websocket_server = __toESM(require_websocket_server(), 1);
35566
+ var wrapper_default = import_websocket.default;
35567
+
35012
35568
  // src/adapters/xlayer-ws.ts
35013
- init_wrapper();
35014
35569
  var WS_URL = process.env.XLAYER_WS_URL || "wss://xlayerws.okx.com";
35015
35570
  var MAX_EVENTS = 500;
35016
35571
  var XLayerWSManager = class {
@@ -35280,25 +35835,47 @@ var subCounter = 0;
35280
35835
  var WsManager = class {
35281
35836
  subscriptions = /* @__PURE__ */ new Map();
35282
35837
  events = [];
35283
- ws = null;
35284
- pingTimer = null;
35285
- channelArgs = /* @__PURE__ */ new Map();
35286
- // channel -> instIds
35838
+ wsPub = null;
35839
+ wsPriv = null;
35840
+ pingPub = null;
35841
+ pingPriv = null;
35842
+ // Fix #1: 按 type 拆分 channelArgs,重连时只遍历同类型
35843
+ channelArgsPub = /* @__PURE__ */ new Map();
35844
+ channelArgsPriv = /* @__PURE__ */ new Map();
35845
+ getWs(type) {
35846
+ return type === "public" ? this.wsPub : this.wsPriv;
35847
+ }
35848
+ setWs(type, ws) {
35849
+ if (type === "public") this.wsPub = ws;
35850
+ else this.wsPriv = ws;
35851
+ }
35852
+ getPing(type) {
35853
+ return type === "public" ? this.pingPub : this.pingPriv;
35854
+ }
35855
+ setPing(type, timer) {
35856
+ if (type === "public") this.pingPub = timer;
35857
+ else this.pingPriv = timer;
35858
+ }
35859
+ getChannelArgs(type) {
35860
+ return type === "public" ? this.channelArgsPub : this.channelArgsPriv;
35861
+ }
35287
35862
  async subscribe(opts) {
35288
- const wsModule = await Promise.resolve().then(() => (init_wrapper(), wrapper_exports));
35289
35863
  const id = `sub_${++subCounter}`;
35290
- this.subscriptions.set(id, { id, channel: opts.channel, instId: opts.instId });
35864
+ const type = opts.type || "public";
35865
+ this.subscriptions.set(id, { id, channel: opts.channel, instId: opts.instId, type });
35291
35866
  const arg = { channel: opts.channel, instId: opts.instId };
35292
- if (!this.ws || this.ws.readyState !== wsModule.WebSocket.OPEN) {
35293
- const url = opts.type === "private" ? WS_PRIVATE : WS_PUBLIC;
35294
- await this.connect(wsModule, url, opts.auth);
35295
- }
35296
- if (this.ws?.readyState === wsModule.WebSocket.OPEN) {
35297
- this.ws.send(JSON.stringify({ op: "subscribe", args: [arg] }));
35298
- }
35299
- const ck = opts.channel;
35300
- if (!this.channelArgs.has(ck)) this.channelArgs.set(ck, /* @__PURE__ */ new Set());
35301
- this.channelArgs.get(ck).add(opts.instId);
35867
+ const currentWs = this.getWs(type);
35868
+ if (!currentWs || currentWs.readyState !== wrapper_default.OPEN) {
35869
+ const url = type === "private" ? WS_PRIVATE : WS_PUBLIC;
35870
+ await this.connect(url, opts.auth, type);
35871
+ }
35872
+ const targetWs = this.getWs(type);
35873
+ if (targetWs?.readyState === wrapper_default.OPEN) {
35874
+ targetWs.send(JSON.stringify({ op: "subscribe", args: [arg] }));
35875
+ }
35876
+ const chanArgs = this.getChannelArgs(type);
35877
+ if (!chanArgs.has(opts.channel)) chanArgs.set(opts.channel, /* @__PURE__ */ new Set());
35878
+ chanArgs.get(opts.channel).add(opts.instId);
35302
35879
  return id;
35303
35880
  }
35304
35881
  drain(subId, limit = 20) {
@@ -35329,37 +35906,60 @@ var WsManager = class {
35329
35906
  }
35330
35907
  close(subId) {
35331
35908
  if (subId) {
35909
+ const sub = this.subscriptions.get(subId);
35910
+ if (sub) {
35911
+ const chanArgs = this.getChannelArgs(sub.type);
35912
+ const instIds = chanArgs.get(sub.channel);
35913
+ if (instIds) {
35914
+ instIds.delete(sub.instId);
35915
+ if (instIds.size === 0) chanArgs.delete(sub.channel);
35916
+ }
35917
+ const ws = this.getWs(sub.type);
35918
+ if (ws?.readyState === wrapper_default.OPEN) {
35919
+ try {
35920
+ ws.send(JSON.stringify({ op: "unsubscribe", args: [{ channel: sub.channel, instId: sub.instId }] }));
35921
+ } catch {
35922
+ }
35923
+ }
35924
+ }
35332
35925
  this.subscriptions.delete(subId);
35333
35926
  this.events = this.events.filter((e) => e.subId !== subId);
35334
35927
  return 1;
35335
35928
  }
35336
35929
  const count = this.subscriptions.size;
35337
35930
  this.subscriptions.clear();
35931
+ this.channelArgsPub.clear();
35932
+ this.channelArgsPriv.clear();
35338
35933
  this.events = [];
35339
- if (this.ws) {
35340
- try {
35341
- this.ws.close();
35342
- } catch {
35934
+ for (const ws of [this.wsPub, this.wsPriv]) {
35935
+ if (ws) {
35936
+ try {
35937
+ ws.close();
35938
+ } catch {
35939
+ }
35343
35940
  }
35344
- ;
35345
- this.ws = null;
35346
35941
  }
35347
- if (this.pingTimer) {
35348
- clearInterval(this.pingTimer);
35349
- this.pingTimer = null;
35942
+ this.wsPub = null;
35943
+ this.wsPriv = null;
35944
+ for (const t of [this.pingPub, this.pingPriv]) {
35945
+ if (t) {
35946
+ clearInterval(t);
35947
+ }
35350
35948
  }
35949
+ this.pingPub = null;
35950
+ this.pingPriv = null;
35351
35951
  return count;
35352
35952
  }
35353
- connect(wsModule, url, auth) {
35953
+ connect(url, auth, type) {
35354
35954
  return new Promise((resolve2, reject) => {
35355
- const ws = new wsModule.WebSocket(url);
35955
+ const ws = new wrapper_default(url);
35356
35956
  const timeout = setTimeout(() => {
35357
35957
  ws.close();
35358
35958
  reject(new Error("WS \u8FDE\u63A5\u8D85\u65F6(10s)"));
35359
35959
  }, 1e4);
35360
35960
  ws.on("open", () => {
35361
35961
  clearTimeout(timeout);
35362
- if (auth && url.includes("private")) {
35962
+ if (auth && type === "private") {
35363
35963
  const ts = Math.floor(Date.now() / 1e3).toString();
35364
35964
  const sign2 = import_node_crypto2.default.createHmac("sha256", auth.secret).update(ts + "GET/users/self/verify").digest("base64");
35365
35965
  ws.send(JSON.stringify({
@@ -35367,15 +35967,17 @@ var WsManager = class {
35367
35967
  args: [{ apiKey: auth.apiKey, passphrase: auth.passphrase, timestamp: ts, sign: sign2 }]
35368
35968
  }));
35369
35969
  }
35370
- for (const [channel, instIds] of this.channelArgs) {
35970
+ const chanArgs = this.getChannelArgs(type);
35971
+ for (const [channel, instIds] of chanArgs) {
35371
35972
  for (const instId of instIds) {
35372
35973
  ws.send(JSON.stringify({ op: "subscribe", args: [{ channel, instId }] }));
35373
35974
  }
35374
35975
  }
35375
- this.pingTimer = setInterval(() => {
35376
- if (ws.readyState === wsModule.WebSocket.OPEN) ws.send("ping");
35976
+ const timer = setInterval(() => {
35977
+ if (ws.readyState === wrapper_default.OPEN) ws.send("ping");
35377
35978
  }, 25e3);
35378
- this.ws = ws;
35979
+ this.setPing(type, timer);
35980
+ this.setWs(type, ws);
35379
35981
  resolve2();
35380
35982
  });
35381
35983
  ws.on("message", (raw) => {
@@ -35383,6 +35985,22 @@ var WsManager = class {
35383
35985
  const msg = raw.toString();
35384
35986
  if (msg === "pong") return;
35385
35987
  const parsed = JSON.parse(msg);
35988
+ if (parsed.event === "error" && parsed.code) {
35989
+ this.events.push({
35990
+ subId: "__error__",
35991
+ channel: parsed.arg?.channel || "unknown",
35992
+ instId: parsed.arg?.instId || "",
35993
+ ts: Date.now(),
35994
+ data: {
35995
+ error: true,
35996
+ code: parsed.code,
35997
+ message: parsed.msg || "WebSocket \u9519\u8BEF",
35998
+ hint: parsed.code === "60001" ? "\u9891\u9053\u540D\u4E0D\u652F\u6301\u6216\u53C2\u6570\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5 channel \u503C" : parsed.code === "60003" ? "\u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u8FDE" : parsed.code === "60009" ? "\u79C1\u6709\u9891\u9053\u9700\u8981\u5148 login\uFF08API Key \u7B7E\u540D\uFF09" : `OKX WS \u9519\u8BEF ${parsed.code}`
35999
+ }
36000
+ });
36001
+ if (this.events.length > 1e4) this.events = this.events.slice(-5e3);
36002
+ return;
36003
+ }
35386
36004
  if (parsed.arg && parsed.data) {
35387
36005
  for (const [id, sub] of this.subscriptions) {
35388
36006
  if (sub.channel === parsed.arg.channel && sub.instId === parsed.arg.instId) {
@@ -35406,11 +36024,12 @@ var WsManager = class {
35406
36024
  reject(err);
35407
36025
  });
35408
36026
  ws.on("close", () => {
35409
- if (this.pingTimer) {
35410
- clearInterval(this.pingTimer);
35411
- this.pingTimer = null;
36027
+ const t = this.getPing(type);
36028
+ if (t) {
36029
+ clearInterval(t);
36030
+ this.setPing(type, null);
35412
36031
  }
35413
- this.ws = null;
36032
+ this.setWs(type, null);
35414
36033
  });
35415
36034
  });
35416
36035
  }
@@ -35422,36 +36041,103 @@ function getOrCreateWs() {
35422
36041
  if (!wsManager) wsManager = new WsManager();
35423
36042
  return wsManager;
35424
36043
  }
35425
- var PUBLIC_CHANNELS = [
35426
- "tickers",
35427
- "trades",
35428
- "candle1m",
35429
- "candle5m",
35430
- "candle15m",
35431
- "candle1H",
35432
- "candle4H",
35433
- "candle1D",
35434
- "books5",
35435
- "books",
35436
- "mark-price",
35437
- "funding-rate",
35438
- "open-interest",
35439
- "price-limit",
35440
- "index-tickers"
35441
- ];
35442
- function registerWsTools(server) {
36044
+ var ALL_CHANNELS = {
36045
+ public: [
36046
+ // 行情类(10)
36047
+ "tickers",
36048
+ "trades",
36049
+ "all-trades",
36050
+ "option-trades",
36051
+ "candle1m",
36052
+ "candle5m",
36053
+ "candle15m",
36054
+ "candle1H",
36055
+ "candle4H",
36056
+ "candle1D",
36057
+ // 深度类(2)
36058
+ "books5",
36059
+ "books",
36060
+ // 市场细节(1)
36061
+ "call-auction-details",
36062
+ // 公共数据(10)
36063
+ "mark-price",
36064
+ "mark-price-candles",
36065
+ "index-tickers",
36066
+ "index-candles",
36067
+ "funding-rate",
36068
+ "open-interest",
36069
+ "price-limit",
36070
+ "instruments",
36071
+ "option-summary",
36072
+ "estimated-price",
36073
+ // 风险预警(3)
36074
+ "liquidation-orders",
36075
+ "adl-warning",
36076
+ "status",
36077
+ // 事件合约(1)
36078
+ "event-contract-markets",
36079
+ // 经济日历(1)
36080
+ "economic-calendar",
36081
+ // 价差公开(4)
36082
+ "sprd/tickers",
36083
+ "sprd/candles",
36084
+ "sprd/order-book",
36085
+ "sprd/public-trades",
36086
+ // 大宗公开(3)
36087
+ "public-structure-block-trades",
36088
+ "public-block-trades",
36089
+ "block-tickers"
36090
+ ],
36091
+ private: [
36092
+ // 账户(5)
36093
+ "account",
36094
+ "positions",
36095
+ "balance_and_position",
36096
+ "position-risk-warning",
36097
+ "account-greeks",
36098
+ // 交易(4)
36099
+ "orders",
36100
+ "fills",
36101
+ "algo-orders",
36102
+ "advance-algo-orders",
36103
+ // 网格(4)
36104
+ "spot-grid-algo-orders",
36105
+ "contract-grid-algo-orders",
36106
+ "grid-positions",
36107
+ "grid-sub-orders",
36108
+ // 定投(1)
36109
+ "recurring-buy-orders",
36110
+ // 跟单(1)
36111
+ "lead-trading-notification",
36112
+ // 资金(2)
36113
+ "deposit-info",
36114
+ "withdrawal-info",
36115
+ // 大宗私有(3)
36116
+ "rfqs",
36117
+ "quotes",
36118
+ "structure-block-trades",
36119
+ // 价差私有(2)
36120
+ "sprd/orders",
36121
+ "sprd/trades"
36122
+ ]
36123
+ };
36124
+ function registerWsTools(server, auth) {
35443
36125
  server.tool(
35444
36126
  "okx_ws_subscribe",
35445
- "CAT:[\u884C\u60C5-WS] | ## \u529F\u80FD\uFF1A\u8BA2\u9605OKX WebSocket\u5B9E\u65F6\u6570\u636E\uFF0C\u4E8B\u4EF6\u81EA\u52A8\u7F13\u51B2\u5728\u5185\u5B58\u4E2D\n## \u573A\u666F\uFF1AAgent \u9700\u8981\u5B9E\u65F6\u76D1\u63A7\u884C\u60C5\u53D8\u5316\u800C\u975E\u8F6E\u8BE2\u65F6\u8C03\u7528\n## \u5173\u952E\u8BCD\uFF1AWebSocket, ws, \u5B9E\u65F6\u63A8\u9001, \u5B9E\u65F6\u884C\u60C5, \u8BA2\u9605, subscribe, \u6D41\u5F0F\n## \u53C2\u6570\uFF1A\n## - instId: \u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT\u3001ETH-USDT-SWAP\n## - channel: \u9891\u9053\u540D\u3002(tickers/trades/candle1m~1D/books5/books\u7B49)\n## - instType: SPOT/SWAP/FUTURES/OPTION\uFF08tickers/trades \u9891\u9053\u9700\u8981\uFF09\n## \u9274\u6743\uFF1APUBLIC \u2014 \u516C\u5F00\u9891\u9053\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u8BA2\u9605\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u8BA2\u9605 \u2192 okx_ws_events \u62C9\u53D6 \u2192 \u51B3\u7B56 \u2192 okx_ws_close \u5173\u95ED",
36127
+ "CAT:[\u884C\u60C5-WS] | ## \u529F\u80FD\uFF1A\u8BA2\u9605 OKX WebSocket \u5B9E\u65F6\u516C\u5F00\u9891\u9053\uFF0C\u4E8B\u4EF6\u81EA\u52A8\u7F13\u51B2\u5728\u5185\u5B58\u4E2D\n## \u573A\u666F\uFF1AAgent \u9700\u8981\u5B9E\u65F6\u76D1\u63A7\u884C\u60C5\u3001\u7206\u4ED3\u5355\u3001\u8D44\u91D1\u8D39\u7387\u3001\u4EF7\u5DEE/\u5927\u5B97\u5E02\u573A\u65F6\u8C03\u7528\uFF0C\u66FF\u4EE3 REST \u8F6E\u8BE2\n## \u5173\u952E\u8BCD\uFF1AWebSocket, ws, \u5B9E\u65F6\u63A8\u9001, \u5B9E\u65F6\u884C\u60C5, \u8BA2\u9605, subscribe, \u7206\u4ED3, \u8D44\u91D1\u8D39\u7387, \u4EF7\u5DEE, \u5927\u5B97\n## \u53C2\u6570\uFF1A\n## - instId: \u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT\u3001ETH-USDT-SWAP\u3002status/instruments/economic-calendar \u7B49\u5168\u5C40\u9891\u9053\u4E0D\u9700\u8981 instId\n## - channel: \u9891\u9053\u540D\u3002\u53EF\u9009: tickers / trades / all-trades / candle1m~1D / books5 / books / funding-rate / open-interest / price-limit / instruments / mark-price / mark-price-candles / index-tickers / index-candles / option-summary / estimated-price / liquidation-orders / adl-warning / event-contract-markets / economic-calendar / status / sprd/* / public-*-block-trades / block-tickers\n## \u9274\u6743\uFF1APUBLIC \u2014 \u516C\u5F00\u9891\u9053\uFF0C\u65E0\u9700 API Key\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u8BA2\u9605 \u2192 okx_ws_events \u62C9\u53D6 \u2192 okx_ws_close \u5173\u95ED",
35446
36128
  {
35447
- instId: external_exports.string().describe("\u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT"),
35448
- channel: external_exports.string().describe("\u9891\u9053\u540D"),
35449
- instType: external_exports.enum(["SPOT", "SWAP", "FUTURES", "OPTION"]).optional().describe("tickers/trades \u9700\u8981")
36129
+ instId: external_exports.string().describe("\u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT\u3001ETH-USDT-SWAP\u3002\u7EAF\u5168\u5C40\u9891\u9053\uFF08status/instruments/economic-calendar\uFF09\u53EF\u4F20\u7A7A\u5B57\u7B26\u4E32"),
36130
+ channel: external_exports.string().describe("\u9891\u9053\u540D\u3002\u516C\u5F00\u9891\u9053\u5171 33 \u4E2A\uFF0C\u652F\u6301 tickers/trades/candle1m~1D/books5/books/funding-rate/open-interest/price-limit/instruments/mark-price/mark-price-candles/index-tickers/index-candles/option-summary/estimated-price/liquidation-orders/adl-warning/event-contract-markets/economic-calendar/status/sprd\u7CFB\u5217/public-block-trades\u7CFB\u5217/block-tickers"),
36131
+ instType: external_exports.enum(["SPOT", "SWAP", "FUTURES", "OPTION"]).optional().describe("\u90E8\u5206\u9891\u9053\u9700\u8981\u4EA7\u54C1\u7C7B\u578B")
35450
36132
  },
35451
36133
  async ({ instId, channel }) => {
35452
36134
  try {
35453
- if (!PUBLIC_CHANNELS.includes(channel)) {
35454
- return toError(new Error(`\u9891\u9053 "${channel}" \u4E0D\u652F\u6301\u3002\u652F\u6301: ${PUBLIC_CHANNELS.join(" ")}`));
36135
+ if (!ALL_CHANNELS.public.includes(channel)) {
36136
+ return toError(new Error(
36137
+ `\u9891\u9053 "${channel}" \u975E\u516C\u5F00\u9891\u9053\u3002
36138
+ \u516C\u5F00\u9891\u9053(${ALL_CHANNELS.public.length}\u4E2A): ${ALL_CHANNELS.public.join(" ")}
36139
+ \u79C1\u6709\u9891\u9053\u8BF7\u7528 okx_ws_subscribe_private\u3002`
36140
+ ));
35455
36141
  }
35456
36142
  const ws = getOrCreateWs();
35457
36143
  const subId = await ws.subscribe({ channel, instId: instId.toUpperCase(), type: "public" });
@@ -35460,8 +36146,48 @@ function registerWsTools(server) {
35460
36146
  subscriptionId: subId,
35461
36147
  channel,
35462
36148
  instId: instId.toUpperCase(),
36149
+ type: "public",
35463
36150
  buffered: ws.countBuffered(subId),
35464
- hint: `\u5DF2\u8BA2\u9605 ${instId.toUpperCase()} ${channel}\u3002\u8C03\u7528 okx_ws_events \u62C9\u53D6\u4E8B\u4EF6\u3002`,
36151
+ hint: `\u5DF2\u8BA2\u9605 ${instId || "\u5168\u5C40"} ${channel}\u3002\u8C03\u7528 okx_ws_events \u62C9\u53D6\u4E8B\u4EF6\u3002`,
36152
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
36153
+ });
36154
+ } catch (e) {
36155
+ return toError(e);
36156
+ }
36157
+ }
36158
+ );
36159
+ server.tool(
36160
+ "okx_ws_subscribe_private",
36161
+ "CAT:[\u884C\u60C5-WS] | ## \u529F\u80FD\uFF1A\u8BA2\u9605 OKX WebSocket \u79C1\u6709\u9891\u9053\u2014\u2014\u5B9E\u65F6\u63A8\u9001\u8D26\u6237\u4F59\u989D\u3001\u6301\u4ED3\u53D8\u52A8\u3001\u8BA2\u5355\u6210\u4EA4\u3001\u7F51\u683C/\u7B56\u7565/\u8DDF\u5355\u72B6\u6001\n## \u573A\u666F\uFF1AAgent \u9700\u8981\u5B9E\u65F6\u8DDF\u8E2A\u8D26\u6237\u53D8\u5316\uFF08\u975E\u8F6E\u8BE2 REST\uFF09\u65F6\u8C03\u7528\n## \u5173\u952E\u8BCD\uFF1AWebSocket, ws, \u79C1\u6709\u9891\u9053, \u5B9E\u65F6\u8D26\u6237, \u8BA2\u5355\u63A8\u9001, positions, orders, \u7F51\u683C, \u8DDF\u5355\n## \u53C2\u6570\uFF1A\n## - instId: \u4EA7\u54C1ID\u3002account/positions/balance_and_position \u7B49\u8D26\u6237\u7EA7\u9891\u9053\u53EF\u4E0D\u4F20\n## - channel: \u79C1\u6709\u9891\u9053\u540D\u3002\u53EF\u9009: account / positions / balance_and_position / position-risk-warning / account-greeks / orders / fills / algo-orders / advance-algo-orders / spot-grid-algo-orders / contract-grid-algo-orders / grid-positions / grid-sub-orders / recurring-buy-orders / lead-trading-notification / deposit-info / withdrawal-info / rfqs / quotes / structure-block-trades / sprd/orders / sprd/trades\n## \u9274\u6743\uFF1A\u26A0\uFE0F \u9700\u8981 API Key\uFF08\u5FC5\u987B\u5F00\u901A\u8BFB\u53D6\u6743\u9650\uFF09\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u8BA2\u9605\uFF0C\u4F46\u9700 API Key\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u8BA2\u9605 \u2192 okx_ws_events \u62C9\u53D6 \u2192 okx_ws_close \u5173\u95ED",
36162
+ {
36163
+ instId: external_exports.string().optional().describe("\u4EA7\u54C1ID\u3002\u8D26\u6237\u7EA7\u9891\u9053\u53EF\u4E0D\u4F20\uFF08\u5982 account/positions/balances\uFF09"),
36164
+ channel: external_exports.string().describe("\u79C1\u6709\u9891\u9053\u540D\u3002\u5171 22 \u4E2A: account / positions / balance_and_position / position-risk-warning / account-greeks / orders / fills / algo-orders / advance-algo-orders / spot-grid-algo-orders / contract-grid-algo-orders / grid-positions / grid-sub-orders / recurring-buy-orders / lead-trading-notification / deposit-info / withdrawal-info / rfqs / quotes / structure-block-trades / sprd/orders / sprd/trades")
36165
+ },
36166
+ async ({ instId, channel }) => {
36167
+ if (!auth) return toError(AUTH_REQUIRED);
36168
+ try {
36169
+ if (!ALL_CHANNELS.private.includes(channel)) {
36170
+ return toError(new Error(
36171
+ `\u9891\u9053 "${channel}" \u975E\u79C1\u6709\u9891\u9053\u3002
36172
+ \u79C1\u6709\u9891\u9053(${ALL_CHANNELS.private.length}\u4E2A): ${ALL_CHANNELS.private.join(" ")}
36173
+ \u516C\u5F00\u9891\u9053\u8BF7\u7528 okx_ws_subscribe\u3002`
36174
+ ));
36175
+ }
36176
+ const ws = getOrCreateWs();
36177
+ const subId = await ws.subscribe({
36178
+ channel,
36179
+ instId: (instId || "").toUpperCase(),
36180
+ type: "private",
36181
+ auth
36182
+ });
36183
+ return toResult({
36184
+ subscribed: true,
36185
+ subscriptionId: subId,
36186
+ channel,
36187
+ instId: (instId || "\u5168\u5C40").toUpperCase(),
36188
+ type: "private",
36189
+ buffered: ws.countBuffered(subId),
36190
+ hint: `\u5DF2\u8BA2\u9605\u79C1\u6709\u9891\u9053 ${channel}\u3002\u8C03\u7528 okx_ws_events \u62C9\u53D6\u5B9E\u65F6\u4E8B\u4EF6\u3002`,
35465
36191
  tsIso: (/* @__PURE__ */ new Date()).toISOString()
35466
36192
  });
35467
36193
  } catch (e) {
@@ -35536,7 +36262,6 @@ function registerWsTools(server) {
35536
36262
  }
35537
36263
 
35538
36264
  // src/adapters/agent-hub.ts
35539
- init_wrapper();
35540
36265
  var MAX_ROOM_MESSAGES = 200;
35541
36266
  var AgentHub = class {
35542
36267
  wss = null;
@@ -36089,97 +36814,210 @@ function registerAgentHubTools(server) {
36089
36814
  var path2 = __toESM(require("node:path"));
36090
36815
  var fs2 = __toESM(require("node:fs"));
36091
36816
  var DatabaseSync = null;
36092
- function getDB() {
36093
- if (DatabaseSync === null) {
36094
- try {
36095
- const sqlite = require("node:sqlite");
36096
- DatabaseSync = sqlite.DatabaseSync;
36097
- } catch {
36098
- return null;
36099
- }
36817
+ var _sqliteAvailable = null;
36818
+ function isSqliteAvailable() {
36819
+ if (_sqliteAvailable !== null) return _sqliteAvailable;
36820
+ try {
36821
+ const sqlite = require("node:sqlite");
36822
+ DatabaseSync = sqlite.DatabaseSync;
36823
+ _sqliteAvailable = true;
36824
+ return true;
36825
+ } catch {
36826
+ _sqliteAvailable = false;
36827
+ return false;
36100
36828
  }
36101
- const dbPath = path2.resolve(".codegraph", "codegraph.db");
36102
- if (!fs2.existsSync(dbPath)) {
36829
+ }
36830
+ function getDBPath() {
36831
+ return path2.resolve(".codegraph", "codegraph.db");
36832
+ }
36833
+ function openDB() {
36834
+ if (!isSqliteAvailable()) return null;
36835
+ const dbPath = getDBPath();
36836
+ if (!fs2.existsSync(dbPath)) return null;
36837
+ try {
36838
+ return new DatabaseSync(dbPath, { readonly: true });
36839
+ } catch {
36103
36840
  return null;
36104
36841
  }
36842
+ }
36843
+ function safeGet(db, sql, ...params) {
36105
36844
  try {
36106
- const db = new DatabaseSync(dbPath, { readonly: true });
36107
- db.prepare("SELECT 1").get();
36108
- return { db };
36109
- } catch (e) {
36845
+ const stmt = db.prepare(sql);
36846
+ return stmt.get(...params.length ? params : []);
36847
+ } catch {
36110
36848
  return null;
36111
36849
  }
36112
36850
  }
36851
+ function safeAll(db, sql, limit, ...params) {
36852
+ try {
36853
+ const stmt = db.prepare(sql);
36854
+ const all = stmt.all(...params.length ? params : []);
36855
+ return (Array.isArray(all) ? all : []).slice(0, limit);
36856
+ } catch {
36857
+ return [];
36858
+ }
36859
+ }
36860
+ function findNodes(db, name, limit = 5) {
36861
+ const exact = safeAll(
36862
+ db,
36863
+ "SELECT * FROM nodes WHERE name = ? LIMIT ?",
36864
+ limit,
36865
+ name,
36866
+ limit
36867
+ );
36868
+ if (exact.length > 0) return exact;
36869
+ return safeAll(
36870
+ db,
36871
+ "SELECT * FROM nodes WHERE name LIKE ? LIMIT ?",
36872
+ limit,
36873
+ `%${name}%`,
36874
+ limit
36875
+ );
36876
+ }
36877
+ function getCallers(db, nodeId, limit = 50) {
36878
+ return safeAll(db, `
36879
+ SELECT n.name, n.kind, n.file_path, n.start_line, e.line, e.kind as edge_kind
36880
+ FROM edges e
36881
+ JOIN nodes n ON e.source = n.id
36882
+ WHERE e.target = ? AND e.kind = 'calls'
36883
+ ORDER BY n.file_path, n.start_line
36884
+ LIMIT ?
36885
+ `, limit, nodeId, limit);
36886
+ }
36887
+ function getCallees(db, nodeId, limit = 50) {
36888
+ return safeAll(db, `
36889
+ SELECT n.name, n.kind, n.file_path, n.start_line, e.line, e.kind as edge_kind
36890
+ FROM edges e
36891
+ JOIN nodes n ON e.target = n.id
36892
+ WHERE e.source = ? AND e.kind = 'calls'
36893
+ ORDER BY n.file_path, n.start_line
36894
+ LIMIT ?
36895
+ `, limit, nodeId, limit);
36896
+ }
36897
+ function getImpact(db, nodeId, maxDepth = 2, limit = 50) {
36898
+ const direct = getCallers(db, nodeId, limit);
36899
+ const indirectMap = /* @__PURE__ */ new Map();
36900
+ for (const d of direct.slice(0, 10)) {
36901
+ const node = safeGet(
36902
+ db,
36903
+ "SELECT id, name, kind, file_path FROM nodes WHERE name = ? AND file_path = ? LIMIT 1",
36904
+ d.name,
36905
+ d.file_path
36906
+ );
36907
+ if (node) {
36908
+ const indirect = safeAll(db, `
36909
+ SELECT n.name, n.kind, n.file_path, n.start_line
36910
+ FROM edges e JOIN nodes n ON e.source = n.id
36911
+ WHERE e.target = ? AND e.kind = 'calls'
36912
+ LIMIT 5
36913
+ `, 5, node.id);
36914
+ for (const idr of indirect) {
36915
+ const key = `${idr.name}@${idr.file_path}`;
36916
+ if (!indirectMap.has(key)) indirectMap.set(key, idr);
36917
+ }
36918
+ }
36919
+ }
36920
+ return { direct, indirect: [...indirectMap.values()].slice(0, limit) };
36921
+ }
36113
36922
  function registerCodeGraphTools(server) {
36114
36923
  server.tool(
36115
36924
  "codegraph_status",
36116
- "CAT:[\u4EE3\u7801\u667A\u80FD] | ## \u529F\u80FD\uFF1A\u68C0\u67E5\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u72B6\u6001\u2014\u2014\u8282\u70B9\u6570\u3001\u8FB9\u6570\u3001\u8986\u76D6\u6587\u4EF6\u3001\u6700\u540E\u7D22\u5F15\u65F6\u95F4\n## \u573A\u666F\uFF1AAgent \u9996\u6B21\u8FDE\u63A5\u65F6\u8C03\u7528\uFF0C\u4E86\u89E3\u4EE3\u7801\u56FE\u8C31\u662F\u5426\u5C31\u7EEA\uFF1B\u6216\u7528\u6237\u95EE\u300C\u4EE3\u7801\u7ED3\u6784\u80FD\u67E5\u5417\u300D\u65F6\u786E\u8BA4\u72B6\u6001\n## \u5173\u952E\u8BCD\uFF1A\u4EE3\u7801\u56FE\u8C31, codegraph, \u77E5\u8BC6\u56FE\u8C31, \u4EE3\u7801\u7ED3\u6784, \u7D22\u5F15\u72B6\u6001\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1APUBLIC \u2014 \u672C\u5730\u53EA\u8BFB\uFF0C\u4E0D\u67E5\u5916\u90E8 API\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u672C\u5730\u6587\u4EF6\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u786E\u8BA4\u72B6\u6001 \u2192 codegraph_query \u67E5\u8BE2 \u2192 \u83B7\u53D6\u8C03\u7528\u94FE/\u4F9D\u8D56/\u7ED3\u6784",
36925
+ "CAT:[\u4EE3\u7801\u667A\u80FD] | ## \u529F\u80FD\uFF1A\u68C0\u67E5\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u72B6\u6001\u2014\u2014\u8282\u70B9\u6570\u3001\u8FB9\u6570\u3001\u8986\u76D6\u6587\u4EF6\u3001\u88AB\u8C03\u6700\u591A\u7684\u51FD\u6570\n## \u573A\u666F\uFF1AAgent \u9996\u6B21\u8FDE\u63A5\u65F6\u786E\u8BA4\u56FE\u8C31\u5C31\u7EEA\n## \u5173\u952E\u8BCD\uFF1A\u4EE3\u7801\u56FE\u8C31, codegraph, \u77E5\u8BC6\u56FE\u8C31, \u7D22\u5F15\u72B6\u6001, \u8C03\u7528\u6392\u884C\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1APUBLIC \u2014 \u672C\u5730\u8BFB DB\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~1KB\n## \u5173\u8054\uFF1A\u786E\u8BA4\u72B6\u6001 \u2192 codegraph_query \u8FFD\u8E2A\u8C03\u7528\u94FE",
36117
36926
  {},
36118
36927
  async () => {
36119
36928
  try {
36120
- const conn = getDB();
36121
- if (!conn) {
36929
+ if (!isSqliteAvailable()) {
36122
36930
  const nodeVersion = process.versions.node;
36123
- const nodeMajor = parseInt(nodeVersion.split(".")[0]);
36124
- const needsUpgrade = nodeMajor < 22 || nodeMajor === 22 && parseInt(nodeVersion.split(".")[1]) < 5;
36125
36931
  return toResult({
36126
36932
  status: "unavailable",
36127
- reason: needsUpgrade ? `Node.js ${nodeVersion} \u4E0D\u652F\u6301\u5185\u7F6E sqlite\uFF0C\u9700\u8981 Node >= 22.5.0` : "\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u6570\u636E\u5E93\u672A\u627E\u5230",
36933
+ reason: `Node.js ${nodeVersion} \u4E0D\u652F\u6301\u5185\u7F6E sqlite\uFF0C\u9700\u8981 Node >= 22.5.0`,
36934
+ nodeVersion,
36935
+ tsIso: (/* @__PURE__ */ new Date()).toISOString(),
36936
+ _summary: `\u4EE3\u7801\u56FE\u8C31\u4E0D\u53EF\u7528\uFF1A\u9700 Node >= 22.5.0\uFF0C\u5F53\u524D ${nodeVersion}`
36937
+ });
36938
+ }
36939
+ const dbPath = getDBPath();
36940
+ if (!fs2.existsSync(dbPath)) {
36941
+ return toResult({
36942
+ status: "no_db",
36943
+ reason: `.codegraph/codegraph.db \u4E0D\u5B58\u5728`,
36128
36944
  how_to_setup: [
36129
36945
  "1. npm i -g @colbymchenry/codegraph",
36130
- "2. cd \u5230\u9879\u76EE\u6839\u76EE\u5F55",
36131
- "3. codegraph index # \u751F\u6210 .codegraph/codegraph.db",
36132
- "4. \u91CD\u542F MCP Server"
36946
+ "2. cd \u5230\u9879\u76EE\u6839\u76EE\u5F55\u8FD0\u884C codegraph index",
36947
+ "3. \u91CD\u542F MCP Server",
36948
+ "\uFF08Claude Code \u7528\u6237\uFF1A\u56FE\u8C31\u7531 CodeGraph \u529F\u80FD\u81EA\u52A8\u751F\u6210\uFF09"
36133
36949
  ].join("\n"),
36134
- nodeVersion,
36135
36950
  tsIso: (/* @__PURE__ */ new Date()).toISOString(),
36136
- _summary: needsUpgrade ? `\u4EE3\u7801\u56FE\u8C31\u4E0D\u53EF\u7528\uFF1ANode ${nodeVersion} \u9700 >= 22.5.0` : "\u4EE3\u7801\u56FE\u8C31\u672A\u521D\u59CB\u5316\u3002\u8BF7\u8FD0\u884C codegraph index \u751F\u6210\u6570\u636E\u5E93\u3002"
36951
+ _summary: "\u4EE3\u7801\u56FE\u8C31\u672A\u751F\u6210\u3002\u8FD0\u884C codegraph index \u540E\u53EF\u7528\u3002"
36137
36952
  });
36138
36953
  }
36139
- const { db } = conn;
36140
- const nodeCount = db.prepare("SELECT count(*) as n FROM nodes").get().n;
36141
- const edgeCount = db.prepare("SELECT count(*) as n FROM edges").get().n;
36142
- const fileCount = db.prepare("SELECT count(*) as n FROM files").get().n;
36143
- const langRows = db.prepare(
36144
- "SELECT language, count(*) as n FROM files GROUP BY language ORDER BY n DESC"
36145
- ).all();
36146
- const kindRows = db.prepare(
36147
- "SELECT kind, count(*) as n FROM nodes GROUP BY kind ORDER BY n DESC LIMIT 10"
36148
- ).all();
36149
- const lastIndexed = db.prepare(
36150
- "SELECT max(indexed_at) as ts FROM files"
36151
- ).get().ts;
36152
- const topCalled = db.prepare(`
36153
- SELECT n.name, n.kind, n.file_path, count(e.id) as caller_count
36154
- FROM edges e
36155
- JOIN nodes n ON e.target = n.id
36156
- WHERE e.kind = 'calls'
36157
- GROUP BY e.target
36158
- ORDER BY caller_count DESC
36159
- LIMIT 10
36160
- `).all();
36161
- const status = {
36162
- status: "ready",
36163
- database: {
36164
- path: ".codegraph/codegraph.db",
36165
- nodeCount,
36166
- edgeCount,
36167
- fileCount,
36168
- languages: langRows.reduce((acc, r) => ({ ...acc, [r.language]: r.n }), {})
36169
- },
36170
- nodesByKind: kindRows.reduce((acc, r) => ({ ...acc, [r.kind]: r.n }), {}),
36171
- lastIndexed: lastIndexed ? new Date(lastIndexed).toISOString() : "unknown",
36172
- topCalledFunctions: topCalled.map((r) => ({
36173
- name: r.name,
36174
- kind: r.kind,
36175
- file: r.file_path,
36176
- callers: r.caller_count
36177
- })).slice(0, 5),
36178
- queryHint: "\u7528 codegraph_query \u67E5\u8BE2\u5177\u4F53\u7B26\u53F7\u7684\u8C03\u7528\u94FE\u6216\u63A2\u7D22\u4EE3\u7801\u7ED3\u6784\u3002\u4F8B\u5982: codegraph_query({ mode: 'callers', symbol: 'toResult' })",
36179
- tsIso: (/* @__PURE__ */ new Date()).toISOString(),
36180
- _summary: `\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u5C31\u7EEA\u3002${nodeCount} \u4E2A\u8282\u70B9\uFF0C${edgeCount} \u6761\u5173\u7CFB\uFF0C\u8986\u76D6 ${fileCount} \u4E2A\u6587\u4EF6\u3002\u88AB\u8C03\u7528\u6700\u591A\u7684\u51FD\u6570: ${topCalled.slice(0, 3).map((r) => r.name).join("\u3001") || "\u65E0"}\u3002`
36181
- };
36182
- return toResult(status);
36954
+ const db = openDB();
36955
+ if (!db) {
36956
+ return toResult({
36957
+ status: "error",
36958
+ reason: "\u65E0\u6CD5\u6253\u5F00\u4EE3\u7801\u56FE\u8C31\u6570\u636E\u5E93\uFF08\u53EF\u80FD\u88AB\u9501\u5B9A\uFF09",
36959
+ dbPath,
36960
+ tsIso: (/* @__PURE__ */ new Date()).toISOString(),
36961
+ _summary: "\u4EE3\u7801\u56FE\u8C31\u6570\u636E\u5E93\u6253\u5F00\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002"
36962
+ });
36963
+ }
36964
+ try {
36965
+ const nodeCount = safeGet(db, "SELECT count(*) as n FROM nodes")?.n || 0;
36966
+ const edgeCount = safeGet(db, "SELECT count(*) as n FROM edges")?.n || 0;
36967
+ const fileCount = safeGet(db, "SELECT count(*) as n FROM files")?.n || 0;
36968
+ const byLang = safeAll(
36969
+ db,
36970
+ "SELECT language, count(*) as n FROM files GROUP BY language ORDER BY n DESC",
36971
+ 20
36972
+ );
36973
+ const byKind = safeAll(
36974
+ db,
36975
+ "SELECT kind, count(*) as n FROM nodes GROUP BY kind ORDER BY n DESC",
36976
+ 20
36977
+ );
36978
+ let topCalled = [];
36979
+ try {
36980
+ topCalled = safeAll(db, `
36981
+ SELECT n.name, n.kind, n.file_path, count(e.id) as caller_count
36982
+ FROM edges e
36983
+ JOIN nodes n ON e.target = n.id
36984
+ WHERE e.kind = 'calls'
36985
+ GROUP BY e.target
36986
+ ORDER BY caller_count DESC
36987
+ LIMIT 5
36988
+ `, 5) || [];
36989
+ } catch {
36990
+ }
36991
+ const lastIndexed = safeGet(
36992
+ db,
36993
+ "SELECT max(indexed_at) as ts FROM files"
36994
+ )?.ts;
36995
+ db.close();
36996
+ const status = {
36997
+ status: "ready",
36998
+ dbPath,
36999
+ database: { nodeCount, edgeCount, fileCount },
37000
+ languages: byLang.reduce((acc, r) => ({ ...acc, [r.language]: r.n }), {}),
37001
+ nodesByKind: byKind.reduce((acc, r) => ({ ...acc, [r.kind]: r.n }), {}),
37002
+ lastIndexed: lastIndexed ? new Date(lastIndexed).toISOString() : "unknown",
37003
+ topCalledFunctions: topCalled.map((r) => ({
37004
+ name: r.name,
37005
+ kind: r.kind,
37006
+ file: r.file_path,
37007
+ callers: r.caller_count
37008
+ })),
37009
+ queryHint: "codegraph_query { mode: 'callers', symbol: 'toResult' }",
37010
+ tsIso: (/* @__PURE__ */ new Date()).toISOString(),
37011
+ _summary: `\u4EE3\u7801\u56FE\u8C31\u5C31\u7EEA\u3002${nodeCount} \u4E2A\u8282\u70B9\uFF0C${edgeCount} \u6761\u5173\u7CFB\uFF0C${fileCount} \u4E2A\u6587\u4EF6\u3002${topCalled.length ? `\u88AB\u8C03\u6700\u591A: ${topCalled.slice(0, 3).map((f) => f.name).join("\u3001")}` : ""}`
37012
+ };
37013
+ return toResult(status);
37014
+ } catch (e) {
37015
+ try {
37016
+ db.close();
37017
+ } catch {
37018
+ }
37019
+ throw e;
37020
+ }
36183
37021
  } catch (e) {
36184
37022
  return toError(e);
36185
37023
  }
@@ -36187,208 +37025,186 @@ function registerCodeGraphTools(server) {
36187
37025
  );
36188
37026
  server.tool(
36189
37027
  "codegraph_query",
36190
- "CAT:[\u4EE3\u7801\u667A\u80FD] | ## \u529F\u80FD\uFF1A\u67E5\u8BE2\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u2014\u2014\u8FFD\u8E2A\u51FD\u6570\u8C03\u7528\u94FE\uFF08\u8C01\u8C03\u4E86\u8C01/\u88AB\u8C01\u8C03\uFF09\u3001\u641C\u7D22\u7B26\u53F7\u3001\u63A2\u7D22\u6A21\u5757\u4F9D\u8D56\n## \u573A\u666F\uFF1AAgent \u56DE\u7B54\u300CtoResult \u88AB\u54EA\u4E9B\u5DE5\u5177\u8C03\u7528\u300D\u300CregisterMarketTools \u7684\u8C03\u7528\u94FE\u300D\u300Cindex.ts \u4F9D\u8D56\u54EA\u4E9B\u6A21\u5757\u300D\u65F6\u8C03\u7528\n## \u5173\u952E\u8BCD\uFF1Acodegraph, \u8C03\u7528\u94FE, callers, callees, \u4F9D\u8D56, \u4EE3\u7801\u641C\u7D22, \u7B26\u53F7\u67E5\u8BE2, \u4E0A\u4E0B\u6E38\n## \u53C2\u6570\uFF1A\n## - mode: \u67E5\u8BE2\u6A21\u5F0F\u3002callers=\u8C01\u8C03\u7528\u5B83, callees=\u5B83\u8C03\u7528\u8C01, explore=\u81EA\u7136\u8BED\u8A00\u641C\u7D22, files=\u6309\u6587\u4EF6\u67E5\u8BE2\n## - symbol: \u7B26\u53F7\u540D\uFF08mode=callers/callees \u65F6\u5FC5\u586B\uFF09\u6216\u6587\u4EF6\u540D\uFF08mode=files\uFF09\n## - question: \u81EA\u7136\u8BED\u8A00\u641C\u7D22\uFF08mode=explore \u65F6\u4F7F\u7528\uFF09\n## - limit: \u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 15\n## \u9274\u6743\uFF1APUBLIC \u2014 \u672C\u5730\u6570\u636E\u5E93\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~2KB\n## \u5173\u8054\uFF1Acodegraph_status \u770B\u72B6\u6001 \u2192 \u672C\u5DE5\u5177\u67E5\u8BE2 \u2192 \u5B9A\u4F4D\u6E90\u7801 \u2192 Agent \u7528 Read \u67E5\u770B\u7EC6\u8282",
37028
+ "CAT:[\u4EE3\u7801\u667A\u80FD] | ## \u529F\u80FD\uFF1A\u67E5\u8BE2\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u2014\u2014\u8FFD\u8E2A\u8C03\u7528\u94FE\uFF08callers/callees\uFF09\u3001\u641C\u7D22\u7B26\u53F7\u3001\u6309\u6587\u4EF6\u5217\u7B26\u53F7\u3001\u5F71\u54CD\u5206\u6790\n## \u573A\u666F\uFF1AAgent \u56DE\u7B54\u300CtoResult \u88AB\u54EA\u4E9B\u5DE5\u5177\u8C03\u7528\u300D\u300C\u6539 shared.ts \u5F71\u54CD\u54EA\u4E9B\u6A21\u5757\u300D\u300CWebSocket \u5728\u54EA\u4E9B\u6587\u4EF6\u91CC\u300D\u65F6\u8C03\u7528\n## \u5173\u952E\u8BCD\uFF1Acodegraph, \u8C03\u7528\u94FE, callers, callees, \u641C\u7D22, \u5F71\u54CD\u5206\u6790, \u4F9D\u8D56\n## \u53C2\u6570\uFF1A\n## - mode: \u67E5\u8BE2\u6A21\u5F0F\u3002callers / callees / search / file / impact\n## - symbol: \u7B26\u53F7\u540D\u6216\u6587\u4EF6\u540D\n## - limit: \u8FD4\u56DE\u6570\uFF0C\u9ED8\u8BA4 15\n## \u9274\u6743\uFF1APUBLIC \u2014 \u672C\u5730\u8BFB DB\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~2KB\n## \u5173\u8054\uFF1Acodegraph_status \u2192 codegraph_query",
36191
37029
  {
36192
- mode: external_exports.enum(["callers", "callees", "explore", "files"]).describe("\u67E5\u8BE2\u6A21\u5F0F\u3002callers=\u8C01\u8C03\u7528\u5B83, callees=\u5B83\u8C03\u7528\u8C01, explore=\u81EA\u7136\u8BED\u8A00\u641C\u7D22, files=\u6309\u6587\u4EF6\u67E5\u8282\u70B9"),
36193
- symbol: external_exports.string().optional().describe("\u7B26\u53F7\u540D\uFF08\u5982 toResult, registerMarketTools\uFF09\u6216\u6587\u4EF6\u540D\uFF08\u5982 agent-utils.ts\uFF09"),
36194
- question: external_exports.string().optional().describe("\u81EA\u7136\u8BED\u8A00\u641C\u7D22\uFF08mode=explore \u65F6\u4F7F\u7528\uFF09\uFF0C\u5982 'HTTP \u8BF7\u6C42\u7B7E\u540D' 'WebSocket \u8FDE\u63A5'"),
36195
- limit: external_exports.number().int().min(1).max(100).optional().describe("\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 15")
37030
+ mode: external_exports.enum(["callers", "callees", "search", "file", "impact"]).describe("callers=\u8C01\u8C03\u7528\u5B83, callees=\u5B83\u8C03\u7528\u8C01, search=\u641C\u7B26\u53F7, file=\u6309\u6587\u4EF6, impact=2\u8DF3\u5F71\u54CD\u5206\u6790"),
37031
+ symbol: external_exports.string().optional().describe("\u7B26\u53F7\u540D\uFF08\u5982 toResult\uFF09\u6216\u6587\u4EF6\u540D\uFF08\u5982 agent-utils.ts\uFF09\u6216\u641C\u7D22\u8BCD"),
37032
+ limit: external_exports.number().int().min(1).max(100).optional().describe("\u8FD4\u56DE\u6570\uFF0C\u9ED8\u8BA4 15")
36196
37033
  },
36197
- async ({ mode, symbol, question, limit }) => {
37034
+ async ({ mode, symbol, limit }) => {
36198
37035
  try {
36199
- const conn = getDB();
36200
- if (!conn) {
36201
- return toError("\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u4E0D\u53EF\u7528\u3002\u8BF7\u5148\u8C03 codegraph_status \u68C0\u67E5\u72B6\u6001\u3002");
36202
- }
36203
- const { db } = conn;
37036
+ const db = openDB();
37037
+ if (!db) return toError("\u4EE3\u7801\u56FE\u8C31\u4E0D\u53EF\u7528\u3002\u8BF7\u8C03 codegraph_status \u68C0\u67E5\u72B6\u6001\u3002");
36204
37038
  const n = limit || 15;
36205
- if (mode === "callers") {
36206
- if (!symbol) return toError("callers \u6A21\u5F0F\u9700\u8981 symbol \u53C2\u6570\uFF0CAgent \u8BF7\u63D0\u4F9B\u51FD\u6570\u540D");
36207
- const nodes = db.prepare(
36208
- "SELECT id, name, kind, file_path, start_line, signature, qualified_name FROM nodes WHERE name = ? OR name LIKE ? LIMIT 5"
36209
- ).all(symbol, `%${symbol}%`);
36210
- if (nodes.length === 0) {
37039
+ try {
37040
+ if (mode === "search") {
37041
+ if (!symbol) return toError("search \u6A21\u5F0F\u9700\u8981 symbol \u53C2\u6570");
37042
+ const q = symbol;
37043
+ let rows = safeAll(db, `
37044
+ SELECT n.id, n.name, n.kind, n.file_path, n.start_line, n.signature,
37045
+ n.docstring, n.qualified_name
37046
+ FROM nodes_fts f
37047
+ JOIN nodes n ON f.id = n.id
37048
+ WHERE nodes_fts MATCH ?
37049
+ ORDER BY rank
37050
+ LIMIT ?
37051
+ `, n, q, n);
37052
+ if (!rows || rows.length === 0) {
37053
+ rows = safeAll(db, `
37054
+ SELECT id, name, kind, file_path, start_line, signature, docstring, qualified_name
37055
+ FROM nodes
37056
+ WHERE name LIKE ? OR qualified_name LIKE ?
37057
+ ORDER BY name
37058
+ LIMIT ?
37059
+ `, n, `%${q}%`, `%${q}%`, n);
37060
+ }
37061
+ if (!rows || rows.length === 0) {
37062
+ return toResult({
37063
+ mode: "search",
37064
+ query: q,
37065
+ found: false,
37066
+ hint: `\u672A\u627E\u5230 "${q}"\u3002\u8BD5\u8BD5\u51FD\u6570\u540D\uFF08\u5982 registerTools\uFF09\u6216\u6587\u4EF6\u540D\u7247\u6BB5\u3002`,
37067
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
37068
+ });
37069
+ }
37070
+ const items = rows.slice(0, n).map((r) => ({
37071
+ name: r.name,
37072
+ kind: r.kind,
37073
+ file: r.file_path,
37074
+ line: r.start_line,
37075
+ signature: r.signature?.slice(0, 120),
37076
+ docstring: r.docstring?.slice(0, 100)
37077
+ }));
37078
+ return toResult({
37079
+ mode: "search",
37080
+ query: q,
37081
+ total: rows.length,
37082
+ results: items,
37083
+ _summary: `\u641C\u7D22 "${q}" \u627E\u5230 ${rows.length} \u4E2A\u7B26\u53F7\u3002${items.slice(0, 3).map((i) => `${i.name}(${i.kind})`).join(" | ")}`,
37084
+ hint: `\u627E\u5230\u540E: codegraph_query({ mode: 'callers', symbol: '<name>' })`,
37085
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
37086
+ });
37087
+ }
37088
+ if (mode === "callers") {
37089
+ if (!symbol) return toError("callers \u6A21\u5F0F\u9700\u8981 symbol");
37090
+ const nodes = findNodes(db, symbol, 3);
37091
+ if (!nodes.length) {
37092
+ return toResult({ mode: "callers", symbol, found: false, tsIso: (/* @__PURE__ */ new Date()).toISOString() });
37093
+ }
37094
+ const results = nodes.map((node) => {
37095
+ const callers = getCallers(db, node.id, n);
37096
+ return {
37097
+ target: { id: node.id, name: node.name, kind: node.kind, file: node.file_path, line: node.start_line },
37098
+ callers: callers.map((c) => ({
37099
+ name: c.name,
37100
+ kind: c.kind,
37101
+ file: c.file_path,
37102
+ line: c.start_line
37103
+ })),
37104
+ total: callers.length
37105
+ };
37106
+ });
37107
+ const total = results.reduce((s, r) => s + r.total, 0);
36211
37108
  return toResult({
36212
37109
  mode: "callers",
36213
37110
  symbol,
36214
- found: false,
36215
- hint: `\u672A\u627E\u5230\u7B26\u53F7 "${symbol}"\u3002\u8BD5\u8BD5 codegraph_query({ mode: 'explore', question: '${symbol}' }) \u5168\u6587\u641C\u7D22`,
37111
+ matched: nodes.length,
37112
+ results,
37113
+ _summary: `"${symbol}" \u5339\u914D ${nodes.length} \u4E2A\u7B26\u53F7\uFF0C\u5171 ${total} \u4E2A\u8C03\u7528\u8005\u3002`,
36216
37114
  tsIso: (/* @__PURE__ */ new Date()).toISOString()
36217
37115
  });
36218
37116
  }
36219
- const results = [];
36220
- for (const node of nodes) {
36221
- const callers = db.prepare(`
36222
- SELECT n.name as caller_name, n.kind, n.file_path, e.line, e.kind as edge_kind
36223
- FROM edges e
36224
- JOIN nodes n ON e.source = n.id
36225
- WHERE e.target = ?
36226
- ORDER BY n.name
36227
- LIMIT ?
36228
- `).all(node.id, n);
36229
- results.push({
36230
- target: { name: node.name, kind: node.kind, file: node.file_path, line: node.start_line },
36231
- callers: callers.map((c) => ({
36232
- name: c.caller_name,
36233
- kind: c.kind,
36234
- file: c.file_path,
36235
- atLine: c.line,
36236
- relation: c.edge_kind
36237
- })),
36238
- totalCallers: callers.length
37117
+ if (mode === "callees") {
37118
+ if (!symbol) return toError("callees \u6A21\u5F0F\u9700\u8981 symbol");
37119
+ const nodes = findNodes(db, symbol, 3);
37120
+ if (!nodes.length) {
37121
+ return toResult({ mode: "callees", symbol, found: false, tsIso: (/* @__PURE__ */ new Date()).toISOString() });
37122
+ }
37123
+ const results = nodes.map((node) => {
37124
+ const callees = getCallees(db, node.id, n);
37125
+ return {
37126
+ source: { id: node.id, name: node.name, kind: node.kind, file: node.file_path, line: node.start_line },
37127
+ callees: callees.map((c) => ({
37128
+ name: c.name,
37129
+ kind: c.kind,
37130
+ file: c.file_path,
37131
+ line: c.start_line
37132
+ })),
37133
+ total: callees.length
37134
+ };
36239
37135
  });
36240
- }
36241
- const total = results.reduce((s, r) => s + r.totalCallers, 0);
36242
- return toResult({
36243
- mode: "callers",
36244
- symbol,
36245
- matched: nodes.length,
36246
- results,
36247
- _summary: `"${symbol}" \u5339\u914D ${nodes.length} \u4E2A\u7B26\u53F7\uFF0C\u5171 ${total} \u4E2A\u8C03\u7528\u8005\u3002${results.slice(0, 3).map((r) => `${r.target.name}: ${r.callers.slice(0, 3).map((c) => c.name).join("\u3001")}`).join(" | ")}`,
36248
- tsIso: (/* @__PURE__ */ new Date()).toISOString()
36249
- });
36250
- }
36251
- if (mode === "callees") {
36252
- if (!symbol) return toError("callees \u6A21\u5F0F\u9700\u8981 symbol \u53C2\u6570");
36253
- const nodes = db.prepare(
36254
- "SELECT id, name, kind, file_path, start_line FROM nodes WHERE name = ? OR name LIKE ? LIMIT 5"
36255
- ).all(symbol, `%${symbol}%`);
36256
- if (nodes.length === 0) {
37136
+ const total = results.reduce((s, r) => s + r.total, 0);
36257
37137
  return toResult({
36258
37138
  mode: "callees",
36259
37139
  symbol,
36260
- found: false,
36261
- hint: `\u672A\u627E\u5230 "${symbol}"\uFF0C\u8BD5\u8BD5 mode='explore' \u5168\u6587\u641C\u7D22`,
37140
+ matched: nodes.length,
37141
+ results,
37142
+ _summary: `"${symbol}" \u5339\u914D ${nodes.length} \u4E2A\u7B26\u53F7\uFF0C\u5171\u8C03\u7528 ${total} \u4E2A\u4E0B\u6E38\u3002`,
36262
37143
  tsIso: (/* @__PURE__ */ new Date()).toISOString()
36263
37144
  });
36264
37145
  }
36265
- const results = [];
36266
- for (const node of nodes) {
36267
- const callees = db.prepare(`
36268
- SELECT n.name as callee_name, n.kind, n.file_path, e.line
36269
- FROM edges e
36270
- JOIN nodes n ON e.target = n.id
36271
- WHERE e.source = ?
36272
- ORDER BY e.kind, n.name
36273
- LIMIT ?
36274
- `).all(node.id, n);
36275
- const byKind = {};
36276
- for (const c of callees) {
36277
- (byKind[c.kind] || (byKind[c.kind] = [])).push(c);
36278
- }
36279
- results.push({
36280
- source: { name: node.name, kind: node.kind, file: node.file_path, line: node.start_line },
36281
- callees: Object.entries(byKind).map(([kind, items]) => ({
36282
- relation: kind,
36283
- count: items.length,
36284
- top: items.slice(0, 10).map((c) => ({ name: c.callee_name, kind: c.kind, file: c.file_path, atLine: c.line }))
37146
+ if (mode === "file") {
37147
+ if (!symbol) return toError("file \u6A21\u5F0F\u9700\u8981 symbol\uFF08\u6587\u4EF6\u540D\uFF09");
37148
+ const file = safeGet(
37149
+ db,
37150
+ "SELECT * FROM files WHERE path LIKE ? LIMIT 1",
37151
+ `%${symbol}%`
37152
+ );
37153
+ const nodes = safeAll(db, `
37154
+ SELECT name, kind, start_line, signature, is_exported
37155
+ FROM nodes WHERE file_path LIKE ?
37156
+ ORDER BY start_line LIMIT ?
37157
+ `, n, `%${symbol}%`, n);
37158
+ return toResult({
37159
+ mode: "file",
37160
+ file: symbol,
37161
+ fileInfo: file ? { path: file.path, language: file.language, size: file.size, nodeCount: file.node_count } : null,
37162
+ symbols: nodes.map((r) => ({
37163
+ name: r.name,
37164
+ kind: r.kind,
37165
+ line: r.start_line,
37166
+ signature: r.signature?.slice(0, 120),
37167
+ exported: r.is_exported === 1
36285
37168
  })),
36286
- totalCallees: callees.length
37169
+ _summary: `\u6587\u4EF6 "${symbol}" \u5305\u542B ${nodes.length} \u4E2A\u7B26\u53F7\u3002`,
37170
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
36287
37171
  });
36288
37172
  }
36289
- const total = results.reduce((s, r) => s + r.totalCallees, 0);
36290
- return toResult({
36291
- mode: "callees",
36292
- symbol,
36293
- matched: nodes.length,
36294
- results,
36295
- _summary: `"${symbol}" \u5339\u914D ${nodes.length} \u4E2A\u7B26\u53F7\uFF0C\u5171\u8C03\u7528 ${total} \u4E2A\u4E0B\u6E38\u3002`,
36296
- tsIso: (/* @__PURE__ */ new Date()).toISOString()
36297
- });
36298
- }
36299
- if (mode === "explore") {
36300
- const q = question || symbol || "";
36301
- if (!q) return toError("explore \u6A21\u5F0F\u9700\u8981 question \u6216 symbol \u53C2\u6570");
36302
- let rows = db.prepare(`
36303
- SELECT n.id, n.name, n.kind, n.file_path, n.start_line, n.signature, n.docstring, n.qualified_name
36304
- FROM nodes_fts f
36305
- JOIN nodes n ON f.id = n.id
36306
- WHERE nodes_fts MATCH ?
36307
- ORDER BY rank
36308
- LIMIT ?
36309
- `).all(q, n);
36310
- if (rows.length === 0) {
36311
- rows = db.prepare(`
36312
- SELECT id, name, kind, file_path, start_line, signature, docstring, qualified_name
36313
- FROM nodes
36314
- WHERE name LIKE ? OR qualified_name LIKE ? OR docstring LIKE ?
36315
- ORDER BY name
36316
- LIMIT ?
36317
- `).all(`%${q}%`, `%${q}%`, `%${q}%`, n);
36318
- }
36319
- if (rows.length === 0) {
37173
+ if (mode === "impact") {
37174
+ if (!symbol) return toError("impact \u6A21\u5F0F\u9700\u8981 symbol");
37175
+ const nodes = findNodes(db, symbol, 1);
37176
+ if (!nodes.length) {
37177
+ return toResult({ mode: "impact", symbol, found: false, tsIso: (/* @__PURE__ */ new Date()).toISOString() });
37178
+ }
37179
+ const node = nodes[0];
37180
+ const { direct, indirect } = getImpact(db, node.id, 2, n);
36320
37181
  return toResult({
36321
- mode: "explore",
36322
- question: q,
36323
- found: false,
36324
- hint: `\u672A\u627E\u5230\u4E0E "${q}" \u76F8\u5173\u7684\u7B26\u53F7\u3002\u8BD5\u8BD5\u66F4\u77ED\u7684\u5173\u952E\u8BCD\u6216\u76F4\u63A5\u641C\u51FD\u6570\u540D\u3002`,
37182
+ mode: "impact",
37183
+ symbol,
37184
+ node: { id: node.id, name: node.name, kind: node.kind, file: node.file_path, line: node.start_line },
37185
+ directlyAffected: direct.map((c) => ({
37186
+ name: c.name,
37187
+ kind: c.kind,
37188
+ file: c.file_path,
37189
+ line: c.start_line
37190
+ })),
37191
+ indirectlyAffected: indirect.map((c) => ({
37192
+ name: c.name,
37193
+ kind: c.kind,
37194
+ file: c.file_path,
37195
+ line: c.start_line
37196
+ })),
37197
+ _summary: `\u4FEE\u6539 "${symbol}" \u76F4\u63A5\u5F71\u54CD ${direct.length} \u4E2A\u8C03\u7528\u8005\uFF0C\u95F4\u63A5\u5F71\u54CD ${indirect.length} \u4E2A\u4E0B\u6E38\u3002`,
36325
37198
  tsIso: (/* @__PURE__ */ new Date()).toISOString()
36326
37199
  });
36327
37200
  }
36328
- const top = rows.slice(0, 5);
36329
- const enriched = top.map((r) => {
36330
- const callers = db.prepare(
36331
- "SELECT count(*) as n FROM edges WHERE target = ? AND kind = 'calls'"
36332
- ).get(r.id).n;
36333
- const callees = db.prepare(
36334
- "SELECT count(*) as n FROM edges WHERE source = ? AND kind = 'calls'"
36335
- ).get(r.id).n;
36336
- return {
36337
- name: r.name,
36338
- kind: r.kind,
36339
- file: r.file_path,
36340
- line: r.start_line,
36341
- signature: r.signature,
36342
- docstring: r.docstring?.slice(0, 120),
36343
- stats: { callers, callees }
36344
- };
36345
- });
36346
- return toResult({
36347
- mode: "explore",
36348
- question: q,
36349
- found: true,
36350
- total: rows.length,
36351
- results: enriched,
36352
- _summary: `\u641C\u7D22 "${q}" \u627E\u5230 ${rows.length} \u4E2A\u7B26\u53F7\u3002${enriched.slice(0, 3).map((r) => `${r.name}(${r.kind}) in ${r.file}`).join(" | ")}`,
36353
- hint: `\u627E\u5230\u5177\u4F53\u7B26\u53F7\u540E\u7528 codegraph_query({ mode: 'callers', symbol: '<name>' }) \u770B\u5B8C\u6574\u8C03\u7528\u94FE\u3002`,
36354
- tsIso: (/* @__PURE__ */ new Date()).toISOString()
36355
- });
36356
- }
36357
- if (mode === "files") {
36358
- const file = symbol || "";
36359
- if (!file) return toError("files \u6A21\u5F0F\u9700\u8981 symbol \u53C2\u6570\uFF08\u6587\u4EF6\u540D\uFF09");
36360
- const fileInfo = db.prepare(
36361
- "SELECT * FROM files WHERE path LIKE ? LIMIT 1"
36362
- ).get(`%${file}%`);
36363
- const nodes = db.prepare(`
36364
- SELECT name, kind, start_line, signature, is_exported
36365
- FROM nodes
36366
- WHERE file_path LIKE ?
36367
- ORDER BY start_line
36368
- LIMIT ?
36369
- `).all(`%${file}%`, n);
36370
- return toResult({
36371
- mode: "files",
36372
- file,
36373
- fileInfo: fileInfo ? {
36374
- path: fileInfo.path,
36375
- language: fileInfo.language,
36376
- size: fileInfo.size,
36377
- nodeCount: fileInfo.node_count,
36378
- indexedAt: fileInfo.indexed_at ? new Date(fileInfo.indexed_at).toISOString() : void 0
36379
- } : null,
36380
- symbols: nodes.map((r) => ({
36381
- name: r.name,
36382
- kind: r.kind,
36383
- line: r.start_line,
36384
- signature: r.signature,
36385
- exported: r.is_exported === 1
36386
- })),
36387
- _summary: `\u6587\u4EF6 "${file}" \u5305\u542B ${nodes.length} \u4E2A\u7B26\u53F7\u3002${nodes.filter((r) => r.is_exported).length} \u4E2A\u5BFC\u51FA\u3002`,
36388
- tsIso: (/* @__PURE__ */ new Date()).toISOString()
36389
- });
37201
+ return toError(`\u672A\u77E5\u6A21\u5F0F: ${mode}`);
37202
+ } finally {
37203
+ try {
37204
+ db.close();
37205
+ } catch {
37206
+ }
36390
37207
  }
36391
- return toError(`\u672A\u77E5\u6A21\u5F0F: ${mode}`);
36392
37208
  } catch (e) {
36393
37209
  return toError(e);
36394
37210
  }
@@ -36449,7 +37265,7 @@ function registerAllTools(server, auth, readOnly) {
36449
37265
  registerIndicatorTools(server);
36450
37266
  registerSmartMoneyTools(server, auth);
36451
37267
  registerXLayerWSTools(server);
36452
- registerWsTools(server);
37268
+ registerWsTools(server, auth);
36453
37269
  registerAgentHubTools(server);
36454
37270
  registerCodeGraphTools(server);
36455
37271
  return { skipped, skipLog };
@@ -36544,7 +37360,7 @@ async function startStdio(server, version2, auth, readOnly, skipped, skipLog) {
36544
37360
  await server.connect(transport);
36545
37361
  }
36546
37362
  async function main() {
36547
- const VERSION = "0.2.49";
37363
+ const VERSION = "0.2.51";
36548
37364
  const auth = getAuth();
36549
37365
  const mode = resolveTransportMode();
36550
37366
  const exec = resolveExecutionMode();
@@ -36552,7 +37368,7 @@ async function main() {
36552
37368
  const server = new McpServer({
36553
37369
  name: "hvip-mcp",
36554
37370
  version: VERSION,
36555
- description: "hvip MCP Server \u2014 364 \u5DE5\u5177\u8986\u76D6 97.7% OKX REST API\uFF0C\u542B\u4EA4\u6613/\u884C\u60C5/\u8D44\u91D1/\u7B56\u7565/\u9884\u6D4B\u5E02\u573A/\u6280\u672F\u6307\u6807/Smart Money\uFF08\u975E OKX \u5B98\u65B9\u4EA7\u54C1\uFF09\u3002\u4ED3\u5E93: https://github.com/okx-wallet-H/hvip-mcp"
37371
+ description: "hvip MCP Server \u2014 365 \u5DE5\u5177\u8986\u76D6 97.7% OKX REST API\uFF0C\u542B\u4EA4\u6613/\u884C\u60C5/\u8D44\u91D1/\u7B56\u7565/\u9884\u6D4B\u5E02\u573A/\u6280\u672F\u6307\u6807/Smart Money/WebSocket/\u4EE3\u7801\u56FE\u8C31\uFF08\u975E OKX \u5B98\u65B9\u4EA7\u54C1\uFF09\u3002\u4ED3\u5E93: https://github.com/okx-wallet-H/hvip-mcp"
36556
37372
  });
36557
37373
  const { skipped, skipLog } = registerAllTools(server, auth, readOnly);
36558
37374
  if (mode === "http") {