Cách triển khai MCP

Model Context Protocol, sử dụng và xây dựng MCP

MCP, một giao thức mã nguồn mở được phát triển bởi Anthropic, cung cấp một giao diện tiêu chuẩn để kết nối các mô hình LLM với các công cụ, API, dịch vụ đa dạng bên ngoài, qua đó nâng cao đáng kể năng lực của các ứng dụng AI. MCP sử dụng JSON-RPC 2.0 làm nền tảng, giúp nó không phụ thuộc vào ngôn ngữ lập trình và dễ dàng triển khai.

Xây dựng công cụ một lần, sử dụng ở mọi nơi. MCP thống nhất cách AI tương tác với thế giới.

MCP là gì?

MCP (Model Context Protocol) là một giao thức được thiết kế để tiêu chuẩn hóa cách các ứng dụng cung cấp, sử dụng các dịch vụ và hỗ trợ tool-calling cho các mô hình LLM.

Hãy tưởng tượng việc kết nối một laptop với nhiều thiết bị — màn hình, bàn phím, ổ cứng — mà không có cổng chung như USB-C; việc tích hợp sẽ trở nên phức tạp. MCP giải quyết vấn đề tương tự trong AI, một tool được phát triển cho một agent có thể dùng cho bất kỳ agent tương thích MCP nào khác — Claude Desktop, Cursor hoặc bất kỳ nền tảng nào khác.

MCP giảm sự phức tạp trong việc phát triển agent cần nhiều dịch vụ tích hợp và giúp cho việc mở rộng trở nên dễ dàng hơn

Tổng quan về MCP

Kiến trúc của MCP

MCP có kiến trúc bao gồm ba thành phần chính:

  • 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 với MCP Server và lấy dịch vụ từ MCP Server để MCP Host sử dụng
  • MCP Server: Chương trình cung cấp dịch vụ cho các MCP Client

Lưu ý: MCP Server đề cập đến là một chương trình cung cấp dịch vụ, bất kể nó chạy ở cục bộ hoặc từ xa.

MCP Server

Một MCP Server có thể cung cấp các chức năng thông qua ba thành phần chính:

Thành phầnKiểm soát bởiMục đích
ToolsLLMMột hàm mà LLM có thể gọi một cách chủ động, quyết định dựa trên yêu cầu của người dùng
ResourcesỨng dụngCác nguồn dữ liệu chỉ đọc mà ứng dụng có thể truy xuất và cung cấp cho các agent
PromptsNgười dùngCác mẫu hướng dẫn được xây dựng sẵn hướng dẫn LLM sử dụng các công cụ và tài nguyên cụ thể

Tool là thành phần phổ biến và quan trọng nhất. Định nghĩa tool sẽ được cung cấp cho LLM để ra quyết định cho việc sử dụng:

  • name — định danh duy nhất, ví dụ: get_keyword_volume
  • description — mô tả cho LLM về chức năng của công cụ và khi nào sử dụng nó
  • inputSchema — JSON Schema định nghĩa các tham số đầu vào (kiểu dữ liệu, giá trị mặc định, enums)
  • annotations — thông tin metadata tuỳ chỉnh về hành vi (readOnlyHint, destructiveHint...)
{
  "name": "get_keyword_volume",
  "description": "Get monthly search volume for a keyword. Use when you need to evaluate keyword demand for content planning.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "keyword": { "type": "string" },
      "country": { "type": "string", "default": "vn" }
    },
    "required": ["keyword"]
  }
}

MCP Client

Một MCP Client cung cấp ba tính năng cho MCP Server:

Tính năngMục đíchTại sao cần thiết
RootsGiới hạn không gian thư mục cho các thao tác của serverNgăn server vượt ngoài ranh giới cho phép
SamplingCho phép server yêu cầu LLM phía client thực hiện các thao tác cụ thểThực thi các agentic workflow mà không cần LLM ở phía server
ElicitationCho phép server hỏi người dùng các thông tin cần thiết trong khi thực thiServer có thể thu thập các dữ liệu còn thiếu thay vì báo lỗi

Transport

MCP định nghĩa hai phương thức transport tiêu chuẩn:

  • stdio — Client khởi chạy server là một tiến trình con trong cùng máy tính. Giao tiếp qua stdin/stdout. Chỉ hỗ trợ một client duy nhất và không cần kết nối mạng nên sẽ phù hợp cho các dịch vụ cục bộ. Lưu ý: không ghi bất cứ gì khác vào stdout (không dùng print(), console.log()...) — sử dụng stderr nếu cần log.

  • Streamable HTTP — Server cung cấp một HTTP endpoint. Client gửi qua POST, và server sẽ phản hồi bằng JSON hoặc SSE. Hỗ trợ nhiều client đồng thời nên sẽ phù hợp cho các server từ xa, cloud. Được sử dụng để thay thế cho transport HTTP+SSE.

Sử dụng MCP Server có sẵn

Nên sử dụng MCP Server có sẵn khi:

  • Các tính năng phổ biến (filesystem, web fetch...)
  • Đã có sẵn server được hỗ trợ tốt
  • Không cần các logic doanh nghiệp cụ thể

Một số MCP Server tiêu biểu có thể kể đến như:

Tính năngThư việnMục đích
Filesystem@modelcontextprotocol/server-filesystemCác thao tác an toàn với file
Memory@modelcontextprotocol/server-memoryBộ nhớ graph-based bền vững
Fetch@modelcontextprotocol/server-fetchTruy xuất nội dung web
Everything@modelcontextprotocol/server-everythingMẫu với đầy đủ các thành phần của MCP Server

Nhiều MCP Server chính thức (Brave Search, Slack, GitHub...) cũng đã có sẵn. Ngoài ra, rất nhiều server khác đã được phát triển bởi cộng đồng — có thể tìm kiếm tại MCP Registry.

Xây dựng MCP Server riêng

Nên tự xây dựng MCP Server khi:

  • Cần các tool chuyên dụng cho lĩnh vực cụ thể (SEO data, API nội bộ)
  • Các server hiện có không đáp ứng đủ nhu cầu
  • Cần logic doanh nghiệp cụ thể hoặc bảo mật

Các MCP SDK

Bạn có thể phát triển các MCP Server bằng các ngôn ngữ khác nhau, hỗ trợ bởi các SDK, một trong số đó như:

Ngôn ngữThư việnHỗ trợ bởi
Pythonmcp (FastMCP)Anthropic
TypeScript@modelcontextprotocol/sdkAnthropic
Gogithub.com/modelcontextprotocol/go-sdkGoogle

Ví dụ, một MCP Server đơn giản được xây dựng bởi FastMCP - high-level API trong thư viện mcp của Python:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("seo-tools")

@mcp.tool()
def get_keyword_volume(keyword: str, country: str = "us") -> dict:
    """Get monthly search volume for a keyword.
    Use when you need to evaluate keyword demand for content planning.
    Returns volume, trend data, and difficulty score."""
    # Thực hiện các logic cụ thể tại đây
    return seo_api.get_volume(keyword, country=country)

@mcp.resource("config://settings")
def get_settings() -> str:
    """Current SEO tool configuration."""
    return json.dumps(load_settings())

if __name__ == "__main__":
    mcp.run()  # Sử dụng transport mặc định là stdio

Các điểm chính:

  • Tên của hàm sẽ trở thành name của tool
  • Các kiểu dữ liệu của tham số sẽ tự động tạo ra JSON Schema (inputSchema)
  • Docstring trở thành description của tool — LLM đọc mô tả này để quyết định khi nào gọi nó
  • mcp.run() mặc định sử dụng stdio. Truyền transport="sse" để sử dụng Streamable HTTP

Xây dựng tool

Tool là thành phần cơ bản phổ biến nhất, vì vậy việc thiết kế chúng một cách chính xác là điều quan trọng nhất. Sau đây là các quy tắc để xây dựng các tools một cách hiệu quả.

Tính nhỏ gọn

Mỗi tool nên thực hiện một tác vụ cụ thể một cách tốt nhất. Đừng gộp nhiều tác vụ vào một tool duy nhất — thay vào đó, hãy kết hợp các tool nhỏ lại với nhau.

Không nênNên
do_seo_analysis (làm tất cả mọi thứ)get_keyword_volume + get_serp_rankings + compare_competitors

Đặt tên

Sử dụng quy tắc đặt tên theo verb_noun để LLM (cũng như con người) có thể dễ dàng hiểu tool này để làm gì. name phải có độ dài từ 1 đến 128 ký tự.

  • Ví dụ: search_keywords, get_rankings, analyze_serp, check_ai_overview
  • Tránh sử dụng các tên chung chung như do_seo hay helper

Mô tả

description là cách LLM quyết định khi nào nên gọi tool. Nó nên trả lời được ba câu hỏi sau: tool này làm gì, khi nào nên sử dụng nó và nó trả về kết quả gì.

Không nênNên
"Gets keyword data""Get search volume, difficulty, and related keywords. Use when you need keyword metrics for content planning."

Tham số

Các tham số được định nghĩa trong inputSchema. Giữ số lượng các tham số bắt buộc ở mức tối thiểu, các tham số tuỳ chọn nâng cao nên có các giá trị mặc định hợp lý.

  • Dùng enum cho các giá trị cố định (mode: "single" | "multiple")
  • Đặt các giá trị mặc định hợp lý
  • Mô tả rõ từng tham số trong description
  • Giới hạn đầu vào

Chú thích

annotations là các chú thích cho biết cách một công cụ hoạt động — tính chất chỉ đọc, phá hủy hay tương tác với các hệ thống bên ngoài:

Chú thíchÝ nghĩa
readOnlyHintTool không làm thay đổi môi trường
destructiveHintTool có thể thực hiện các thao tác mang tính phá hủy
idempotentHintCác lần gọi lặp lại với cùng tham số sẽ không gây ảnh hưởng lớn
openWorldHintTool có thể tương tác với các thực thể bên ngoài

Client sử dụng những gợi ý này để quyết định liệu có cần yêu cầu người dùng xác nhận hay không.

Ví dụ tổng hợp

Đây là một ví dụ áp dụng tất cả các hướng dẫn bên trên:

from enum import Enum
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("seo-tools")

class SearchEngine(Enum):
    GOOGLE = "google"
    BING = "bing"

@mcp.tool(annotations={"readOnlyHint": True})
def get_keyword_volume(
    keyword: str,
    engine: SearchEngine = SearchEngine.GOOGLE,
    country: str = "us",
) -> dict:
    """Get monthly search volume for a keyword.
    Use when you need to evaluate keyword demand for content planning.
    Returns volume, trend data, and difficulty score."""
    ...

@mcp.tool(annotations={"readOnlyHint": True})
def get_serp_rankings(
    keyword: str,
    limit: int = 10,
) -> dict:
    """Get current SERP rankings for a keyword.
    Use when you need to see who ranks and what content types appear.
    Returns top results with titles, URLs, and positions."""
    ...

@mcp.tool(annotations={"readOnlyHint": True, "openWorldHint": True})
def check_ai_overview(keyword: str) -> dict:
    """Check if a keyword triggers an AI Overview in Google.
    Use when evaluating whether AI summaries affect organic traffic.
    Returns whether AI Overview exists and its content summary."""
    ...

Xử lý lỗi

Các tool có thể gặp lỗi — sự cố API, chạm rate limit, dữ liệu đầu vào không hợp lệ. Điểm mấu chốt là cần trả về các lỗi giúp mô hình LLM phục hồi một cách trơn tru thay vì làm sập hệ thống agent.

Protocol Error và Tool Error

MCP phân biệt hai mức lỗi:

  • Protocol Error xảy ra khi bản thân request không hợp lệ — tên tool không hợp lệ, các lỗi không được bắt và xử lý. Máy chủ trả về response JSON-RPC lỗi kèm mã lỗi và thông báo lỗi. Client cần xử lý các lỗi.

  • Tool Error xảy ra khi tool đã chạy nhưng thất bại — API timeout, chạm rate limit. Những lỗi này được trả về trong response bình thường với trường isError: true. LLM đọc kết quả và quyết định các bước tiếp theo.

ToolError của FastMCP sẽ tự động đặt isError: true trong response, do đó LLM có thể xử lý nó:

from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.utilities.types import ToolError

mcp = FastMCP("seo-tools")

@mcp.tool()
def get_keyword_volume(keyword: str, country: str = "us") -> dict:
    """Get monthly search volume for a keyword."""
    try:
        return seo_api.get_volume(keyword, country=country)
    except RateLimitError:
        raise ToolError(
            "Rate limit exceeded. Wait 60 seconds or try fewer keywords."
        )
    except KeywordNotFoundError:
        raise ToolError(
            f"Keyword '{keyword}' not found. Try a more common term or check spelling."
        )
    except APIConnectionError:
        raise ToolError(
            "SEO API is temporarily unavailable. Try again in a few minutes."
        )

Thông báo lỗi

Một thông báo lỗi tốt có thể cho LLM biết cái gì đã xảy ra, có nên thử lại hay không và các hướng thay thế.

Không nênNên
"Error""Rate limit exceeded. Wait 60 seconds or try fewer keywords."
"Failed""Keyword not found. Try a more common term or check spelling."