hvip-mcp-server 0.2.55 → 0.2.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -44
- package/dist/index.js +80 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,101 +1,155 @@
|
|
|
1
1
|
# hvip MCP Server
|
|
2
2
|
|
|
3
|
-
> OKX
|
|
3
|
+
> OKX 全部能力接入 AI —— 365 个 MCP 工具,覆盖 97.7% OKX REST API
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/hvip-mcp-server)
|
|
6
6
|
[](https://github.com/okx-wallet-H/hvip-mcp/blob/master/LICENSE)
|
|
7
|
-
[](https://github.com/okx-wallet-H/hvip-mcp)
|
|
8
7
|
|
|
9
|
-
📦
|
|
10
|
-
🐛 **Issue**: [提交反馈](https://github.com/okx-wallet-H/hvip-mcp/issues/new)
|
|
11
|
-
📖 **贡献**: [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
8
|
+
📦 [github.com/okx-wallet-H/hvip-mcp](https://github.com/okx-wallet-H/hvip-mcp) · 🐛 [提交反馈](https://github.com/okx-wallet-H/hvip-mcp/issues/new)
|
|
12
9
|
|
|
13
10
|
---
|
|
14
11
|
|
|
15
|
-
##
|
|
12
|
+
## 安装
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
**这不是命令行工具**——hvip-mcp 是 MCP (Model Context Protocol) 服务器,由 AI 客户端在后台自动运行。你只需要在配置文件中加一行 JSON,AI 自己会启动它。
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
### Claude Desktop
|
|
17
|
+
|
|
18
|
+
Claude Desktop → 设置 → Developer → Edit Config:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"hvip": {
|
|
24
|
+
"command": "npx",
|
|
25
|
+
"args": ["-y", "hvip-mcp-server"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Claude Code
|
|
32
|
+
|
|
33
|
+
在项目根目录或全局 `.claude/settings.json`:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"hvip": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "hvip-mcp-server@latest"]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### VS Code / Cline / 其他 MCP 客户端
|
|
47
|
+
|
|
48
|
+
在 MCP 配置中添加同样的 JSON。
|
|
49
|
+
|
|
50
|
+
> **配置完需要完全退出并重启客户端**,重开后 AI 自动连接 hvip。
|
|
51
|
+
|
|
52
|
+
### 需要 API Key?
|
|
53
|
+
|
|
54
|
+
行情、技术指标、市场扫描等公开数据无需 Key。查看账户、下单交易需要 OKX API Key:
|
|
20
55
|
|
|
21
56
|
```json
|
|
22
57
|
{
|
|
23
58
|
"mcpServers": {
|
|
24
|
-
"hvip
|
|
59
|
+
"hvip": {
|
|
25
60
|
"command": "npx",
|
|
26
61
|
"args": ["-y", "hvip-mcp-server"],
|
|
27
62
|
"env": {
|
|
28
|
-
"OKX_API_KEY": "<你的API Key>",
|
|
29
|
-
"OKX_SECRET_KEY": "<你的Secret Key>",
|
|
30
|
-
"OKX_PASSPHRASE": "<你的Passphrase>"
|
|
63
|
+
"OKX_API_KEY": "<你的 API Key>",
|
|
64
|
+
"OKX_SECRET_KEY": "<你的 Secret Key>",
|
|
65
|
+
"OKX_PASSPHRASE": "<你的 Passphrase>"
|
|
31
66
|
}
|
|
32
67
|
}
|
|
33
68
|
}
|
|
34
69
|
}
|
|
35
70
|
```
|
|
36
71
|
|
|
37
|
-
|
|
72
|
+
> API Key 在 [OKX 官网](https://www.okx.com) → 个人中心 → API 中创建,开通「读取」权限即可查账户,「交易」权限可下单。
|
|
38
73
|
|
|
39
|
-
|
|
40
|
-
npx hvip-mcp-server
|
|
41
|
-
```
|
|
74
|
+
---
|
|
42
75
|
|
|
43
|
-
|
|
76
|
+
## 工作流
|
|
44
77
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
AI 连接 hvip 后自动执行:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
1. tools/list → 365 个工具,但只有 agent_catalog 带完整描述
|
|
82
|
+
2. agent_catalog → 15 个域的地图(7 公开 + 8 需 Key),按需直达
|
|
83
|
+
3. 用户说 "BTC 怎么样" → AI 调 okx_quick_market
|
|
84
|
+
4. 用户说 "买 0.1 BTC" → AI 先预检再下单
|
|
51
85
|
```
|
|
52
86
|
|
|
87
|
+
**无需手动操作,全程 AI 自己来。**
|
|
88
|
+
|
|
53
89
|
---
|
|
54
90
|
|
|
55
91
|
## 工具覆盖
|
|
56
92
|
|
|
57
93
|
| 模块 | 工具数 | 说明 |
|
|
58
94
|
|------|--------|------|
|
|
59
|
-
| 🔹
|
|
60
|
-
| 🔹
|
|
61
|
-
| 🔹
|
|
62
|
-
| 🔹
|
|
63
|
-
| 🔹
|
|
64
|
-
| 🔹
|
|
65
|
-
| 🔹
|
|
66
|
-
| 🔹
|
|
95
|
+
| 🔹 账户 | 40+ | 余额/持仓/配置/杠杆/估值 |
|
|
96
|
+
| 🔹 行情 | 17 | Ticker/K线/深度/成交 |
|
|
97
|
+
| 🔹 交易 | 27 | 下单/撤单/改单/批量/平仓 |
|
|
98
|
+
| 🔹 公共数据 | 34 | 产品规格/资金费率/标记价 |
|
|
99
|
+
| 🔹 资金 | 18 | 划转/提现/充值/兑换 |
|
|
100
|
+
| 🔹 策略委托 | 6 | 止损止盈/冰山/移动止盈 |
|
|
101
|
+
| 🔹 网格 | 13 | 现货网格/合约网格/定投 |
|
|
102
|
+
| 🔹 跟单 | 23 | 交易员/跟单/带单 |
|
|
103
|
+
| 🔹 信号 | 10 | 信号订阅/历史信号 |
|
|
104
|
+
| 🔹 价差 | 16 | 跨品种/跨期价差 |
|
|
105
|
+
| 🔹 RFQ | 12 | 大宗询价/报价/成交 |
|
|
106
|
+
| 🔹 金融 | 27 | 赚币/质押/借贷 |
|
|
107
|
+
| 🔹 预测市场 | 36 | 事件合约/预测交易 |
|
|
108
|
+
| 🔹 技术指标 | 2 | RSI/MACD/布林带等 17 种 |
|
|
109
|
+
| 🔹 聪明钱 | 3 | 交易员排行榜/市场情绪 |
|
|
110
|
+
| 🔹 WebSocket | 5 | 55 频道实时推送 |
|
|
111
|
+
| 🔹 代码图谱 | 2 | 函数调用链/符号搜索 |
|
|
112
|
+
| 🔹 系统工具 | 19 | 导航/偏好/反馈/Agent 协作 |
|
|
113
|
+
|
|
114
|
+
**365 个 MCP 工具 · 覆盖 97.7% OKX REST API**
|
|
67
115
|
|
|
68
|
-
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 本地开发
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
git clone https://github.com/okx-wallet-H/hvip-mcp.git
|
|
122
|
+
cd hvip-mcp
|
|
123
|
+
npm install
|
|
124
|
+
npm run build
|
|
125
|
+
npm start
|
|
126
|
+
```
|
|
69
127
|
|
|
70
128
|
---
|
|
71
129
|
|
|
72
130
|
## 架构
|
|
73
131
|
|
|
74
132
|
```
|
|
75
|
-
原子层 (
|
|
76
|
-
|
|
77
|
-
Skill 组合层 (
|
|
78
|
-
|
|
79
|
-
|
|
133
|
+
原子层 (350 工具) → [L:READ] 权限标记 → AI Agent 按需调用
|
|
134
|
+
↓
|
|
135
|
+
Skill 组合层 (13 个) → 串联多工具,一次完成复杂任务
|
|
136
|
+
↓
|
|
137
|
+
agent_catalog → 15 域地图 → 按意图路由 → 直达目标工具
|
|
80
138
|
```
|
|
81
139
|
|
|
82
140
|
---
|
|
83
141
|
|
|
84
142
|
## 贡献
|
|
85
143
|
|
|
86
|
-
AI Agent 或开发者都可以贡献 Skill:
|
|
87
|
-
|
|
88
144
|
1. 阅读 [`CLAUDE.md`](./CLAUDE.md) 了解项目规范
|
|
89
145
|
2. 阅读 [`CONTRIBUTING.md`](./CONTRIBUTING.md) 了解提交流程
|
|
90
|
-
3. Fork →
|
|
91
|
-
|
|
92
|
-
每个 Skill 串联多个原子工具,解决一个具体的使用场景。
|
|
146
|
+
3. Fork → 创建分支 → 开发 → `npm run build` → 提 PR
|
|
93
147
|
|
|
94
148
|
---
|
|
95
149
|
|
|
96
150
|
## 文档
|
|
97
151
|
|
|
98
152
|
- [`CLAUDE.md`](./CLAUDE.md) — AI Agent 项目指南
|
|
99
|
-
- [`CONTRIBUTING.md`](./CONTRIBUTING.md) —
|
|
100
|
-
- [`docs/OKX-MCP-API对接标准-v0.
|
|
153
|
+
- [`CONTRIBUTING.md`](./CONTRIBUTING.md) — 贡献流程
|
|
154
|
+
- [`docs/OKX-MCP-API对接标准-v0.2.49.md`](./docs/OKX-MCP-API对接标准-v0.2.49.md) — API 对接规范
|
|
101
155
|
- [`docs/OKX-MCP-防幻觉对接SOP-v1.0.md`](./docs/OKX-MCP-防幻觉对接SOP-v1.0.md) — 防幻觉 SOP
|
package/dist/index.js
CHANGED
|
@@ -37023,11 +37023,73 @@ var AgentHub = class {
|
|
|
37023
37023
|
rooms = /* @__PURE__ */ new Map();
|
|
37024
37024
|
heartbeatTimer = null;
|
|
37025
37025
|
version = "0.0.0";
|
|
37026
|
+
port = 0;
|
|
37027
|
+
db = null;
|
|
37028
|
+
// ── 持久化绑定 ──
|
|
37029
|
+
setDB(db) {
|
|
37030
|
+
this.db = db;
|
|
37031
|
+
const rows = db.loadTasks();
|
|
37032
|
+
for (const r of rows) {
|
|
37033
|
+
this.tasks.set(r.taskId, {
|
|
37034
|
+
status: r.status,
|
|
37035
|
+
assignedTo: r.assignedTo || void 0,
|
|
37036
|
+
claimedAt: r.claimedAt || void 0,
|
|
37037
|
+
result: r.result || void 0,
|
|
37038
|
+
branch: r.branch || void 0
|
|
37039
|
+
});
|
|
37040
|
+
}
|
|
37041
|
+
if (rows.length > 0) {
|
|
37042
|
+
console.log(`[AgentHub] \u4ECE DB \u6062\u590D ${rows.length} \u4E2A\u4EFB\u52A1`);
|
|
37043
|
+
}
|
|
37044
|
+
}
|
|
37026
37045
|
// ── 启动 ──
|
|
37027
37046
|
start(port, host = "0.0.0.0", version2 = "0.0.0") {
|
|
37028
37047
|
this.version = version2;
|
|
37029
|
-
|
|
37030
|
-
|
|
37048
|
+
const startWss = (p) => {
|
|
37049
|
+
return new Promise((resolve2) => {
|
|
37050
|
+
const wss = new import_websocket_server.default({ port: p, host });
|
|
37051
|
+
let resolved = false;
|
|
37052
|
+
const done = (ok) => {
|
|
37053
|
+
if (!resolved) {
|
|
37054
|
+
resolved = true;
|
|
37055
|
+
resolve2(ok);
|
|
37056
|
+
}
|
|
37057
|
+
};
|
|
37058
|
+
wss.on("listening", () => {
|
|
37059
|
+
this.wss = wss;
|
|
37060
|
+
this.port = p;
|
|
37061
|
+
done(true);
|
|
37062
|
+
});
|
|
37063
|
+
wss.on("error", () => {
|
|
37064
|
+
try {
|
|
37065
|
+
wss.close();
|
|
37066
|
+
} catch {
|
|
37067
|
+
}
|
|
37068
|
+
done(false);
|
|
37069
|
+
});
|
|
37070
|
+
setTimeout(() => done(false), 1e3);
|
|
37071
|
+
});
|
|
37072
|
+
};
|
|
37073
|
+
const ports = [port, port + 1, port + 2];
|
|
37074
|
+
startWss(ports[0]).then((ok) => {
|
|
37075
|
+
if (!ok) return startWss(ports[1]);
|
|
37076
|
+
return true;
|
|
37077
|
+
}).then((ok) => {
|
|
37078
|
+
if (!ok) return startWss(ports[2]);
|
|
37079
|
+
return ok === true ? true : false;
|
|
37080
|
+
}).then((ok) => {
|
|
37081
|
+
if (!ok) {
|
|
37082
|
+
process.stderr.write(`[AgentHub] WS Hub \u8DF3\u8FC7\uFF08\u7AEF\u53E3 ${ports.join("/")} \u4E0D\u53EF\u7528\uFF09
|
|
37083
|
+
`);
|
|
37084
|
+
return;
|
|
37085
|
+
}
|
|
37086
|
+
process.stderr.write(`[AgentHub] WS Hub v${version2} ws://${host}:${this.port}
|
|
37087
|
+
`);
|
|
37088
|
+
this.setupHub();
|
|
37089
|
+
});
|
|
37090
|
+
}
|
|
37091
|
+
setupHub() {
|
|
37092
|
+
if (!this.wss) return;
|
|
37031
37093
|
this.ensureRoom("#lobby");
|
|
37032
37094
|
this.ensureRoom("#review");
|
|
37033
37095
|
this.wss.on("connection", (ws) => {
|
|
@@ -37035,7 +37097,8 @@ var AgentHub = class {
|
|
|
37035
37097
|
ws.on("message", (raw) => {
|
|
37036
37098
|
try {
|
|
37037
37099
|
const msg = JSON.parse(raw.toString());
|
|
37038
|
-
this.handleMessage(ws, agentId, msg);
|
|
37100
|
+
const newId = this.handleMessage(ws, agentId, msg);
|
|
37101
|
+
if (newId) agentId = newId;
|
|
37039
37102
|
} catch {
|
|
37040
37103
|
this.send(ws, { type: "error", message: "\u6D88\u606F\u683C\u5F0F\u9519\u8BEF\uFF1A\u975E JSON" });
|
|
37041
37104
|
}
|
|
@@ -37052,7 +37115,7 @@ var AgentHub = class {
|
|
|
37052
37115
|
if (now - a.lastSeen > 12e4) {
|
|
37053
37116
|
a.ws.close();
|
|
37054
37117
|
this.agents.delete(id);
|
|
37055
|
-
console.log(
|
|
37118
|
+
console.log("[AgentHub] Agent \u5FC3\u8DF3\u8D85\u65F6: " + id);
|
|
37056
37119
|
}
|
|
37057
37120
|
}
|
|
37058
37121
|
}, 3e4);
|
|
@@ -37061,8 +37124,7 @@ var AgentHub = class {
|
|
|
37061
37124
|
handleMessage(ws, authAgentId, msg) {
|
|
37062
37125
|
switch (msg.type) {
|
|
37063
37126
|
case "agent:hello":
|
|
37064
|
-
this.handleHello(ws, msg);
|
|
37065
|
-
break;
|
|
37127
|
+
return this.handleHello(ws, msg);
|
|
37066
37128
|
case "agent:status":
|
|
37067
37129
|
if (authAgentId) this.handleAgentStatus(authAgentId);
|
|
37068
37130
|
break;
|
|
@@ -37088,6 +37150,7 @@ var AgentHub = class {
|
|
|
37088
37150
|
default:
|
|
37089
37151
|
this.send(ws, { type: "error", message: `\u672A\u77E5\u6D88\u606F\u7C7B\u578B: ${msg.type}` });
|
|
37090
37152
|
}
|
|
37153
|
+
return null;
|
|
37091
37154
|
}
|
|
37092
37155
|
// ── Agent 注册 ──
|
|
37093
37156
|
handleHello(ws, msg) {
|
|
@@ -37096,7 +37159,7 @@ var AgentHub = class {
|
|
|
37096
37159
|
const capabilities = Array.isArray(msg.capabilities) ? msg.capabilities : [];
|
|
37097
37160
|
if (!agentId) {
|
|
37098
37161
|
this.send(ws, { type: "error", message: "\u7F3A\u5C11 agentId" });
|
|
37099
|
-
return;
|
|
37162
|
+
return "";
|
|
37100
37163
|
}
|
|
37101
37164
|
const existing = this.agents.get(agentId);
|
|
37102
37165
|
if (existing) existing.ws.close();
|
|
@@ -37134,17 +37197,17 @@ var AgentHub = class {
|
|
|
37134
37197
|
}
|
|
37135
37198
|
}
|
|
37136
37199
|
}
|
|
37200
|
+
return agentId;
|
|
37137
37201
|
}
|
|
37138
37202
|
handleDisconnect(agentId) {
|
|
37139
37203
|
const info = this.agents.get(agentId);
|
|
37140
37204
|
console.log(`[AgentHub] Agent \u79BB\u7EBF: ${agentId} (${info?.name || "?"})`);
|
|
37141
|
-
for (const [, room] of this.rooms) {
|
|
37205
|
+
for (const [roomId, room] of this.rooms) {
|
|
37142
37206
|
if (room.members.has(agentId)) {
|
|
37143
37207
|
room.members.delete(agentId);
|
|
37144
37208
|
this.sendToRoomMembers(room, {
|
|
37145
37209
|
type: "room:member_left",
|
|
37146
|
-
roomId
|
|
37147
|
-
// fixed below
|
|
37210
|
+
roomId,
|
|
37148
37211
|
agentId
|
|
37149
37212
|
});
|
|
37150
37213
|
}
|
|
@@ -37155,6 +37218,7 @@ var AgentHub = class {
|
|
|
37155
37218
|
t.status = "unassigned";
|
|
37156
37219
|
t.assignedTo = void 0;
|
|
37157
37220
|
t.claimedAt = void 0;
|
|
37221
|
+
this.db?.saveTask({ taskId: tid, status: "unassigned" });
|
|
37158
37222
|
this.broadcast({ type: "task:released", taskId: tid, reason: "Agent \u79BB\u7EBF" });
|
|
37159
37223
|
}
|
|
37160
37224
|
}
|
|
@@ -37187,6 +37251,7 @@ var AgentHub = class {
|
|
|
37187
37251
|
if (a) a.status = "working";
|
|
37188
37252
|
this.joinRoom(agentId, `#task-${taskId}`);
|
|
37189
37253
|
console.log(`[AgentHub] ${agentId} \u8BA4\u9886 ${taskId}`);
|
|
37254
|
+
this.db?.saveTask({ taskId, status: "assigned", title: this.getTaskTitle(taskId), assignedTo: agentId, claimedAt: task.claimedAt });
|
|
37190
37255
|
this.sendTo(agentId, {
|
|
37191
37256
|
type: "task:assigned",
|
|
37192
37257
|
taskId,
|
|
@@ -37212,6 +37277,7 @@ var AgentHub = class {
|
|
|
37212
37277
|
const a = this.agents.get(agentId);
|
|
37213
37278
|
if (a) a.status = "idle";
|
|
37214
37279
|
console.log(`[AgentHub] ${agentId} \u5B8C\u6210 ${taskId}: ${result}`);
|
|
37280
|
+
this.db?.saveTask({ taskId, status: "done", title: this.getTaskTitle(taskId), assignedTo: agentId, result, branch });
|
|
37215
37281
|
this.sendToRoom(`#task-${taskId}`, agentId, `\u5DF2\u5B8C\u6210 ${taskId}: ${result} (branch: ${branch})\uFF0C\u7B49\u5F85\u5BA1\u6838\u3002`);
|
|
37216
37282
|
this.sendToRoom("#review", agentId, `${taskId} \u63D0\u4EA4\u5B8C\u6210\uFF0Cbranch: ${branch}`);
|
|
37217
37283
|
this.broadcast({
|
|
@@ -37243,10 +37309,12 @@ var AgentHub = class {
|
|
|
37243
37309
|
if (!task) return;
|
|
37244
37310
|
if (verdict === "approved") {
|
|
37245
37311
|
task.status = "reviewed";
|
|
37312
|
+
this.db?.saveTask({ taskId, status: "reviewed", reviewedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
37246
37313
|
} else {
|
|
37247
37314
|
task.status = "unassigned";
|
|
37248
37315
|
task.assignedTo = void 0;
|
|
37249
37316
|
task.claimedAt = void 0;
|
|
37317
|
+
this.db?.saveTask({ taskId, status: "unassigned" });
|
|
37250
37318
|
}
|
|
37251
37319
|
const roomId = `#task-${taskId}`;
|
|
37252
37320
|
const msg = verdict === "approved" ? `\u2705 ${taskId} \u5BA1\u6838\u901A\u8FC7\u3002\u5DF2\u5408\u5E76\u5230 master \u5E76\u5220\u9664\u8FDC\u7A0B\u5206\u652F\u3002` : `\u274C ${taskId} \u5BA1\u6838\u4E0D\u901A\u8FC7\u3002${feedback || "\u8BF7\u4FEE\u6539\u540E\u91CD\u65B0 push\u3002"}`;
|
|
@@ -37297,6 +37365,7 @@ var AgentHub = class {
|
|
|
37297
37365
|
const msg = { roomId, from, text, ts: (/* @__PURE__ */ new Date()).toISOString() };
|
|
37298
37366
|
room.messages.push(msg);
|
|
37299
37367
|
if (room.messages.length > MAX_ROOM_MESSAGES) room.messages.shift();
|
|
37368
|
+
this.db?.saveMessage(roomId, from, text, msg.ts);
|
|
37300
37369
|
const raw = JSON.stringify({ type: "room:message", ...msg });
|
|
37301
37370
|
for (const agentId of room.members) {
|
|
37302
37371
|
const a = this.agents.get(agentId);
|
|
@@ -38212,7 +38281,7 @@ async function startStdio(server, version2, auth, readOnly, skipped, skipLog) {
|
|
|
38212
38281
|
await server.connect(transport);
|
|
38213
38282
|
}
|
|
38214
38283
|
async function main() {
|
|
38215
|
-
const VERSION = "0.2.
|
|
38284
|
+
const VERSION = "0.2.57";
|
|
38216
38285
|
const argv = process.argv.slice(2);
|
|
38217
38286
|
if (argv.includes("--help") || argv.includes("-h")) printHelpAndExit(VERSION);
|
|
38218
38287
|
if (argv.includes("--version") || argv.includes("-v")) {
|
package/package.json
CHANGED