Xây dựng và triển khai MCP server đa công cụ

Bạn đã học về kiến ​​trúc, xây dựng các công cụ, tài nguyên và prompt, kết nối với cơ sở dữ liệu và API, và bảo mật server của mình. Giờ là lúc kết hợp tất cả lại với nhau.

Trong dự án cuối khóa này, bạn sẽ xây dựng một MCP server "Project Assistant" hoàn chỉnh giúp các nhà phát triển quản lý dự án phần mềm — kết hợp mọi khái niệm từ khóa học vào một gói có thể triển khai.

🔄 Tóm tắt nhanh: Xuyên suốt khóa học này, bạn đã học về kiến ​​trúc MCP (Bài 2), xây dựng server đầu tiên của mình (Bài 3), thành thạo các công cụ (Bài 4), resource và prompt (Bài 5), các mô hình thực tế (Bài 6) và bảo mật (Bài 7). Dự án cuối khóa này tích hợp tất cả chúng.

Trợ lý dự án dành cho nhà phát triển

Bạn sẽ xây dựng một MCP server giúp nhà phát triển quản lý dự án của họ bằng cách kết hợp:

  • Tools: Truy vấn cơ sở dữ liệu dự án, quản lý nhiệm vụ, tìm kiếm file code
  • Resources: README dự án, schema cơ sở dữ liệu, thư mục nhóm
  • Prompts: Template đánh giá code, template lập kế hoạch sprint
  • Security: Cơ sở dữ liệu chỉ đọc theo mặc định, truy cập file bị hạn chế theo đường dẫn, xác thực đầu vào

Sơ đồ server

📍 Nơi dán: Mở ChatGPT (chat.openai.com), Claude (claude.ai) hoặc Gemini (gemini.google.com) và bắt đầu một cuộc trò chuyện mới.

📋 Cách sao chép prompt này: Nhấp vào bất kỳ đâu bên trong khối màu xám, nhấn Cmd+A rồi Cmd+C (Mac) hoặc Ctrl+A rồi Ctrl+C (Windows). Hoặc sử dụng biểu tượng sao chép xuất hiện.

Project Assistant MCP Server
├── Tools
│   ├── query_tasks — Tìm kiếm và lọc các nhiệm vụ dự án
│   ├── create_task — Thêm nhiệm vụ mới vào cơ sở dữ liệu
│   ├── search_code — Tìm các mẫu code trong những file dự án
│   └── get_git_log — Hiển thị các lần commit gần đây
├── Resources
│   ├── project://readme — Tài liệu dự án
│   ├── project://schema — Cấu trúc bảng cơ sở dữ liệu
│   └── project://team — Thư mục thành viên nhóm
└── Prompts
    ├── code_review — Template đánh giá code có cấu trúc
    └── sprint_plan — Khởi đầu cuộc trò chuyện lập kế hoạch sprint

✏️ Cách điền thông tin chi tiết: Thay thế mỗi dấu ngoặc vuông [] và trình giữ chỗ trong ngoặc bằng thông tin cụ thể từ tình huống thực tế của bạn. Thông tin không rõ ràng sẽ tạo ra kết quả không rõ ràng — hãy cụ thể.

👀 Những gì bạn sẽ thấy: Trong vòng vài giây, AI sẽ trả về một phản hồi có cấu trúc dựa trên prompt ở trên. Hãy đọc kỹ và coi đó là bản nháp, không phải câu trả lời cuối cùng.

📌 Nên làm gì với kết quả: Lưu phản hồi vào file Notes. Chọn gợi ý có hiệu quả cao nhất và thực hiện nó trong tuần này — đừng cố gắng làm tất cả cùng một lúc.

⚠️ Nếu kết quả không ổn: Nếu các gợi ý có vẻ chung chung, hãy dán nội dung sau: "Hãy cụ thể hơn với bối cảnh thực tế của tôi. Bỏ qua những lời khuyên chung chung." Nếu nó bỏ qua các chi tiết quan trọng bạn đã cung cấp, hãy hỏi: "Bạn đã bỏ sót [X] trong bối cảnh của tôi — hãy thực hiện lại với điều đó làm ràng buộc chính."

Kiểm tra nhanh: Nhìn vào sơ đồ trên, thành phần nào được điều khiển bởi mô hình (AI quyết định khi nào sử dụng), thành phần nào được điều khiển bởi ứng dụng (client tìm nạp) và thành phần nào được điều khiển bởi người dùng (người dùng lựa chọn)?

Đáp án: Tools được điều khiển bởi mô hình — AI gọi query_tasks hoặc search_code khi cần. Resources được điều khiển bởi ứng dụng — Client load README và schema làm ngữ cảnh. Prompts được điều khiển bởi người dùng — nhà phát triển chọn rõ ràng code_review hoặc sprint_plan để bắt đầu quy trình làm việc.

Xây dựng server

Đây là cấu trúc server hoàn chỉnh, áp dụng các mẫu từ mỗi bài học:

Thiết lập cốt lõi

import os
import sqlite3
import subprocess
from mcp.server.fastmcp import FastMCP
from mcp.types import UserMessage

mcp = FastMCP("Project Assistant")

# Configuration from environment
PROJECT_DIR = os.environ.get("PROJECT_DIR", os.getcwd())
DB_PATH = os.environ.get("DB_PATH", "tasks.db")

Resources (Bài 5)

@mcp.resource("project://readme")
def get_readme() -> str:
    """Project README for context."""
    readme_path = os.path.join(PROJECT_DIR, "README.md")
    if os.path.exists(readme_path):
        return open(readme_path).read()
    return "No README.md found in project directory."

@mcp.resource("project://schema")
def get_schema() -> str:
    """Database schema for task queries."""
    return """
    Table: tasks
    - id INTEGER PRIMARY KEY
    - title TEXT NOT NULL
    - status TEXT (open, in_progress, done)
    - assignee TEXT
    - priority TEXT (low, medium, high, critical)
    - created_at TIMESTAMP
    - updated_at TIMESTAMP
    """

Tools (Bài 4, 6)

@mcp.tool()
def query_tasks(
    status: str = "",
    assignee: str = "",
    priority: str = ""
) -> str:
    """Search project tasks. Filter by status, assignee, or priority."""
    conditions = []
    params = []
    if status:
        conditions.append("status = ?")
        params.append(status)
    if assignee:
        conditions.append("assignee = ?")
        params.append(assignee)
    if priority:
        conditions.append("priority = ?")
        params.append(priority)

    where = " AND ".join(conditions)
    sql = "SELECT id, title, status, assignee, priority FROM tasks"
    if where:
        sql += f" WHERE {where}"
    sql += " ORDER BY created_at DESC LIMIT 20"

    conn = sqlite3.connect(DB_PATH)
    rows = conn.execute(sql, params).fetchall()
    conn.close()

    if not rows:
        return "No tasks match your filters."
    lines = ["ID | Title | Status | Assignee | Priority"]
    for row in rows:
        lines.append(f"{row[0]} | {row[1]} | {row[2]} | {row[3]} | {row[4]}")
    return "\n".join(lines)

Lưu ý: Các truy vấn tham số hóa (dấu ? thay thế) ngăn chặn tấn công SQL injection, và kết quả được giới hạn ở 20 hàng.

Truy cập file với khả năng bảo mật (Bài 7)

@mcp.tool()
def search_code(pattern: str, file_extension: str = "") -> str:
    """Search for a text pattern in project files."""
    if len(pattern) < 2:
        return "Error: search pattern must be at least 2 characters"

    cmd = ["grep", "-rn", "--include", f"*.{file_extension}" if file_extension else "*", pattern]
    try:
        result = subprocess.run(
            cmd, cwd=PROJECT_DIR,
            capture_output=True, text=True, timeout=10
        )
        if result.stdout:
            lines = result.stdout.strip().split("\n")[:20]
            return "\n".join(lines)
        return f"No matches found for '{pattern}'"
    except subprocess.TimeoutExpired:
        return "Search timed out — try a more specific pattern"

Quá trình tìm kiếm chỉ chạy trong thư mục PROJECT_DIR (được thiết lập thông qua biến môi trường) và có thời gian chờ 10 giây.

Prompts (Bài 5)

@mcp.prompt()
def code_review(filepath: str) -> list:
    """Perform a structured code review."""
    return [UserMessage(
        content=f"""Review the file at {filepath}. Analyze:
1. **Bugs** — Logic errors, edge cases, null/undefined handling
2. **Security** — Input validation, injection risks, auth issues
3. **Performance** — Unnecessary allocations, algorithmic complexity
4. **Readability** — Naming clarity, function length, comments

For each issue, cite the line number and suggest a specific fix."""
    )]

@mcp.prompt()
def sprint_plan(sprint_name: str) -> list:
    """Plan a new sprint with task prioritization."""
    return [UserMessage(
        content=f"""Let's plan sprint '{sprint_name}'. Help me:
1. Review open tasks (use query_tasks to see what's available)
2. Prioritize by impact and urgency
3. Assign tasks based on team capacity
4. Identify blockers and dependencies
5. Set sprint goals (2-3 measurable outcomes)"""
    )]
@mcp.prompt()
def code_review(filepath: str) -> list:
    """Perform a structured code review."""
    return [UserMessage(
        content=f"""Review the file at {filepath}. Analyze:
1. **Bugs** — Logic errors, edge cases, null/undefined handling
2. **Security** — Input validation, injection risks, auth issues
3. **Performance** — Unnecessary allocations, algorithmic complexity
4. **Readability** — Naming clarity, function length, comments

For each issue, cite the line number and suggest a specific fix."""
    )]

@mcp.prompt()
def sprint_plan(sprint_name: str) -> list:
    """Plan a new sprint with task prioritization."""
    return [UserMessage(
        content=f"""Let's plan sprint '{sprint_name}'. Help me:
1. Review open tasks (use query_tasks to see what's available)
2. Prioritize by impact and urgency
3. Assign tasks based on team capacity
4. Identify blockers and dependencies
5. Set sprint goals (2-3 measurable outcomes)"""
    )]

Kiểm tra server của bạn

Hãy kiểm tra mọi khía cạnh trước khi triển khai:

Kiểm tra chức năng

Kiểm tra Những điều cần xác minh
Truy vấn các tác vụ không có bộ lọc Trả về tất cả các tác vụ (tối đa 20 tác vụ)
Truy vấn với status="open" Chỉ trả về các tác vụ đang mở
Tìm kiếm code theo một mẫu đã biết Tìm đúng file
Tải xuống tài liệu README Trả về tài liệu dự án
Sử dụng prompt code_review Tạo tin nhắn đánh giá có cấu trúc

Kiểm tra bảo mật

Kiểm tra Kết quả dự kiến
Tìm kiếm với mẫu ../../etc/passwd Nằm trong thư mục PROJECT_DIR
Truy vấn với tấn công SQL injection: '; DROP TABLE tasks; -- Sử dụng truy vấn tham số hóa, không có tấn công injection
Đầu vào rất dài (10.000 ký tự) Bị từ chối hoặc bị cắt bớt
Tìm kiếm theo mẫu 1 ký tự Trả về lỗi (tối thiểu 2 ký tự)

Các trường hợp ngoại lệ

Kiểm tra Kết quả dự kiến
Thực hiện các tác vụ truy vấn khi cơ sở dữ liệu trống "Không có tác vụ nào phù hợp với bộ lọc của bạn"
Tìm kiếm một mẫu không tồn tại "Không tìm thấy kết quả phù hợp"
Tài nguyên README khi file không tồn tại "Không tìm thấy README.md"

Triển khai cho nhóm của bạn

Bước 1: Đóng gói vào container

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY server.py .
EXPOSE 8080
CMD ["python", "server.py", "--transport", "http", "--port", "8080"]

Bước 2: Chia sẻ cấu hình

Tạo một file claude_desktop_config.json mẫu cho các đồng đội:

{
  "mcpServers": {
    "project-assistant": {
      "command": "python",
      "args": ["/path/to/server.py"],
      "env": {
        "PROJECT_DIR": "/path/to/your/project",
        "DB_PATH": "/path/to/tasks.db"
      }
    }
  }
}

Bước 3: Soạn thảo tài liệu

Viết một file README bao gồm: Chức năng của server, cách cài đặt, các công cụ có sẵn và cách cấu hình.

Các bước tiếp theo

Khám phá các server hiện có: Duyệt qua hơn 3.000 MCP server cộng đồng tại mcp.so hoặc kho lưu trữ GitHub chính thức.

Xây dựng cho nhóm của bạn: Xác định 3 tác vụ thủ công hàng đầu trong quy trình làm việc của bạn và xây dựng các công cụ MCP cho chúng.

Đóng góp vào hệ sinh thái: Xuất bản server của bạn lên kho lưu trữ MCP. Cộng đồng đang phát triển nhanh chóng, và mỗi server mới đều làm cho hệ sinh thái trở nên có giá trị hơn.

Những điểm chính cần ghi nhớ

  • Một MCP server được thiết kế tốt kết hợp Tools, Resources và Prompts để mang lại trải nghiệm hoàn chỉnh
  • Các công cụ có trách nhiệm đơn lẻ với tên gọi rõ ràng hoạt động tốt hơn những công cụ đa năng
  • Kiểm tra hành vi chức năng, ranh giới bảo mật và các trường hợp ngoại lệ trước khi triển khai
  • Đóng gói bằng Docker và cung cấp các template cấu hình để phân phối cho nhóm
  • MCP là tiêu chuẩn đang nổi lên — các kỹ năng bạn đã xây dựng sẽ được chuyển giao giữa Claude, ChatGPT, Gemini và mọi MCP client trong tương lai.
  • Câu 1:

    Bạn đã xây dựng một MCP server hỗ trợ dự án. Bạn nên chia sẻ nó với nhóm của mình như thế nào?

    GIẢI THÍCH:

    Docker đảm bảo mọi người đều chạy cùng một phiên bản trong cùng một môi trường. File README với hướng dẫn cài đặt và file cấu hình mẫu giúp các thành viên nhóm nhanh chóng thiết lập trong vài phút. Đây là mô hình tiêu chuẩn để phân phối MCP server cho nhóm.

  • Câu 2:

    Bạn nên kiểm tra những gì trước khi triển khai MCP server?

    GIẢI THÍCH:

    Kiểm tra toàn diện bao gồm: Sử dụng bình thường (nó có hoạt động không?), các trường hợp ngoại lệ (đầu vào trống, giá trị tối đa), xử lý lỗi (lỗi mạng, dữ liệu không hợp lệ) và bảo mật (tấn công SQL injection, tấn công duyệt thư mục, các lệnh gọi công cụ trái phép). Một MCP server chưa được kiểm tra trong môi trường sản xuất là một rủi ro.

  • Câu 3:

    Khi xây dựng MCP server đa công cụ, nguyên tắc thiết kế quan trọng nhất là gì?

    GIẢI THÍCH:

    Nguyên tắc trách nhiệm duy nhất áp dụng cho các công cụ MCP. Một công cụ có tên 'quản lý cơ sở dữ liệu' xử lý các truy vấn, chèn, cập nhật và xóa sẽ khó để AI sử dụng chính xác hơn so với những công cụ 'truy vấn dữ liệu', 'chèn bản ghi', 'cập nhật bản ghi' riêng biệt. Tên gọi rõ ràng và phạm vi tập trung giúp AI chọn đúng công cụ.

Thứ Ba, 02/06/2026 14:07
51 👨 38
Xác thực tài khoản!

Theo Nghị định 147/2024/ND-CP, bạn cần xác thực tài khoản trước khi sử dụng tính năng này. Chúng tôi sẽ gửi mã xác thực qua SMS hoặc Zalo tới số điện thoại mà bạn nhập dưới đây:

Số điện thoại chưa đúng định dạng!
Số điện thoại này đã được xác thực!
Bạn có thể dùng Sđt này đăng nhập tại đây!
Lỗi gửi SMS, liên hệ Admin
0 Bình luận
Sắp xếp theo
❖ MCP Tools