monacloud-mcp 0.2.0 → 0.2.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 +17 -2
- package/STATUS.md +5 -5
- package/dist/clients.d.ts +7 -0
- package/dist/clients.js +13 -0
- package/dist/index.js +1 -1
- package/dist/server.js +61 -43
- package/docs/ai-agent.md +17 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,7 +99,21 @@ Các tên cũ như `monapay_create_qr`, `monapay_link_bank_start`, `monapay_crea
|
|
|
99
99
|
| `cloud_prices` / `cloud_packages` | Đơn giá và gói cấu hình |
|
|
100
100
|
| `cloud_agent_deploy` | Stub có cấu trúc cho runtime MONA Agent wave sau |
|
|
101
101
|
|
|
102
|
-
`cloud_service_stop` không bị chặn bởi số dư để người dùng luôn có thể hạn chế chi phí. Những lệnh tạo/start/rebuild đọc `GET /v1/balance` trước khi gọi compute MONA Cloud.
|
|
102
|
+
`cloud_service_stop` không bị chặn bởi số dư để người dùng luôn có thể hạn chế chi phí. Những lệnh tạo/start/rebuild thật đọc `GET /v1/balance` trước khi gọi compute MONA Cloud.
|
|
103
|
+
|
|
104
|
+
## Thử 0đ bằng sandbox
|
|
105
|
+
|
|
106
|
+
Truyền `sandbox: true` cho `cloud_vps_create`, `cloud_db_create`, `cloud_service_start`, `cloud_service_rebuild` hoặc `cloud_agent_deploy` để thử luồng mà không cần số dư ví. Có thể bật mặc định cho cả MCP process bằng `MONACLOUD_SANDBOX=1`; các alias `vibecloud_*` có cùng hành vi.
|
|
107
|
+
|
|
108
|
+
Ở chế độ này MCP bỏ qua `GET /v1/balance`, tự gửi `X-Vibecloud-Sandbox: 1` đến compute API và bảo đảm response có `sandbox: true`. Ví dụ:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
cloud_vps_create({ app_name: "shop-demo", package_slug: "standard-2", sandbox: true })
|
|
112
|
+
cloud_job_status({ job_id: "...", sandbox: true })
|
|
113
|
+
cloud_services_list({ sandbox: true })
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`cloud_job_status` tự tìm job sandbox theo ID mà không cần header. `cloud_services_list({ sandbox: true })` dùng khả năng `include_sandbox` của API để gộp service thật và sandbox. Sandbox không tạo hạ tầng thật, không trừ tiền và có thể bị dọn theo TTL của compute API. `cloud_agent_deploy` vẫn là stub cho đến khi runtime MONA Agent được phát hành, nhưng response sandbox được đánh dấu nhất quán.
|
|
103
117
|
|
|
104
118
|
### MONA Agent
|
|
105
119
|
|
|
@@ -115,7 +129,7 @@ Các tên cũ như `monapay_create_qr`, `monapay_link_bank_start`, `monapay_crea
|
|
|
115
129
|
|
|
116
130
|
## Spend guard và lỗi cho AI
|
|
117
131
|
|
|
118
|
-
Trước lệnh compute MONA Cloud có thể phát sinh tiền, MCP đọc ví chung. HTTP `402 insufficient_funds` và `402 budget_exceeded` được chuẩn hoá thành text JSON:
|
|
132
|
+
Trước lệnh compute MONA Cloud thật có thể phát sinh tiền, MCP đọc ví chung. Sandbox bỏ qua bước này vì chi phí 0đ. HTTP `402 insufficient_funds` và `402 budget_exceeded` được chuẩn hoá thành text JSON:
|
|
119
133
|
|
|
120
134
|
```json
|
|
121
135
|
{
|
|
@@ -156,6 +170,7 @@ Chi tiết dành riêng cho agent: [`docs/ai-agent.md`](docs/ai-agent.md).
|
|
|
156
170
|
| `MONACLOUD_API` | `https://api.monacloud.vn` | Compute API của MONA Cloud |
|
|
157
171
|
| `MONACLOUD_CONSOLE_URL` | `https://monacloud.vn/console` | URL trả cho bước human |
|
|
158
172
|
| `MONACLOUD_TOKEN` | — | PAT/access token ưu tiên token store |
|
|
173
|
+
| `MONACLOUD_SANDBOX` | — | Đặt `1` để mọi lệnh compute hỗ trợ sandbox chạy thử 0đ, không cần ví |
|
|
159
174
|
| `MONACLOUD_CONFIG_DIR` | `~/.config/monacloud` | Token và link cache |
|
|
160
175
|
| `MONACLOUD_TEMPLATES_DIR` | `~/monacloud/templates` | Catalog agent local |
|
|
161
176
|
| `MONACLOUD_TEMPLATES_URL` | — | Catalog JSON từ xa, chỉ dùng khi local không có |
|
package/STATUS.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# STATUS — monacloud-mcp 0.2.
|
|
1
|
+
# STATUS — monacloud-mcp 0.2.1
|
|
2
2
|
|
|
3
3
|
Updated: 2026-09-04 (Asia/Ho_Chi_Minh)
|
|
4
4
|
|
|
5
5
|
## Hoàn thành
|
|
6
6
|
|
|
7
|
-
- [x] Package Node 20 + TypeScript, ESM, stdio MCP; bin `monacloud-mcp`, version `0.2.
|
|
7
|
+
- [x] Package Node 20 + TypeScript, ESM, stdio MCP; bin `monacloud-mcp`, version `0.2.1`.
|
|
8
8
|
- [x] OAuth device flow client `monacloud-mcp`, scope `offline_access`, token store private `0600`, refresh tự động; CLI `login`, `logout`, `whoami`.
|
|
9
9
|
- [x] 10 tool `cloud_*`: identity, balance, ledger, topup VietQR, usage, services aggregation, budget, token limit và console URL.
|
|
10
10
|
- [x] Import package `monapay-mcp` và re-export toàn bộ tool, không copy code. Dependency offline tại lần verify cuối là 0.5.5/47 tool (superset 24 tool yêu cầu); cộng `monapay_link` chuyển tiếp.
|
|
11
11
|
- [x] 11 tool compute tên mới `cloud_*`: link, VPS, database, job poll, list, start/stop/rebuild, prices, packages và agent-deploy stub.
|
|
12
12
|
- [x] 11 alias kỹ thuật `vibecloud_*` vẫn gọi được cho client cũ, không xuất hiện trong README/hướng dẫn agent.
|
|
13
13
|
- [x] 3 tool `agent_*`: list/get catalog local/remote/built-in và deploy qua cùng stub MONA Cloud.
|
|
14
|
-
- [x] Spend guard đọc billing balance trước create/start/rebuild;
|
|
14
|
+
- [x] Spend guard đọc billing balance trước create/start/rebuild thật; `sandbox: true` hoặc `MONACLOUD_SANDBOX=1` bỏ qua Billing, gửi header compute và đánh dấu response. Stop luôn được phép.
|
|
15
15
|
- [x] 2 resource đúng brief: `monacloud://llms`, `monacloud://status`.
|
|
16
16
|
- [x] 1 prompt `dung-app-ban-hang-monacloud`: VPS → DB → VA/QR → webhook → deploy.
|
|
17
17
|
- [x] Không log token; token và linked credential được lưu bằng atomic write, directory `0700`, file `0600`.
|
|
@@ -28,7 +28,7 @@ $ node_modules/.bin/tsc -p tsconfig.json
|
|
|
28
28
|
exit 0, không có diagnostic
|
|
29
29
|
|
|
30
30
|
$ node --test
|
|
31
|
-
tests
|
|
31
|
+
tests 13, pass 13, fail 0
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Không chạy `npm install`; toàn bộ build/test dùng `node_modules` có sẵn và không gọi Internet.
|
|
@@ -47,7 +47,7 @@ CODEX DONE
|
|
|
47
47
|
|
|
48
48
|
- Tên người đọc và 11 tool chính đã chuyển sang MONA Cloud / `cloud_*`; VibeCloud chỉ còn trong alias và định danh kỹ thuật tương thích.
|
|
49
49
|
- Resource `monacloud://llms`, prompt dựng app, README và `docs/ai-agent.md` chỉ hướng dẫn tên mới.
|
|
50
|
-
- Package, MCP server và binary version đồng bộ `0.2.
|
|
50
|
+
- Package, MCP server và binary version đồng bộ `0.2.1`; build và test được ghi ở gate mới bên trên.
|
|
51
51
|
|
|
52
52
|
## QC Claude (03/09 tối) — ZERO-DASHBOARD TEST LOCAL: PASS
|
|
53
53
|
- Build tsc sạch · `node --test` 7/7 · stdio thật: **72 tool** (cloud 10 · monapay 48 · vibecloud 11 · agent 3), 2 resource, 1 prompt.
|
package/dist/clients.d.ts
CHANGED
|
@@ -20,11 +20,18 @@ export declare class CloudClients {
|
|
|
20
20
|
budgetGet(): Promise<unknown>;
|
|
21
21
|
tokenLimit(spendLimitVnd: number, period: string, tokenId?: string): Promise<unknown>;
|
|
22
22
|
spendGuard(): Promise<JsonObject>;
|
|
23
|
+
sandboxEnabled(requested?: boolean): boolean;
|
|
23
24
|
private vibecloudToken;
|
|
24
25
|
vibecloud<T = unknown>(path: string, options?: {
|
|
25
26
|
method?: string;
|
|
26
27
|
body?: unknown;
|
|
28
|
+
query?: Record<string, string | number | undefined>;
|
|
29
|
+
headers?: Record<string, string>;
|
|
27
30
|
}): Promise<T>;
|
|
31
|
+
guardedVibecloud(path: string, options?: {
|
|
32
|
+
method?: string;
|
|
33
|
+
body?: unknown;
|
|
34
|
+
}, requestedSandbox?: boolean): Promise<unknown>;
|
|
28
35
|
vibecloudLink(): Promise<JsonObject>;
|
|
29
36
|
monapayLink(): Promise<JsonObject>;
|
|
30
37
|
prices(): Promise<unknown>;
|
package/dist/clients.js
CHANGED
|
@@ -69,6 +69,9 @@ export class CloudClients {
|
|
|
69
69
|
}
|
|
70
70
|
return current;
|
|
71
71
|
}
|
|
72
|
+
sandboxEnabled(requested = false) {
|
|
73
|
+
return requested || this.auth.env.MONACLOUD_SANDBOX === '1';
|
|
74
|
+
}
|
|
72
75
|
async vibecloudToken() {
|
|
73
76
|
if (this.auth.env.VIBECLOUD_API_TOKEN)
|
|
74
77
|
return this.auth.env.VIBECLOUD_API_TOKEN;
|
|
@@ -86,6 +89,16 @@ export class CloudClients {
|
|
|
86
89
|
fetchImpl: this.fetchImpl,
|
|
87
90
|
});
|
|
88
91
|
}
|
|
92
|
+
async guardedVibecloud(path, options = {}, requestedSandbox = false) {
|
|
93
|
+
const sandbox = this.sandboxEnabled(requestedSandbox);
|
|
94
|
+
if (!sandbox)
|
|
95
|
+
await this.spendGuard();
|
|
96
|
+
const result = await this.vibecloud(path, {
|
|
97
|
+
...options,
|
|
98
|
+
...(sandbox ? { headers: { 'X-Vibecloud-Sandbox': '1' } } : {}),
|
|
99
|
+
});
|
|
100
|
+
return sandbox ? { ...asObject(result), sandbox: true } : result;
|
|
101
|
+
}
|
|
89
102
|
async vibecloudLink() {
|
|
90
103
|
if (this.auth.env.VIBECLOUD_API_TOKEN) {
|
|
91
104
|
return { linked: true, product: 'vibecloud', mode: 'legacy_env', next_step: 'Dùng các tool cloud_*.' };
|
package/dist/index.js
CHANGED
package/dist/server.js
CHANGED
|
@@ -9,7 +9,9 @@ import { requestJson, unwrapData } from './http.js';
|
|
|
9
9
|
import { createMonaPayClient, importedMonaPayTools, normalizeImportedResult } from './monapay.js';
|
|
10
10
|
import { TemplateCatalog } from './templates.js';
|
|
11
11
|
const ENTITY = 'MONA Cloud là hệ công cụ cho vibecoder Việt Nam: một MONA Pass, một ví VND và một MCP để chạy app/VPS, thu tiền MONA Pay và dùng các sản phẩm MONA.';
|
|
12
|
-
const TERMINAL_JOBS = new Set(['succeeded', 'failed', 'cancelled']);
|
|
12
|
+
const TERMINAL_JOBS = new Set(['done', 'succeeded', 'failed', 'cancelled']);
|
|
13
|
+
const SANDBOX_DESCRIPTION = 'sandbox=true: thử 0đ, không cần ví';
|
|
14
|
+
const sandboxSchema = z.boolean().optional().describe(SANDBOX_DESCRIPTION);
|
|
13
15
|
const asObject = (value) => (value && typeof value === 'object' ? value : {});
|
|
14
16
|
function collection(value) {
|
|
15
17
|
const data = unwrapData(value);
|
|
@@ -29,6 +31,7 @@ const sizingSchema = {
|
|
|
29
31
|
cpu: z.number().int().min(1).max(16).optional(),
|
|
30
32
|
ram_gb: z.number().int().min(1).max(64).optional(),
|
|
31
33
|
disk_gb: z.number().int().min(10).max(1000).optional(),
|
|
34
|
+
sandbox: sandboxSchema,
|
|
32
35
|
};
|
|
33
36
|
const provisionSchema = z.object(sizingSchema).superRefine((value, context) => {
|
|
34
37
|
const dimensions = [value.cpu, value.ram_gb, value.disk_gb];
|
|
@@ -41,28 +44,34 @@ const provisionSchema = z.object(sizingSchema).superRefine((value, context) => {
|
|
|
41
44
|
context.addIssue({ code: 'custom', message: 'Cần package_slug hoặc đủ cpu, ram_gb và disk_gb.' });
|
|
42
45
|
}
|
|
43
46
|
});
|
|
44
|
-
function agentRuntimeStub(template) {
|
|
47
|
+
function agentRuntimeStub(template, sandbox = false) {
|
|
45
48
|
return {
|
|
46
49
|
status: 'not_available',
|
|
47
50
|
code: 'agent_runtime_pending',
|
|
48
51
|
template,
|
|
49
52
|
message: 'Runtime MONA Agent trên MONA Cloud chưa được phát hành; tool này là slot wave kế tiếp theo brief.',
|
|
50
53
|
next_step: 'Dùng agent_templates_get để lấy nội dung template và triển khai thủ công, hoặc thử lại khi MONA Cloud bật runtime agent.',
|
|
54
|
+
...(sandbox ? { sandbox: true } : {}),
|
|
51
55
|
};
|
|
52
56
|
}
|
|
53
|
-
async function pollJob(clients, jobId, wait, intervalSeconds, timeoutSeconds) {
|
|
57
|
+
async function pollJob(clients, jobId, wait, intervalSeconds, timeoutSeconds, sandbox) {
|
|
54
58
|
let result = await clients.vibecloud(`/api/jobs/${encodeURIComponent(jobId)}`);
|
|
55
59
|
if (!wait)
|
|
56
|
-
return result;
|
|
60
|
+
return sandbox ? { ...asObject(result), sandbox: true } : result;
|
|
57
61
|
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
58
62
|
while (!TERMINAL_JOBS.has(String(asObject(result).status || '')) && Date.now() < deadline) {
|
|
59
63
|
await delay(intervalSeconds * 1000);
|
|
60
64
|
result = await clients.vibecloud(`/api/jobs/${encodeURIComponent(jobId)}`);
|
|
61
65
|
}
|
|
62
66
|
if (!TERMINAL_JOBS.has(String(asObject(result).status || ''))) {
|
|
63
|
-
return {
|
|
67
|
+
return {
|
|
68
|
+
...asObject(result),
|
|
69
|
+
...(sandbox ? { sandbox: true } : {}),
|
|
70
|
+
polling: 'timeout',
|
|
71
|
+
next_step: `Gọi lại cloud_job_status với job_id=${jobId}.`,
|
|
72
|
+
};
|
|
64
73
|
}
|
|
65
|
-
return result;
|
|
74
|
+
return sandbox ? { ...asObject(result), sandbox: true } : result;
|
|
66
75
|
}
|
|
67
76
|
async function providerHealth(name, url, fetchImpl) {
|
|
68
77
|
const started = Date.now();
|
|
@@ -81,7 +90,7 @@ export function createServer(dependencies = {}) {
|
|
|
81
90
|
const auth = new AuthManager(config, env, fetchImpl);
|
|
82
91
|
const clients = new CloudClients(config, auth, fetchImpl);
|
|
83
92
|
const catalog = new TemplateCatalog(config, fetchImpl);
|
|
84
|
-
const server = new McpServer({ name: 'monacloud-mcp', version: '0.2.
|
|
93
|
+
const server = new McpServer({ name: 'monacloud-mcp', version: '0.2.1' }, { instructions: `${ENTITY}\nDùng cloud_* cho tài khoản, ví và hạ tầng; monapay_* cho thu tiền; agent_* cho catalog. Không bao giờ yêu cầu mật khẩu sản phẩm. Chỉ dừng hỏi người dùng khi cần nạp tiền, OTP ngân hàng hoặc KYC bắt buộc.` });
|
|
85
94
|
server.registerTool('cloud_whoami', {
|
|
86
95
|
title: 'Tài khoản MONA Cloud',
|
|
87
96
|
description: 'Xác minh MONA Pass hiện tại. / Return the current MONA Pass profile.',
|
|
@@ -187,82 +196,91 @@ export function createServer(dependencies = {}) {
|
|
|
187
196
|
}, () => runTool(() => clients.vibecloudLink()));
|
|
188
197
|
server.registerTool('cloud_vps_create', {
|
|
189
198
|
title: 'Tạo VPS MONA Cloud',
|
|
190
|
-
description:
|
|
199
|
+
description: `Kiểm tra ví chung rồi tạo LXC VPS; trả job_id để poll. ${SANDBOX_DESCRIPTION}.`,
|
|
191
200
|
inputSchema: provisionSchema,
|
|
192
201
|
}, (body) => runTool(async () => {
|
|
193
|
-
|
|
194
|
-
return clients.
|
|
202
|
+
const { sandbox, ...payload } = body;
|
|
203
|
+
return clients.guardedVibecloud('/api/lxc', { method: 'POST', body: payload }, sandbox);
|
|
195
204
|
}));
|
|
196
205
|
server.registerTool('vibecloud_create_vps', {
|
|
197
206
|
title: 'Alias cũ của cloud_vps_create',
|
|
198
|
-
description:
|
|
207
|
+
description: `Alias tương thích; dùng cloud_vps_create cho tích hợp mới. ${SANDBOX_DESCRIPTION}.`,
|
|
199
208
|
inputSchema: provisionSchema,
|
|
200
209
|
}, (body) => runTool(async () => {
|
|
201
|
-
|
|
202
|
-
return clients.
|
|
210
|
+
const { sandbox, ...payload } = body;
|
|
211
|
+
return clients.guardedVibecloud('/api/lxc', { method: 'POST', body: payload }, sandbox);
|
|
203
212
|
}));
|
|
204
213
|
const databaseSchema = provisionSchema.extend({ engine: z.enum(['mongodb', 'postgresql', 'mysql']).default('mongodb') });
|
|
205
214
|
server.registerTool('cloud_db_create', {
|
|
206
215
|
title: 'Tạo database MONA Cloud',
|
|
207
|
-
description:
|
|
216
|
+
description: `Kiểm tra ví chung rồi tạo MongoDB/PostgreSQL/MySQL; trả job_id để poll. ${SANDBOX_DESCRIPTION}.`,
|
|
208
217
|
inputSchema: databaseSchema,
|
|
209
218
|
}, (body) => runTool(async () => {
|
|
210
|
-
|
|
211
|
-
return clients.
|
|
219
|
+
const { sandbox, ...payload } = body;
|
|
220
|
+
return clients.guardedVibecloud('/api/databases', { method: 'POST', body: payload }, sandbox);
|
|
212
221
|
}));
|
|
213
222
|
server.registerTool('vibecloud_create_database', {
|
|
214
223
|
title: 'Alias cũ của cloud_db_create',
|
|
215
|
-
description:
|
|
224
|
+
description: `Alias tương thích; dùng cloud_db_create cho tích hợp mới. ${SANDBOX_DESCRIPTION}.`,
|
|
216
225
|
inputSchema: databaseSchema,
|
|
217
226
|
}, (body) => runTool(async () => {
|
|
218
|
-
|
|
219
|
-
return clients.
|
|
227
|
+
const { sandbox, ...payload } = body;
|
|
228
|
+
return clients.guardedVibecloud('/api/databases', { method: 'POST', body: payload }, sandbox);
|
|
220
229
|
}));
|
|
221
230
|
const jobStatusSchema = {
|
|
222
231
|
job_id: z.string().min(1),
|
|
223
232
|
wait: z.boolean().default(true),
|
|
224
233
|
interval_sec: z.number().int().min(1).max(30).default(3),
|
|
225
234
|
timeout_sec: z.number().int().min(1).max(600).default(180),
|
|
235
|
+
sandbox: sandboxSchema,
|
|
226
236
|
};
|
|
227
237
|
server.registerTool('cloud_job_status', {
|
|
228
238
|
title: 'Theo dõi job MONA Cloud',
|
|
229
|
-
description: 'Đọc
|
|
239
|
+
description: 'Đọc job thật hoặc sandbox theo ID; API tự nhận diện sandbox nên không cần header.',
|
|
230
240
|
inputSchema: jobStatusSchema,
|
|
231
|
-
}, ({ job_id, wait, interval_sec, timeout_sec }) => runTool(() => pollJob(clients, job_id, wait, interval_sec, timeout_sec)));
|
|
241
|
+
}, ({ job_id, wait, interval_sec, timeout_sec, sandbox }) => runTool(() => pollJob(clients, job_id, wait, interval_sec, timeout_sec, clients.sandboxEnabled(sandbox))));
|
|
232
242
|
server.registerTool('vibecloud_job_status', {
|
|
233
243
|
title: 'Alias cũ của cloud_job_status',
|
|
234
|
-
description: 'Alias tương thích; dùng cloud_job_status cho tích hợp mới.',
|
|
244
|
+
description: 'Alias tương thích; dùng cloud_job_status cho tích hợp mới. Job sandbox được tự nhận diện, không cần header.',
|
|
235
245
|
inputSchema: jobStatusSchema,
|
|
236
|
-
}, ({ job_id, wait, interval_sec, timeout_sec }) => runTool(() => pollJob(clients, job_id, wait, interval_sec, timeout_sec)));
|
|
246
|
+
}, ({ job_id, wait, interval_sec, timeout_sec, sandbox }) => runTool(() => pollJob(clients, job_id, wait, interval_sec, timeout_sec, clients.sandboxEnabled(sandbox))));
|
|
237
247
|
server.registerTool('cloud_services_list', {
|
|
238
248
|
title: 'Danh sách service MONA Cloud',
|
|
239
|
-
description: 'Liệt kê VPS
|
|
240
|
-
|
|
249
|
+
description: 'Liệt kê VPS/database; sandbox=true gộp cả service thử 0đ bằng API, không cần header.',
|
|
250
|
+
inputSchema: { sandbox: sandboxSchema },
|
|
251
|
+
}, ({ sandbox }) => runTool(() => clients.vibecloud('/api/services', {
|
|
252
|
+
query: clients.sandboxEnabled(sandbox) ? { include_sandbox: 1 } : undefined,
|
|
253
|
+
})));
|
|
241
254
|
server.registerTool('vibecloud_list_services', {
|
|
242
255
|
title: 'Alias cũ của cloud_services_list',
|
|
243
|
-
description: 'Alias tương thích; dùng cloud_services_list cho tích hợp mới.',
|
|
244
|
-
|
|
256
|
+
description: 'Alias tương thích; dùng cloud_services_list cho tích hợp mới. sandbox=true gộp service thử 0đ, không cần header.',
|
|
257
|
+
inputSchema: { sandbox: sandboxSchema },
|
|
258
|
+
}, ({ sandbox }) => runTool(() => clients.vibecloud('/api/services', {
|
|
259
|
+
query: clients.sandboxEnabled(sandbox) ? { include_sandbox: 1 } : undefined,
|
|
260
|
+
})));
|
|
245
261
|
for (const action of ['start', 'stop', 'rebuild']) {
|
|
246
262
|
const name = `cloud_service_${action}`;
|
|
247
263
|
server.registerTool(name, {
|
|
248
264
|
title: `${action} service MONA Cloud`,
|
|
249
265
|
description: action === 'stop'
|
|
250
266
|
? 'Dừng VPS/database MONA Cloud; luôn cho phép dừng để người dùng hạn chế chi phí.'
|
|
251
|
-
: `${action} VPS/database MONA Cloud. Lệnh có thể phát sinh chi phí và kiểm tra ví trước.`,
|
|
252
|
-
inputSchema: { service_id: z.string().min(1) },
|
|
253
|
-
}, ({ service_id }) => runTool(async () => {
|
|
267
|
+
: `${action} VPS/database MONA Cloud. Lệnh có thể phát sinh chi phí và kiểm tra ví trước. ${SANDBOX_DESCRIPTION}.`,
|
|
268
|
+
inputSchema: { service_id: z.string().min(1), sandbox: sandboxSchema },
|
|
269
|
+
}, ({ service_id, sandbox }) => runTool(async () => {
|
|
270
|
+
const path = `/api/services/${encodeURIComponent(service_id)}/${action}`;
|
|
254
271
|
if (action !== 'stop')
|
|
255
|
-
|
|
256
|
-
return clients.vibecloud(
|
|
272
|
+
return clients.guardedVibecloud(path, { method: 'POST' }, sandbox);
|
|
273
|
+
return clients.vibecloud(path, { method: 'POST' });
|
|
257
274
|
}));
|
|
258
275
|
server.registerTool(`vibecloud_${action}`, {
|
|
259
276
|
title: `Alias cũ của ${name}`,
|
|
260
|
-
description: `Alias tương thích; dùng ${name} cho tích hợp mới
|
|
261
|
-
inputSchema: { service_id: z.string().min(1) },
|
|
262
|
-
}, ({ service_id }) => runTool(async () => {
|
|
277
|
+
description: `Alias tương thích; dùng ${name} cho tích hợp mới.${action === 'stop' ? '' : ` ${SANDBOX_DESCRIPTION}.`}`,
|
|
278
|
+
inputSchema: { service_id: z.string().min(1), sandbox: sandboxSchema },
|
|
279
|
+
}, ({ service_id, sandbox }) => runTool(async () => {
|
|
280
|
+
const path = `/api/services/${encodeURIComponent(service_id)}/${action}`;
|
|
263
281
|
if (action !== 'stop')
|
|
264
|
-
|
|
265
|
-
return clients.vibecloud(
|
|
282
|
+
return clients.guardedVibecloud(path, { method: 'POST' }, sandbox);
|
|
283
|
+
return clients.vibecloud(path, { method: 'POST' });
|
|
266
284
|
}));
|
|
267
285
|
}
|
|
268
286
|
server.registerTool('cloud_prices', {
|
|
@@ -283,14 +301,14 @@ export function createServer(dependencies = {}) {
|
|
|
283
301
|
}, () => runTool(() => clients.packages()));
|
|
284
302
|
server.registerTool('cloud_agent_deploy', {
|
|
285
303
|
title: 'Deploy MONA Agent trên MONA Cloud',
|
|
286
|
-
description:
|
|
287
|
-
inputSchema: { template: z.string().regex(/^[a-z0-9][a-z0-9-]{0,79}$/) },
|
|
288
|
-
}, ({ template }) => runTool(() => agentRuntimeStub(template)));
|
|
304
|
+
description: `Slot runtime agent wave kế tiếp; hiện trả trạng thái stub rõ ràng. ${SANDBOX_DESCRIPTION}.`,
|
|
305
|
+
inputSchema: { template: z.string().regex(/^[a-z0-9][a-z0-9-]{0,79}$/), sandbox: sandboxSchema },
|
|
306
|
+
}, ({ template, sandbox }) => runTool(() => agentRuntimeStub(template, clients.sandboxEnabled(sandbox))));
|
|
289
307
|
server.registerTool('vibecloud_agent_deploy', {
|
|
290
308
|
title: 'Alias cũ của cloud_agent_deploy',
|
|
291
|
-
description:
|
|
292
|
-
inputSchema: { template: z.string().regex(/^[a-z0-9][a-z0-9-]{0,79}$/) },
|
|
293
|
-
}, ({ template }) => runTool(() => agentRuntimeStub(template)));
|
|
309
|
+
description: `Alias tương thích; dùng cloud_agent_deploy cho tích hợp mới. ${SANDBOX_DESCRIPTION}.`,
|
|
310
|
+
inputSchema: { template: z.string().regex(/^[a-z0-9][a-z0-9-]{0,79}$/), sandbox: sandboxSchema },
|
|
311
|
+
}, ({ template, sandbox }) => runTool(() => agentRuntimeStub(template, clients.sandboxEnabled(sandbox))));
|
|
294
312
|
server.registerTool('agent_templates_list', {
|
|
295
313
|
title: 'Catalog MONA Agent',
|
|
296
314
|
description: 'Đọc template từ thư mục local, URL catalog hoặc catalog wave 1 tích hợp.',
|
package/docs/ai-agent.md
CHANGED
|
@@ -5,7 +5,7 @@ Tài liệu này dành cho Claude, Codex, Cursor và agent dùng Model Context P
|
|
|
5
5
|
## Quy tắc vận hành
|
|
6
6
|
|
|
7
7
|
1. Bắt đầu bằng `cloud_whoami`. Nếu nhận `login_required`, yêu cầu người dùng chạy `monacloud-mcp login`; không hỏi username hoặc password trong chat.
|
|
8
|
-
2. Trước khi provision, đọc `cloud_balance`, `cloud_packages` và `cloud_prices`.
|
|
8
|
+
2. Trước khi provision thật, đọc `cloud_balance`, `cloud_packages` và `cloud_prices`. Với `sandbox: true`, không cần đọc hoặc nạp ví.
|
|
9
9
|
3. Khi cần nạp, gọi `cloud_topup`; đưa nguyên `qr_data_url`, số tiền, nội dung và hạn thanh toán cho người dùng. Chỉ tiếp tục sau khi `cloud_balance` phản ánh tiền vào.
|
|
10
10
|
4. Với OTP ngân hàng, dừng đúng sau `monapay_link_bank_start` và `monapay_notification_register`. Hỏi người dùng mã vừa nhận; không suy đoán, brute-force hoặc ghi OTP vào source/log.
|
|
11
11
|
5. Mọi endpoint webhook phải xác minh HMAC, chống replay theo timestamp và idempotent theo `transaction_code`.
|
|
@@ -130,7 +130,7 @@ Deploy source lên VPS từ credential của job, đưa database connection stri
|
|
|
130
130
|
|
|
131
131
|
## Spend guard
|
|
132
132
|
|
|
133
|
-
`cloud_vps_create`, `cloud_db_create`, `cloud_service_start` và `cloud_service_rebuild` đọc `GET /v1/balance` trước khi gọi sản phẩm. Upstream vẫn là nguồn quyết định cuối và có thể trả:
|
|
133
|
+
`cloud_vps_create`, `cloud_db_create`, `cloud_service_start` và `cloud_service_rebuild` đọc `GET /v1/balance` trước khi gọi sản phẩm thật. Upstream vẫn là nguồn quyết định cuối và có thể trả:
|
|
134
134
|
|
|
135
135
|
```json
|
|
136
136
|
{
|
|
@@ -142,6 +142,21 @@ Deploy source lên VPS từ credential của job, đưa database connection stri
|
|
|
142
142
|
|
|
143
143
|
hoặc `budget_exceeded`. Khi gặp hai code này, không retry. Gọi `cloud_topup`, `cloud_budget_get` hoặc yêu cầu user tăng budget. `cloud_service_stop` luôn được phép vì chặn stop có thể làm tăng rủi ro chi phí.
|
|
144
144
|
|
|
145
|
+
## Thử 0đ bằng sandbox
|
|
146
|
+
|
|
147
|
+
Thêm `sandbox: true` khi gọi `cloud_vps_create`, `cloud_db_create`, `cloud_service_start`, `cloud_service_rebuild` hoặc `cloud_agent_deploy`. Có thể đặt `MONACLOUD_SANDBOX=1` để bật cho toàn bộ MCP process. Alias `vibecloud_*` tương ứng hoạt động giống hệt.
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
cloud_vps_create({ app_name: "shop-demo", package_slug: "standard-2", sandbox: true })
|
|
151
|
+
cloud_db_create({ app_name: "shop-demo", engine: "postgresql", package_slug: "standard-2", sandbox: true })
|
|
152
|
+
cloud_job_status({ job_id: "...", sandbox: true })
|
|
153
|
+
cloud_services_list({ sandbox: true })
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Với lệnh tạo/start/rebuild sandbox, MCP không gọi Billing, tự gửi `X-Vibecloud-Sandbox: 1`, và response có `sandbox: true`. `cloud_job_status` tra job theo ID mà không cần header; trạng thái `done` là terminal hợp lệ của sandbox. `cloud_services_list({ sandbox: true })` dùng `include_sandbox=1`, cũng không cần header, để gộp service thật và sandbox.
|
|
157
|
+
|
|
158
|
+
Sandbox không gọi Proxmox, không cấp IP thật, không trừ tiền và có TTL do compute API quản lý. Chỉ chuyển sang lệnh thật khi người dùng yêu cầu rõ ràng. `cloud_agent_deploy` hiện vẫn trả `agent_runtime_pending`; sandbox chỉ đánh dấu response nhất quán, không giả vờ đã deploy.
|
|
159
|
+
|
|
145
160
|
## Catalog MONA Agent
|
|
146
161
|
|
|
147
162
|
`agent_templates_list` trả nguồn catalog và danh sách slug. `agent_templates_get` trả toàn bộ file text cần để agent build local. Không tự nối path từ input ngoài; chỉ dùng slug đã trả.
|