Skip to main content
Glama
Pranavdmg20

pdf-extract-mcp

by Pranavdmg20

pdf-extract-mcp

CI Python License: MIT MCP

비정형 PDF 문서에서 구조화된 데이터를 결정적으로 추출하는 Model Context Protocol(MCP) 서버입니다. 일반 텍스트 추출과 정규식/휴리스틱 필드 매칭을 사용하며, 추출 시점에 LLM API 호출이 없습니다.

기능

  • 실제 MCP 서버 — 공식 MCP Python SDK(2.x) 기반으로, stdio, SSE 또는 streamable HTTP를 통해 프로토콜을 사용합니다. 공식 클라이언트로 실제 서버를 구동하는 엔드투엔드 테스트로 검증되었습니다.

  • 스키마 기반 추출 — extract_fields에 임의의 JSON Schema를 지정하면 요청한 필드만 정확히 담긴 구조화된 JSON을 반환합니다.

  • 결정적이고 검증 가능 — 정규식/휴리스틱 매칭 방식이라 LLM API 호출이 없고, 숨은 비용도, 블랙박스도 없습니다. 모든 추출은 반복 가능하고 감사 가능합니다.

  • 사람이 읽을 수 있는 검증 보고서 — validate_against_schema가 필드별로 통과, 실패, 누락 사유를 설명합니다.

  • 사전 구축 스키마 — invoice, resume, purchase_order가 바로 사용 가능한 상태로 제공되며, 합성 샘플 PDF도 포함되어 있어 모든 기능을 즉시 시연할 수 있습니다.

  • 우아한 오류 처리 — 손상된 PDF, 없는 파일, 잘못된 스키마에 대해 스택 트레이스 대신 구조화된 오류를 반환합니다.

Related MCP server: StructureAI MCP Server

MCP란 무엇이며 왜 유용한가

Model Context Protocol은 AI 어시스턴트(Claude, Cursor 등)가 지속적인 양방향 연결을 통해 외부 도구를 호출할 수 있게 하는 개방형 표준입니다. PDF 텍스트를 채팅에 붙여넣고 모델에게 "알아서 처리해"라고 요청하는 대신, 어시스턴트가 pdf-extract-mcp를 직접 호출하여 사용자가 제공한 스키마에 맞는 구조화된 JSON을 받아 그에 따라 작업할 수 있습니다. 여기서 추출은 확률적 모델 호출이 아닌 결정적 방식(정규식 + 휴리스틱)이므로 모든 결과를 검사하고 반복할 수 있으며 비용도 저렴합니다. 따라서 필드가 특정 방식으로 추출된 이유를 알아야 하는 자동화된 문서 파이프라인(회계용 인보이스, ATS용 이력서, 조달용 구매 주문서)에 이상적입니다.

설치

cd pdf-extract-mcp
python3 -m venv .venv
source .venv/bin/activate
make install          # pip install -e ".[dev]"  (installs the console script too)

또는 일반 pip 사용 시:

pip install -e ".[dev]"

이 서버는 공식 MCP Python SDK(mcp >= 2.x, MCPServer API를 제공하는 현재 릴리스 라인)를 사용합니다. pdfplumber가 텍스트 추출을, jsonschema가 검증을, reportlab이 샘플 PDF 생성을 담당합니다.

설치 시 pdf-extract-mcp 콘솔 스크립트도 함께 제공되므로 어디서든 다음 명령으로 서버를 실행할 수 있습니다:

pdf-extract-mcp                     # stdio (default)
pdf-extract-mcp --transport streamable-http --host 127.0.0.1 --port 8000

실행

python server.py

이 명령은 MCP를 stdio로 제공합니다(기본값이며 Claude Code / Claude Desktop이 기대하는 방식). 네트워크 서비스로 노출할 수도 있습니다:

python server.py --transport streamable-http --host 127.0.0.1 --port 8000
python server.py --transport sse --host 127.0.0.1 --port 8001

Claude Code / Claude Desktop에 연결

Claude Code — 프로젝트 루트에 .mcp.json을 추가하세요:

{
  "mcpServers": {
    "pdf-extract": {
      "command": "python",
      "args": ["/absolute/path/to/pdf-extract-mcp/server.py"],
      "env": {}
    }
  }
}

Claude Desktop — 동일한 블록을 Claude Desktop 설정(claude_desktop_config.json, macOS에서는 ~/Library/Application Support/Claude/ 아래에 있음)에 추가하세요:

{
  "mcpServers": {
    "pdf-extract": {
      "command": "python",
      "args": ["/absolute/path/to/pdf-extract-mcp/server.py"]
    }
  }
}

저장 후 클라이언트를 재시작하세요. extract_fields, validate_against_schema, list_supported_document_types의 세 가지 도구가 표시됩니다.

도구

도구

용도

extract_fields(pdf_path, schema)

JSON Schema에 맞는 PDF에서 구조화된 필드 추출 -> {"ok": true, "data": {...}}

validate_against_schema(data, schema)

추출된 데이터를 스키마와 대조 검증 -> 사람이 읽을 수 있는 사유와 함께 통과/실패/누락 보고

list_supported_document_types()

사전 구축 스키마가 포함된 문서 유형 목록 표시

extract_fields의 schema 인자는 JSON Schema 객체, 기본 제공 스키마 이름(예: "invoice"), 또는 .json 스키마 파일 경로를 받을 수 있습니다. 기본 제공 스키마는 schemas/에 있습니다:

  • invoice — vendor_name, invoice_number, total_amount, due_date(필수) + issue_date, customer_name

  • resume — name, email(필수) + phone, skills

  • purchase_order — po_number, vendor_name, total_amount(필수) + issue_date, customer_name

실제 예제

먼저 샘플 PDF를 생성합니다(리포지토리에 이미 있음; 필요할 때마다 재생성 가능):

python sample_pdfs/generate_samples.py

이제 기본 제공 invoice 스키마 이름을 사용하여 샘플 인보이스에서 extract_fields를 호출합니다. Claude Code에서 "sample_pdfs/invoice.pdf에서 invoice 스키마로 필드를 추출해줘"라고 말하면 됩니다. 내부적으로는 다음에 해당하는 도구 호출이 실행됩니다:

{
  "name": "extract_fields",
  "arguments": {
    "pdf_path": "/absolute/path/to/pdf-extract-mcp/sample_pdfs/invoice.pdf",
    "schema": "invoice"
  }
}

실제 기대 결과:

{
  "ok": true,
  "data": {
    "vendor_name": "Acme Widgets Corp",
    "invoice_number": "INV-2024-0087",
    "total_amount": 1750.0,
    "due_date": "April 1, 2024",
    "issue_date": "March 1, 2024",
    "customer_name": "Globex Industries"
  },
  "text_length": 372
}

동일한 스키마로 validate_against_schema에 데이터를 넣으면:

{
  "ok": true,
  "valid": true,
  "passed": ["customer_name", "due_date", "invoice_number", "issue_date", "total_amount", "vendor_name"],
  "failed": [],
  "missing": [],
  "summary": "Valid: all 6 present field(s) conform to the schema.",
  "error": null
}

Python에서 직접 실행하여 실제 동작을 확인할 수 있습니다:

import json
from tools.extract import extract_fields
from tools.validate import validate_against_schema

schema = json.load(open("schemas/invoice.json"))
result = extract_fields("sample_pdfs/invoice.pdf", schema)
print(result["data"])
print(validate_against_schema(result["data"], schema))

server.py에서 MCP 도구 등록이 작동하는 방식

이것이 이 프로젝트의 핵심이므로 SDK가 대신 수행하는 작업을 정확히 이해할 가치가 있습니다.

1. 서버 객체 생성.

from mcp.server.mcpserver import MCPServer

mcp = MCPServer(
    "pdf-extract-mcp",
    title="PDF Extract MCP",
    description="Deterministic structured-data extraction from PDF documents",
    version="0.2.0",
)

MCPServer는 mcp SDK 2.x의 서버 클래스입니다. MCP 핸드셰이크 중 클라이언트가 보내는 JSON-RPC 메시지(initialize, tools/list, tools/call 등)에 응답하는 방법을 알고 있는 MCP 와이어 프로토콜을 구현합니다. 생성자 인자는 메타데이터입니다 — 서버 이름(프로토콜 핸드셰이크에 필수)과 클라이언트가 사용자에게 표시할 수 있는 선택적 title/description/version입니다.

2. 데코레이터로 각 도구 등록.

@mcp.tool()
def extract_fields(pdf_path: str, schema: dict) -> dict:
    """Extract structured fields from an unstructured PDF ..."""
    return _extract_fields(pdf_path, schema)

데코레이터는 세 가지 작업을 대신 수행합니다:

  • 이름 등록 — 함수 이름 extract_fields가 클라이언트가 호출하는 도구 이름이 됩니다. (@mcp.tool(name="...")로 재정의할 수 있습니다.)

  • 스키마 추론 — SDK가 함수의 타입 어노테이션(pdf_path: str, schema: dict)을 검사하여 도구의 JSON 입력 스키마를 자동 생성합니다. 그래서 MCP 클라이언트는 호출 전에 pdf_path가 문자열이고 schema가 객체임을 알 수 있습니다. FastAPI와 동일한 패턴입니다 — 타입이 곧 계약입니다.

  • 설명 — docstring이 도구 설명이 되며, Claude는 이를 읽고 언제 어떤 인자로 도구를 호출할지 결정합니다.

따라서 클라이언트가 서버에 "무엇을 할 수 있나요?"(tools/list)라고 묻으면 SDK는 데코레이트된 각 함수의 이름, 설명, 추론된 입력 스키마로 응답합니다 — 수동으로 동기화할 등록 테이블이 없습니다.

3. 함수 본문은 그냥 Python입니다.

클라이언트가 도구를 호출하면(tools/call with arguments) SDK가 JSON 인자를 역직렬화하고 함수를 호출한 다음 반환 값을 와이어를 통해 직렬화합니다. 반환 값이 클라이언트가 보는 것입니다 — 그래서 도구는 항상 일반 JSON 직렬화 가능한 dict를 반환하고 절대 예외를 발생시키지 않습니다. 예외는 불투명한 프로토콜 오류가 되지만, 구조화된 {"ok": false, "error": "..."} dict는 Claude가 읽고 대응할 수 있습니다. 실제 추출/검증 로직은 tools/extract.py와 tools/validate.py에 있어 MCP 클라이언트 없이도 단위 테스트가 가능합니다.

4. 실행.

if __name__ == "__main__":
    main()   # argparse -> mcp.run(transport="stdio")

mcp.run(transport="stdio")는 프로토콜 루프를 시작합니다: stdin에서 줄바꿈으로 구분된 JSON-RPC 요청을 읽고 등록된 도구에 디스패치한 다음 stdout에 응답을 씁니다. 이것이 서버의 전부입니다 — HTTP 프레임워크도, 라우트도, 수동 요청 처리도 없습니다. (streamable-http / sse의 경우 동일한 run() 호출이 내부 ASGI 앱을 시작합니다.)

한 가지 더 주목할 세부 사항: extract_fields는 스키마 dict, 기본 제공 스키마 이름, 또는 파일 경로를 받는 작은 헬퍼 _load_schema를 사용합니다 — 따라서 동일한 도구가 "invoice" 또는 전체 스키마 객체와 함께 작동합니다. 실제 추출 함수는 엄격하게(dict만) 유지되고 서버 계층에서 편의 변환을 처리합니다.

추출 작동 방식(결정적, 검증 가능)

  1. 텍스트 추출 — pdfplumber가 PDF를 열고 모든 페이지에서 일반 텍스트를 가져옵니다.

  2. 필드 매칭 — 스키마의 각 속성에 대해 정규식의 정렬된 목록을 시도하고 첫 번째 일치가 승리합니다(tools/extract.py -> _FIELD_PATTERNS). 패턴은 가장 구체적인 것부터 시도되며, 알 수 없는 필드 이름은 일반적인 "Field Name: value" 매칭과 동의어 테이블(_FIELD_ALIASES)로 폴백됩니다.

  3. 타입 변환 — 일치된 문자열을 JSON Schema 타입으로 변환합니다(예: "$1,750.00" -> "type": "number"에 대해 1750.0; 배열은 쉼표로 분할). 변환 실패 시 데이터 손실 대신 원시 문자열로 폴백됩니다.

  4. 검증 — validate_against_schema가 jsonschema 패키지로 추출된 데이터를 재검사하고 필드별로 통과, 실패(사람이 읽을 수 있는 사유 포함), 또는 완전 누락 여부를 보고합니다.

모든 단계가 일반 코드이므로 필드가 추출되었거나 추출되지 않은 정확한 이유를 추적할 수 있습니다 — 블랙박스가 없습니다.

오류 처리

세 도구 모두 모든 경로에서 구조화된 JSON을 반환합니다 — MCP 경계를 넘어 스택 트레이스를 발생시키지 않습니다:

  • 손상되었거나 읽을 수 없는 PDF -> {"ok": false, "error": "Could not read PDF ..."}

  • 없는 파일 -> {"ok": false, "error": "PDF not found: ..."}

  • 추출 가능한 텍스트가 없는 PDF -> {"ok": false, "error": "... contains no extractable text."}

  • 잘못된 스키마(비어 있음, 속성 없음, 또는 잘못된 JSON Schema) -> 구조화된 오류 키

  • 누락된 필수 필드 -> "missing"에 나열; 잘못된 값 -> 사유와 함께 "failed"에 나열

테스트

pytest tests/ -v

19개 테스트:

  • 세 가지 문서 유형(invoice, resume, purchase_order) 모두에 대한 성공적인 추출

  • 필수 필드가 누락된 PDF(부정 추출)

  • 잘못된 필드 타입, 누락된 필수 필드, enum/pattern 위반을 잡아내는 스키마 검증

  • 오류 경로: 손상된 PDF, 존재하지 않는 파일, 텍스트 없는 PDF, 잘못된 스키마

  • 실제 엔드투엔드 MCP 테스트(tests/test_mcp_end_to_end.py) — server.py를 하위 프로세스로 실행하고 공식 MCP 클라이언트로 stdio를 통해 연결한 다음 세 도구를 모두 와이어로 호출 — 이것이 라이브러리가 아닌 진짜 MCP 서버임을 증명합니다

샘플 PDF는 누락된 경우 tests/conftest.py가 자동으로 재생성합니다.

리포지토리 구조

pdf-extract-mcp/
  server.py                    # MCP server: MCPServer + tool registration + transports
  tools/
    __init__.py
    extract.py                 # pdfplumber text extraction + regex field matching
    validate.py                # jsonschema validation with structured reports
  schemas/
    invoice.json               # pre-built schema: invoice
    resume.json                # pre-built schema: resume
    purchase_order.json        # pre-built schema: purchase_order
  sample_pdfs/
    generate_samples.py        # reportlab generator for the 4 sample PDFs
    invoice.pdf
    invoice_missing_fields.pdf
    resume.pdf
    purchase_order.pdf
  tests/
    conftest.py                # auto-generates sample PDFs if missing
    test_tools.py              # unit tests for extract/validate
    test_mcp_end_to_end.py     # end-to-end test over the real MCP stdio transport
  README.md
  requirements.txt

문제 해결

  • ModuleNotFoundError: No module named 'mcp' — 가상환경에 있지 않은 것입니다: source .venv/bin/activate(또는 ./.venv/bin/python server.py 사용).

  • FastMCP import 오류 — server.py는 mcp 2.x API(MCPServer)를 대상으로 합니다. 환경에 mcp 1.x가 있다면 pip install -U "mcp>=2.0"으로 재설치하세요.

  • Claude에 도구가 표시되지 않음 — 설정 편집 후 클라이언트를 재시작하고, "args"가 server.py의 절대 경로를 가리키는지 확인하며, 필요한 경우 venv의 python을 명령으로 사용하세요.

  • 추출이 필드를 놓침 — tools/extract.py의 _FIELD_PATTERNS에 해당 필드의 패턴을 추가하세요(또는 일반적인 "Field Name: value" 폴백과 동의어 테이블에 의존).

A
license - permissive license
A
quality
C
maintenance

Maintenance

UpdatingMaintainers
UpdatingResponse time
Release cycle
0Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI-powered extraction and analysis of PDF documents with 40+ specialized tools for text, tables, images, layout analysis, security assessment, and document intelligence. Supports both text-based and scanned PDFs with OCR capabilities.
    10
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Extracts structured JSON data from unstructured text using predefined schemas for receipts, invoices, resumes, and emails. It allows users to transform messy text into organized data through built-in or custom-defined fields.
    1
  • A
    license
    A
    quality
    D
    maintenance
    Enables RAG over messy PDFs — extract, chunk, embed, and search scanned, multi-column, and table-heavy documents.
    6
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Extracts text and tables from PDFs for AI agents via MCP, enabling structured data retrieval from invoices, reports, and statements.
    1
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Pranavdmg20/pdf-extract-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server