Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 2 — Kiến trúc Client–Server và luồng giao tiếp MCP

Đã đọc 0/9 mục · còn khoảng 4 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Để xây được MCP, bạn phải nắm rõ ai là ai và dữ liệu chảy theo hướng nào. Bài này bóc tách kiến trúc và vòng đời một phiên MCP.

Ba vai trò

  • Host — ứng dụng chứa agent (ví dụ: Claude Desktop, IDE, app chatbot của bạn). Host quản lý model và điều phối.
  • Client — thành phần bên trong host, giữ một kết nối 1–1 tới một MCP server. Một host có nhiều client nếu kết nối nhiều server.
  • Server — chương trình phơi bày tools/resources/prompts của một hệ thống.
> Khung tư duy: Host là tòa nhà, Client là các ổ cắm trên tường, Server là thiết bị bạn cắm vào. Mỗi ổ cắm nối tới đúng một thiết bị.

Giao thức bên dưới: JSON-RPC 2.0

MCP dùng JSON-RPC 2.0 để trao đổi message. Có ba loại message:

  • Request (có id, cần phản hồi): tools/call, resources/read.
  • Response (khớp id của request): chứa result hoặc error.
  • Notification (không id, không cần phản hồi): ví dụ thông báo danh sách tool thay đổi.
Một request gọi tool trông như sau:

{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "tools/call",
  "params": {
    "name": "query_orders",
    "arguments": { "phone": "0909123456" }
  }
}

Server trả về:

{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "content": [{ "type": "text", "text": "Đơn #4821 đang giao" }]
  }
}

Vòng đời một phiên

  • Khởi tạo (initialize): client gửi request initialize, khai báo phiên bản protocol và khả năng (capabilities) của mình.
  • Đàm phán capabilities: server đáp lại, cho biết nó hỗ trợ tools/resources/prompts nào.
  • Xác nhận (initialized): client gửi notification báo đã sẵn sàng.
  • Khám phá (discovery): client gọi tools/list, resources/list để biết server có gì.
  • Sử dụng: client gọi tools/call, resources/read khi agent cần.
  • Đóng phiên: khi host tắt hoặc ngắt kết nối.
Bước 1–3 là handshake. Bỏ qua nó thì server không chấp nhận request.

Ví dụ luồng đầy đủ

Client → initialize (protocolVersion, capabilities)
Server → result (capabilities: tools, resources)
Client → notifications/initialized
Client → tools/list
Server → result [query_orders, refund_order]
... (agent quyết định cần gọi tool) ...
Client → tools/call query_orders {phone}
Server → result (đơn hàng)

Điểm mấu chốt: agent quyết định, client thực thi

MCP client không tự quyết định gọi tool nào. Nó cung cấp danh sách tool cho model; model (agent) chọn tool và tham số dựa trên câu hỏi người dùng; rồi client mới thực thi lời gọi qua server. Đây là lý do mô tả tool phải rõ ràng — model đọc mô tả để chọn đúng.

Capabilities: hai bên khai báo mình làm được gì

Bước handshake không chỉ là chào hỏi. Nó là lúc client và server đàm phán capabilities — mỗi bên tuyên bố mình hỗ trợ tính năng nào. Ví dụ server khai báo có tools và resources nhưng không có prompts; client khai báo hỗ trợ sampling (cho phép server nhờ model sinh text) hay không. Nhờ đàm phán này, hai bên ở các phiên bản khác nhau vẫn hợp tác được: chỉ dùng phần cả hai cùng hỗ trợ. Đây là cơ chế giúp MCP tiến hóa mà không phá vỡ hệ thống cũ — một điểm rất quan trọng khi bạn vận hành nhiều server ở nhiều phiên bản.

Một khả năng nâng cao đáng biết là sampling: server có thể yêu cầu client (host) chạy model để hoàn thành một tác vụ con — ví dụ tóm tắt một đoạn dữ liệu trước khi trả về. Ngược hướng thông thường, nhưng vẫn do client kiểm soát (client có thể từ chối hoặc lọc). Bạn chưa cần dùng ngay, nhưng biết nó tồn tại giúp bạn hiểu tại sao MCP không đơn thuần là "client hỏi, server đáp".

Checklist thiết kế luồng

  • [ ] Đã có bước handshake initialize trước mọi request chưa?
  • [ ] Client có gọi tools/list để khám phá thay vì hardcode tên tool?
  • [ ] Mỗi request có id duy nhất để khớp response?
  • [ ] Notification (như tools/list_changed) được xử lý để cập nhật danh sách?

Sai lầm thường gặp

  • Gọi tool trước khi handshake xong. Server sẽ từ chối; luôn đợi initialized.
  • Nhầm hướng gọi: nghĩ server chủ động đẩy lệnh cho agent. Không — client khởi xướng request; server phản hồi (trừ notification/sampling nâng cao).
  • Hardcode danh sách tool trong client thay vì tools/list. Khi server thêm/bớt tool, client sẽ lệch.
  • Trộn id giữa các request song song, khiến response gắn nhầm. Mỗi request phải có id riêng và client phải khớp đúng.
Hiểu kiến trúc rồi, bài 3 ta bàn về transport — kênh vật lý client và server dùng để nói chuyện (stdio vs HTTP/SSE) và khi nào chọn cái nào.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi