AI Agents & Skills

Tự viết MCP server bằng Python trong 30 dòng

Tóm tắt

Với SDK Python, MCP server chỉ cần type hint, docstring và mcp.run(). Lỗi phổ biến nhất là in ra stdout làm hỏng kênh stdio; hãy test bằng MCP Inspector trước, dùng đường dẫn tuyệt đối và bắt đầu với tool chỉ đọc.

Bạn có một API nội bộ (tra đơn hàng, xem tồn kho, đọc báo cáo) và muốn Claude gọi được nó trong Claude Desktop hay Claude Code. Cách chuẩn hiện nay là bọc API đó thành một MCP server. Với SDK Python chính thức, một server tối giản chỉ khoảng 30 dòng. Bài này đi từ con số 0 tới lúc Claude gọi được tool của bạn, kèm những lỗi người mới hay gặp nhất.

Chuẩn bị

  • Python 3.10 trở lên và uv (trình quản lý gói/dự án).
  • Gói mcp[cli] từ SDK chính thức.
uv init order-server
cd order-server
uv venv && source .venv/bin/activate
uv add "mcp[cli]"

Viết server

SDK tự sinh định nghĩa tool từ type hint và docstring, nên hãy viết chúng cẩn thận: đó chính là "tài liệu" mà model đọc để quyết định gọi tool nào, với tham số gì.

import logging
from mcp.server import MCPServer

logging.basicConfig(level=logging.INFO)   # ghi ra stderr
log = logging.getLogger("orders")
mcp = MCPServer("orders")

ORDERS = {"A100": "Đang giao", "A101": "Đã huỷ"}

@mcp.tool()
async def get_order_status(order_id: str) -> str:
    """Tra trạng thái đơn hàng theo mã.

    Args:
        order_id: Mã đơn, ví dụ A100
    """
    log.info("lookup %s", order_id)
    return ORDERS.get(order_id.upper(), "Không tìm thấy đơn hàng.")

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

Ở các bản SDK và bài hướng dẫn cũ, lớp này có tên FastMCP; tài liệu quickstart hiện tại dùng MCPServer. Ngoài @mcp.tool(), server còn có thể cung cấp resources (dữ liệu dạng tệp để đọc) và prompts (mẫu prompt dựng sẵn).

Lỗi số 1: in ra stdout

Với transport stdio, stdout là kênh truyền thông điệp JSON-RPC. Chỉ một lệnh print() cũng đủ làm hỏng giao tiếp và server "chết" không rõ lý do. Tài liệu nhấn mạnh: không bao giờ ghi gì ra stdout; dùng module logging (mặc định ghi ra stderr).

Kiểm thử bằng MCP Inspector

Trước khi nối vào Claude, thử bằng Inspector (cần Node 22.19+):

# Giao diện web
npx @modelcontextprotocol/inspector uv run server.py

# CLI, hợp cho CI
npx @modelcontextprotocol/inspector --cli uv run server.py --method tools/list

Inspector cho xem danh sách tool, gọi thử với tham số tuỳ ý và đọc toàn bộ thông điệp JSON-RPC. Nếu muốn chắc server chạy được với cả client cũ và client theo spec mới, chạy CLI với --protocol-era legacy và --protocol-era modern.

Kết nối với Claude

Claude Desktop: sửa ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) rồi khởi động lại app:

{
  "mcpServers": {
    "orders": {
      "command": "uv",
      "args": ["--directory", "/ĐƯỜNG/DẪN/TUYỆT/ĐỐI/order-server", "run", "server.py"]
    }
  }
}

Claude Code: claude mcp add orders -- uv --directory /ĐƯỜNG/DẪN/order-server run server.py, rồi kiểm tra bằng /mcp.

Khi không chạy

Triệu chứngHướng xử lý
Server không xuất hiệnDùng đường dẫn tuyệt đối; có thể phải ghi đường dẫn đầy đủ tới uv (which uv)
Kết nối rồi đứt ngayTìm print() hay thư viện ghi ra stdout
Muốn xem logClaude Desktop trên macOS: tail -f ~/Library/Logs/Claude/mcp*.log
Claude không gọi toolViết lại docstring rõ hơn: tool làm gì, khi nào dùng, ví dụ tham số

Rủi ro và lưu ý

  • Tool là cửa vào hệ thống: tool ghi/xoá dữ liệu cần kiểm tra quyền và xác nhận; bắt đầu bằng tool chỉ đọc.
  • Kết quả tool là dữ liệu không tin cậy: nội dung trả về có thể chứa prompt injection nếu lấy từ nguồn bên ngoài.
  • Bí mật: truyền API key qua biến môi trường (env trong config), không hard-code trong code.
  • Trả về gọn: kết quả dài tốn context; lọc và định dạng trước khi trả.

Áp dụng thế nào?

  • Dev: Bọc một API nội bộ chỉ đọc thành 2–3 tool, test bằng Inspector, rồi dùng trong Claude Code hằng ngày.
  • Tech Lead: Đưa lệnh Inspector CLI tools/list vào CI để phát hiện server hỏng trước khi phát hành.
  • PM: Liệt kê 5 câu hỏi nội bộ được hỏi nhiều nhất; mỗi câu là ứng viên cho một tool MCP.

Nguồn & tham khảo

  1. Build an MCP server — Model Context Protocol
  2. MCP Python SDK — Model Context Protocol (GitHub)
  3. MCP Inspector — Model Context Protocol