@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.
Files changed (3) hide show
  1. package/README.md +63 -59
  2. package/dist/server.js +34 -2
  3. package/package.json +7 -2
package/README.md CHANGED
@@ -1,19 +1,22 @@
1
- # DichVuRight Admin MCP Server
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 bảo mật
5
+ ## Kiến trúc
6
6
 
7
7
  ```
8
- AI Agent
9
- |
10
- MCP Server (chỉ có: API_URL + API_KEY + API_SECRET)
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 API (verify HMAC + scope mcp:admin)
15
- |
16
- MongoDB / Redis ← MCP không bao giờ kết nối thẳng vào đây
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
- cd D:/nextjs/hosting/mcp
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** (hoặc trang quản lý ApiClient)
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
- Điền vào `mcp/.env`:
38
+ Truyền biến trực tiếp qua `env` trong MCP config JSON:
37
39
 
38
- ```env
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
- ## Kết nối Antigravity / Cursor / Cline
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": ["tsx", "D:/nextjs/hosting/mcp/server.ts"],
54
- "cwd": "D:/nextjs/hosting/mcp"
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
- ## Kết nối Claude Desktop
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": ["tsx", "D:/nextjs/hosting/mcp/server.ts"],
70
- "cwd": "D:/nextjs/hosting/mcp"
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
- ## Test thủ công
78
+ ### Dev local (chỉ dùng app local)
77
79
 
78
- ```bash
79
- cd D:/nextjs/hosting/mcp
80
- npm run dev
81
- # Output: [MCP] DichVuRight Admin MCP Server v2.0 started
82
- # Output: [MCP] API endpoint: http://localhost:3000/api/mcp/tools/call
83
- # Output: [MCP] Tools registered: 28
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
- | Group | Tools |
89
- |-------|-------|
90
- | 🏥 Health (5) | health_check_all, health_check_mongodb, health_check_redis, health_check_suppliers, get_stuck_tasks |
91
- | 📋 Logs (5) | query_logs*, get_error_summary, detect_suspicious_ips*, get_critical_events, get_admin_activity_digest |
92
- | 🔔 Alerts (3) | send_alert✏️, get_alert_history, silence_alert✏️ |
93
- | 📊 Dashboard (5) | get_revenue_stats, get_user_stats, get_service_utilization, get_ticket_stats, get_payment_health |
94
- | 👤 Users (6) | find_user, get_user_profile, get_user_transactions, get_user_security_events, get_user_services, flag_user_for_review✏️ |
95
- | 🎫 Tickets (4) | list_open_tickets, get_ticket_summary, get_overdue_tickets, get_ticket_stats |
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**: 100 req/min (normal), 10 req/min (heavy queries)
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
- **"MCP_API_KEY MCP_API_SECRET bắt buộc"**
111
- → Kiểm tra file `mcp/.env`
112
-
113
- **"Invalid API key" hoặc "Insufficient scope"**
114
- API key chưa có scope `mcp:admin`, hoặc key bị revoke
115
-
116
- **"Request expired"**
117
- Đồng hồ máy lệch >5 phút, sync lại NTP
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
- **Tools không xuất hiện trong IDE**
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 trong Admin → API Keys với scope 'mcp:admin'");
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.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": ["mcp", "dichvuright", "admin", "ai-agent"],
28
+ "keywords": [
29
+ "mcp",
30
+ "dichvuright",
31
+ "admin",
32
+ "ai-agent"
33
+ ],
29
34
  "license": "UNLICENSED",
30
35
  "private": false,
31
36
  "dependencies": {