Xây Dựng MCP Server Bằng Python Với FastMCP: Từ Zero Đến Production

Hướng dẫn xây dựng MCP Server bằng Python và FastMCP 3.0 — từ cài đặt, code ví dụ thực tế, tích hợp Claude Desktop, đến deploy production với OAuth 2.1, OpenTelemetry và Docker.

Xây dựng MCP Server với Python & FastMCP: Từ Zero đến Production

Nếu bạn đang làm việc với AI agents trong năm 2026, chắc chắn bạn đã nghe đến MCP — Model Context Protocol. Nói thật nhé, khi mình lần đầu nghe về MCP vào cuối 2024, phản ứng đầu tiên là "lại thêm một chuẩn giao tiếp nữa à?" Nhưng sau hơn một năm chứng kiến gần như cả ngành AI xoay quanh nó, mình phải thừa nhận: MCP đã thay đổi hoàn toàn cách chúng ta kết nối AI với dữ liệu và công cụ bên ngoài.

Bài viết này là phần bổ trợ cho bài về Context Engineering trên AI Workflow Lab. Nếu Context Engineering trả lời câu hỏi "làm thế nào để cung cấp đúng context cho LLM", thì MCP chính là cơ sở hạ tầng để thực hiện điều đó — một cách chuẩn hóa, có thể tái sử dụng, và sẵn sàng cho production.

Chúng ta sẽ đi từ khái niệm cơ bản đến deploy một MCP Server thực tế bằng Python và FastMCP, framework đang chiếm khoảng 70% thị phần MCP server hiện nay. Okay, bắt đầu thôi.

MCP là gì và tại sao bạn cần quan tâm

Hãy tưởng tượng thế này: bạn có 5 ứng dụng AI (Claude Desktop, Cursor, Windsurf, một chatbot nội bộ, một pipeline tự động) và 10 nguồn dữ liệu (database, API nội bộ, Google Drive, Slack, GitHub...). Không có MCP, bạn phải viết 5 x 10 = 50 integration riêng biệt. Mỗi ứng dụng AI phải "biết" cách gọi từng nguồn dữ liệu theo cách khác nhau.

Đây chính là bài toán N x M kinh điển — và thành thật mà nói, nó là cơn ác mộng bảo trì.

MCP giải quyết vấn đề này bằng cách tạo ra một giao thức chuẩn duy nhất. Mỗi nguồn dữ liệu chỉ cần implement một MCP Server, mỗi ứng dụng AI chỉ cần implement một MCP Client. Bài toán N x M biến thành N + M. Người ta hay ví MCP như "USB-C cho AI" — một cổng kết nối chung cho mọi thiết bị. Mình thấy so sánh này cực kỳ chính xác.

Anthropic giới thiệu MCP vào tháng 11/2024, và ban đầu nhiều người (bao gồm cả mình) coi đó chỉ là "giải pháp riêng của Anthropic". Nhưng mọi thứ thay đổi nhanh chóng. Đầu năm 2025, OpenAI tuyên bố tích hợp MCP vào ChatGPT Desktop và Agents SDK. Google DeepMind theo sau. Đến giữa 2025, MCP được chuyển giao cho AI Alliance Integration Foundation (AAIF) thuộc Linux Foundation để quản trị — biến nó từ dự án của một công ty thành chuẩn mở của cả ngành.

Bước sang 2026, MCP thực sự đã trở thành tiêu chuẩn kết nối giữa AI và thế giới bên ngoài. Không còn là "nên dùng" nữa, mà gần như là "phải dùng".

Kiến trúc MCP: Host, Client, Server

MCP có kiến trúc 3 tầng khá rõ ràng. Đừng lo, nó không phức tạp như tên gọi đâu — đúng kiểu "đơn giản nhưng mạnh mẽ".

┌─────────────────────────────────────────┐
│              MCP HOST                   │
│    (Claude Desktop, IDE, Chatbot)       │
│                                         │
│  ┌─────────────┐  ┌─────────────┐      │
│  │ MCP Client  │  │ MCP Client  │ ...  │
│  └──────┬──────┘  └──────┬──────┘      │
└─────────┼────────────────┼──────────────┘
          │ JSON-RPC 2.0   │ JSON-RPC 2.0
          │ (stdio/SSE/    │
          │  Streamable    │
          │  HTTP)         │
     ┌────▼─────┐    ┌────▼─────┐
     │MCP Server│    │MCP Server│
     │(Weather) │    │(Database)│
     └──────────┘    └──────────┘

Ba thành phần chính:

  • MCP Host — Ứng dụng AI mà người dùng tương tác trực tiếp: Claude Desktop, Cursor IDE, Windsurf, hoặc chatbot bạn tự xây dựng. Host chứa LLM và quản lý toàn bộ trải nghiệm người dùng.
  • MCP Client — Lớp trung gian nằm bên trong Host, chịu trách nhiệm quản lý kết nối đến các MCP Server. Mỗi Client duy trì kết nối 1:1 với một Server. Nếu Host cần nói chuyện với 5 Server thì nó sẽ tạo 5 Client instance.
  • MCP Server — Nơi "phép thuật" xảy ra. Server expose các khả năng (tools, resources, prompts) cho phía AI sử dụng. Đây chính là thứ chúng ta sẽ xây dựng trong bài viết này.

Giao tiếp giữa Client và Server sử dụng JSON-RPC 2.0 qua các transport layer như STDIO (cho local), Server-Sent Events (SSE), hoặc Streamable HTTP (chuẩn mới nhất, dành cho remote deployment). Điểm quan trọng cần nhớ: MCP là giao thức stateful — Client và Server duy trì phiên kết nối liên tục, cho phép trao đổi context theo thời gian thực. Khác hẳn với REST API stateless truyền thống mà chúng ta quen thuộc.

Ba khả năng chính của MCP Server

Mỗi MCP Server có thể expose ba loại khả năng cho AI. Hiểu rõ ba loại này là chìa khóa để thiết kế server hiệu quả, nên mình sẽ giải thích kỹ một chút.

1. Resources — Đọc dữ liệu

Resources giống như các endpoint GET — cho phép AI đọc dữ liệu mà không thay đổi gì. Ví dụ: nội dung file, kết quả query database, danh sách sản phẩm. Resources được xác định bằng URI (như file:///logs/app.log hoặc db://users/active).

Điểm khá hay: Resources có thể tĩnh (dữ liệu cố định) hoặc động (dữ liệu thay đổi theo tham số). AI có quyền tự quyết định khi nào cần đọc resource nào dựa trên ngữ cảnh hội thoại.

2. Tools — Thực thi hành động

Tools là khả năng mạnh mẽ nhất — cho phép AI thực hiện hành động trong thế giới thực: gửi email, tạo ticket Jira, chạy query, gọi API, thao tác file. Về bản chất, Tools là "function calling" nhưng được chuẩn hóa qua giao thức MCP.

Quan trọng: Tools thường yêu cầu xác nhận từ người dùng trước khi thực thi (human-in-the-loop), vì chúng có thể thay đổi trạng thái hệ thống. Khi thiết kế tool, hãy mô tả rõ ràng tool làm gì trong docstring — LLM sẽ dựa vào đó để quyết định có gọi hay không.

3. Prompts — Template tái sử dụng

Prompts là các template được định nghĩa sẵn mà AI sử dụng để tạo output có cấu trúc. Ví dụ: template báo cáo phân tích, template review code, template email chuyên nghiệp. Nói cách khác, đây là cách bạn "dạy" AI output theo đúng format của tổ chức mình.

Tóm lại: Resources = đọc dữ liệu, Tools = thực thi hành động, Prompts = template output. Ba thứ này kết hợp lại tạo nên một MCP Server toàn diện.

Cài đặt môi trường & bắt đầu với FastMCP

Để xây dựng MCP Server với Python, bạn có hai lựa chọn: dùng MCP Python SDK (low-level) hoặc FastMCP (high-level). Mình khuyên bạn dùng FastMCP — và đây là lý do.

FastMCP ban đầu là thư viện riêng do Jeremiah Lowin tạo ra, nhưng đã được chính thức merge vào MCP Python SDK vì quá phổ biến. FastMCP 3.0 phát hành ngày 18 tháng 2 năm 2026, mang đến hàng loạt cải tiến: proxy server, OpenTelemetry tracing tích hợp sẵn, cải thiện hiệu năng đáng kể. Hiện tại nó chiếm khoảng 70% số MCP server trong hệ sinh thái Python.

Cái mình thích nhất? FastMCP giảm boilerplate code xuống mức tối thiểu. Thay vì hàng chục dòng setup, bạn chỉ cần vài decorator là xong.

Bắt đầu cài đặt môi trường với uv — package manager hiện đại cho Python:

uv init mcp-weather-server
cd mcp-weather-server
uv add "mcp[cli]"

Lệnh uv add "mcp[cli]" sẽ cài MCP Python SDK kèm FastMCP và CLI tools. Kiểm tra nhanh cài đặt thành công:

uv run mcp version

Tại sao dùng uv thay vì pip? Vì uv nhanh hơn 10-100 lần, quản lý dependency tốt hơn, và quan trọng nhất — MCP SDK chính thức khuyến nghị dùng uv. Nếu bạn chưa có, chạy curl -LsSf https://astral.sh/uv/install.sh | sh trên macOS/Linux hoặc xem hướng dẫn trên trang chủ Astral.

Xây dựng MCP Server đầu tiên: Weather Service

Okay, giờ mới đến phần hấp dẫn nhất — code thực tế. Chúng ta sẽ xây một MCP Server cung cấp thông tin thời tiết, sử dụng cả ba khả năng: Tools, Resources, và Prompts.

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Weather Service")

@mcp.tool()
async def get_weather(city: str) -> dict:
    """Lấy thông tin thời tiết hiện tại cho một thành phố."""
    # Simulate API call
    weather_data = {
        "city": city,
        "temperature": 28,
        "humidity": 75,
        "condition": "Partly Cloudy",
        "wind_speed": 12
    }
    return weather_data

@mcp.resource("weather://cities")
def list_cities() -> str:
    """Danh sách các thành phố được hỗ trợ."""
    cities = ["Hà Nội", "TP.HCM", "Đà Nẵng", "Huế", "Cần Thơ"]
    return "\n".join(cities)

@mcp.prompt()
def weather_report(city: str) -> str:
    """Tạo prompt báo cáo thời tiết chi tiết."""
    return f"Hãy tạo báo cáo thời tiết chi tiết cho thành phố {city}, bao gồm nhiệt độ, độ ẩm, tình trạng gió và lời khuyên cho người dân."

if __name__ == "__main__":
    mcp.run(transport="stdio")

Ít code vậy thôi mà đã có một MCP Server hoàn chỉnh rồi. Hãy phân tích từng phần:

  • FastMCP("Weather Service") — Tạo instance server với tên "Weather Service". Tên này sẽ hiển thị trong các MCP Host như Claude Desktop.
  • @mcp.tool() — Decorator biến một hàm Python thường thành MCP Tool. FastMCP tự động đọc type hints (city: str) và docstring để tạo schema cho tool. LLM sẽ "nhìn thấy" mô tả này và biết khi nào nên gọi.
  • @mcp.resource("weather://cities") — Đăng ký resource với URI weather://cities. Khi AI cần danh sách thành phố, nó đọc resource này.
  • @mcp.prompt() — Đăng ký prompt template. AI có thể sử dụng template này để tạo báo cáo thời tiết theo format đã định.
  • mcp.run(transport="stdio") — Khởi chạy server với STDIO transport, phù hợp cho local development và tích hợp Claude Desktop.

Lưu ý quan trọng về type hints và docstring: FastMCP sử dụng chúng để tự động tạo JSON Schema cho mỗi tool. Viết city: str thì LLM biết tham số city là kiểu string. Thêm giá trị mặc định như min_price: float = 0 thì tham số đó trở thành optional. Còn docstring? Đó chính là mô tả mà LLM đọc để hiểu tool làm gì — nên viết rõ ràng, súc tích nhé.

Để test nhanh, bạn dùng MCP Inspector:

uv run mcp dev server.py

Inspector sẽ mở một giao diện web cho phép bạn gọi thử từng tool, đọc resource, kiểm tra prompt. Cực kỳ tiện cho debug — mình dùng nó suốt.

Ví dụ nâng cao: MCP Server truy vấn Database

Weather Service là ví dụ tốt để bắt đầu, nhưng thực tế bạn sẽ cần những thứ phức tạp hơn nhiều. Nào, hãy xây dựng một MCP Server thực tế hơn — kết nối trực tiếp với database SQLite để phân tích sản phẩm và doanh số.

import sqlite3
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Product Analytics")

DATABASE_PATH = "products.db"

@mcp.tool()
def query_products(category: str, min_price: float = 0, max_price: float = 999999) -> list[dict]:
    """Tìm kiếm sản phẩm theo danh mục và khoảng giá."""
    conn = sqlite3.connect(DATABASE_PATH)
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()

    cursor.execute(
        "SELECT name, price, stock FROM products WHERE category = ? AND price BETWEEN ? AND ? ORDER BY price",
        (category, min_price, max_price)
    )

    results = [dict(row) for row in cursor.fetchall()]
    conn.close()
    return results

@mcp.tool()
def get_sales_summary(period: str = "month") -> dict:
    """Tổng hợp doanh số bán hàng theo kỳ."""
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()

    if period == "month":
        query = "SELECT SUM(total) as revenue, COUNT(*) as orders FROM orders WHERE date >= date('now', '-30 days')"
    elif period == "week":
        query = "SELECT SUM(total) as revenue, COUNT(*) as orders FROM orders WHERE date >= date('now', '-7 days')"
    else:
        query = "SELECT SUM(total) as revenue, COUNT(*) as orders FROM orders WHERE date >= date('now', '-1 day')"

    cursor.execute(query)
    row = cursor.fetchone()
    conn.close()

    return {"period": period, "revenue": row[0] or 0, "total_orders": row[1] or 0}

@mcp.resource("analytics://top-products")
def top_products() -> str:
    """Top 10 sản phẩm bán chạy nhất."""
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    cursor.execute(
        "SELECT p.name, SUM(oi.quantity) as sold FROM order_items oi JOIN products p ON oi.product_id = p.id GROUP BY p.id ORDER BY sold DESC LIMIT 10"
    )
    results = cursor.fetchall()
    conn.close()
    return "\n".join(f"{i+1}. {name} - {sold} đã bán" for i, (name, sold) in enumerate(results))

if __name__ == "__main__":
    mcp.run(transport="stdio")

Ví dụ này minh họa một use case rất hay: bạn có database sản phẩm, và thay vì xây dashboard phức tạp, bạn tạo MCP Server để AI trực tiếp truy vấn dữ liệu.

Imagine cảnh này: quản lý bạn mở Claude Desktop và hỏi "Doanh số tuần này thế nào? Sản phẩm nào bán chạy nhất?" — Claude sẽ tự động gọi get_sales_summary và đọc resource analytics://top-products để trả lời. Không cần mở database client, không cần biết SQL, không cần chờ team analytics. Đó chính là sức mạnh thực sự của MCP.

Một số điểm đáng chú ý:

  • Parameterized queries: Chúng ta dùng ? placeholder thay vì f-string để tránh SQL injection. Đây là best practice bắt buộc khi kết nối database — đừng bao giờ bỏ qua bước này.
  • Connection management: Mỗi tool call mở và đóng connection riêng. Trong production, bạn nên dùng connection pool (ví dụ aiosqlite với async hoặc sqlalchemy với pool).
  • Return types rõ ràng: list[dict] cho danh sách sản phẩm, dict cho summary, str cho resource. FastMCP tự động serialize chúng thành JSON phù hợp.

Tích hợp MCP Server với Claude Desktop

Đã xây xong server, giờ đến phần kết nối với Claude Desktop — MCP Host phổ biến nhất hiện nay. Bạn cần chỉnh sửa file cấu hình claude_desktop_config.json.

Trên macOS, file nằm ở:

~/Library/Application Support/Claude/claude_desktop_config.json

Trên Windows:

%APPDATA%\Claude\claude_desktop_config.json

Thêm cấu hình server của bạn:

{
  "mcpServers": {
    "weather-service": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/mcp-weather-server",
        "run",
        "server.py"
      ]
    },
    "product-analytics": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/mcp-product-analytics",
        "run",
        "server.py"
      ]
    }
  }
}

Sau khi lưu file, khởi động lại Claude Desktop. Bạn sẽ thấy biểu tượng búa (hammer icon) ở góc dưới bên trái hộp chat — đó là danh sách tools từ MCP Server của bạn. Thử hỏi "Thời tiết Hà Nội thế nào?" và Claude sẽ tự động gọi tool get_weather rồi hiển thị kết quả.

Khá là satisfying khi thấy nó hoạt động lần đầu tiên, nói thật.

Ngoài Claude Desktop, bạn có thể test bằng MCP Inspector — công cụ debug chuyên dụng:

# Chạy Inspector cho server
uv run mcp dev server.py

# Hoặc cài global
npx @modelcontextprotocol/inspector uv run server.py

MCP Inspector mở giao diện web tại localhost:6274 (mặc định), cho phép bạn:

  • Xem danh sách tất cả tools, resources, prompts đã đăng ký
  • Gọi thử từng tool với tham số tùy chỉnh
  • Đọc resource và kiểm tra output
  • Xem log JSON-RPC messages giữa client và server

Mình luôn test với Inspector trước khi kết nối Claude Desktop. Nó giúp phát hiện lỗi sớm hơn nhiều so với việc ngồi debug qua giao diện chat.

Đưa lên Production: Best Practices 2026

Xây MCP Server cho demo là một chuyện, đưa lên production là chuyện khác hoàn toàn. Đây là những best practices mà mình đúc kết sau hơn một năm triển khai MCP trong các dự án thực tế.

1. Xác thực với OAuth 2.1

Spec MCP mới nhất yêu cầu OAuth 2.1 cho remote MCP Server. Đây là bước tiến lớn so với thời kỳ đầu khi nhiều server chạy không có authentication (nhìn lại thấy hơi sợ). Nếu server của bạn expose qua network — không phải localhost — thì OAuth 2.1 là bắt buộc. FastMCP 3.0 hỗ trợ OAuth middleware tích hợp sẵn nên setup không quá phức tạp.

2. Xử lý lỗi với ToolError

Trong production, lỗi sẽ xảy ra — database timeout, API rate limit, dữ liệu không hợp lệ. Bạn cần xử lý gracefully bằng ToolError thay vì để exception bay ra ngoài. ToolError cho phép bạn trả về thông báo lỗi có ý nghĩa cho LLM, giúp nó hiểu vấn đề và có thể thử cách tiếp cận khác.

3. Logging — Đừng bao giờ ghi ra stdout!

Đây là lỗi mà gần như ai mới làm MCP cũng mắc phải (mình cũng từng dính). Với STDIO transport, stdout được dùng để giao tiếp JSON-RPC giữa client và server. Nếu bạn print() ra stdout, nó sẽ làm hỏng toàn bộ giao tiếp. Luôn ghi log ra stderr.

4. OpenTelemetry Tracing

FastMCP 3.0 tích hợp sẵn OpenTelemetry tracing — feature khá hữu ích cho production. Bạn có thể trace toàn bộ lifecycle của mỗi tool call: thời gian xử lý, lỗi phát sinh, tham số đầu vào. Kết hợp với Jaeger hoặc Grafana Tempo, bạn có observability đầy đủ cho MCP Server.

5. Rate Limiting

Khi nhiều người dùng cùng kết nối đến MCP Server, rate limiting là bắt buộc để tránh quá tải. FastMCP hỗ trợ config rate limit khá đơn giản qua tham số khởi tạo.

Đây là ví dụ một MCP Server được cấu hình cho production:

import sys
import logging
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.exceptions import ToolError

logging.basicConfig(level=logging.INFO, stream=sys.stderr)
logger = logging.getLogger(__name__)

mcp = FastMCP(
    "Production Server",
    mask_error_details=True,
    rate_limit="100/hour"
)

@mcp.tool()
async def safe_query(query: str) -> dict:
    """Truy vấn an toàn với xử lý lỗi production."""
    if not query.upper().startswith("SELECT"):
        raise ToolError("Chỉ cho phép truy vấn SELECT để đảm bảo an toàn dữ liệu.")

    try:
        # execute query...
        logger.info(f"Query executed: {query[:100]}")
        return {"status": "success", "data": results}
    except Exception as e:
        logger.error(f"Query failed: {e}")
        raise ToolError("Không thể thực hiện truy vấn. Vui lòng thử lại.")

Phân tích mấy điểm quan trọng:

  • logging.basicConfig(stream=sys.stderr) — Tất cả log đi ra stderr, không bao giờ stdout. Ghi nhớ kỹ cái này.
  • mask_error_details=True — Ẩn chi tiết lỗi nội bộ khỏi client. Trong development, bạn tắt flag này để debug dễ hơn.
  • rate_limit="100/hour" — Giới hạn 100 request mỗi giờ.
  • Kiểm tra SQL injection — Tool safe_query chỉ cho phép câu lệnh SELECT, chặn mọi attempt INSERT/UPDATE/DELETE/DROP.
  • ToolError — Thay vì raise Exception chung chung, dùng ToolError để LLM nhận thông báo lỗi rõ ràng và phản hồi phù hợp cho người dùng.

6. Docker Containerization

Cho deployment production, đóng gói MCP Server trong Docker container là best practice:

FROM python:3.12-slim

WORKDIR /app
COPY . .

RUN pip install uv && uv sync

EXPOSE 8000

CMD ["uv", "run", "server.py", "--transport", "streamable-http", "--host", "0.0.0.0", "--port", "8000"]

Khi deploy remote, bạn chuyển từ STDIO sang Streamable HTTP transport — chuẩn mới nhất cho remote MCP deployment, hỗ trợ cả request-response lẫn streaming, và tương thích với load balancer, API gateway.

MCP vs API truyền thống: Khi nào nên dùng cái nào?

Đây là câu hỏi mình nhận được nhiều nhất: "MCP có thay thế REST API không?" Câu trả lời ngắn gọn: Không, và cũng không nên.

Chúng phục vụ mục đích khác nhau và bổ trợ cho nhau.

Tiêu chí MCP REST API truyền thống
Mục đích chính Kết nối AI/LLM với dữ liệu & công cụ Giao tiếp giữa các hệ thống phần mềm
Ai gọi LLM tự quyết định dựa trên context Code xác định sẵn (deterministic)
Trạng thái Stateful — duy trì phiên kết nối Stateless — mỗi request độc lập
Discovery Tự động — LLM "nhìn thấy" tools/resources Cần documentation, SDK riêng
Phù hợp nhất cho Agentic workflows, AI assistants Web/mobile apps, microservices

MCP tỏa sáng trong các agentic workflow — nơi LLM cần tự suy luận và quyết định sử dụng tool nào, với context nào, theo thứ tự nào. Ví dụ: "Phân tích doanh số tháng này, so sánh với tháng trước, và gửi báo cáo qua email cho sếp." Trong kịch bản này, AI cần gọi nhiều tools liên tiếp dựa trên kết quả từng bước — đây đúng là thứ MCP được sinh ra để làm.

Ngược lại, REST API phù hợp hơn cho các luồng deterministic — nơi bạn biết trước chính xác endpoint nào cần gọi, với tham số gì. Ví dụ: mobile app gọi /api/products để hiển thị danh sách sản phẩm.

Trong thực tế, MCP thường wrap các API có sẵn. Bạn không cần viết lại logic nghiệp vụ — chỉ cần tạo MCP Server "bọc" quanh API hiện tại, expose chúng dưới dạng tools và resources chuẩn MCP. Đây là pattern phổ biến nhất mà mình thấy ngoài production.

Kết luận: Bắt đầu nhỏ, nghĩ lớn

MCP không phải trend nhất thời — nó đã được chứng minh qua hơn một năm adoption rộng rãi, được quản trị bởi Linux Foundation, và được hỗ trợ bởi tất cả các AI provider lớn. Nếu bạn đang xây dựng bất kỳ hệ thống AI nào cần tương tác với dữ liệu hoặc công cụ bên ngoài, MCP là con đường đúng đắn.

Lời khuyên của mình: bắt đầu với một MCP Server đơn giản cho use case cụ thể nhất của bạn. Wrap một internal API, kết nối database, hoặc tích hợp với tool nội bộ. Dùng FastMCP, test với Inspector, deploy local với Claude Desktop trước. Khi đã ổn định, mới nghĩ đến remote deployment, OAuth, monitoring.

MCP kết hợp với Context Engineering (mà chúng tôi đã phân tích chi tiết trong bài viết trước) tạo nên bộ đôi nền tảng cho mọi hệ thống AI production hiện đại. Context Engineering đảm bảo AI nhận được đúng thông tin cần thiết, còn MCP cung cấp cơ sở hạ tầng chuẩn hóa để truyền tải thông tin đó. Nắm vững cả hai, bạn đã có đủ công cụ để xây dựng AI agents thực sự hữu ích.

Câu hỏi thường gặp (FAQ)

MCP Server là gì và khác gì với API thông thường?

MCP Server là chương trình implement giao thức Model Context Protocol, cho phép các ứng dụng AI (như Claude Desktop) kết nối và sử dụng dữ liệu, công cụ bên ngoài một cách chuẩn hóa. Điểm khác biệt lớn nhất so với API thông thường: MCP được thiết kế để AI tự khám phá và quyết định sử dụng — LLM "nhìn thấy" danh sách tools/resources và tự quyết định gọi cái nào dựa trên ngữ cảnh. Với API truyền thống, developer phải viết code xác định sẵn endpoint nào được gọi khi nào. Ngoài ra, MCP là stateful (duy trì phiên kết nối), trong khi REST API thường là stateless.

Tôi có cần biết Python để xây dựng MCP Server không?

Không bắt buộc, nhưng Python hiện là lựa chọn phổ biến nhất nhờ FastMCP. MCP SDK chính thức cũng hỗ trợ TypeScript, và cộng đồng đã phát triển SDK cho nhiều ngôn ngữ khác: Java, C#, Go, Rust, Kotlin. Tuy nhiên, hệ sinh thái Python + FastMCP hiện tại là trưởng thành nhất với nhiều tài liệu và ví dụ nhất. Nếu bạn quen TypeScript, TypeScript SDK cũng rất ổn. Chọn ngôn ngữ bạn thoải mái nhất — MCP là giao thức chuẩn, nên server viết bằng ngôn ngữ nào cũng tương thích với mọi MCP Client.

FastMCP có miễn phí không?

Có, hoàn toàn miễn phí và mã nguồn mở (MIT License). FastMCP là phần chính thức của MCP Python SDK, được maintain bởi cộng đồng với sự hỗ trợ từ Anthropic. Bạn sử dụng cho cả dự án cá nhân lẫn thương mại mà không cần lo về licensing. Source code có trên GitHub tại modelcontextprotocol/python-sdk.

MCP Server có an toàn cho production không?

Có, nếu bạn tuân thủ các best practices. MCP spec yêu cầu OAuth 2.1 cho remote server, hỗ trợ TLS encryption, và có cơ chế permission rõ ràng cho tools (human-in-the-loop confirmation). Tuy nhiên, bảo mật phụ thuộc vào cách bạn implement: luôn validate input, dùng parameterized queries cho database, không expose thông tin nhạy cảm qua error messages (dùng mask_error_details=True), và thiết lập rate limiting. FastMCP 3.0 đã tích hợp sẵn nhiều tính năng bảo mật, nhưng bạn vẫn cần review kỹ logic nghiệp vụ — đặc biệt là các tools có khả năng write dữ liệu.

Làm thế nào để debug MCP Server?

Có ba cách chính. Thứ nhất, dùng MCP Inspector (uv run mcp dev server.py) — công cụ debug số một, cho phép bạn tương tác trực tiếp với server qua giao diện web, xem request/response JSON-RPC, và gọi thử từng tool. Thứ hai, kiểm tra log — nhớ ghi log ra stderr (không phải stdout), và dùng logging module với level DEBUG khi cần trace chi tiết. Thứ ba, trong Claude Desktop, xem log tại ~/Library/Logs/Claude/ (macOS) để thấy chi tiết giao tiếp giữa Claude và MCP Server. Nếu dùng FastMCP 3.0 với OpenTelemetry, bạn còn có thể trace performance và phát hiện bottleneck qua Jaeger hoặc Grafana.

Về Tác Giả Editorial Team

Our team of expert writers and editors.