dual-extract-mcp

dual-extract-mcp

Enables structured document understanding of local PDFs via a dual-extract MCP server, combining MinerU text/layout and Qwen3-VL vision with fusion adjudication for field extraction, tables, formulas, and validation. Fully local and offline.

Category
访问服务器

README

双路抽取 MCP Server(dual-extract-mcp)

把「MinerU 文本/版面路 + Qwen3-VL 视觉路 + 双路融合裁决」封装成 MCP 工具集(8 个 Tool), 让 Claude Desktop / Cursor 等 MCP 客户端通过 stdio 调用,对本地 PDF 做结构化文档理解 (字段抽取 / 表格 / 公式 / 探查 / 校验)。完全本地、离线、零外部 API。

  • 状态:v0.2.1(v0.2.0 GA 之后修复 BUG-4 子区间页号偏移,353 回归全绿;M1-M7 全量完成:8 个 Tool 全注册 + 安全加固 + 降级完善 + 文档,G4 gate 真连验收 PASS;V1.0 增量落地:generation / artifact_id / field_id / quality_report.json / cell_provenance,406 回归全绿)
  • 传输:stdio(本期不监听端口)
  • 语言:Python 3.11+(受管 3.13.14 实测可用)

1. 功能一览(8 个 Tool)

Tool 说明 里程碑
dual_extract 双路+融合主入口(字段抽取) M3(T03)
parse_text 文本路单跑 M2(T02)
vision_extract 视觉路单跑 M2(T02)
extract_table 表格(跨页 + 大表分层 + CSV/XLSX) M4(T04)
extract_formulas 公式(LaTeX + PNG 渲染) M5(T04)
inspect_document 文档探查(页数/表格/图片/公式统计) M6(T05)
validate_output 输出结构校验(schema/manifest) M6(T05)
health MinerU + Ollama 双服务探活 M1

完整输入/输出契约见 docs/api.md。


2. 环境要求

  • Python 3.11+(Windows 优先,Linux 兼容)
  • 本地已部署:
    • MinerU 服务 http://127.0.0.1:8000(/health 返回 {"status":"ok"})
    • Ollama http://127.0.0.1:11434(含 qwen3-vl:30b 视觉模型)

⚠️ 沙箱提示:本沙箱内 python -m venv 会静默失败,须用受管 Python 建 venv (C:\Users\Administrator\.workbuddy\binaries\python\versions\3.13.12\python.exe -m venv .venv)。 用户本机无此坑,按下方标准命令即可。


3. 安装

# 1. 建 venv(受管 Python 3.13.14;用户本机可直接 python -m venv .venv)
C:\Users\Administrator\.workbuddy\binaries\python\versions\3.13.12\python.exe -m venv .venv

# 2. 激活 + 安装(含测试依赖)
.\.venv\Scripts\Activate.ps1
pip install -e ".[test]"

# 3. 复制配置模板并按需修改(可选;不配则用默认值)
Copy-Item .env.example .env

4. 运行

# 开发期直跑(stdio 交互;起几秒确认无报错即可 Ctrl+C)
python -m dual_extract.server
# 或等价的 console script
mcp-server

接入 Claude Desktop(claude_desktop_config.json)

{
  "mcpServers": {
    "dual-extract": {
      "command": "D:/Dual-Extract-MCP/.venv/Scripts/python.exe",
      "args": ["D:/Dual-Extract-MCP/src/dual_extract/server.py"]
    }
  }
}

接入 Cursor

~/.cursor/mcp.json:

{
  "mcpServers": {
    "dual-extract": {
      "command": "D:/Dual-Extract-MCP/.venv/Scripts/python.exe",
      "args": ["D:/Dual-Extract-MCP/src/dual_extract/server.py"]
    }
  }
}

B1:MCP 客户端 CWD 不可控,建议在 .env 中把 DUAL_EXTRACT_OUTPUT_DIR 配成绝对路径。


5. 测试

# 单元测试(默认跳过 smoke)
pytest -q

# 冒烟:真连本机 MinerU/Ollama(需服务在线)
pytest -m smoke -q

当前回归:353 passed,9 smoke deselected(2026-08-03 v0.2.1 全量回归核实); V1.0 增量后:406 passed,9 smoke deselected(2026-08-03 V1.0 全量回归核实)。


5.1 V1.0 增量说明(2026-08-03)

V1.0 在 v0.2.1 基础上新增 5 项可选/默认关能力(全部 additive,schema_version 保持 "1.0",旧客户端零改动):

增量 落点 说明
meta.generation extraction.json → meta.generation 生成环境信息:{generator, version, mineru_version, vlm, vlm_backend}(PRD §5.1)
artifact_id extraction.json 顶层 + document.artifact_id 产物唯一身份:{pdf_stem}_{YYYYMMDD}_{seq:03d}(同 run 幂等复用)
fields[].field_id extraction.json → fields[] / aggregated_pages[] 字段审计 ID:{artifact_id}.field.{key_snake}.p{page}.{seq:03d}
quality_report.json 抽取类 Tool job 结束自动落盘({产物目录}/quality_report.json) 质量报告:17 顶层键,overall 自动三态判定(达标/有条件达标/不达标)
tables[].cell_provenance extract_table 输出(默认关,DUAL_EXTRACT_CELL_PROVENANCE=true 开启) 单元格溯源五字段 {row, col, value, page, bbox};chunked 大表 >500 行只记录前 500 行 + warning

挂接约定(artifact_manifest,V1.0 P2):产物唯一身份由 artifact_id + manifest.json 的 SHA256 + 相对路径 三元组确定——artifact_id 标识「哪次抽取」,SHA256 保证「内容未被篡改」,相对路径定位「文件在哪」。详见 docs/最终输出说明.md §4 / docs/api.md §2.4。


6. 配置项(全部前缀 DUAL_EXTRACT_,仅 config.py 读取)

键 默认值 说明
DUAL_EXTRACT_MINERU_BASE_URL http://127.0.0.1:8000 MinerU HTTP 端点
DUAL_EXTRACT_MINERU_TIMEOUT 120 MinerU 请求超时(秒)
DUAL_EXTRACT_OLLAMA_BASE_URL http://127.0.0.1:11434 Ollama 端点
DUAL_EXTRACT_OLLAMA_MODEL qwen3-vl:30b 视觉模型
DUAL_EXTRACT_OLLAMA_TIMEOUT 600 Ollama 超时(秒;冷启动模型加载可达)
DUAL_EXTRACT_OLLAMA_THINK false 视觉路 thinking 开关(G2,默认关)
DUAL_EXTRACT_OUTPUT_DIR ./outputs 输出根目录(建议绝对路径)
DUAL_EXTRACT_OUTPUT_VERSIONED false true 时输出加时间戳子目录
DUAL_EXTRACT_CONFIDENCE_THRESHOLD 0.7 低置信阈值
DUAL_EXTRACT_PARALLEL false 页并行(默认串行防 3090 OOM)
DUAL_EXTRACT_MAX_FILE_MB 500 输入 PDF 大小上限
DUAL_EXTRACT_MAX_PAGES 1000 页数上限
DUAL_EXTRACT_IMAGE_DPI 200 页图/图片 DPI
DUAL_EXTRACT_CROP_FIGURES false 图表/印章裁剪开关
DUAL_EXTRACT_SINGLE_PATH_DEGRADE true 单路降级开关
DUAL_EXTRACT_CELL_PROVENANCE false 表格单元格溯源(V1.0;开启后 tables[].cell_provenance 记录 row/col/value/page/bbox,chunked 大表自动降级)
DUAL_EXTRACT_MODEL_JUDGE false 模型裁判(默认关,v0.4 前不实现)
DUAL_EXTRACT_LOG_LEVEL INFO 日志级别
DUAL_EXTRACT_TEMP_DIR ./tmp 临时目录(退出清理)
DUAL_EXTRACT_CSV_SPLIT_ROWS 500 CSV 分片行数

7. 真实样例用法

# 1. 探查:先「ls」一份 PDF 再决定抽取策略
#    inspect_document 返回 {pages, tables, images, formulas, text_chars}
#    样例:232 页财报 → 421 图 / 213,232 字符(MinerU 不可达时自动降级 PyMuPDF)

# 2. 双路字段抽取
#    dual_extract(pdf_path="D:/samples/中芯国际_年报.pdf",
#                 fields=["公司代码","公司简称","法定代表人","报告期","资产总计"],
#                 field_types={"资产总计":"money","报告期":"date"})

# 3. 表格(跨页 + 大表分层 + CSV/XLSX)
#    extract_table(pdf_path="D:/samples/中芯国际_年报.pdf", pages=[10,11],
#                  format=["json","csv"], cross_page=true)

# 4. 公式
#    extract_formulas(pdf_path="D:/samples/中芯国际_年报.pdf", pages=[20],
#                     render=true, tex=false)

# 5. 校验结果
#    validate_output(output_dir="D:/Dual-Extract-MCP/outputs/中芯_年报")
#    → {"schema_version": "1.0", "ok": true, "errors": [], "manifest_ok": true}
#    (产物目录含 extraction.json + manifest.json;manifest 记录各产物 SHA256,
#      validate_output 会与磁盘实文件比对,防产物漂移/被篡改)

8. 项目结构(四层架构,依赖单向向下)

MCP Layer       server.py → mcp/{tools,handlers,converters}.py
    ↓
Service Layer   services/*.py(extract/parse/vision/table/formula/inspect/validate/health)
    ↓
Pipeline Layer  pipelines/*.py + fusion/*.py
    ↓
Adapter Layer   adapters/base.py(接口缝)+ mineru/ollama/storage 实现
  • 与外部服务唯一耦合点 = 三个 Adapter 的 Protocol 接口(MinerUAdapter / OllamaAdapter / StorageAdapter)。
  • 铁律:不建注册表、不预写第二后端(Docling/云模型/对象存储 v0.4+ 再说)。
  • 详见 docs/architecture.md。

9. 常见问题(FAQ)

9.1 VPN 代理导致 localhost 请求 502 / 超时(trust_env 陷阱)

Windows 上挂极光 VPN(端口 29290)时,Python httpx 默认 trust_env=True 会读取系统 注册表代理,把 http://127.0.0.1:8000 的 localhost 请求也走代理 → 502。 本项目所有 Adapter 的 httpx.AsyncClient 一律 trust_env=False,无需手动处理。 若在自定义脚本里直接调 httpx,请同样加 trust_env=False。

9.2 Ollama 冷启动 600s 超时

qwen3-vl:30b(30B 模型)首次加载进显存可能耗时 1-5 分钟,第一请求容易超时。 本项目 DUAL_EXTRACT_OLLAMA_TIMEOUT 默认 600 秒,足够冷启动; 若你的显存/磁盘更慢,可调大该值。探活(health)用固定 8s 短超时,不受此影响。

9.3 3090 24G 显存:默认串行防 OOM

qwen3-vl:30b 在 3090 24G 下并行多页易 OOM。默认 DUAL_EXTRACT_PARALLEL=false(串行), 页图渲染也是串行(F1)。若显存充裕可开并行,但建议先压测单页显存占用。

9.4 MinerU 不可达时怎么办

  • dual_extract / vision_extract / parse_text:自动降级(视觉路单跑或纯文本), 输出 warnings 标 degraded,不整体失败;
  • inspect_document:自动降级为纯 PyMuPDF 本地统计(页数/图片/文本字符), degraded=true + warnings 标注。

9.5 输出目录找不到产物

MCP 客户端 CWD 不可控,务必在 .env 把 DUAL_EXTRACT_OUTPUT_DIR 配成绝对路径 (如 D:/Dual-Extract-MCP/outputs)。产物按 pdf_stem 分目录: {输出根}/{pdf文件名}/extraction.json + manifest.json。


10. Roadmap

  • v0.2-alpha gate(T01-T03 = M1-M3):骨架 + 单路 + 双路融合闭环 ✅
  • T04(M4-M5):表格 + 公式 ✅
  • T05(M6-M7):inspect/validate + 安全加固 + 降级完善 + 文档 ✅
  • v0.2.0(2026-08-03 转正):G4 gate 真连验收 PASS(8 Tool 真连全通 + 3 P1 修复闭环 + 349 回归全绿)✅
  • v0.2.1(2026-08-03 发版):BUG-4 MinerUAdapter 子区间页号偏移修复(parse(pages=[7]) 时产物 page_idx 从 0 重编号,blocks 全标 page=1;应按 pages[0] 偏移)——commit bec69aa,353 回归全绿(4 个 BUG-4 专项回归)✅
  • V1.0(2026-08-03 增量):meta.generation / artifact_id / fields[].field_id / quality_report.json 自动产出 / tables[].cell_provenance(默认关)——5 项 additive 增量,406 回归全绿,QA 独立验证 PASS ✅
  • 模型裁判(C3 默认关)→ v0.4 前不实现
  • 多后端注册表(Docling/云模型/对象存储)→ 保持 roadmap

详细设计见 docs/技术方案设计_双路抽取MCP.md / docs/双路抽取MCP_架构设计.md / docs/双路抽取MCP_PRD.md / docs/architecture.md / docs/api.md。 输出质量评估(三层框架 + 可执行脚本)见 docs/输出质量评估指南.md / tools/assess_output_quality.py。

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选