0

MCP là gì? Dựng MCP server đơn giản bằng Python

Nếu bạn từng viết code để một mô hình ngôn ngữ gọi hàm tra cứu đơn hàng, rồi lại viết một bản khác cho công cụ khác, bạn sẽ hiểu vì sao MCP ra đời. Mỗi ứng dụng AI một kiểu kết nối thì rất khó dùng lại.

Bài này giải thích MCP là gì, rồi dựng một server nhỏ bằng Python để bạn tự thử. Code theo tài liệu chính thức của MCP Python SDK, hiện là phiên bản 2.x. Dựng MCP server đơn giản bằng Python

MCP là gì

MCP (Model Context Protocol) là một giao thức chuẩn để ứng dụng AI kết nối với công cụ và dữ liệu bên ngoài. Hiểu đơn giản, nó giống một cổng chung: bạn viết một lần, nhiều ứng dụng đều dùng được.

Có ba vai trò cần phân biệt:

  • Host là ứng dụng AI mà người dùng đang trò chuyện, ví dụ trợ lý AI hoặc IDE.
  • Client nằm trong host và nói chuyện với server bằng giao thức MCP.
  • Server là phần bạn viết. Nó cung cấp công cụ và dữ liệu, chứ không tự nói chuyện với mô hình.

Một server có thể cung cấp ba loại thứ: tools (hàm mô hình quyết định gọi, như tra cứu hay ghi dữ liệu), resources (dữ liệu ứng dụng nạp vào ngữ cảnh) và prompts (mẫu câu lệnh người dùng chọn). Bài này chỉ làm tools cho gọn.

Khi làm các dự án agent cho doanh nghiệp trên ***nền tảng AI Hive***, mình thấy phần kết nối với hệ thống nội bộ thường tốn thời gian hơn phần gọi mô hình. Một chuẩn chung giúp giảm đáng kể việc viết lại phần này cho từng ứng dụng.

Cài đặt

SDK yêu cầu Python 3.11 trở lên.

pip install "mcp[cli]"

Phần cli thêm lệnh mcp để chạy thử và gỡ lỗi. Nếu bạn dùng uv, lệnh tương ứng là uv add "mcp[cli]".

Lưu ý nhỏ: nhiều bài hướng dẫn cũ dùng from mcp.server.fastmcp import FastMCP. Đó là cú pháp của phiên bản 1. Từ phiên bản 2, lớp này tên là MCPServer và nằm trong mcp.server.

Viết server đầu tiên

Tạo file server.py với hai công cụ: tra trạng thái đơn hàng và tính phí vận chuyển.

from mcp.server import MCPServer

mcp = MCPServer("Order Helper")

ORDERS = {
    "A100": "Đang giao, dự kiến tới trong 2 ngày",
    "A101": "Đã giao thành công",
}


@mcp.tool()
def order_status(order_id: str) -> str:
    """Tra cứu trạng thái đơn hàng theo mã đơn."""
    return ORDERS.get(order_id, "Không tìm thấy đơn hàng này")


@mcp.tool()
def shipping_fee(weight_kg: int) -> int:
    """Tính phí vận chuyển (VND) theo số kg, tối thiểu 1 kg."""
    return 20000 + max(0, weight_kg - 1) * 5000

Chỉ có hai hàm Python thường và hai decorator. Tên hàm, docstring và kiểu dữ liệu được SDK đọc để tạo mô tả công cụ và schema đầu vào, bạn không phải khai báo riêng.

Docstring quan trọng hơn bạn nghĩ. Mô hình dựa vào đó để biết khi nào nên gọi công cụ, nên hãy viết rõ ràng như viết cho đồng nghiệp.

Chạy thử bằng MCP Inspector

uv run mcp dev server.py

Lệnh này mở MCP Inspector, một giao diện web để gọi thử từng công cụ. Nếu cài bằng pip, bạn có thể chạy mcp dev server.py. Trong tab Tools, bạn sẽ thấy order_status và shipping_fee, mỗi công cụ có form nhập tự sinh từ kiểu dữ liệu. Thử gọi shipping_fee với weight_kg = 3 để kiểm tra kết quả.

Kiểm thử không cần giao diện

SDK có sẵn client trong bộ nhớ, rất tiện để viết test.

import asyncio

from mcp import Client

from server import mcp


async def main() -> None:
    async with Client(mcp) as client:
        result = await client.call_tool("shipping_fee", {"weight_kg": 3})
        print(result.structured_content)


asyncio.run(main())

Cách này không cần tiến trình con hay cổng mạng, vì client nối thẳng vào đối tượng server. Bạn có thể đưa các đoạn như vậy vào pytest để chạy mỗi lần sửa code.

Vài lưu ý khi đưa vào dự án thật

  • Mỗi công cụ là một ranh giới quyền. Đừng để công cụ chạy với quyền rộng hơn cần thiết. Công cụ chỉ đọc và công cụ ghi dữ liệu nên tách riêng.

  • Làm rõ hành động không thể hoàn tác. Xóa dữ liệu, hoàn tiền, gửi email cho khách nên có bước người duyệt trước khi chạy.

  • Ghi log mọi lần gọi. Khi có sự cố, bạn cần biết công cụ nào được gọi, với tham số gì, bởi ai.

  • Trả lỗi rõ ràng. Thông báo như "Không tìm thấy đơn hàng này" giúp mô hình biết phải hỏi lại người dùng, thay vì đoán.

Bước tiếp theo

Sau khi chạy ổn trên Inspector, bạn có thể nối server vào một host thật. Tài liệu SDK có phần hướng dẫn kết nối host và phần chạy server qua HTTP khi cần triển khai cho nhiều người dùng.

Nếu muốn xem bức tranh rộng hơn về kiến trúc và các mẫu kết nối, bài viết về tích hợp MCP với Claude đi qua từng bước chi tiết hơn.

Bạn đang dùng MCP cho công cụ nội bộ nào, và phần nào khiến bạn mất nhiều thời gian nhất?


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí