@dichvuright/mcp-hosting-server 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -59
- package/dist/server.js +34 -2
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @dichvuright/mcp-hosting-server
|
|
2
2
|
|
|
3
|
-
Kết nối AI Agent (Claude, Cursor, Antigravity...) vào hệ thống quản trị DichVuRight.
|
|
3
|
+
Kết nối AI Agent (Claude, Cursor, Antigravity, OpenClaw...) vào hệ thống quản trị DichVuRight qua giao thức MCP.
|
|
4
4
|
|
|
5
|
-
## Kiến trúc
|
|
5
|
+
## Kiến trúc
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
AI Agent
|
|
9
|
-
|
|
10
|
-
MCP
|
|
11
|
-
|
|
8
|
+
AI Agent (Claude / Cursor / OpenClaw)
|
|
9
|
+
|
|
|
10
|
+
MCP Protocol (JSON-RPC 2.0, stdio)
|
|
11
|
+
|
|
|
12
|
+
@dichvuright/mcp-hosting-server
|
|
13
|
+
| chỉ biết: API_URL + API_KEY + API_SECRET
|
|
14
|
+
|
|
|
12
15
|
POST /api/mcp/tools/call ← HMAC-SHA256 signed
|
|
13
|
-
|
|
14
|
-
Next.js
|
|
15
|
-
|
|
16
|
-
MongoDB / Redis ← MCP không
|
|
16
|
+
|
|
|
17
|
+
Next.js App (verify HMAC + scope mcp:admin)
|
|
18
|
+
|
|
|
19
|
+
MongoDB / Redis ← MCP không kết nối trực tiếp
|
|
17
20
|
```
|
|
18
21
|
|
|
19
22
|
**MCP server không bao giờ biết:** JWT_SECRET, MongoDB URI, Redis password.
|
|
@@ -21,100 +24,101 @@ MongoDB / Redis ← MCP không bao giờ kết nối thẳng vào đây
|
|
|
21
24
|
## Cài đặt
|
|
22
25
|
|
|
23
26
|
```bash
|
|
24
|
-
|
|
25
|
-
npm install
|
|
27
|
+
npx -y @dichvuright/mcp-hosting-server
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
## Tạo API Key
|
|
29
31
|
|
|
30
|
-
1. Vào **Admin → API Keys**
|
|
32
|
+
1. Vào **Admin → API Keys**
|
|
31
33
|
2. Tạo key mới với scope **`mcp:admin`**
|
|
32
34
|
3. Copy `API Key` và `Secret`
|
|
33
35
|
|
|
34
|
-
## Cấu hình
|
|
36
|
+
## Cấu hình (không dùng .env)
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
Truyền biến trực tiếp qua `env` trong MCP config JSON:
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
MCP_API_URL=http://localhost:3000
|
|
40
|
-
MCP_API_KEY=mc_xxxxxxxxxxxx
|
|
41
|
-
MCP_API_SECRET=sk_xxxxxxxxxxxx
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Chỉ 3 biến. Không có secret nào của hệ thống ở đây.
|
|
40
|
+
### Claude Desktop
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
Mở `%APPDATA%\Claude\claude_desktop_config.json`:
|
|
47
43
|
|
|
48
44
|
```json
|
|
49
45
|
{
|
|
50
46
|
"mcpServers": {
|
|
51
47
|
"dichvuright": {
|
|
52
48
|
"command": "npx",
|
|
53
|
-
"args": ["
|
|
54
|
-
"
|
|
49
|
+
"args": ["-y", "@dichvuright/mcp-hosting-server"],
|
|
50
|
+
"env": {
|
|
51
|
+
"MCP_API_URL": "https://dichvuright.com",
|
|
52
|
+
"MCP_API_KEY": "mc_xxxxxxxxxxxx",
|
|
53
|
+
"MCP_API_SECRET": "sk_xxxxxxxxxxxx"
|
|
54
|
+
}
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
Mở `%APPDATA%\Claude\claude_desktop_config.json`:
|
|
60
|
+
### Antigravity / Cursor / Cline
|
|
63
61
|
|
|
64
62
|
```json
|
|
65
63
|
{
|
|
66
64
|
"mcpServers": {
|
|
67
65
|
"dichvuright": {
|
|
68
66
|
"command": "npx",
|
|
69
|
-
"args": ["
|
|
70
|
-
"
|
|
67
|
+
"args": ["-y", "@dichvuright/mcp-hosting-server"],
|
|
68
|
+
"env": {
|
|
69
|
+
"MCP_API_URL": "https://dichvuright.com",
|
|
70
|
+
"MCP_API_KEY": "mc_xxxxxxxxxxxx",
|
|
71
|
+
"MCP_API_SECRET": "sk_xxxxxxxxxxxx"
|
|
72
|
+
}
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
```
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
### Dev local (chỉ dùng app local)
|
|
77
79
|
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"env": {
|
|
83
|
+
"MCP_API_URL": "http://localhost:3000",
|
|
84
|
+
"MCP_API_KEY": "mc_xxxxxxxxxxxx",
|
|
85
|
+
"MCP_API_SECRET": "sk_xxxxxxxxxxxx"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
84
88
|
```
|
|
85
89
|
|
|
86
90
|
## Tools (28 tools)
|
|
87
91
|
|
|
88
|
-
|
|
|
89
|
-
|
|
90
|
-
|
|
|
91
|
-
| 📋 Logs (5) | query_logs
|
|
92
|
-
| 🔔 Alerts (3) | send_alert
|
|
93
|
-
| 📊 Dashboard (5) | get_revenue_stats
|
|
94
|
-
| 👤 Users (6) | find_user
|
|
95
|
-
| 🎫 Tickets (4) | list_open_tickets
|
|
92
|
+
| Nhóm | Tools |
|
|
93
|
+
|------|-------|
|
|
94
|
+
| 🔍 Health (5) | `health_check_all`, `health_check_mongodb`, `health_check_redis`, `health_check_suppliers`, `get_stuck_tasks` |
|
|
95
|
+
| 📋 Logs (5) | `query_logs`*, `get_error_summary`, `detect_suspicious_ips`*, `get_critical_events`, `get_admin_activity_digest` |
|
|
96
|
+
| 🔔 Alerts (3) | `send_alert`✏️, `get_alert_history`, `silence_alert`✏️ |
|
|
97
|
+
| 📊 Dashboard (5) | `get_revenue_stats`, `get_user_stats`, `get_service_utilization`, `get_ticket_stats`, `get_payment_health` |
|
|
98
|
+
| 👤 Users (6) | `find_user`, `get_user_profile`, `get_user_transactions`, `get_user_security_events`, `get_user_services`, `flag_user_for_review`✏️ |
|
|
99
|
+
| 🎫 Tickets (4) | `list_open_tickets`, `get_ticket_summary`, `get_overdue_tickets`, `get_ticket_stats_summary` |
|
|
96
100
|
|
|
97
|
-
`*` Heavy query: giới hạn 10 req/min
|
|
101
|
+
`*` Heavy query: giới hạn 10 req/min
|
|
98
102
|
`✏️` Write op: tạo audit log
|
|
99
103
|
|
|
100
104
|
## Bảo mật
|
|
101
105
|
|
|
106
|
+
- **HMAC-SHA256**: mọi request đều signed, timestamp drift 60s, dedup Redis
|
|
102
107
|
- **PII masking**: email, phone, name, IP tự động masked trước khi trả về AI
|
|
103
108
|
- **Không expose**: password hash, CCCD data, encrypted secrets
|
|
104
|
-
- **Rate limit**:
|
|
109
|
+
- **Rate limit**: 60 req/min per IP global, 30 req/min per API key
|
|
110
|
+
- **IP Rules**: blocklist/allowlist quản lý trong Admin → IP Rules
|
|
105
111
|
- **Audit trail**: mọi tool call ghi vào MongoDB logs
|
|
106
|
-
- **Revoke ngay**: vào Admin → API Keys → Revoke nếu bị lộ key
|
|
107
112
|
|
|
108
113
|
## Troubleshooting
|
|
109
114
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
| Lỗi | Nguyên nhân | Fix |
|
|
116
|
+
|-----|-------------|-----|
|
|
117
|
+
| `MCP_API_KEY và MCP_API_SECRET là bắt buộc` | Chưa set env | Thêm vào `env` trong MCP config |
|
|
118
|
+
| `Invalid API key` | Key sai hoặc bị revoke | Kiểm tra Admin → API Keys |
|
|
119
|
+
| `Insufficient scope` | Key chưa có scope `mcp:admin` | Tạo key mới với đúng scope |
|
|
120
|
+
| `Request expired` | Đồng hồ máy lệch >60s | Sync NTP |
|
|
121
|
+
| `IP blocked` | IP bị block trong Admin → IP Rules | Kiểm tra và xóa rule |
|
|
122
|
+
| Tools không xuất hiện trong IDE | Sai config | Restart IDE sau khi sửa config |
|
|
118
123
|
|
|
119
|
-
|
|
120
|
-
→ Kiểm tra `cwd` trỏ đúng `D:/nextjs/hosting/mcp`, restart IDE
|
|
124
|
+
<!-- trigger -->
|
package/dist/server.js
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
|
-
import "dotenv/config";
|
|
2
1
|
import crypto from "crypto";
|
|
3
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
4
|
import { z } from "zod";
|
|
5
|
+
/**
|
|
6
|
+
* DichVuRight Admin MCP Server v2.0
|
|
7
|
+
*
|
|
8
|
+
* Không dùng .env file — truyền biến qua env trong MCP config JSON:
|
|
9
|
+
*
|
|
10
|
+
* {
|
|
11
|
+
* "mcpServers": {
|
|
12
|
+
* "dichvuright": {
|
|
13
|
+
* "command": "npx",
|
|
14
|
+
* "args": ["-y", "@dichvuright/mcp-hosting-server"],
|
|
15
|
+
* "env": {
|
|
16
|
+
* "MCP_API_URL": "https://dichvuright.com",
|
|
17
|
+
* "MCP_API_KEY": "mc_xxx",
|
|
18
|
+
* "MCP_API_SECRET": "sk_xxx"
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
6
24
|
const API_URL = process.env.MCP_API_URL ?? "http://localhost:3000";
|
|
7
25
|
const API_KEY = process.env.MCP_API_KEY ?? "";
|
|
8
26
|
const API_SECRET = process.env.MCP_API_SECRET ?? "";
|
|
9
27
|
if (!API_KEY || !API_SECRET) {
|
|
10
28
|
console.error("[MCP] ERROR: MCP_API_KEY và MCP_API_SECRET là bắt buộc");
|
|
11
|
-
console.error("[MCP] Tạo API key
|
|
29
|
+
console.error("[MCP] Tạo API key: Admin → API Keys → scope 'mcp:admin'");
|
|
30
|
+
console.error("[MCP] Truyền qua env trong MCP config JSON (không dùng .env file)");
|
|
12
31
|
process.exit(1);
|
|
13
32
|
}
|
|
14
33
|
// ── HMAC call helper ───────────────────────────────────────────────────────
|
|
@@ -44,18 +63,23 @@ const server = new McpServer({ name: "dichvuright-admin", version: "2.0.0" });
|
|
|
44
63
|
// ── Health ─────────────────────────────────────────────────────────────────
|
|
45
64
|
server.registerTool("health_check_all", {
|
|
46
65
|
description: "Kiểm tra tổng quan hệ thống: MongoDB, Redis, task bị kẹt, WHM servers, VPS suppliers.",
|
|
66
|
+
annotations: { readOnlyHint: true },
|
|
47
67
|
}, async () => ({ content: text(await callApi("health_check_all", {})) }));
|
|
48
68
|
server.registerTool("health_check_mongodb", {
|
|
49
69
|
description: "Kiểm tra MongoDB: latency, connection state, số task theo trạng thái.",
|
|
70
|
+
annotations: { readOnlyHint: true },
|
|
50
71
|
}, async () => ({ content: text(await callApi("health_check_mongodb", {})) }));
|
|
51
72
|
server.registerTool("health_check_redis", {
|
|
52
73
|
description: "Kiểm tra Redis: memory, connected clients, hit rate, eviction policy.",
|
|
74
|
+
annotations: { readOnlyHint: true },
|
|
53
75
|
}, async () => ({ content: text(await callApi("health_check_redis", {})) }));
|
|
54
76
|
server.registerTool("health_check_suppliers", {
|
|
55
77
|
description: "Số WHM servers và VPS suppliers theo trạng thái active/inactive.",
|
|
78
|
+
annotations: { readOnlyHint: true },
|
|
56
79
|
}, async () => ({ content: text(await callApi("health_check_suppliers", {})) }));
|
|
57
80
|
server.registerTool("get_stuck_tasks", {
|
|
58
81
|
description: "Tasks đang running (status=2) quá 30 phút — có thể bị stuck.",
|
|
82
|
+
annotations: { readOnlyHint: true },
|
|
59
83
|
}, async () => ({ content: text(await callApi("get_stuck_tasks", {})) }));
|
|
60
84
|
// ── Logs ───────────────────────────────────────────────────────────────────
|
|
61
85
|
server.registerTool("query_logs", {
|
|
@@ -66,12 +90,14 @@ server.registerTool("query_logs", {
|
|
|
66
90
|
hours: z.number().optional().describe("Bao nhiêu giờ gần đây (mặc định 24)"),
|
|
67
91
|
limit: z.number().optional().describe("Số kết quả tối đa (mặc định 50, tối đa 200)"),
|
|
68
92
|
},
|
|
93
|
+
annotations: { readOnlyHint: true },
|
|
69
94
|
}, async (args) => ({ content: text(await callApi("query_logs", args)) }));
|
|
70
95
|
server.registerTool("get_error_summary", {
|
|
71
96
|
description: "Group errors theo module/severity. Dùng để xem điểm yếu hệ thống.",
|
|
72
97
|
inputSchema: {
|
|
73
98
|
hours: z.number().optional().describe("Bao nhiêu giờ gần đây (mặc định 24)"),
|
|
74
99
|
},
|
|
100
|
+
annotations: { readOnlyHint: true },
|
|
75
101
|
}, async (args) => ({ content: text(await callApi("get_error_summary", args)) }));
|
|
76
102
|
server.registerTool("detect_suspicious_ips", {
|
|
77
103
|
description: "Phát hiện IP có nhiều failed auth — dấu hiệu brute force. ⚠️ Heavy query.",
|
|
@@ -79,18 +105,21 @@ server.registerTool("detect_suspicious_ips", {
|
|
|
79
105
|
threshold: z.number().optional().describe("Số lần thất bại tối thiểu (mặc định 5)"),
|
|
80
106
|
hours: z.number().optional().describe("Khoảng thời gian (mặc định 1 giờ)"),
|
|
81
107
|
},
|
|
108
|
+
annotations: { readOnlyHint: true },
|
|
82
109
|
}, async (args) => ({ content: text(await callApi("detect_suspicious_ips", args)) }));
|
|
83
110
|
server.registerTool("get_critical_events", {
|
|
84
111
|
description: "Lấy events có severity error/critical gần đây.",
|
|
85
112
|
inputSchema: {
|
|
86
113
|
hours: z.number().optional().describe("Bao nhiêu giờ gần đây (mặc định 6)"),
|
|
87
114
|
},
|
|
115
|
+
annotations: { readOnlyHint: true },
|
|
88
116
|
}, async (args) => ({ content: text(await callApi("get_critical_events", args)) }));
|
|
89
117
|
server.registerTool("get_admin_activity_digest", {
|
|
90
118
|
description: "Tóm tắt hoạt động của admin trong ngày theo module/action.",
|
|
91
119
|
inputSchema: {
|
|
92
120
|
date: z.string().optional().describe("Ngày cần xem YYYY-MM-DD (mặc định hôm nay)"),
|
|
93
121
|
},
|
|
122
|
+
annotations: { readOnlyHint: true },
|
|
94
123
|
}, async (args) => ({ content: text(await callApi("get_admin_activity_digest", args)) }));
|
|
95
124
|
// ── Alerts ─────────────────────────────────────────────────────────────────
|
|
96
125
|
server.registerTool("send_alert", {
|
|
@@ -106,6 +135,7 @@ server.registerTool("get_alert_history", {
|
|
|
106
135
|
inputSchema: {
|
|
107
136
|
hours: z.number().optional().describe("Bao nhiêu giờ gần đây (mặc định 24)"),
|
|
108
137
|
},
|
|
138
|
+
annotations: { readOnlyHint: true },
|
|
109
139
|
}, async (args) => ({ content: text(await callApi("get_alert_history", args)) }));
|
|
110
140
|
server.registerTool("silence_alert", {
|
|
111
141
|
description: "Tắt alert tạm thời. key='all' để tắt hết. ✏️ WRITE.",
|
|
@@ -121,12 +151,14 @@ server.registerTool("get_revenue_stats", {
|
|
|
121
151
|
inputSchema: {
|
|
122
152
|
period: z.enum(["day", "week", "month"]).describe("Kỳ thống kê"),
|
|
123
153
|
},
|
|
154
|
+
annotations: { readOnlyHint: true },
|
|
124
155
|
}, async (args) => ({ content: text(await callApi("get_revenue_stats", args)) }));
|
|
125
156
|
server.registerTool("get_user_stats", {
|
|
126
157
|
description: "Thống kê user: mới đăng ký, active, bị ban trong kỳ.",
|
|
127
158
|
inputSchema: {
|
|
128
159
|
period: z.enum(["day", "week", "month"]).describe("Kỳ thống kê"),
|
|
129
160
|
},
|
|
161
|
+
annotations: { readOnlyHint: true },
|
|
130
162
|
}, async (args) => ({ content: text(await callApi("get_user_stats", args)) }));
|
|
131
163
|
server.registerTool("get_service_utilization", {
|
|
132
164
|
description: "VPS + hosting đang chạy theo status.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dichvuright/mcp-hosting-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "DichVuRight Admin MCP Server — AI agent integration via HMAC API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,12 @@
|
|
|
25
25
|
"url": "https://github.com/dichvuright/hosting-dichvuright.git",
|
|
26
26
|
"directory": "mcp"
|
|
27
27
|
},
|
|
28
|
-
"keywords": [
|
|
28
|
+
"keywords": [
|
|
29
|
+
"mcp",
|
|
30
|
+
"dichvuright",
|
|
31
|
+
"admin",
|
|
32
|
+
"ai-agent"
|
|
33
|
+
],
|
|
29
34
|
"license": "UNLICENSED",
|
|
30
35
|
"private": false,
|
|
31
36
|
"dependencies": {
|