Tool Plane: danh mục tool và cách thêm một tool
Trang này liệt kê những năng lực Tool Plane thật sự có, và mô tả đường đúng để thêm một năng lực mới. Danh mục cố tình ngắn: mục tiêu của MVP là chứng minh một vòng lặp, không phải có nhiều tool.
Danh mục hiện có
github.*
| Tool | Rủi ro | Làm gì |
|---|---|---|
github.get_repository | thấp | Đọc repo: nhánh mặc định, chế độ hiển thị, mô tả |
github.get_file | thấp | Đọc một file tại một ref, trả về UTF-8 đã giải mã |
github.create_branch | thấp | Tạo nhánh từ một nhánh gốc |
github.commit | trung bình | Ghi nhiều file trong một commit |
github.create_pull_request | trung bình | Mở PR |
github.get_pull_request | thấp | Trạng thái, khả năng merge, head sha |
github.get_ci_status | thấp | Gộp combined status và check runs, kèm danh sách đang đỏ |
Xác thực bằng GitHub App, không phải personal access token. Lý do là ba điều, và cả ba đều quan trọng: token cài đặt của App chỉ có phạm vi các repo đã cài, hết hạn sau một giờ, và thu hồi được mà không đụng tới tài khoản của một con người nào.
Token cài đặt được đúc trong Worker, giữ trong bộ nhớ ngắn hạn, và không bao giờ rời khỏi đó.
cloudflare.*
| Tool | Rủi ro | Làm gì |
|---|---|---|
cloudflare.get_worker | thấp | Đọc metadata một Worker |
cloudflare.get_deployment | thấp | Lịch sử deploy gần nhất |
cloudflare.get_d1 | thấp | Metadata một cơ sở dữ liệu D1 |
cloudflare.deploy_staging | trung bình | Kích hoạt workflow CI deploy staging → trả operation_id |
cloudflare.deploy_production | tới hạn | Như trên, nhưng luôn phải có người duyệt |
Đọc thì gọi thẳng REST API của Cloudflare bằng token phía máy chủ. Ghi thì không, xem vì sao deploy đi qua CI.
conan.*
| Tool | Rủi ro | Làm gì |
|---|---|---|
conan.list_courses | thấp | Liệt kê khoá học kèm số unit |
conan.get_course | thấp | Một khoá theo slug, kèm các unit |
Đọc thẳng qua binding D1, không qua REST API, không cần đúc token, không có egress, không dính giới hạn tần suất, và câu truy vấn nằm ngay trong repo này thay vì ẩn sau một lượt gọi HTTP.
Executor này không có đường ghi, và đó là chủ ý
conan.* chỉ đọc. Từ 03.09.2026 ai viết nội dung khoá học cũng được, nhưng hàng rào còn lại là vào repo trước, D1 sau ([luật nền](/curriculum/content-ops#luat-nen-ai-viet-cung-đuoc-tu-03-09-2026-, -nhung-vao-repo-truoc-d1-sau)). Một tool cho phép agent ghi nội dung học thẳng vào D1 phá đúng hàng rào đó, và đi vòng qua POST /ops/audit/:slug lẫn course_content_runs. Agent muốn viết nội dung thì viết migration và mở PR. Tool Plane không được trở thành cái cửa sau.
plane.*
| Tool | Làm gì |
|---|---|
plane.get_operation | Trạng thái, tiến độ, kết quả của một việc chạy lâu |
plane.get_approval | Trạng thái một lượt gọi đang đỗ chờ duyệt, kèm bước tiếp theo viết bằng lời |
Một agent chỉ xem được operation và approval của chính nó.
Lỗi nói được thành hành động
Mọi thất bại, của ta hay của API bên ngoài, đều mang cùng một hình dạng:
{
"success": false,
"error": {
"code": "GITHUB_PERMISSION_DENIED",
"message": "The agent does not have permission to modify this repository",
"retryable": false
}
}retryable là trường quan trọng nhất. Một agent không biết thử lại có ích không sẽ hoặc thử lại vô nghĩa cho tới khi hết lượt, hoặc bỏ cuộc trước một trục trặc thoáng qua. Cả hai đều là hỏng, và cả hai đều tránh được bằng một trường boolean.
Ánh xạ mã trạng thái: 401/403 → _PERMISSION_DENIED (không thử lại) · 404 → _NOT_FOUND · 409 → _CONFLICT · 422 → _INVALID_REQUEST · 429 → _RATE_LIMITED (thử lại được) · 5xx → _UPSTREAM_ERROR (thử lại được).
Thân lỗi từ API bên ngoài luôn đi qua bộ che trước khi tới agent, API đôi khi vọng lại chính token trong thông báo lỗi. Có một bài kiểm riêng cho việc này.
Thêm một tool
Bốn chỗ, theo thứ tự:
- Định nghĩa trong
src/registry/tools.ts, tên, mô tả, danh mục, mức rủi ro, cờ duyệt, schemazod, và hai hàmresourceOf/environmentOf. - Thi hành, một nhánh
casetrong executor tương ứng. - Đồng bộ registry,
POST /admin/registry/syncsau khi deploy. - Cấp quyền,
POST /admin/agents/:id/grants. Chưa cấp thì chưa agent nào gọi được, kể cả sau khi tool đã lên.
Mô tả trường là thứ model đọc
.describe() trên mọi trường zod chảy thẳng vào JSON Schema mà MCP trả về. Đó là toàn bộ thứ model dựa vào để điền đúng đối số. Một trường không có mô tả là một trường model sẽ đoán.
resourceOf không phải trang trí
Hàm này quyết định lượt gọi bị soi theo phạm vi nào và ghi vào vết kiểm toán thế nào. Trả về null nghĩa là "lượt gọi này không chạm tài nguyên nào", và một grant có phạm vi sẽ không khớp nó. Viết sai resourceOf là cách êm ái nhất để làm hỏng phân quyền mà mọi bài kiểm vẫn xanh.
Chọn mức rủi ro
| Mức | Nghĩa là | Ví dụ |
|---|---|---|
low | Chỉ đọc, không đổi gì | github.get_file |
medium | Ghi, nhưng hoàn tác được | github.commit |
high | Ghi khó hoàn tác | merge PR |
critical | Chạm production hoặc phá được | cloudflare.deploy_production |
critical phải kèm requiresApproval: true. Đây là quy ước con người phải giữ; hãy đặt câu hỏi này trong lúc review, vì mã không hỏi hộ.
Danh mục agent được thấy
tools/list chỉ trả về những tool agent thật sự có grant khác deny, và chưa bị tắt.
Đây không phải biện pháp an toàn, máy chính sách mới là. Nhưng một tool agent không gọi được là một thứ nó sẽ tiêu tốn lượt để thử, và một danh mục nói dối về năng lực còn tệ hơn một danh mục ngắn.
Tool đáng thêm tiếp: và điều kiện
Không thêm cho tới khi vòng lặp đầu chạy ổn định.
| Tool | Điều kiện trước khi thêm |
|---|---|
github.merge_pull_request | Phải là high + bắt buộc duyệt. Merge là hành động khó lùi. |
github.create_issue, github.comment_issue | Cần giới hạn tần suất riêng, chặt hơn mặc định |
cloudflare.create_d1, create_r2_bucket | Cần chính sách hạn ngạch; tạo tài nguyên là tạo hoá đơn |
coral.*, nemo.* | Chỉ khi các hệ đó đã có ranh giới đọc/ghi rõ ràng |
| Bất kỳ tool nào ghi nội dung học | Không. Xem luật tối thượng ở trên. |