0
0
Lập trình
Admin Team
Admin Teamtechmely

Xây Dựng Công Cụ MCP: Máy Chủ Xử Lý PDF Hiệu Quả

Đăng vào 1 tháng trước

• 9 phút đọc

Chủ đề:

#ai#python#mcp#pdf

Giới Thiệu

Mô hình Giao thức Ngữ cảnh Mô hình (MCP) đã trở thành một tiêu chuẩn đột phá trong việc kết nối các mô hình AI với các công cụ và dịch vụ bên ngoài, nhằm nâng cao khả năng của chúng. Bài viết này sẽ hướng dẫn bạn qua một cái nhìn tổng quan về hành trình phát triển máy chủ xử lý PDF toàn diện bằng FastMCP, với kiến trúc hợp lý, xử lý lỗi, và các tính năng đạt tiêu chuẩn sản xuất.

Danh Sách Công Cụ Sẵn Có

Máy Chủ & Tiện Ích Tập Tin

  • server_info(): Lấy cấu hình và trạng thái của máy chủ.
  • list_temp_resources(): Liệt kê các tập tin hiện có trong thư mục tạm thời của máy chủ.
  • upload_file(), upload_file_base64(), upload_file_url(): Tải lên các tập tin từ máy tính của bạn hoặc từ một URL.
  • get_resource_base64(): Tải xuống một tập tin từ thư mục tạm thời của máy chủ.

Văn Bản & Siêu Dữ Liệu

  • get_pdf_info(): Nhanh chóng lấy số trang, kích thước tập tin và trạng thái mã hóa.
  • extract_text(): Trích xuất toàn bộ nội dung văn bản từ một PDF.
  • extract_text_by_page(): Trích xuất văn bản từ các trang cụ thể hoặc dãy trang.
  • extract_metadata(): Đọc siêu dữ liệu của PDF (tác giả, tiêu đề, ngày tạo, v.v.).

Xử Lý PDF

  • merge_pdfs(): Kết hợp nhiều tập tin PDF thành một tài liệu duy nhất.
  • split_pdf(): Chia một PDF thành nhiều tập tin nhỏ hơn dựa trên dãy trang.
  • rotate_pages(): Xoay các trang cụ thể trong một PDF.

Chuyển Đổi

  • pdf_to_images(): Chuyển đổi các trang PDF đã chỉ định thành các tập tin hình ảnh (PNG, JPEG).
  • images_to_pdf(): Tạo một PDF mới từ danh sách các tập tin hình ảnh.

Bạn có thể tìm thấy mã nguồn trong GitHub Repo 📁 MCP PDF Server.

Nghiên Cứu Tình Huống: Theo Dõi Công Cụ "extract_text"

Chúng ta sẽ khám phá công cụ 'extract_text'; tất cả các công cụ khác đều chia sẻ một quy trình nhất quán và dễ dàng truy cập trong repo, nếu bạn muốn kiểm tra.

Mô Hình

Bằng cách tách logic thành "Dịch vụ" -> "Công cụ" -> "Đăng ký", chúng ta giữ cho mã nguồn sạch sẽ, có thể kiểm tra và dễ dàng mở rộng. Bạn có thể thêm công cụ của riêng mình bằng cách làm theo mô hình này.

Bước 1: Logic Cốt Lõi - "Dịch Vụ"

Trước khi nghĩ về máy chủ, công cụ hay giao thức, chúng ta cần một hàm Python đơn giản và đáng tin cậy có thể thực hiện nhiệm vụ cốt lõi của chúng ta. Đây là "Lớp Dịch Vụ" - động cơ.

Tập tin: src/fastmcp_pdf_server/services/pdf_processor.py

Bước đầu tiên là viết một hàm nhận một đường dẫn tệp và trả về văn bản, chúng ta sử dụng thư viện "pdfplumber" cho việc này. Lưu ý rằng hàm trả về một lớp TextExtractionResult, giúp đảm bảo cấu trúc dữ liệu nhất quán.

python Copy
from __future__ import annotations

from dataclasses import dataclass
from typing import List

import pdfplumber

from ..utils.validators import validate_pdf

@dataclass
class TextExtractionResult:
    text: str
    page_count: int
    char_count: int


def extract_text(file_path: str, encoding: str = "utf-8") -> TextExtractionResult:
    pdf_path = validate_pdf(file_path)

    with pdfplumber.open(str(pdf_path)) as pdf:
        texts: List[str] = []
        for page in pdf.pages:
            texts.append(page.extract_text() or "")

        text = "\n".join(texts)

    return TextExtractionResult(text=text, page_count=len(texts), char_count=len(text))

Hàm này hoàn toàn bằng Python. Nó không biết gì về FastMCP. Nó có thể được kiểm tra đơn vị bằng "pytest" hoặc được sử dụng trong một ứng dụng hoàn toàn khác. Sự tách biệt này là nền tảng của một hệ thống có thể bảo trì. Khi chúng ta đã thực hiện logic dịch vụ của mình, chúng ta tiếp tục với "Công cụ" MCP.

Bước 2: Cây Cầu - "Công Cụ"

Bây giờ chúng ta cần phơi bày hàm dịch vụ của mình cho thế giới bên ngoài như một Công cụ MCP. "Lớp Công cụ" này đóng vai trò như một cây cầu. Nó xử lý thực tế rối rắm của cuộc gọi công cụ và chuyển đổi nó thành một cuộc gọi sạch sẽ đến dịch vụ của chúng ta.

Tập tin: src/fastmcp_pdf_server/tools/text_extraction.py

Đây là phần quan trọng nhất của câu đố. Nó sẽ xử lý cuộc gọi công cụ, giải quyết tệp, gọi dịch vụ và định dạng phản hồi.

python Copy
from __future__ import annotations

import time
import uuid
from typing import Any

from fastmcp import FastMCP  # type: ignore

from ..services import pdf_processor
from ..services.file_manager import resolve_to_path
from ..utils.logger import get_logger

logger = get_logger(__name__)


def register(app: FastMCP) -> None:
    @app.tool()
    async def extract_text(file: Any, encoding: str | None = "utf-8") -> dict:
        op_id = uuid.uuid4().hex
        start = time.perf_counter()

        try:
            resolved = resolve_to_path(file, filename_hint="uploaded.pdf")
            res = pdf_processor.extract_text(str(resolved), encoding or "utf-8")
            duration_ms = int((time.perf_counter() - start) * 1000)
            return {
                "text": res.text,
                "page_count": res.page_count,
                "char_count": res.char_count,
                "meta": {
                    "operation_id": op_id,
                    "execution_ms": duration_ms,
                    "resolved_path": str(resolved),
                },
            }
        except Exception as e:
            logger.error("extract_text error: %s", e)
            hint = (
                "Cung cấp một đường dẫn đầy đủ, tải lên tệp trước qua 'upload_file', "
                "hoặc truyền bytes/base64. Ví dụ payload:\n"
                "{\n"
                "  \"name\": \"upload_file\",\n"
                "  \"arguments\": {\n"
                "    \"file\": { \"base64\": \"<...>\", \"filename\": \"my.pdf\" }\n"
                "  }\n"
                "}"
            )
            raise ValueError(f"extract_text failed: {e}. {hint}")

Công cụ chỉ là một lớp bọc. Nó là một trình quản lý điều phối các phần khác của mã. Nó xử lý các đầu vào rối rắm, gọi logic dịch vụ sạch sẽ và đóng gói phản hồi cuối cùng. Mô hình 'try...except ValueError' là một thực tiễn tốt nhất quan trọng.

Bước 3: Kết Nối Cuối Cùng - "Đăng Ký"

Hàm công cụ của chúng ta đã được định nghĩa, nhưng ứng dụng máy chủ vẫn chưa biết nó tồn tại. Bước cuối cùng là kết nối, hoặc đăng ký, mô-đun công cụ của chúng ta với phiên bản ứng dụng "FastMCP" chính.

Tập tin: src/fastmcp_pdf_server/main.py

Tập tin này là điểm vào của toàn bộ máy chủ. Nhiệm vụ của nó là xây dựng đối tượng ứng dụng và đăng ký tất cả các bộ công cụ.

python Copy
from __future__ import annotations

from typing import Any

from .config import settings
from .utils.logger import get_logger

logger = get_logger(__name__)


def build_app() -> Any:
    try:
        from fastmcp import FastMCP  # type: ignore
    except Exception as exc:
        raise SystemExit(
            "fastmcp chưa được cài đặt. Vui lòng cài đặt các phụ thuộc trước."
        ) from exc

    app = FastMCP(settings.server_name, version=settings.server_version)

    from .tools import utilities, text_extraction, pdf_manipulation, conversion, uploads
    from .services.file_manager import cleanup_expired

    utilities.register(app)
    text_extraction.register(app)
    pdf_manipulation.register(app)
    conversion.register(app)
    uploads.register(app)

    try:
        cleanup_expired()
    except Exception as exc:
        logger.error("cleanup_expired at startup failed: %s", exc)

    return app

Bằng cách nhập các mô-đun và gọi hàm "register" từ mỗi mô-đun. Tập tin chính vẫn sạch sẽ và hoạt động như một tóm tắt cấp cao về khả năng của máy chủ. Thêm hoặc xóa một loại công cụ hoàn toàn đơn giản như thêm hoặc xóa một dòng ở đây.

Bức Tranh Hoàn Chỉnh

Bây giờ, hãy theo dõi một yêu cầu từ đầu đến cuối:

  1. Một LLM gọi công cụ extract_text.
  2. Ứng dụng FastMCP, được xây dựng trong main.py, chuyển hướng cuộc gọi đến hàm bất đồng bộ extract_text bên trong text_tools.py.
  3. Hàm công cụ gọi resolve_to_path để có đường dẫn tệp sạch.
  4. Hàm công cụ sau đó gọi dịch vụ pdf_processor.extract_text với đường dẫn sạch đó.
  5. Dịch vụ thực hiện công việc nặng nhọc và trả về một từ điển đơn giản: {'text': ..., 'page_count': ...}.
  6. Hàm công cụ nhận từ điển này, thêm char_count và khối meta, và trả về từ điển cuối cùng và đã được làm giàu.
  7. FastMCP gửi từ điển cuối cùng này trở lại LLM dưới dạng phản hồi JSON.

Kết Quả Cuối Cùng

Sử dụng Claude Desktop như là khách hàng MCP, chúng ta có thể kiểm tra công cụ "extract_text" từ máy chủ của chúng ta, đơn giản bằng cách đăng ký MCP, thêm nó vào tệp cấu hình "claude_desktop_config.json"

json Copy
{
  "mcpServers": {
    "pdf-processor-server": {
      "command": "D:\\Github Projects\\mcp_pdf_server\\.venv\\Scripts\\python.exe",
      "args": [
        "-m",
        "fastmcp_pdf_server"
      ],
      "env": {
        "TEMP_DIR": "D:\\Github Projects\\mcp_pdf_server\\temp_files"
      }
    }
  }
}

Khi bạn đã thêm MCP, nó sẽ trông như thế này.

Thông thường, đối với loại khách hàng MCP này, bạn nên thêm vào prompt của mình việc sử dụng Máy chủ MCP, trong trường hợp này là "Máy chủ xử lý PDF" của chúng ta; đôi khi, bạn cũng phải chỉ định đường dẫn đầy đủ của tệp.

Hướng Đi Tiếp Theo

Bạn đã hoàn thành! Bạn đã thiết lập một máy chủ, học cách kết nối với nó, yêu cầu nó trích xuất văn bản, và thậm chí đã nhìn thấy cách mọi thứ hoạt động.

Tiếp theo là gì?

  • Khám Phá Các Công Cụ Khác: Xem tệp README.md. Bạn sẽ tìm thấy danh sách các công cụ khác mà bạn có thể gọi, như merge_pdfs, split_pdf, và pdf_to_images.
  • Mở Rộng Máy Chủ: Cố gắng thêm công cụ của riêng bạn! Làm theo mô hình.
  • Tự Động Hóa Cuộc Sống Của Bạn: Nghĩ về các quy trình làm việc của bạn. Bạn có thể sử dụng máy chủ này để tự động trích xuất văn bản từ hóa đơn? Hoặc để kết hợp các báo cáo hàng tuần của bạn thành một PDF duy nhất? Quyền lực nằm trong tay bạn.

Chúc bạn lập trình vui vẻ! 🤖

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào