文件解析微服务

Parsival 是一个基于 MCP Python SDK 的文件解析微服务,支持多种文档格式转换为结构化输出(如 Markdown、JSON、文本),适用于流处理和代理集成。

  • by Aldrin-Joan
  • Python
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 Aldrin-Joan/Parsival-mcp

使用说明

帕西瓦尔

Parsival是一个基于MCP Python SDK的生产环境友好、基于工具的文件解析微服务。它旨在将常见的文档格式转换为丰富的结构化输出(Markdown、JSON、文本),并对流处理和代理集成进行性能调优和安全强化。

  • 支持的输入格式:PDF、DOCX、DOC、PPTX、XLSX、CSV、HTML、MD、TXT
  • 对大型文档的流式解析支持
  • 缓存层:内存LRU+可选Redis
  • 对损坏/加密文档的稳健处理、大小限制、子流程隔离
  • 插件式解析器注册表和后处理管道

目录

  1. 快速启动
  2. 特性
  3. 建筑
  4. 存储库布局
  5. 配置
  6. 本地开发
  7. 在Docker中运行
  8. API和工具
  9. 解析器详细信息
  10. 缓存行为
  11. 测试和CI
  12. 故障排除

快速启动

克隆存储库

git clone https://github.com/Aldrin-Joan/Parsival-mcp.git
cd Parsival-mcp

Python虚拟环境

Linux/macOS:

python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt

Windows(PowerShell):

python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

运行服务器

推荐(本地stdio MCP):

python -m src.mcp_entrypoint

这使用 MCP_TRANSPORT=stdio 默认情况下,在项目工具中,stdout专用于MCP协议流量。

验证支持的格式

from src.app import list_supported_formats
print(list_supported_formats())

特性

  • 使用专用解析器插件进行多格式文件解析
  • 以Markdown、JSON或原始文本输出
  • 流解析器模式(stream=True)对于早期块
  • Redis支持缓存,具有本地LRU回退功能
  • 可配置的文件大小上限和解析器超时
  • LibreOffice转换路径 .doc 支持
  • 通过以下方式进行过程中和工人过程隔离 ProcessPoolExecutor
  • 富有的 ParseResult 带有元数据、错误和可恢复性标志的模型
  • 可插拔的后处理管道:元数据丰富、表规范化、图像提取

建筑

逻辑层

  • src/app.py -工具定义和解析编排
  • src/core -配置、缓存、路由、执行器、安全
  • src/parsers -特定格式解析逻辑
  • src/post_processors -结果富集管道
  • src/serialisers -输出封送(Markdown、JSON、文本)
  • src/tools -公共工具API包装器

堆芯流量

  1. 客户端调用MCP工具(例如。, read_file).
  2. src/tools/read_file.py 通过验证路径 validate_safe_path().
  3. src.app.parse_file() 用途 FormatRouter 推断 FileFormat.
  4. 解析器从以下位置获取 src.parsers.registry.
  5. core.executor.run_parse_in_pool() 在进程池中执行解析器。
  6. PostProcessingPipeline 使输出正常化。
  7. 缓存密钥生成于 ContentHashStore 从文件哈希+选项。
  8. 返回序列化响应。

格式检测(路由器)

  • magic MIME嗅探(如果可用)
  • 扩展图(例如。, .pdf, .docx, .pptx)
  • CSV/HTML/Markdown的内容启发式

支持的工具

  • read_file
  • get_metadata
  • extract_table
  • extract_images
  • convert_to_markdown
  • search_file
  • list_supported_formats

存储库布局

.
├── Dockerfile
├── docker-compose.yml
├── pyproject.toml
├── requirements.txt
├── src/
│   ├── app.py
│   ├── config.py
│   ├── core/
│   ├── parsers/
│   ├── post_processors/
│   ├── serialisers/
│   ├── tools/
│   └── models/
└── tests/
    ├── unit/
    └── benchmarks/
  • src/config.py -环境驱动设置对象
  • src/core/cache.py -内存+Redis缓存层
  • src/core/router.py -文件格式确定
  • src/core/executor.py -具有线程限制的进程池执行
  • src/parsers/* -按格式解析逻辑
  • src/post_processors/* -丰富解析结果
  • src/serialisers/* -Markdown/JSON/文本序列化器
  • src/tools/* -MCP请求的工具包装器

配置

所需包

  • python>=3.11
  • 中列出的软件包 requirements.txt

可选服务

  • Redis(用于共享缓存)
  • LibreOffice(for .doc 转换;安装在Dockerfile中)

环境变量(MCP_ 前缀)

变量 默认值 描述
MCP_APP_NAME Parsival 应用程序名称(当前代码中未使用)
MCP_PROCESS_POOL_SIZE 4 解析的最大工作进程数
MCP_MAX_FILE_SIZE_MB 500 非流解析的最大文件字节数
MCP_MAX_STREAM_FILE_SIZE_MB 2048 流解析的最大文件字节数
MCP_HYBRID_HASH_THRESHOLD_MB 50 缓存键中完整哈希值与部分哈希值的阈值
MCP_REDIS_ENABLED false 启用Redis缓存后端
MCP_REDIS_URL None Redis服务器的URL
MCP_REDIS_TTL 3600 Redis密钥TTL(秒)
MCP_SENTRY_ENABLED false 启用Sentry(未捆绑在代码路径中)
MCP_SENTRY_DSN None 哨兵DSN
MCP_LIBREOFFICE_PATH None 覆盖LibreOffice路径
MCP_MAX_LIBREOFFICE_WORKERS 2 最大并发LibreOffice转换数
MCP_SUBPROCESS_TIMEOUT_SEC 30 文档解析器中的子进程超时
MCP_ALLOWED_DIRECTORIES [., /tmp] 允许用于文件读取路径的目录
MCP_WORKSPACE_ROOT . 根目录安全边界
MCP_TRANSPORT stdio MCP传输模式(仅限stdio)

来自解析器的无前缀环境变量

变量 默认值 用途
LIBREOFFICE_BINARY soffice LibreOffice CLI二进制文件
LIBREOFFICE_TIMEOUT_SEC 30 转换过程超时
LIBREOFFICE_SECONDARY_KILL_TIMEOUT_SEC 5 在终止信号缓冲区之前等待
LIBREOFFICE_MAX_CONCURRENT 2 并发转换

本地开发

安装

pip install -r requirements.txt

运行单元测试

pytest -q

运行stdio烟雾测试

python scripts/tool_smoke_test_stdio.py

运行基准测试

pytest -q tests/benchmarks/test_benchmarks.py

静态检查

ruff check .
python -m mypy src tests

添加预提交

pip install pre-commit
pre-commit install
pre-commit run --all-files

在Docker中运行

构建

docker build -t parsival:latest .

跑

运行(stdio模式,不需要端口映射):

docker run --rm -i -e PYTHONUNBUFFERED=1 -e MCP_TRANSPORT=stdio -e PYTHONPATH=/app parsival:latest

使用docker compose运行

运行stdio服务:

docker compose up parsival

作曲(单主机)

docker compose up --build

容器包括LibreOffice和 python-magic DOC/DOCX和格式嗅探所需的依赖关系。


API和工具

Parsival通过stdio公开MCP工具。使用您首选的MCP客户端按名称调用工具。

read_file

  • path:str
  • output_format:“markdown”|“json”|“text”(默认为“markdown”)
  • page_range:[开始,结束](1-索引)
  • include_images:bool(默认为true)
  • max_tokens_hint:int
  • stream:bool(默认值为false)

退货 ReadFileResult (状态、格式、内容、元数据、错误、cachehit、request_id)。

get_metadata

  • path:str
  • 退货 DocumentMetadata 对象(文件格式、页面计数、表格计数等)

extract_table

  • path:str
  • table_index:int
  • sheet_name:可选[str]
  • 退货 TableResult

extract_images

  • path:str
  • page_range:可选[tuple[int,int]]
  • max_dimension:可选[int]
  • 退货列表[ImageRef]

convert_to_markdown

  • path:str
  • 返回标记字符串

search_file

  • path:str
  • query:str
  • top_k:int
  • 在章节文本上使用BM25排名(通过 rank-bm25)

list_supported_formats

  • 无参数
  • 退货可用 FileFormat 值和服务器版本

解析器详细信息

支持的文件格式

  • PDF: src/parsers/pdf_parser.py (PyMuPDF+可选pdfplumber桌子)
  • DOCX: src/parsers/docx_parser.py (python docx)
  • 医生: src/parsers/doc_parser.py (LibreOffice转换+DOCX解析器)
  • XLSX: src/parsers/xlsx_parser.py (波兰openpyxl)
  • CSV: src/parsers/csv_parser.py (波兰,utf-8后撤)
  • PPTX: src/parsers/pptx_parser.py (python pptx)
  • HTML: src/parsers/html_parser.py (美汤+降价)
  • TXT/MD: src/parsers/text_parser.py (纯文本启发式)

解析工作流

  • parse_file 确定格式 FormatRouter.detect.
  • 解析器返回 ParseResult,包括 sections, tables, images, metadata, errors.
  • stream=True 分派解析器 stream_chunks,绕过缓存预取。
  • max_tokens_hint 是解析后应用的软截断。

错误处理

  • 损坏/加密的文档返回 ParseStatus.FAILED 和 ParseError 代码(例如。 encrypted, corrupt).
  • 超大文件返回 ParseStatus.OVERSIZE (元数据中的源路径/大小)。
  • 解析流防止在读取和结果刷新之间更改文件状态。

缓存行为

  • 内置缓存密钥 src/core/cache.py 作为 SHA256(file) + ':' + SHA256(opts).
  • 考虑的选项:output_format、page_range、include_images、max_tokens_hint、max_dision。
  • 内存LRU缓存 cachetools.LRUCache 样本大小基于ParseResult的JSON大小。
  • Redis后端如果 MCP_REDIS_ENABLED=true 和 MCP_REDIS_URL 已设置。
  • 连接失败时,Redis会自动回退到内存中。
  • 使用 MCP_REDIS_TTL (默认3600秒)。

测试和CI

本地试运行

pytest -q

覆盖

coverage run -m pytest -q
coverage report -m --fail-under=90

CI管道处于

  • .github/workflows/ci.yml
    • 针对Python 3.11/3.12/3.13的测试
    • ruff check .
    • 覆盖+编解码器

故障排除

道路卫生

src/core/security.py 强制执行 MCP_WORKSPACE_ROOT 和 MCP_ALLOWED_DIRECTORIES如果你得到 SecurityError:

  • 集 MCP_WORKSPACE_ROOT 到您的repo根目录
  • 通过添加允许的目录 MCP_ALLOWED_DIRECTORIES

不支持的格式

如果解析失败,格式不受支持,请检查扩展名+文件魔术,并仅使用标准格式。

LibreOffice失败

  • 确保 soffice 安装在PATH中(Dockerfile包括 libreoffice-* 包装)
  • 增加:
    • export LIBREOFFICE_TIMEOUT_SEC=60
    • export MCP_MAX_LIBREOFFICE_WORKERS=4

Redis缓存

  • 如果没有配置Redis,该服务将使用内存缓存。
  • 集 MCP_REDIS_ENABLED=true 和 MCP_REDIS_URL=redis://localhost:6379/0.

维护人员注意事项

  • 此README由以下代码和支持的配置生成 src/ 和 Docs/.
  • 对于扩展,请在中添加解析器类 src/parsers 并注册 @register(FileFormat.X).
  • 要公开新的MCP工具,请在中定义 src/tools 并在中添加装饰功能 src/app.py.