Bỏ qua tới nội dung
Track 04 · Hướng dẫn

Tổng quan kiến trúc MCP

Phạm vi, các thành phần tham gia, hai tầng giao thức và ví dụ trao đổi JSON-RPC giữa MCP client và MCP server.

Cơ bản@shine190424 phút đọc

Bài này giới thiệu phạm vi và các khái niệm cốt lõi của Model Context Protocol (MCP), kèm một ví dụ minh hoạ từng khái niệm.

Vì các MCP SDK đã che bớt nhiều chi tiết, phần lớn lập trình viên sẽ thấy mục giao thức tầng dữ liệu hữu ích nhất. Mục này nói về cách MCP server cung cấp ngữ cảnh (context) cho một ứng dụng AI.

Chi tiết triển khai cụ thể, bạn xem tài liệu SDK theo ngôn ngữ của mình.

Phạm vi

Model Context Protocol gồm các dự án sau:

  • MCP Specification: bản đặc tả MCP, nêu các yêu cầu triển khai cho client và server.
  • MCP SDKs: SDK cho các ngôn ngữ lập trình khác nhau, hiện thực MCP.
  • MCP Development Tools: công cụ để phát triển MCP server và client, trong đó có MCP Inspector.
  • MCP Reference Server Implementations: các bản triển khai MCP server tham khảo.

Các khái niệm của MCP

Thành phần tham gia

MCP theo kiến trúc client–server. Trong đó một MCP host, tức một ứng dụng AI như Claude Code hay Claude Desktop, thiết lập kết nối tới một hoặc nhiều MCP server. MCP host làm việc này bằng cách tạo một MCP client cho mỗi MCP server. Mỗi MCP client duy trì một kết nối riêng với MCP server tương ứng.

MCP server cục bộ dùng cơ chế truyền tải (transport) STDIO thường chỉ phục vụ một MCP client. Còn MCP server từ xa dùng transport Streamable HTTP thường phục vụ nhiều MCP client.

Các thành phần chính trong kiến trúc MCP:

  • MCP Host: ứng dụng AI điều phối và quản lý một hoặc nhiều MCP client.
  • MCP Client: thành phần duy trì kết nối tới một MCP server và lấy ngữ cảnh từ MCP server đó cho MCP host dùng.
  • MCP Server: chương trình cung cấp ngữ cảnh cho MCP client.

Ví dụ: Visual Studio Code đóng vai trò MCP host. Khi Visual Studio Code thiết lập kết nối tới một MCP server, chẳng hạn Sentry MCP server, runtime của Visual Studio Code tạo một đối tượng MCP client để duy trì kết nối tới Sentry MCP server. Khi Visual Studio Code kết nối tiếp tới một MCP server khác, chẳng hạn local filesystem server, runtime của Visual Studio Code tạo thêm một đối tượng MCP client nữa để duy trì kết nối này.

mermaid
graph TB
    subgraph "MCP Host (AI Application)"
        Client1["MCP Client 1"]
        Client2["MCP Client 2"]
        Client3["MCP Client 3"]
        Client4["MCP Client 4"]
    end

    ServerA["MCP Server A - Local<br/>(e.g. Filesystem)"]
    ServerB["MCP Server B - Local<br/>(e.g. Database)"]
    ServerC["MCP Server C - Remote<br/>(e.g. Sentry)"]

    Client1 ---|"Dedicated<br/>connection"| ServerA
    Client2 ---|"Dedicated<br/>connection"| ServerB
    Client3 ---|"Dedicated<br/>connection"| ServerC
    Client4 ---|"Dedicated<br/>connection"| ServerC

Lưu ý: MCP server là chương trình cung cấp dữ liệu ngữ cảnh, bất kể nó chạy ở đâu. MCP server có thể chạy cục bộ hoặc từ xa. Ví dụ, khi Claude Desktop khởi chạy filesystem server, server chạy cục bộ trên cùng máy vì nó dùng transport STDIO. Loại này thường được gọi là MCP server "cục bộ" (local). Sentry MCP server chính thức chạy trên nền tảng Sentry và dùng transport Streamable HTTP. Loại này thường được gọi là MCP server "từ xa" (remote).

Các tầng

MCP gồm hai tầng:

  • Tầng dữ liệu (data layer): định nghĩa giao thức dựa trên JSON-RPC cho giao tiếp client–server, gồm việc khám phá khả năng (capability) và phiên bản, cùng các primitive cốt lõi như tool, resource, prompt và thông báo (notification).
  • Tầng truyền tải (transport layer): định nghĩa cơ chế và kênh giao tiếp giúp client và server trao đổi dữ liệu, gồm việc thiết lập kết nối theo từng transport, đóng khung thông điệp và phân quyền.

Về mặt khái niệm, tầng dữ liệu là tầng trong, còn tầng truyền tải là tầng ngoài.

Tầng dữ liệu

Tầng dữ liệu hiện thực một giao thức trao đổi dựa trên JSON-RPC 2.0, định nghĩa cấu trúc và ngữ nghĩa của thông điệp. Tầng này gồm:

  • Khám phá (discovery): cho client truy vấn các phiên bản giao thức server hỗ trợ, khả năng và danh tính của server qua yêu cầu (request) server/discover.
  • Tính năng phía server: cho server cung cấp chức năng cốt lõi, gồm tool cho các hành động AI, resource cho dữ liệu ngữ cảnh và prompt cho các mẫu tương tác từ và tới client.
  • Tính năng phía client: cho server yêu cầu người dùng nhập thêm thông tin. Sampling đã bị ngừng khuyến nghị (deprecated) kể từ phiên bản giao thức 2026-07-28.
  • Tính năng tiện ích: hỗ trợ các khả năng bổ sung như thông báo để cập nhật theo thời gian thực và theo dõi tiến độ cho các thao tác chạy lâu.

Tầng truyền tải

Tầng truyền tải quản lý kênh giao tiếp và xác thực giữa client và server. Nó lo việc thiết lập kết nối, đóng khung thông điệp và giao tiếp an toàn giữa các thành phần MCP.

MCP hỗ trợ hai cơ chế truyền tải:

  • Stdio transport: dùng luồng nhập/xuất chuẩn để các tiến trình cục bộ trên cùng máy giao tiếp trực tiếp, cho hiệu năng tối ưu vì không tốn chi phí mạng.
  • Streamable HTTP transport: dùng HTTP POST cho thông điệp từ client tới server, có thể kèm Server-Sent Events để stream. Transport này cho phép giao tiếp với server từ xa và hỗ trợ các phương thức xác thực HTTP tiêu chuẩn như bearer token, API key và header tuỳ chỉnh. MCP khuyến nghị dùng OAuth để lấy token xác thực.

Tầng truyền tải che các chi tiết giao tiếp khỏi tầng giao thức, nhờ đó mọi cơ chế truyền tải đều dùng chung một định dạng thông điệp JSON-RPC 2.0.

Giao thức tầng dữ liệu

Một phần cốt lõi của MCP là định nghĩa schema và ngữ nghĩa giữa MCP client và MCP server. Lập trình viên nhiều khả năng sẽ thấy tầng dữ liệu, đặc biệt là tập primitive, là phần thú vị nhất của MCP. Đây là phần định nghĩa các cách lập trình viên chia sẻ ngữ cảnh từ MCP server tới MCP client.

MCP dùng JSON-RPC 2.0 làm giao thức RPC nền. Client và server gửi yêu cầu cho nhau và trả phản hồi (response) tương ứng. Khi không cần phản hồi thì dùng thông báo.

Phi trạng thái và khám phá

MCP là một giao thức phi trạng thái (stateless): mỗi yêu cầu chứa đủ thông tin cần để xử lý nó, nên server không suy ra gì từ các yêu cầu trước. Mỗi yêu cầu mang phiên bản giao thức và các khả năng (những tính năng và thao tác mà client hoặc server hỗ trợ, như tool, resource hay prompt) liên quan tới yêu cầu đó trong trường _meta, để server xử lý từng yêu cầu độc lập. Client cũng nên tự định danh trong cùng trường này, trừ khi được cấu hình không làm vậy. Server công bố các phiên bản và khả năng mình hỗ trợ qua yêu cầu bắt buộc server/discover, mà client có thể gửi trước mọi yêu cầu khác. Thông tin chi tiết có trong đặc tả, còn phần ví dụ bên dưới minh hoạ metadata theo từng yêu cầu và trình tự khám phá.

Primitive

Primitive là khái niệm quan trọng nhất trong MCP. Chúng định nghĩa những gì client và server có thể cung cấp cho nhau. Các primitive này xác định loại thông tin ngữ cảnh có thể chia sẻ với ứng dụng AI và phạm vi hành động có thể thực hiện.

MCP định nghĩa ba primitive cốt lõi mà server có thể cung cấp:

  • Tools: hàm thực thi được mà ứng dụng AI có thể gọi để thực hiện hành động (ví dụ thao tác file, gọi API, truy vấn cơ sở dữ liệu).
  • Resources: nguồn dữ liệu cung cấp thông tin ngữ cảnh cho ứng dụng AI (ví dụ nội dung file, bản ghi cơ sở dữ liệu, phản hồi API).
  • Prompts: mẫu tái sử dụng giúp định hình tương tác với model ngôn ngữ (ví dụ system prompt, ví dụ few-shot).

Mỗi loại primitive có các phương thức đi kèm để khám phá (*/list), lấy về (*/get) và trong một số trường hợp là thực thi (tools/call). MCP client dùng các phương thức */list để khám phá primitive sẵn có. Ví dụ, client có thể liệt kê mọi tool sẵn có (tools/list) rồi thực thi chúng. Thiết kế này cho phép danh sách thay đổi động.

Một ví dụ cụ thể: hãy hình dung một MCP server cung cấp ngữ cảnh về một cơ sở dữ liệu. Server có thể cung cấp tool để truy vấn cơ sở dữ liệu, một resource chứa schema của cơ sở dữ liệu và một prompt chứa các ví dụ few-shot để tương tác với các tool.

Chi tiết về primitive phía server, xem server concepts.

MCP cũng định nghĩa các primitive mà client có thể cung cấp. Các primitive này giúp tác giả MCP server xây dựng tương tác phong phú hơn.

  • Elicitation: cho server yêu cầu người dùng cung cấp thêm thông tin. Tính năng này hữu ích khi tác giả server muốn lấy thêm thông tin từ người dùng hoặc xin xác nhận trước một hành động. Server yêu cầu người dùng nhập liệu bằng phương thức elicitation/create.

Yêu cầu elicitation được gửi qua mẫu Multi Round-Trip Requests, được giải thích trong phần tổng quan về elicitation.

Deprecated: các primitive phía client sau đây bị ngừng khuyến nghị kể từ phiên bản giao thức 2026-07-28.

  • Sampling: cho server yêu cầu completion từ model ngôn ngữ thông qua ứng dụng AI của client. Tính năng này hữu ích khi tác giả server muốn dùng model ngôn ngữ nhưng vẫn giữ server độc lập với model và không nhúng SDK của model ngôn ngữ vào MCP server. Server yêu cầu completion bằng phương thức sampling/createMessage, cũng được gửi qua mẫu Multi Round-Trip Requests. Các bản triển khai mới nên tích hợp (integrate) trực tiếp với API của nhà cung cấp LLM.
  • Logging: cho server gửi thông điệp log tới client để gỡ lỗi và giám sát. Các bản triển khai mới nên ghi log ra stderr (với stdio transport) hoặc dùng OpenTelemetry.

Chi tiết về primitive phía client, xem client concepts.

Ngoài primitive phía server và client, giao thức còn hỗ trợ các extension tuỳ chọn xây trên giao thức lõi. Ví dụ, Tasks extension cho server trả về một handle bền vững cho các yêu cầu chạy lâu, để client hỏi trạng thái định kỳ và lấy kết quả sau.

Thông báo

Giao thức hỗ trợ thông báo theo thời gian thực để server và client cập nhật động cho nhau. Ví dụ, khi danh sách tool của server thay đổi (chẳng hạn có chức năng mới hoặc tool hiện có bị sửa), server có thể gửi thông báo cập nhật tool để báo cho các client đang kết nối. Thông báo được gửi dưới dạng thông điệp notification của JSON-RPC 2.0 (không chờ phản hồi). Thông báo thay đổi là tuỳ chọn (opt-in): client mở một luồng subscriptions/listen tồn tại lâu, nêu tên các loại thông báo muốn nhận, và server gửi các thông báo khớp trên luồng đó.

Ví dụ

Tầng dữ liệu

Mục này đi từng bước qua một lượt tương tác giữa MCP client và server, tập trung vào giao thức tầng dữ liệu. Chúng ta sẽ minh hoạ việc khám phá, thao tác với tool và thông báo bằng các thông điệp JSON-RPC 2.0.

Bước 1: Khám phá

Như đã nói ở mục phi trạng thái và khám phá, mọi yêu cầu MCP đều mang phiên bản giao thức và khả năng của client trong trường _meta, và client cũng nên đưa danh tính của mình vào đó. Client muốn biết server hỗ trợ gì trước khi gửi các yêu cầu khác sẽ gửi yêu cầu server/discover, mà mọi server đều phải hiện thực. Phản hồi khám phá thường cache được, nghĩa là có thể dùng lại để không phải chạy luồng khám phá cho mỗi yêu cầu.

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "server/discover",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {
        "elicitation": {}
      }
    }
  }
}

Hiểu lượt trao đổi khám phá

Các trường _meta và phản hồi khám phá cùng phục vụ nhiều mục đích:

  1. Chọn phiên bản giao thức: trường io.modelcontextprotocol/protocolVersion khai báo phiên bản client đang dùng cho yêu cầu này, còn supportedVersions trong phản hồi liệt kê các phiên bản server chấp nhận. Nếu server không hỗ trợ phiên bản được yêu cầu, nó từ chối yêu cầu bằng một UnsupportedProtocolVersionError liệt kê các phiên bản nó hỗ trợ, và client thử lại với một phiên bản cả hai cùng hỗ trợ.
  2. Khám phá khả năng: client khai báo khả năng của mình trong io.modelcontextprotocol/clientCapabilities ở mọi yêu cầu, còn server trả đối tượng capabilities của nó từ server/discover. Nhờ đó mỗi bên biết bên kia xử lý được primitive nào (tool, resource, prompt) và có thông báo thay đổi hay không, nên không bao giờ thử các thao tác không được hỗ trợ.
  3. Trao đổi danh tính: trường io.modelcontextprotocol/clientInfo trong _meta của yêu cầu và trường io.modelcontextprotocol/serverInfo trong _meta của kết quả cung cấp thông tin định danh và phiên bản, phục vụ gỡ lỗi và tương thích.

Trong ví dụ này, lượt trao đổi cho thấy cách khai báo khả năng MCP:

Khả năng của client:

  • "elicitation": {}: client khai báo nó có thể thu thập thêm thông tin từ người dùng khi server yêu cầu.

Khả năng của server:

  • "tools": {"listChanged": true}: server hỗ trợ primitive tools và có thể đáp ứng bộ lọc toolsListChanged trong subscriptions/listen. Client yêu cầu bộ lọc này sẽ nhận notifications/tools/list_changed khi danh sách tool thay đổi.
  • "resources": {}: server cũng hỗ trợ primitive resources (xử lý được các phương thức resources/list và resources/read).

Gọi server/discover là tuỳ chọn. Vì mọi yêu cầu đều mang cùng các trường _meta, client có thể gửi thẳng bất kỳ yêu cầu nào và xử lý lỗi phiên bản nếu có. Khám phá là cách tiện để lấy danh tính, khả năng và các phiên bản được hỗ trợ của server chỉ trong một yêu cầu.

Cách hoạt động trong ứng dụng AI

Trình quản lý MCP client của ứng dụng AI kết nối tới các server đã cấu hình và lưu lại các khả năng khám phá được để dùng sau. Ứng dụng dùng thông tin này để xác định server nào cung cấp được loại chức năng nào (tool, resource, prompt) và server có hỗ trợ cập nhật thời gian thực không. Trong Python SDK, việc khám phá diễn ra khi client kết nối. Kết quả sau đó có sẵn trên đối tượng client.

python
# Pseudo Code
async with Client(stdio_client(server_config)) as client:
    if client.server_capabilities.tools:
        app.register_mcp_server(client, supports_tools=True)
    app.set_server_ready(client)

Bước 2: Khám phá tool (primitive)

Client có thể khám phá các tool sẵn có bằng cách gửi yêu cầu tools/list. Yêu cầu này là nền tảng của cơ chế khám phá tool trong MCP: nó cho client biết server có những tool nào trước khi thử dùng.

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {
        "elicitation": {}
      }
    }
  }
}

Hiểu yêu cầu khám phá tool

Yêu cầu tools/list không cần tham số nào ngoài các trường _meta chuẩn đi kèm mọi yêu cầu MCP. Nó cũng nhận một tham số cursor tuỳ chọn để phân trang, ví dụ trên không dùng tham số này.

Hiểu phản hồi khám phá tool

Phản hồi chứa mảng tools cung cấp đầy đủ metadata về từng tool sẵn có. Cấu trúc dạng mảng này cho server cung cấp nhiều tool cùng lúc mà vẫn giữ ranh giới rõ ràng giữa các chức năng.

Mỗi đối tượng tool trong phản hồi có một số trường chính:

  • name: định danh duy nhất của tool trong không gian tên của server. Đây là khoá chính để thực thi tool và nên theo quy tắc đặt tên rõ ràng (ví dụ calculator_arithmetic thay vì chỉ calculate).
  • title: tên hiển thị dễ đọc mà client có thể cho người dùng thấy.
  • description: giải thích chi tiết tool làm gì và khi nào nên dùng.
  • inputSchema: một JSON Schema định nghĩa các tham số đầu vào mong đợi, cho phép kiểm tra kiểu và mô tả rõ tham số nào bắt buộc, tham số nào tuỳ chọn.

Kết quả được đánh dấu "resultType": "complete" và có hai trường về cache. ttlMs là gợi ý độ mới tính bằng mili giây, nên danh sách tool này có thể được cache trong năm phút. cacheScope cho biết ai được dùng lại phản hồi. Caching utility trong đặc tả định nghĩa đầy đủ các quy tắc.

Cách hoạt động trong ứng dụng AI

Ứng dụng AI lấy các tool sẵn có từ mọi MCP server đã kết nối và gộp chúng vào một sổ đăng ký tool thống nhất mà model ngôn ngữ truy cập được. Nhờ đó LLM hiểu nó có thể thực hiện những hành động nào và tự sinh các lời gọi tool phù hợp trong hội thoại.

python
# Pseudo-code using MCP Python SDK patterns
available_tools = []
for client in app.mcp_clients():
    tools_response = await client.list_tools()
    available_tools.extend(tools_response.tools)
conversation.register_available_tools(available_tools)

Client kết hợp nhiều server có thể dùng progressive tool discovery thay vì nạp mọi tool ngay từ đầu.

Bước 3: Thực thi tool (primitive)

Giờ client có thể thực thi một tool bằng phương thức tools/call. Bước này cho thấy primitive MCP được dùng trong thực tế thế nào: sau khi khám phá các tool sẵn có, client gọi chúng với đối số phù hợp.

Hiểu yêu cầu thực thi tool

Yêu cầu tools/call theo một định dạng có cấu trúc, đảm bảo an toàn kiểu và giao tiếp rõ ràng giữa client và server. Lưu ý chúng ta dùng đúng tên tool từ phản hồi khám phá (weather_current) chứ không dùng tên rút gọn:

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "weather_current",
    "arguments": {
      "location": "San Francisco",
      "units": "imperial"
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {
        "elicitation": {}
      }
    }
  }
}

Các thành phần chính khi thực thi tool

Cấu trúc yêu cầu gồm một số thành phần quan trọng:

  1. name: phải khớp chính xác tên tool trong phản hồi khám phá (weather_current). Điều này giúp server xác định đúng tool cần thực thi.
  2. arguments: chứa các tham số đầu vào theo inputSchema của tool. Trong ví dụ này:
    • location: "San Francisco" (tham số bắt buộc)
    • units: "imperial" (tham số tuỳ chọn, mặc định là "metric" nếu không chỉ định)
  3. _meta: mang các trường chuẩn theo từng yêu cầu: phiên bản giao thức và khả năng của client mà mọi yêu cầu MCP phải có, cùng danh tính của client, thứ client nên đưa vào trừ khi được cấu hình không làm vậy.
  4. Cấu trúc JSON-RPC: dùng định dạng JSON-RPC 2.0 chuẩn với id duy nhất để ghép yêu cầu với phản hồi.

Hiểu phản hồi thực thi tool

Phản hồi cho thấy hệ thống nội dung linh hoạt của MCP:

  1. Mảng content: phản hồi của tool trả về một mảng đối tượng nội dung, cho phép phản hồi phong phú, nhiều định dạng (văn bản, hình ảnh, resource…).
  2. Loại nội dung: mỗi đối tượng nội dung có trường type. Trong ví dụ này, "type": "text" nghĩa là nội dung văn bản thuần, nhưng MCP hỗ trợ nhiều loại nội dung cho các trường hợp dùng khác nhau.
  3. Đầu ra có cấu trúc: phản hồi cung cấp thông tin dùng được ngay, mà ứng dụng AI có thể dùng làm ngữ cảnh khi tương tác với model ngôn ngữ.

Mẫu thực thi này cho ứng dụng AI gọi chức năng của server một cách động và nhận phản hồi có cấu trúc để đưa vào hội thoại với model ngôn ngữ.

Cách hoạt động trong ứng dụng AI

Khi model ngôn ngữ quyết định dùng một tool trong hội thoại, ứng dụng AI chặn lời gọi tool, chuyển nó tới MCP server phù hợp, thực thi, rồi trả kết quả về cho LLM như một phần của luồng hội thoại. Nhờ đó LLM truy cập được dữ liệu thời gian thực và thực hiện hành động ở thế giới bên ngoài.

python
# Pseudo-code for AI application tool execution
async def handle_tool_call(conversation, tool_name, arguments):
    client = app.find_mcp_client_for_tool(tool_name)
    result = await client.call_tool(tool_name, arguments)
    conversation.add_tool_result(result.content)

Bước 4: Cập nhật thời gian thực (thông báo)

MCP hỗ trợ thông báo thời gian thực, cho phép server báo cho client về các thay đổi mà không cần client hỏi định kỳ. Bước này minh hoạ hệ thống thông báo, một tính năng chính giúp client luôn đồng bộ và phản hồi nhanh.

Đăng ký nhận thay đổi

Thông báo thay đổi là opt-in. Để nhận, client mở một luồng thông báo tồn tại lâu bằng cách gửi yêu cầu subscriptions/listen với bộ lọc notifications nêu tên các loại sự kiện muốn nhận. Ở đây client yêu cầu nhận thay đổi danh sách tool:

json
{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "subscriptions/listen",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {
        "elicitation": {}
      }
    },
    "notifications": {
      "toolsListChanged": true
    }
  }
}

Mọi yêu cầu từ client đều mang các trường io.modelcontextprotocol/protocolVersion và io.modelcontextprotocol/clientCapabilities trong _meta, thường kèm cả io.modelcontextprotocol/clientInfo, để server nhận diện client mà không phải dựa vào trạng thái kết nối.

Server xác nhận đăng ký bằng notifications/subscriptions/acknowledged. Đây là thông điệp đầu tiên mang ID của đăng ký đó trong _meta (server không gửi thông báo nào khác cho đăng ký đó trước nó). Trường notifications của nó phản ánh phần bộ lọc mà server đồng ý đáp ứng, các loại thông báo không được hỗ trợ sẽ bị bỏ đi:

json
{
  "jsonrpc": "2.0",
  "method": "notifications/subscriptions/acknowledged",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/subscriptionId": 4
    },
    "notifications": {
      "toolsListChanged": true
    }
  }
}

Hiểu thông báo thay đổi danh sách tool

Sau khi xác nhận, mỗi khi danh sách tool của server thay đổi (ví dụ có chức năng mới, tool hiện có bị sửa, hoặc tool tạm thời không dùng được), server gửi một thông báo trên luồng đó:

json
{
  "jsonrpc": "2.0",
  "method": "notifications/tools/list_changed",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/subscriptionId": 4
    }
  }
}

Đặc điểm chính của thông báo MCP

  1. Không cần phản hồi: thông báo không có trường id. Điều này theo ngữ nghĩa notification của JSON-RPC 2.0, không mong đợi và không gửi phản hồi.
  2. Opt-in: thông báo này chỉ được gửi tới client đã yêu cầu "toolsListChanged": true trong bộ lọc subscriptions/listen, và chỉ có ở server đã khai báo "listChanged": true trong khả năng tools (như ở Bước 1).
  3. Gắn ID đăng ký: mọi thông báo trên luồng đều mang io.modelcontextprotocol/subscriptionId trong _meta. Giá trị này là ID JSON-RPC của yêu cầu subscriptions/listen đã mở luồng (4 trong ví dụ này), để client ghép từng thông báo với đăng ký đã sinh ra nó.
  4. Hướng sự kiện: server quyết định khi nào gửi thông báo dựa trên thay đổi trạng thái nội bộ, giúp kết nối MCP động và phản hồi nhanh.
  5. Best effort: không có gì đảm bảo mọi thông báo đều được gửi hoặc nhận, nhất là khi transport kết nối lại. Client cũng nên dựa vào việc hỏi định kỳ (polling) để giữ kết quả luôn mới.

Client phản hồi thông báo

Khi nhận thông báo này, client thường phản ứng bằng cách yêu cầu danh sách tool mới. Việc này tạo một vòng làm mới, giữ cho hiểu biết của client về các tool sẵn có luôn cập nhật:

json
{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {
        "elicitation": {}
      }
    }
  }
}

Vì sao thông báo quan trọng

Hệ thống thông báo này quan trọng vì nhiều lý do:

  1. Môi trường động: tool có thể xuất hiện hoặc biến mất tuỳ trạng thái server, phụ thuộc bên ngoài hoặc quyền của người dùng.
  2. Hiệu quả: client không cần hỏi định kỳ để biết thay đổi, mà được báo khi có cập nhật.
  3. Nhất quán: đảm bảo client luôn có thông tin chính xác về các khả năng sẵn có của server.
  4. Cộng tác thời gian thực: giúp ứng dụng AI phản hồi nhanh và thích ứng với ngữ cảnh thay đổi.

Mẫu thông báo này không chỉ áp dụng cho tool mà còn cho các primitive MCP khác, giúp client và server đồng bộ toàn diện theo thời gian thực.

Cách hoạt động trong ứng dụng AI

Ứng dụng AI giữ một luồng thông báo mở cho những thay đổi nó quan tâm. Khi có thông báo, nó lập tức làm mới sổ đăng ký tool và cập nhật các khả năng sẵn có của LLM. Nhờ vậy các hội thoại đang diễn ra luôn có bộ tool mới nhất, và LLM có thể thích ứng động với chức năng mới khi chúng xuất hiện.

python
# Pseudo-code for AI application notification handling
async def follow_tool_changes(client):
    async with client.listen(tools_list_changed=True) as sub:
        async for _event in sub:
            tools_response = await client.list_tools()
            app.update_available_tools(client, tools_response.tools)
            if app.conversation.is_active():
                app.conversation.notify_llm_of_new_capabilities()

Nguồn

Viết thêm guide cho track này