#
tokens: 2917/50000 4/5 files (page 1/2)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 2. Use http://codebase.md/deepseekmine/mcp-pdf-reader?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .idea
│   ├── vcs.xml
│   └── workspace.xml
├── pdf_server.py
├── README.md
└── requirements.txt
```

# Files

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # 📄 MCP PDF Server
  2 | 
  3 | A PDF file reading server based on [FastMCP](https://github.com/minimaxir/fastmcp).
  4 | 
  5 | Supports PDF text extraction, OCR recognition, and image extraction via the MCP protocol, with a built-in web debugger for easy testing.
  6 | 
  7 | ---
  8 | 
  9 | ## 🚀 Features
 10 | 
 11 | - **read_pdf_text**  
 12 |   Extracts normal text from a PDF (page by page).
 13 | 
 14 | - **read_by_ocr**  
 15 |   Uses OCR to recognize text from scanned or image-based PDFs.
 16 | 
 17 | - **read_pdf_images**  
 18 |   Extracts all images from a specified PDF page (Base64 encoded output).
 19 | 
 20 | ---
 21 | 
 22 | ## 📂 Project Structure
 23 | 
 24 | ```
 25 | mcp-pdf-server/
 26 | ├── pdf_resources/        # Directory for uploaded and processed PDF files
 27 | ├── txt_server.py         # Main server entry point
 28 | └── README.md             # Project documentation
 29 | ```
 30 | 
 31 | ---
 32 | 
 33 | ## ⚙️ Installation
 34 | 
 35 | Recommended Python version: 3.9+
 36 | 
 37 | ```bash
 38 | pip install pymupdf mcp
 39 | ```
 40 | 
 41 | > Note: To use OCR features, you may need a MuPDF build with OCR support or external OCR libraries.
 42 | 
 43 | ---
 44 | 
 45 | ## 🔦 Start the Server
 46 | 
 47 | Run the following command:
 48 | 
 49 | ```bash
 50 | python txt_server.py
 51 | ```
 52 | 
 53 | You should see logs like:
 54 | 
 55 | ```
 56 | Serving on http://127.0.0.1:6231
 57 | ```
 58 | 
 59 | ---
 60 | 
 61 | ## 🌐 Web Debugging Interface
 62 | 
 63 | Open your browser and visit:
 64 | 
 65 | ```
 66 | http://127.0.0.1:6231
 67 | ```
 68 | 
 69 | - Select a tool from the left panel
 70 | - Fill in parameters on the right panel
 71 | - Click "Run" to test the tool
 72 | 
 73 | No coding required — easily debug and test via the web UI.
 74 | 
 75 | ---
 76 | 
 77 | ## 🛠️ API Tool List
 78 | 
 79 | | Tool | Description | Input Parameters | Returns |
 80 | |:-----|:------------|:-----------------|:--------|
 81 | | `read_pdf_text` | Extracts normal text from PDF pages | `file_path`, `start_page`, `end_page` | List of page texts |
 82 | | `read_by_ocr` | Recognizes text via OCR | `file_path`, `start_page`, `end_page`, `language`, `dpi` | OCR extracted text |
 83 | | `read_pdf_images` | Extracts images from a PDF page | `file_path`, `page_number` | List of images (Base64 encoded) |
 84 | 
 85 | ---
 86 | 
 87 | ## 📝 Example Usage
 88 | 
 89 | Extract text from pages 1 to 5:
 90 | 
 91 | ```bash
 92 | mcp run read_pdf_text --args '{"file_path": "pdf_resources/example.pdf", "start_page": 1, "end_page": 5}'
 93 | ```
 94 | 
 95 | Perform OCR recognition on page 1:
 96 | 
 97 | ```bash
 98 | mcp run read_by_ocr --args '{"file_path": "pdf_resources/example.pdf", "start_page": 1, "end_page": 1, "language": "eng"}'
 99 | ```
100 | 
101 | Extract all images from page 3:
102 | 
103 | ```bash
104 | mcp run read_pdf_images --args '{"file_path": "pdf_resources/example.pdf", "page_number": 3}'
105 | ```
106 | 
107 | ---
108 | 
109 | ## 📢 Notes
110 | 
111 | - Files must be placed inside the `pdf_resources/` directory, or an absolute path must be provided.
112 | - OCR functionality requires appropriate OCR support in the environment.
113 | - When processing large files, adjust memory and timeout settings as needed.
114 | 
115 | ---
116 | 
117 | ## 📜 License
118 | 
119 | This project is licensed under the MIT License.  
120 | For commercial use, please credit the original source.
121 | 
122 | ---
```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
1 | fitz
2 | mcp
3 | 
```

--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------

```
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <project version="4">
3 |   <component name="VcsDirectoryMappings">
4 |     <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
5 |     <mapping directory="$PROJECT_DIR$" vcs="Git" />
6 |   </component>
7 | </project>
```

--------------------------------------------------------------------------------
/pdf_server.py:
--------------------------------------------------------------------------------

```python
  1 | from typing import Optional, List, Dict, Any
  2 | import os, json
  3 | import base64
  4 | import fitz
  5 | from mcp.server.fastmcp import FastMCP
  6 | import uuid
  7 | import logging
  8 | from datetime import datetime
  9 | 
 10 | logging.basicConfig(level=logging.INFO)
 11 | logger = logging.getLogger('mcp-pdf-server')
 12 | 
 13 | PDF_DIR = os.path.join(os.getcwd(), "pdf_resources")
 14 | os.makedirs(PDF_DIR, exist_ok=True)
 15 | 
 16 | mcp = FastMCP("PDF Reader", version="1.0.0", description="MCP server for PDF reading")
 17 | 
 18 | pdf_resources = {}
 19 | pdf_cache = {}
 20 | 
 21 | 
 22 | @mcp.tool()
 23 | def read_pdf_text(file_path: str, start_page: int = 1, end_page: Optional[int] = None) -> Dict[
 24 |     str, Any]:
 25 |     """
 26 |     Read normal text from a PDF file, one text per page.
 27 | 
 28 |     Args:
 29 |         file_path: Path to the PDF file
 30 |         start_page: Start page (1-based)
 31 |         end_page: End page (inclusive)
 32 | 
 33 |     Returns:
 34 |         Dict containing:
 35 |             - page_count: total number of pages
 36 |             - pages: list of {page_number, text}
 37 |     """
 38 |     if not os.path.exists(file_path):
 39 |         raise ValueError(f"File not found: {file_path}")
 40 | 
 41 |     doc = fitz.open(file_path)
 42 |     total_pages = len(doc)
 43 | 
 44 |     if start_page < 1:
 45 |         start_page = 1
 46 |     if end_page is None or end_page > total_pages:
 47 |         end_page = total_pages
 48 |     if start_page > end_page:
 49 |         start_page, end_page = end_page, start_page
 50 | 
 51 |     pages = []
 52 | 
 53 |     for page_num in range(start_page - 1, end_page):
 54 |         page = doc[page_num]
 55 |         page_text = page.get_text()
 56 | 
 57 |         pages.append({"page_number": page_num + 1, "text": page_text.strip()})
 58 | 
 59 |     doc.close()
 60 | 
 61 |     return json.loads(json.dumps({"page_count": total_pages, "pages": pages}, ensure_ascii=False))
 62 | 
 63 | 
 64 | @mcp.tool()
 65 | def read_by_ocr(file_path: str, start_page: int = 1, end_page: Optional[int] = None,
 66 |         language: str = "eng", dpi: int = 300) -> Dict[str, Any]:
 67 |     """
 68 |     Read text from PDF file using OCR.
 69 |     Args:
 70 |         file_path: Path to the PDF file
 71 |         start_page: Start page (1-based)
 72 |         end_page: End page (inclusive)
 73 |         language: OCR language code
 74 |         dpi: OCR DPI
 75 |     Returns:
 76 |         Dict with extracted text, page_count, extracted_pages
 77 |     """
 78 |     if not os.path.exists(file_path):
 79 |         raise ValueError(f"File not found: {file_path}")
 80 | 
 81 |     doc = fitz.open(file_path)
 82 |     total_pages = len(doc)
 83 | 
 84 |     if start_page < 1:
 85 |         start_page = 1
 86 |     if end_page is None or end_page > total_pages:
 87 |         end_page = total_pages
 88 |     if start_page > end_page:
 89 |         start_page, end_page = end_page, start_page
 90 | 
 91 |     text_content = ""
 92 |     for page_num in range(start_page - 1, end_page):
 93 |         page = doc[page_num]
 94 |         try:
 95 |             textpage = page.get_textpage_ocr(flags=3, language=language, dpi=dpi, full=True)
 96 |             page_text = page.get_text(textpage=textpage)
 97 |         except Exception as e:
 98 |             logger.warning(f"OCR failed on page {page_num + 1}, fallback to normal text: {e}")
 99 |             page_text = page.get_text()
100 | 
101 |         text_content += page_text + "\n\n"
102 | 
103 |     doc.close()
104 | 
105 |     return {"text": text_content, "page_count": total_pages,
106 |         "extracted_pages": list(range(start_page, end_page + 1))}
107 | 
108 | 
109 | @mcp.tool()
110 | def read_pdf_images(file_path: str, page_number: int=1) -> Dict[str, List[Dict[str, Any]]]:
111 |     """
112 |     Extract images from a specific page in PDF.
113 |     Args:
114 |         file_path: Path to the PDF file
115 |         page_number: Page number (1-based)
116 |     Returns:
117 |         Dict with list of images (base64 format)
118 |     """
119 |     if not os.path.exists(file_path):
120 |         raise ValueError(f"File not found: {file_path}")
121 | 
122 |     doc = fitz.open(file_path)
123 |     total_pages = len(doc)
124 | 
125 |     if page_number < 1 or page_number > total_pages:
126 |         raise ValueError(f"Page number {page_number} out of range (1-{total_pages})")
127 | 
128 |     page = doc[page_number - 1]
129 |     image_list = page.get_images(full=True)
130 | 
131 |     images = []
132 |     for idx, img in enumerate(image_list):
133 |         xref = img[0]
134 |         base_image = doc.extract_image(xref)
135 |         image_data = base_image["image"]
136 |         image_ext = base_image["ext"]
137 |         image_b64 = base64.b64encode(image_data).decode('utf-8')
138 | 
139 |         images.append({"image_id": f"p{page_number}_img{idx}", "width": base_image["width"],
140 |             "height": base_image["height"], "format": image_ext, "image_b64": image_b64})
141 | 
142 |     doc.close()
143 | 
144 |     return {"images": images}
145 | 
146 | 
147 | if __name__ == "__main__":
148 |     logger.info("Starting MCP PDF Server...")
149 |     logger.info(f"PDF resources will be stored in: {PDF_DIR}")
150 |     mcp.run()
151 | 
```
Page 1/2FirstPrevNextLast