Chương 9. MCP Server
Back To BlogsChương 9. MCP Server
📚 Mục lục sáchỞ Chương 3, bạn đã cài đặt MCP Server như một bước "nâng cao" trong bộ công cụ làm việc. Đến đây, sau khi đã biết cách xây dựng giao diện và chức năng cùng AI, đã đến lúc tìm hiểu kỹ MCP Server thực sự làm được gì — và vì sao nó là mảnh ghép giúp AI Assistant của bạn không chỉ viết code, mà còn "nhìn thấy" dữ liệu thật trên EzyPlatform.
MCP Server là gì?
MCP Server — viết tắt của Model Context Protocol Server — cho phép AI Assistant không chỉ sinh code tĩnh, mà còn có thể truy vấn và thao tác trực tiếp với dữ liệu thật trên EzyPlatform của bạn. Ví dụ, thay vì phải đoán hoặc viết code mẫu, bạn có thể hỏi thẳng AI "cho tôi biết 5 sản phẩm bán chạy nhất tuần này", và AI sẽ tự lấy dữ liệu thật để trả lời.
Đây là bước tiến quan trọng: AI không còn chỉ là công cụ viết code, mà trở thành một trợ lý có thể "nhìn thấy" dữ liệu thật của bạn để đưa ra quyết định và hành động chính xác hơn.
Cách hoạt động, nhìn từ góc độ của bạn, rất đơn giản: bạn hỏi bằng lời bình thường, AI chuyển câu hỏi đó thành một yêu cầu gửi tới MCP Server, MCP Server lấy đúng dữ liệu thật rồi trả về cho AI, và AI diễn giải lại thành câu trả lời:
flowchart LR
A["Bạn hỏi bằng lời"] --> B["AI + MCP Server"]
B --> C[("Dữ liệu thật")]
C --> B --> D["Câu trả lời chính xác"]
classDef user fill:#db2777,stroke:#9d174d,color:#ffffff;
classDef ai fill:#6366f1,stroke:#4338ca,color:#ffffff;
classDef data fill:#10b981,stroke:#047857,color:#ffffff;
class A,D user;
class B ai;
class C data;
linkStyle default stroke:#94a3b8,stroke-width:1.5px;
Cho tôi biết 5 sản phẩm bán chạy nhất tuần này, kèm số lượng đã bán và doanh thu mang lại của từng sản phẩm.
Với MCP Server được kết nối, AI không trả lời chung chung — nó truy vấn thẳng vào dữ liệu thật của bạn rồi mới trả lời.
Bên trong MCP Server có những gì?
Bạn có thể hình dung MCP Server như một "quầy dịch vụ" đứng giữa AI và EzyPlatform: nó không tự nghĩ ra câu trả lời, mà cung cấp cho AI một bộ "công cụ" (mỗi công cụ làm đúng một việc — ví dụ tra một danh sách, lưu một cấu hình, kiểm tra một cú pháp) để AI tự chọn dùng đúng công cụ phù hợp với từng yêu cầu của bạn. EzyPlatform trang bị sẵn hàng chục công cụ như vậy, chia thành năm nhóm việc chính:
flowchart TD
M["MCP Server<br/>hàng chục công cụ"] --> A["Tạo & quản lý fetcher"]
M --> N["Tạo & quản lý event handler"]
M --> B["Tra cứu dữ liệu có sẵn"]
M --> C["Quản lý nội dung & cấu hình"]
M --> D["Tra bản đồ hệ thống"]
classDef mcp fill:#3b82f6,stroke:#1d4ed8,color:#ffffff;
classDef fetcher fill:#6366f1,stroke:#4338ca,color:#ffffff;
classDef event fill:#8b5cf6,stroke:#6d28d9,color:#ffffff;
classDef lookup fill:#10b981,stroke:#047857,color:#ffffff;
classDef manage fill:#db2777,stroke:#9d174d,color:#ffffff;
classDef map fill:#f59e0b,stroke:#b45309,color:#ffffff;
class M mcp;
class A fetcher;
class N event;
class B lookup;
class C manage;
class D map;
linkStyle default stroke:#94a3b8,stroke-width:1.5px;
| Nhóm công cụ | Việc nó làm | Vài ví dụ |
|---|---|---|
| Tạo & quản lý fetcher | Giúp AI tự "sáng tác" một câu truy vấn dữ liệu hoàn toàn mới khi chưa có sẵn, kiểm tra và xuất bản an toàn | create_graphql_fetcher_draft, validate_graphql_fetcher, save_graphql_fetcher |
| Tạo & quản lý event handler | Giúp AI viết kịch bản tự động chạy khi một sự kiện có sẵn trong hệ thống xảy ra, cùng cơ chế kiểm tra/xuất bản an toàn như fetcher | validate_event_handler, list_event_handlers, save_event_handler |
| Tra cứu dữ liệu có sẵn | Trả lời nhanh bằng dữ liệu đã có sẵn hoặc chạy một câu truy vấn đơn giản, không cần tạo fetcher mới | search_posts, search_pages, admin_graphql_data_fetching |
| Quản lý nội dung & cấu hình | Tạo hoặc sửa trực tiếp mẫu email, mẫu nội dung, danh mục, bản dịch đa ngôn ngữ thay bạn | save_mail_template, save_content_template, save_i18n_messages |
| Tra "bản đồ" hệ thống | Cho AI biết hệ thống đang có sẵn những loại dữ liệu và chức năng nào, trước khi thao tác — tránh đoán mò | get_web_graphql_schema, get_admin_swagger |
Ngoài các công cụ để "hành động" ở trên, MCP Server còn cấp cho AI một loại thứ hai: guide resource — những tài liệu hướng dẫn AI đọc trước khi bắt tay vào việc, giống như bạn đọc kỹ hướng dẫn sử dụng trước khi lắp một món đồ mới, thay vì lắp bừa rồi sửa sau. EzyPlatform có sẵn hai guide resource quan trọng nhất:
- Cẩm nang viết fetcher (
guide://graphql-fetcher-authoring): hướng dẫn từng bước AI phải làm khi tạo một câu truy vấn dữ liệu mới — kiểm tra trùng tên, kiểm tra cú pháp, hỏi bạn trước khi xuất bản. - Cẩm nang viết event handler (
guide://event-handler-authoring): hướng dẫn tương tự nhưng dành riêng cho kịch bản gắn vào sự kiện, kèm lưu ý về cách đặt tên cho "ezy function".
Nhờ đọc guide resource trước, AI không cần bạn nhắc lại quy tắc an toàn mỗi lần trò chuyện — quy tắc đã được "đóng gói" sẵn cùng bộ công cụ, AI tự động tuân theo ngay từ lần đầu sử dụng.
Phần còn lại của chương này sẽ đi sâu vào hai nhóm công cụ đặc biệt nhất — nhóm giúp AI tự tạo ra một câu truy vấn dữ liệu hoàn toàn mới (fetcher), và nhóm giúp AI tự viết kịch bản chạy khi có việc gì đó xảy ra (event handler) — vì đây là nơi thể hiện rõ nhất sự khác biệt giữa MCP Server và một API thông thường.
Fetcher: câu truy vấn dữ liệu do AI tự tạo
Điều thú vị hơn nữa: AI có thể tự tạo ra một "câu truy vấn dữ liệu" hoàn toàn mới — gọi là fetcher — để trả lời một câu hỏi mà trước đó hệ thống chưa từng hỗ trợ, mà không cần lập trình viên can thiệp, không cần build lại phần mềm, không cần khởi động lại máy chủ.
Tôi muốn xem doanh thu theo từng danh mục sản phẩm trong tháng này, sắp xếp từ cao xuống thấp.
Nếu chưa có sẵn câu truy vấn nào trả lời đúng câu hỏi trên, AI sẽ tự viết một fetcher mới để làm việc đó — thay vì trả lời "tôi không có dữ liệu này".
- Không cần hạ tầng riêng cho fetcher: mỗi fetcher thực chất được lưu như một bài viết bình thường trong CMS — tên truy vấn đóng vai trò "slug", đoạn kịch bản xử lý đóng vai trò "nội dung", còn mô tả dữ liệu vào/ra được lưu như "tóm tắt". Nhờ vậy hệ thống tái dùng toàn bộ cơ chế lưu trữ, phân quyền và xuất bản (nháp/công khai) vốn đã có sẵn cho bài viết, thay vì phải xây riêng một hạ tầng mới.
- Sửa xong là chạy ngay, không cần build/deploy: mỗi khi có yêu cầu, hệ thống luôn đọc lại nội dung fetcher mới nhất trực tiếp từ cơ sở dữ liệu rồi thực thi ngay, chứ không giữ lại bản cũ trong bộ nhớ đệm. Vì vậy khi bạn (hoặc AI) chỉnh sửa và xuất bản một fetcher trong trang quản trị, thay đổi có hiệu lực ngay ở lượt truy cập kế tiếp — không cần chờ đội kỹ thuật build và triển khai lại như một máy chủ GraphQL truyền thống.
- Kịch bản chạy trong một "hộp cát" riêng: đoạn code xử lý dữ liệu được viết bằng JavaScript, nhưng chạy trên một engine JavaScript gọn nhẹ nhúng sẵn trong máy chủ (Mozilla Rhino), không phải Node.js. Vì vậy fetcher sẽ không dùng được thư viện cài qua npm hay các cú pháp bất đồng bộ hiện đại (async/await) — đổi lại nó được cấp sẵn quyền truy cập trực tiếp vào các thành phần dùng chung của hệ thống, thay vì phải tự viết code kết nối từ đầu.
Vì fetcher được lưu và đọc lại y như một bài viết, luồng hoạt động của nó rất dễ hình dung:
flowchart LR
A["AI viết fetcher,<br/>lưu như một bài viết"] --> B["Có câu hỏi mới:<br/>đọc lại bản mới nhất"]
B --> C["Chạy ngay,<br/>không cần build/deploy"]
classDef ai fill:#6366f1,stroke:#4338ca,color:#ffffff;
classDef store fill:#3b82f6,stroke:#1d4ed8,color:#ffffff;
classDef run fill:#10b981,stroke:#047857,color:#ffffff;
class A ai;
class B store;
class C run;
linkStyle default stroke:#94a3b8,stroke-width:1.5px;
Kịch bản của fetcher được phép "nhìn thấy" và "dùng" những gì?
Để trả lời được câu hỏi của bạn, kịch bản của fetcher cần được cấp một số thông tin và quyền truy cập nhất định — nhưng chỉ trong phạm vi cần thiết, không phải toàn quyền trên hệ thống:
- Tham số của câu hỏi: ví dụ khi bạn hỏi "top 5 sản phẩm bán chạy nhất tuần này", con số 5 và khoảng thời gian "tuần này" được truyền thẳng vào kịch bản như tham số đầu vào.
- Ai đang hỏi: nếu câu hỏi đến từ một trang trên website (không phải từ trang quản trị), fetcher còn biết được người dùng nào đang đăng nhập và thuộc nhóm quyền nào — để chỉ trả về đúng dữ liệu người đó được phép xem, ví dụ đơn hàng của chính khách hàng đó chứ không phải của người khác.
- "Chìa khóa" vào các dịch vụ dữ liệu có sẵn: thay vì phải tự viết code kết nối cơ sở dữ liệu từ đầu, fetcher được cấp sẵn quyền gọi tới các dịch vụ dữ liệu đã có của hệ thống (ví dụ dịch vụ tra cứu bài viết, dịch vụ truy vấn có điều kiện) — giống như được phát sẵn chìa khóa vào đúng những phòng cần vào, thay vì phải tự đục tường.
- Ghi log để gỡ lỗi: fetcher có thể ghi lại thông tin trong lúc chạy, giúp AI (hoặc bạn) xem lại và tìm nguyên nhân nếu kết quả trả về không đúng như mong đợi.
Event handler: kịch bản tự động chạy khi có việc gì đó xảy ra
Nếu fetcher trả lời khi bạn chủ động hỏi, thì event handler lại làm việc ngược lại: nó tự động chạy khi một sự kiện đã có sẵn trong hệ thống xảy ra, mà không cần ai hỏi gì cả. EzyPlatform đã sẵn một số "điểm móc nối" (sự kiện) ở những bước quan trọng — ví dụ ngay trước khi một tài khoản mới hoàn tất đăng ký, hay khi cần hiển thị khung xem trước cho một tệp media trong trang quản trị. AI có thể viết một kịch bản gắn vào đúng điểm đó để kiểm tra thêm điều kiện hoặc tùy biến hành vi ở bước ấy, thay vì bạn phải nhờ lập trình viên chỉnh sửa sâu vào hệ thống.
Trước khi cho phép đăng ký tài khoản mới, hãy kiểm tra thêm là email không thuộc các domain dùng một lần như mailinator.com hay 10minutemail.com. Nếu vi phạm, từ chối đăng ký kèm thông báo phù hợp.
Event handler dùng chung nền tảng với fetcher — cũng là một kịch bản JavaScript chạy trong "hộp cát" Rhino, cũng được lưu như một bài viết trong CMS — nhưng có hai điểm khác biệt đáng chú ý:
- Trigger là tên sự kiện có sẵn, không phải câu hỏi tự do: thay vì "tên truy vấn" như fetcher, event handler dùng đúng tên của sự kiện muốn gắn vào làm định danh. AI có công cụ riêng để tra cứu trước những sự kiện nào đang có sẵn trong hệ thống, thay vì đoán mò.
- Bản nháp không bao giờ được kích hoạt: khác với fetcher (vốn luôn đọc bản mới nhất mỗi lần được gọi), một event handler chỉ thực sự chạy khi sự kiện xảy ra nếu đã ở trạng thái xuất bản — bản nháp hoàn toàn vô hình với hệ thống, dù đã lưu sẵn trong CMS. Đây là một lớp an toàn bổ sung: bạn có thể nhờ AI chuẩn bị trước một event handler mà không lo nó lỡ chạy khi chưa sẵn sàng.
Đây cũng chính là cơ chế đứng sau việc tạo "hàm tùy chỉnh" (ezy function) mà bạn có thể gọi trực tiếp trong trang hoặc bài viết — nhờ AI viết một event handler cho một cái tên hàm mới, xuất bản xong là gọi được ngay trong template, không cần build lại phần mềm.
Quy trình an toàn khi AI tạo fetcher và event handler
Vì cả fetcher lẫn event handler đều chỉ là những đoạn kịch bản lưu trong CMS nên về lý thuyết AI có thể tự tạo và chỉnh sửa chúng bất cứ lúc nào. Để việc đó vừa hiệu quả vừa an toàn, EzyPlatform trang bị cho AI hai guide resource riêng — chính là "cẩm nang" đã nhắc ở phần trước — đóng vai trò kim chỉ nam, buộc AI phải đi qua đúng các bước sau trước khi một thay đổi thực sự ảnh hưởng đến hệ thống thật (ví dụ dưới đây minh hoạ cho fetcher, nhưng event handler cũng đi qua đúng các bước tương tự — chỉ thay "tên truy vấn" bằng "tên sự kiện"):
flowchart TD
A["AI định tạo một fetcher mới"] --> B{"Tên truy vấn đã tồn tại chưa?"}
B -- "Đã tồn tại" --> C["Hỏi bạn: sửa fetcher cũ hay đặt tên khác"]
B -- "Chưa có" --> D["Tạo bản nháp, tự kiểm tra cú pháp và xem trước dữ liệu"]
C --> D
D --> E{"Bạn muốn lưu nháp hay xuất bản?"}
E -- "Lưu nháp" --> F["Lưu ở trạng thái nháp"]
E -- "Xuất bản" --> G["Hỏi bạn xác nhận rõ ràng"]
G -- "Đồng ý" --> H["Xuất bản, có hiệu lực ngay"]
G -- "Chưa đồng ý" --> F
classDef decision fill:#f59e0b,stroke:#b45309,color:#ffffff;
classDef ai fill:#6366f1,stroke:#4338ca,color:#ffffff;
classDef ask fill:#db2777,stroke:#9d174d,color:#ffffff;
classDef done fill:#10b981,stroke:#047857,color:#ffffff;
class A ai;
class B,E decision;
class C,G ask;
class D,F,H done;
linkStyle default stroke:#94a3b8,stroke-width:1.5px;
- Kiểm tra trùng tên trước tiên: AI luôn phải tra lại danh sách fetcher đã có — dù đang ở trạng thái nháp hay đã công khai — trước khi đề xuất một tên truy vấn mới. Nếu tên đó đã tồn tại, AI bắt buộc phải hỏi bạn muốn sửa lại fetcher cũ hay đặt một tên khác, không được tự ý ghi đè.
- Tạo và kiểm tra bản nháp trước khi động vào dữ liệu thật: AI có thể tự tạo bản nháp fetcher, kiểm tra cú pháp, xem trước cấu trúc dữ liệu sẽ trả về — tất cả trước khi bất kỳ thay đổi nào được lưu chính thức.
- Luôn hỏi bạn: lưu nháp hay xuất bản: sau khi bản nháp đã ổn, AI phải hỏi rõ bạn muốn chỉ lưu tạm (nháp) hay xuất bản để dùng thật.
- Chỉ xuất bản sau khi bạn xác nhận rõ ràng: nếu bạn chọn xuất bản, AI vẫn phải hỏi lại và chờ bạn xác nhận một lần nữa trước khi công khai — đây là điểm dừng bắt buộc, AI không được tự ý quyết định thay bạn.
Với event handler, "cẩm nang" đi kèm cũng yêu cầu đúng như vậy: tra danh sách sự kiện đã đăng ký trước khi đề xuất tên mới, kiểm tra kịch bản, rồi luôn hỏi bạn muốn lưu nháp hay xuất bản — không có ngoại lệ nào cho phép AI tự ý bỏ qua bước xác nhận.
Đây chính là ranh giới giữa "vibe coding" và "yolo coding": AI được trao quyền tự động hóa rất nhiều bước, nhưng quyết định ghi đè hay công khai dữ liệu luôn phải đi qua bạn.
| Khái niệm | Vai trò |
|---|---|
| MCP Server | Cầu nối để AI Assistant truy vấn và thao tác dữ liệu thật trên EzyPlatform |
| Fetcher | Câu truy vấn dữ liệu do AI tự tạo, lưu và chạy ngay như một bài viết trong CMS |
| Event handler | Kịch bản do AI tự tạo, tự động chạy khi một sự kiện có sẵn trong hệ thống xảy ra, cũng là cách tạo ra "ezy function" gọi được trong template |
| Bản nháp / Xuất bản | Ở trạng thái nháp chỉ AI và bạn xem trước được; xuất bản rồi mới có hiệu lực thật (với event handler, bản nháp không bao giờ tự chạy) |
| Guide resource (cẩm nang) | Tài liệu AI đọc trước khi hành động, buộc AI kiểm tra trùng tên, xem trước, và luôn hỏi bạn trước khi ghi đè hoặc công khai |
Cài đặt MCP Server
Muốn AI Assistant thực sự dùng được các công cụ đã nói ở trên, bạn cần bật MCP Server ở phía máy chủ EzyPlatform, rồi kết nối VS Code tới đúng địa chỉ đó. Gồm ba bước.
Bước 1: Cấu hình phía máy chủ EzyPlatform
Để cài đặt được MCP Server, hãy đảm bảo bạn đã cài đặt thành công plugin GraphQL trên EzyPlatform (xem lại Bước 2, Chương 3). Nếu bạn đang dùng theme Freestyle, vào trang quản trị, mục GraphQL → Cài đặt, rồi dán đúng cấu hình sau vào ô Cấu hình:
graphql.packages_to_scan=org.youngmonkeys.ezyarticle.web.controller.view, org.youngmonkeys.ezyarticle.web.controller.api, org.youngmonkeys.ecommerce.web.controller.view, org.youngmonkeys.ecommerce.web.controller.api
graphql.packages_to_scan vào ô Cấu hình rồi bấm Lưu.Sau khi lưu, bạn cần khởi động lại Web để cấu hình có hiệu lực: vào Bảng điều khiển → Web, bấm Khởi động lại.
Bước 2: Kết nối VS Code tới MCP Server
Sau khi máy chủ đã sẵn sàng, quay lại VS Code và nhờ AI Assistant tự tạo file cấu hình kết nối, dựa trên đúng những thông tin đã có sẵn trong environment.json từ Chương 3:
Lưu thông tin mcp server giúp tôi vào dự án này với cú pháp:
{
"mcpServers": {
"{tên miền của admin_url mặc định lấy từ tập tin environment.json}": {
"type": "http",
"url": "{admin_url mặc định lấy từ tập tin environment.json}/graphql/mcp",
"headers": {
"Authorization": "Bearer {admin_access_token mặc định lấy từ tập tin environment.json}"
}
}
}
}
AI sẽ tự tạo một tập tin cấu hình trong dự án của bạn — ví dụ với Claude Code, tập tin đó thường có tên .mcp.json. Tên của MCP Server chính là phần tên miền của admin_url, ví dụ freestyle-admin.ezyplatform.com — bạn nên nhớ đúng tên này vì sẽ cần dùng lại ở bước tiếp theo.
Bước 3: Kiểm tra kết nối
Mở một phiên chat mới (để AI Assistant nạp lại cấu hình MCP Server vừa tạo), rồi thử hỏi:
Bạn kết nối được đến mcp server {tên mcp server của bạn} chứ?
Nếu AI báo kết nối thành công như hình trên, MCP Server đã sẵn sàng — bạn có thể bắt đầu hỏi những câu hỏi dữ liệu thật, hoặc nhờ AI tạo fetcher, event handler như các phần trước của chương.
📌 Tóm tắt chương
- MCP Server cho phép AI Assistant truy vấn và thao tác trực tiếp với dữ liệu thật, không chỉ viết code tĩnh — thông qua một bộ công cụ có sẵn mà AI tự chọn dùng cho đúng việc, cộng thêm các guide resource (cẩm nang) để AI đọc trước khi hành động.
- Fetcher là câu truy vấn dữ liệu do AI tự tạo, lưu ngay trong CMS như một bài viết, sửa xong chạy ngay không cần build/deploy.
- Event handler là kịch bản do AI tự tạo, tự động chạy khi một sự kiện có sẵn trong hệ thống xảy ra — chỉ khác fetcher ở chỗ trigger là tên sự kiện, và bản nháp không bao giờ tự kích hoạt.
- Kịch bản của fetcher/event handler chỉ được cấp đúng những gì cần: tham số đầu vào, thông tin người dùng liên quan, và "chìa khóa" vào các dịch vụ dữ liệu có sẵn — không phải toàn quyền hệ thống.
- Trước khi một fetcher hay event handler ảnh hưởng đến hệ thống thật, AI phải đi qua đủ các bước: kiểm tra trùng tên, tạo và kiểm tra bản nháp, rồi hỏi bạn xác nhận trước khi xuất bản.
- Để dùng được MCP Server, cần cấu hình plugin GraphQL và khởi động lại Web phía máy chủ, rồi nhờ AI Assistant tự tạo file kết nối trong VS Code và kiểm tra lại bằng một câu hỏi thử kết nối.
- Ranh giới giữa "vibe coding" và "yolo coding" nằm ở chỗ: tự động hóa nhiều bước, nhưng quyết định cuối cùng luôn thuộc về bạn.
Young Monkeys - Founder