1_Architecture‐and‐Process‐Guide - EEager/pdf-mcp-server GitHub Wiki

PDF MCP Server - Architecture & Process Guide

✅전체 아키텍처 개요

✅핵심 구성 요소

1. Cursor IDE (클라이언트)

  • 사용자 인터페이스를 제공
  • AI 어시스턴트가 MCP 서버의 도구들을 활용
  • MCP 프로토콜을 통해 외부 서버와 통신

2. MCP Protocol (통신 계층)

  • JSON-RPC 기반 통신 프로토콜
  • stdin/stdout을 통한 메시지 교환
  • Tools, Resources, Prompts 세 가지 기본 개념

3. PDF MCP Server (우리가 만든 서버)

  • MCP 프로토콜 구현
  • PDF 처리 로직 제공
  • 도구(Tools) 등록 및 실행

4. pdf-parse Library (PDF 처리 엔진)

  • 실제 PDF 파일 파싱 담당
  • 바이너리 데이터를 텍스트로 변환
  • 메타데이터 추출

✅상세 데이터 플로우

시나리오: 사용자가 "document.pdf의 내용을 읽어줘"라고 요청

1. 사용자 입력
   ┌─────────────────┐
   │ Cursor IDE      │
   │ User: "document.│
   │ pdf의 내용을    │  
   │ 읽어줘"         │
   └─────────┬───────┘
             │

2. AI가 적절한 도구 선택
   ┌─────────┴───────┐
   │ Cursor AI       │
   │ "PDF 파일을     │
   │ 읽어야 하니까   │
   │ extract_pdf_text│
   │ 도구를 사용하자"│
   └─────────┬───────┘
             │

3. MCP 요청 생성 및 전송
   ┌─────────┴───────┐
   │ MCP Client      │
   │ {               │
   │   "method":     │
   │   "tools/call", │
   │   "params": {   │
   │     "name":     │
   │     "extract_   │
   │     pdf_text",  │
   │     "arguments":│
   │     {"filePath":│
   │     "document.  │
   │     pdf"}       │
   │   }             │
   │ }               │
   └─────────┬───────┘
             │ JSON-RPC over stdin

4. MCP 서버가 요청 수신
   ┌─────────┴───────┐
   │ PDF MCP Server  │
   │ - 요청 파싱     │
   │ - 도구 이름 확인│
   │ - 매개변수 검증 │
   └─────────┬───────┘
             │

5. PDF 파일 처리
   ┌─────────┴───────┐
   │ PDFParser       │
   │ 1. 파일 존재확인│
   │ 2. 확장자 검증  │
   │ 3. 크기 제한확인│
   │ 4. 바이너리 읽기│
   └─────────┬───────┘
             │

6. pdf-parse 라이브러리 호출
   ┌─────────┴───────┐
   │ pdf-parse       │
   │ - PDF 구조 분석 │
   │ - 텍스트 추출   │
   │ - 메타데이터 수집│
   │ - 페이지 수 계산│
   └─────────┬───────┘
             │

7. 결과 데이터 구성
   ┌─────────┴───────┐
   │ PDFParser       │
   │ {               │
   │   "text": "...",│
   │   "pageCount": 5│
   │   "metadata": { │
   │     "title":... │
   │   }             │
   │ }               │
   └─────────┬───────┘
             │

8. MCP 응답 생성
   ┌─────────┴───────┐
   │ MCP Server      │
   │ {               │
   │   "content": [  │
   │     {           │
   │       "type":   │
   │       "text",   │
   │       "text":   │
   │       JSON.     │
   │       stringify(│
   │       result)   │
   │     }           │
   │   ]             │
   │ }               │
   └─────────┬───────┘
             │ JSON-RPC over stdout

9. Cursor AI가 결과 처리
   ┌─────────┴───────┐
   │ Cursor AI       │
   │ "PDF 파일에서   │
   │ 다음 내용을     │
   │ 찾았습니다:     │
   │ [텍스트 내용]   │
   │                 │
   │ 페이지 수: 5    │
   │ 제목: ...       │
   └─────────┬───────┘
             │

10. 사용자에게 결과 표시
   ┌─────────┴───────┐
   │ Cursor IDE      │
   │ Assistant:      │
   │ "이 PDF 파일은  │
   │ 5페이지로 구성  │
   │ 되어있고...     │
   │ [요약된 내용]   │
   └─────────────────┘

✅MCP 프로토콜 상세

Tools (도구)

MCP에서 Tools는 서버가 제공하는 기능들입니다. 우리 서버는 3개의 도구를 제공합니다:

// 1. extract_pdf_text - PDF 텍스트 추출
{
  name: 'extract_pdf_text',
  description: 'Extract text content from a PDF file',
  inputSchema: {
    filePath: z.string().describe('Path to the PDF file')
  }
}

// 2. get_pdf_metadata - PDF 메타데이터 추출  
{
  name: 'get_pdf_metadata',
  description: 'Get metadata information from a PDF file',
  inputSchema: {
    filePath: z.string().describe('Path to the PDF file')
  }
}

// 3. validate_pdf - PDF 파일 검증
{
  name: 'validate_pdf', 
  description: 'Validate if a file is a valid PDF',
  inputSchema: {
    filePath: z.string().describe('Path to the file to validate')
  }
}

통신 방식

MCP는 JSON-RPC 프로토콜을 사용하여 stdin/stdout으로 통신합니다:

// 요청 (Cursor → MCP Server)
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "extract_pdf_text",
    "arguments": {
      "filePath": "/path/to/document.pdf"
    }
  }
}

// 응답 (MCP Server → Cursor)
{
  "jsonrpc": "2.0", 
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"text\":\"PDF content...\",\"pageCount\":5,\"metadata\":{...}}"
      }
    ]
  }
}

✅코드 구조 심화 분석

src/index.ts - MCP 서버 진입점

class PDFMCPServer {
  private server: McpServer;     // MCP 프로토콜 서버
  private pdfParser: PDFParser;  // PDF 처리 로직

  constructor() {
    // 1. MCP 서버 초기화
    this.server = new McpServer({
      name: 'pdf-mcp-server',
      version: '1.0.0'
    });

    // 2. PDF 파서 초기화
    this.pdfParser = new PDFParser();
    
    // 3. 도구들 등록
    this.setupTools();
  }

  private setupTools(): void {
    // 각 도구를 MCP 서버에 등록
    // - 도구 이름, 설명, 입력 스키마 정의
    // - 실행 함수 연결
  }
}

핵심 역할:

  • MCP 프로토콜 구현
  • 도구 등록 및 라우팅
  • 요청/응답 처리
  • 에러 핸들링

src/pdf-parser.ts - PDF 처리 로직

export class PDFParser {
  async extractText(filePath: string): Promise<PDFTextExtractResult> {
    // 1. 파일 검증
    if (!existsSync(filePath)) throw new Error('File not found');
    if (extname(filePath) !== '.pdf') throw new Error('Invalid file type');
    
    // 2. 파일 읽기
    const dataBuffer = readFileSync(filePath);
    
    // 3. pdf-parse 라이브러리 호출
    const data = await pdfParse(dataBuffer);
    
    // 4. 결과 구성
    return {
      text: data.text,
      pageCount: data.numpages, 
      metadata: data.info
    };
  }
}

핵심 역할:

  • 파일 시스템 상호작용
  • PDF 파일 검증
  • pdf-parse 라이브러리 래핑
  • 결과 데이터 구조화

src/types.ts - 타입 정의

// PDF 파싱 결과 구조
export interface PDFTextExtractResult {
  text: string;           // 추출된 텍스트
  pageCount: number;      // 페이지 수
  metadata: PDFInfo;      // 메타데이터
}

// PDF 메타데이터 구조
export interface PDFInfo {
  Title?: string;         // 제목
  Author?: string;        // 작성자
  CreationDate?: Date;    // 생성일
  // ... 기타 메타데이터
}

✅PDF 처리 과정 상세

1. 파일 검증 단계

// 파일 존재 확인
if (!existsSync(filePath)) {
  throw new Error('File not found');
}

// 확장자 검증  
if (extname(filePath) !== '.pdf') {
  throw new Error('Invalid file type');
}

// 크기 제한 (100MB)
const stats = statSync(filePath);
if (stats.size > 100 * 1024 * 1024) {
  throw new Error('File too large');
}

2. pdf-parse 라이브러리 동작

// 바이너리 데이터 읽기
const dataBuffer = readFileSync(filePath);

// pdf-parse 호출 - 내부적으로:
// 1. PDF 헤더 분석
// 2. 객체 트리 파싱  
// 3. 폰트 정보 추출
// 4. 텍스트 좌표 계산
// 5. 텍스트 순서 정렬
const data = await pdfParse(dataBuffer);

3. 결과 데이터 구조화

// pdf-parse 원시 결과를 우리 형식으로 변환
return {
  text: data.text,                    // 전체 텍스트
  pageCount: data.numpages,           // 페이지 수
  metadata: {
    title: data.info?.Title,          // 제목
    author: data.info?.Author,        // 작성자  
    creationDate: data.info?.CreationDate?.toISOString(),
    // ... 기타 메타데이터
  }
};

✅에러 처리 방식

1. 파일 레벨 에러

  • 파일 없음: "File not found: {path}"
  • 잘못된 형식: "Invalid file type: .txt"
  • 크기 초과: "File too large: {size} bytes"

2. PDF 파싱 에러

  • 손상된 PDF: pdf-parse가 내부적으로 처리
  • 암호화된 PDF: "Encrypted PDFs not supported"
  • 메모리 부족: "PDF too complex to parse"

3. MCP 프로토콜 에러

  • 잘못된 매개변수: JSON Schema 검증 실패
  • 도구 없음: "Unknown tool: {name}"
  • 내부 오류: "Internal server error"

✅실제 사용 시나리오

시나리오 1: 단순 텍스트 추출

사용자: "research.pdf 파일의 내용을 요약해줘"

1. Cursor AI가 extract_pdf_text 도구 선택
2. 파일 경로를 매개변수로 전달
3. PDF에서 텍스트 추출
4. AI가 텍스트를 분석하여 요약 생성
5. 사용자에게 요약 결과 제시

시나리오 2: 메타데이터 분석

사용자: "이 PDF는 언제 만들어졌고 누가 작성했어?"

1. Cursor AI가 get_pdf_metadata 도구 선택  
2. 메타데이터 추출
3. 생성일, 작성자, 제목 등 정보 반환
4. AI가 자연어로 정보 설명

시나리오 3: 파일 검증

사용자: "이 파일이 유효한 PDF인지 확인해줘"

1. Cursor AI가 validate_pdf 도구 선택
2. 파일 형식, 크기, 구조 검증
3. 검증 결과 반환 (true/false + 상세 정보)
4. AI가 검증 결과 설명

✅확장 가능성

1. 추가 기능

  • 페이지별 텍스트 추출: 특정 페이지만 읽기
  • 표 데이터 추출: 구조화된 데이터 파싱
  • 이미지 추출: PDF 내 이미지 파일 저장
  • OCR 지원: 스캔된 PDF 텍스트 인식

2. 성능 최적화

  • 스트리밍 처리: 대용량 파일을 청크 단위로 처리
  • 캐싱: 자주 사용되는 PDF 결과 저장
  • 병렬 처리: 여러 PDF 동시 처리

3. 보안 강화

  • 바이러스 스캔: 악성 PDF 탐지
  • 접근 권한: 파일 권한 확인
  • 입력 검증: 경로 순회 공격 방지