doc-splitter

doc-splitter

Conceptual document splitter that parses PDF/DOCX into study-sized chunks with safe-cut constraints, verified output, and bilingual study indexes, exposed as MCP tools for AI coding assistants.

Category
访问服务器

README

ducsplit

Conceptual document splitter for verified, study-sized chunks — CLI and MCP.

ducsplit splits large PDF and DOCX documents into study-sized conceptual chunks, not blind page ranges. It is built for developers using AI coding assistants (Claude Code, Codex, Cursor, Grok, OpenCode, or any MCP-capable host) who need to break textbooks, lecture notes, and manuals into sessions an agent can actually work with.

Repository: github.com/alifazelidehkordi/ducsplit

Table of Contents

Why This Exists

Long study documents overwhelm AI assistants: they exceed context windows, trigger lost-in-the-middle failures, and waste tokens. Simple page slicing makes it worse — it cuts through arguments, divorces tables from their explanations, and ignores how the author actually structured the material.

ducsplit combines deterministic document parsing with host-agent reasoning:

  • The tool extracts structured elements from PDF or DOCX into a shared intermediate representation (IR).
  • It proposes structurally safe boundary candidates — only after complete paragraphs, headings, lists, or tables.
  • Your host AI agent reads the surrounding content and chooses the best conceptual cut (or extends the window if the topic continues).
  • Output is verified for missing, duplicated, or mismatched content.
  • Each chunk can be analyzed into bilingual Persian/English study metadata.
  • Final study indexes link to every session and include a practical Study Focus column.

ducsplit does not bundle its own LLM. The host agent supplies judgment; ducsplit supplies parsing, constraints, persistence, writing, and verification.

Key Features

  • Conceptual splitting — targets 5–10 page study sessions, but lets concept completeness override page count.
  • Safe-cut constraints — the LLM can only choose from deterministic candidates, preventing mid-paragraph, mid-list, and mid-table cuts.
  • Dual PDF parsingpymupdf4llm for Markdown-like extraction plus OpenDataLoader for layout reconciliation when Java is available.
  • DOCX support — headings, paragraphs, lists, tables, and embedded images via python-docx.
  • CLI and MCP — use doc-splitter directly or expose it as an MCP server to AI coding assistants.
  • Verified output — checks element coverage, duplicates, word-count drift, table rows, image references, and PDF page coverage.
  • Markdown and PDF chunks — write semantic Markdown chunks, extracted PDF chunks, or both.
  • Boundary overlap for PDFs — includes adjacent boundary pages to reduce loss when conceptual cuts occur mid-page.
  • Agent-authored bilingual study indexes — provides verified context for the host agent to write study-index-fa.md and study-index-en.md with session links, study focus, page ranges, and estimated reading time.
  • Agent-decision enforcement — rejects auto-generated reasons (auto-cut, auto from section_headings), template study-focus, and index commits without reading every chunk file.
  • Realistic study-time estimates — defaults to 80 words per minute (study speed) rather than casual reading speed (200 wpm) for technical/medical content.

Architecture

flowchart TD
    A[PDF or DOCX input] --> B[Format Detector]

    B -->|PDF| C[pymupdf4llm Parser]
    B -->|PDF| D[OpenDataLoader Layout Parser]
    C --> E[Document IR]
    D --> F[PDF Reconciler]
    F --> E

    B -->|DOCX| G[python-docx Parser]
    G --> E

    E --> H[Structure Analyzer]
    H --> I[Safe Boundary Candidate Generator]
    I --> J{Host AI Agent}
    J -->|cut| K[Boundary Session]
    J -->|extend| I

    K --> L[Writer]
    L -->|markdown| M[.md Chunks]
    L -->|pdf| N[.pdf Chunks]
    L --> O[manifest.json]

    O --> P[Verifier]
    P --> Q[verification-report.json]

    M --> R{Host AI Agent}
    N --> R
    R --> S[Chunk Analysis Store]
    S --> T[Index Generator]
    T --> U[study-index-fa.md]
    T --> V[study-index-en.md]

Requirements

Dependency Version Purpose
Python 3.10+ Core pipeline and CLI
Java 11+ OpenDataLoader PDF layout reconciliation (recommended)
Node.js 18+ MCP server only
Host AI agent Boundary decisions and chunk content analysis

Java is recommended for better PDF reconciliation. Parsing falls back to pymupdf4llm alone if OpenDataLoader cannot run.

Installation

git clone https://github.com/alifazelidehkordi/ducsplit.git
cd ducsplit

python3 -m venv .venv
source .venv/bin/activate

pip install -e ".[dev]"
npm install

java -version   # must succeed for full PDF reconciliation

The Python package exposes the CLI:

doc-splitter --help

If the command is not on your shell path:

python -m doc_splitter.cli --help

Quick Start: CLI

Start a split session:

doc-splitter run \
  --input ./book.pdf \
  --out ./output/book \
  --min-pages 5 \
  --max-pages 10

This parses the document, writes ir.json, creates .split-session.json, and prints the first boundary decision context.

Repeat the boundary loop until the context reports status: "complete":

doc-splitter boundary-context --out ./output/book

Ask your host agent to read the JSON, choose one safe candidate, and return either:

{
  "action": "cut",
  "element_id": "el-042",
  "reason": "The current explanation ends here; the next section starts a different topic."
}

Commit the decision:

doc-splitter commit-boundary \
  --out ./output/book \
  --action cut \
  --element-id el-042 \
  --reason "The current explanation ends here; the next section starts a different topic."

If the concept continues beyond the current window:

doc-splitter commit-boundary \
  --out ./output/book \
  --action extend \
  --reason "The same mechanism continues into the next example."

After boundaries are complete, write and verify chunks:

doc-splitter write --out ./output/book

Analyze each chunk:

doc-splitter analysis-context --out ./output/book --chunk-id 1

Commit the host agent's bilingual analysis:

doc-splitter commit-analysis \
  --out ./output/book \
  --chunk-id 1 \
  --topic-fa "تنظیم گلوکز و پاسخ انسولین" \
  --topic-en "Glucose Regulation and Insulin Response" \
  --study-focus-fa "مسیرهای اصلی تنظیم قند خون، نقش انسولین و تفاوت پاسخ طبیعی و پاتولوژیک را مرور کنید." \
  --study-focus-en "Review the main glucose-control pathways, insulin's role, and how normal and pathological responses differ." \
  --coherence confident \
  --reason "The chunk covers one continuous regulatory mechanism."

Ask the host agent to write the final indexes after every chunk has analysis:

doc-splitter index --out ./output/book
doc-splitter commit-index \
  --out ./output/book \
  --fa-file ./agent-written-study-index-fa.md \
  --en-file ./agent-written-study-index-en.md

PDF-native chunks

doc-splitter run \
  --input ./book.pdf \
  --out ./output/book-pdf \
  --output-format pdf \
  --overlap-pages 1

Quick Start: MCP

After npm install, register the MCP server with your host CLI (replace the path if you cloned elsewhere):

REPO=/absolute/path/to/ducsplit

claude mcp add doc-splitter -s user -- node "$REPO/server.js"
codex mcp add doc-splitter -- node "$REPO/server.js"
grok mcp add doc-splitter -s user -- node "$REPO/server.js"
opencode mcp add doc-splitter -- node "$REPO/server.js"

Or use the helper script:

./scripts/install-mcp.sh

For project-level MCP configuration, use .mcp.json:

{
  "mcpServers": {
    "doc-splitter": {
      "command": "node",
      "args": ["/absolute/path/to/ducsplit/server.js"],
      "env": {
        "DOC_SPLITTER_PYTHON": "/absolute/path/to/ducsplit/.venv/bin/python3"
      }
    }
  }
}

Then ask your agent:

Use the doc-splitter MCP tools to split book.pdf into 5–10 page conceptual Markdown chunks under output/book. Choose only safe boundary candidates, write the chunks, verify integrity, analyze every chunk in Persian and English, then author and commit the study indexes.

CLI Reference

Commands

Command Purpose
doc-splitter run Parse a document and start a boundary session.
doc-splitter parse Parse only and write ir.json; useful for debugging parser output.
doc-splitter boundary-context Print the current content window, instructions, and safe cut candidates.
doc-splitter commit-boundary Commit a cut or extend decision.
doc-splitter write Write chunks and run verification.
doc-splitter verify Re-run verification against existing chunks and manifest.
doc-splitter get-chunk Read one chunk's content by numeric ID.
doc-splitter analysis-context Print full chunk content and analysis instructions.
doc-splitter commit-analysis Store bilingual topic, study focus, coherence, and reason for one chunk.
doc-splitter index Return context for agent-authored study-index-fa.md and study-index-en.md.
doc-splitter commit-index Store final Persian and English indexes written by the host agent.

Common Options

Available on run, parse, boundary-context, commit-boundary, write, verify, and index unless noted.

Option Default Description
--out PATH output Output/session directory.
--min-pages N 5 Target minimum chunk size (converted to words via words_per_page).
--max-pages N 10 Target maximum chunk size; guidance for the host agent.
--reading-speed-wpm N 80 Study reading-speed estimate (wpm) for index time calculations. Use 80–100 for technical/medical content, 150–200 for general reading.
--output-format markdown|pdf|both markdown Chunk output format. PDF output requires PDF input.
--overlap-pages N 1 Extra neighboring pages around PDF boundary pages.

run

doc-splitter run --input ./book.pdf --out ./output/book

Required: --input PATH (source .pdf or .docx).

parse

doc-splitter parse --input ./book.docx --out ./output/debug

Writes ir.json without starting a boundary workflow.

boundary-context

Returns JSON with status, chunk_number, content_window, safe_candidates, instructions, min_pages, and max_pages. The host agent must choose only from safe_candidates.

commit-boundary

Option Required Description
--action cut|extend yes cut commits a boundary; extend expands the decision window.
--element-id ID for cut Safe candidate element ID.
--reason TEXT no Human-readable rationale stored for auditability.

write / verify

write writes chunk files, manifest.json, and verification-report.json. Exits non-zero if verification fails.

verify checks:

  • every expected IR element appears exactly once
  • no unknown elements are present
  • chunk word counts match the source within tolerance
  • Markdown tables preserve expected rows
  • Markdown image references are present
  • PDF outputs cover all non-skipped source pages

commit-analysis

coherence must be confident or needs_review. When all chunks have analysis, semantic-review-report.json is written.

index

Requires every chunk to have committed content analysis, including both study-focus fields. Returns verified chunk metadata and instructions for the host agent. It does not write the index prose.

commit-index

Stores the final study-index-fa.md and study-index-en.md bodies authored by the host agent. The command validates that every chunk file is referenced.

MCP Tools

Tool Inputs Mutates? Description
split_document file_path, optional min_pages, max_pages, output_dir, output_format, overlap_pages yes Parses a PDF/DOCX and starts the boundary session.
get_boundary_context optional output_dir no Returns the current content window and safe cut candidates.
commit_boundary action, optional element_id, reason, output_dir yes Commits a boundary cut or extends the window.
write_chunks optional output_dir yes Writes chunk files and runs verification.
get_chunk chunk_id, optional output_dir no Reads generated chunk content.
verify_integrity optional output_dir no Re-runs verification.
get_chunk_analysis_context chunk_id, optional output_dir no Returns full chunk content for analysis.
commit_chunk_analysis chunk_id, topic_fa, topic_en, study_focus_fa, study_focus_en, coherence, optional reason, output_dir yes Stores bilingual chunk analysis.
get_study_index_context optional output_dir, reading_speed_wpm no Returns context for agent-authored Persian and English study indexes.
commit_study_index index_fa, index_en, optional output_dir yes Stores final Persian and English study indexes written by the host agent.

The MCP server is a thin Node.js wrapper around the Python CLI. It uses DOC_SPLITTER_PYTHON when set; otherwise it runs python3.

Configuration

CLI / MCP Options

Setting CLI Option Default Notes
Output directory --out output Session state, IR, chunks, reports, indexes.
Minimum pages --min-pages 5 Filters early safe candidates.
Maximum pages --max-pages 10 Target guidance for the host agent.
Output format --output-format markdown markdown, pdf, or both.
Boundary overlap --overlap-pages 1 PDF outputs only.
Reading speed --reading-speed-wpm 80 Index time estimates; 80 wpm for technical/medical study, 150+ for general content.

Internal Defaults

Defined in src/doc_splitter/config.py. Not all have CLI flags yet.

Setting Default Purpose
boundary_window_pages 15 Initial content window shown to the host agent.
boundary_window_extension_pages 10 Pages added when the host chooses extend.
words_per_page 400 Converts page targets into word-count windows.
image_extraction true Extracts and preserves image references.
ocr_enabled false Scanned pages may be skipped.
on_missing_text_page skip_and_flag Missing-text pages recorded in verification output.
word_count_tolerance_pct 0.005 Allows small word-count drift during verification.
word_count_tolerance_min 10 Minimum word-count tolerance.
min_chunks_per_chapter 2 Minimum chunks for chapter grouping in indexes.
slug_max_length 60 Maximum semantic filename slug length.

Output Structure

A typical Markdown run:

output/book/
├── 01_intro-to-glucose-regulation.md
├── 02-insulin-signaling-and-feedback.md
├── images/
├── ir.json
├── manifest.json
├── verification-report.json
├── semantic-review-report.json
├── study-index-fa.md
├── study-index-en.md
└── .split-session.json

A PDF or both run may also include .pdf files per chunk.

Important Files

File Description
ir.json Parsed document intermediate representation.
.split-session.json Boundary decisions, stage, config snapshot, chunk analyses.
manifest.json Chunk list, filenames, page ranges, element IDs, boundary reasons.
verification-report.json Integrity report: coverage, word-count checks, skipped pages, reconciliation notes.
semantic-review-report.json Summary of chunk analyses and any needs_review chunks.
study-index-fa.md Persian study index (Overview, chapter table, Study Focus per session).
study-index-en.md English study index.
images/ Extracted image assets referenced by Markdown chunks.

Study Index Structure

Each agent-authored study-index-*.md should include:

  1. Overview — session count, PDF page coverage, total study time
  2. Session table — topic links, page ranges, estimated time, and Study Focus
  3. Optional grouping — chapters or sections only when they naturally fit the document
  4. Document-specific study guidance — only when useful for that source

Host-Agent Workflow

Boundary Loop

  1. ducsplit parses the document into ordered elements.
  2. It computes a window starting at the current cursor.
  3. It finds safe cut candidates after complete headings, paragraphs, lists, or tables.
  4. The host agent reads the content window and candidate list.
  5. The host agent chooses cut with an allowed element_id, or extend if the concept is incomplete.
  6. ducsplit validates the decision and moves the cursor.
  7. The loop continues until the document is fully covered.

Example context returned to the host agent:

{
  "status": "needs_agent_decision",
  "chunk_number": 4,
  "content_window": "...",
  "safe_candidates": [
    {
      "element_id": "el-042",
      "after_type": "paragraph",
      "snippet": "This completes the comparison of...",
      "cumulative_word_count": 9850
    }
  ],
  "min_pages": 5,
  "max_pages": 10
}

The LLM must not invent boundaries. Committing an element_id not in safe_candidates fails.

Analysis Loop

  1. analysis-context returns full chunk content and neighboring titles.
  2. The host agent writes a concise bilingual topic and practical study focus. topic_en becomes the final chunk filename slug.
  3. commit-analysis stores the result in .split-session.json, renames the chunk from the agent-selected topic, and updates manifest.json.
  4. Chunks marked needs_review appear in semantic-review-report.json and block final index commit until the boundary/coherence issue is resolved.
  5. Every get_chunk call is tracked. The agent must read all chunk files before commit-index is accepted.
  6. index returns context for the final index-writing pass, including chunks_unread so the agent knows which files remain.
  7. The host agent writes both complete Markdown indexes and stores them with commit-index.

The study focus should answer: What should the learner master in this session?

Good:

{
  "topic_en": "Insulin Signaling and Glucose Uptake",
  "study_focus_en": "Master the insulin receptor cascade, GLUT4 translocation, and how defects in the pathway explain insulin resistance."
}

Weak:

{
  "topic_en": "Insulin",
  "study_focus_en": "This section is about insulin."
}

Output Format Trade-Offs

Format Best For Trade-Offs
markdown AI reading, search, notes Loses exact PDF visual layout.
pdf Preserving original page appearance Boundaries are page-extracted; mid-page cuts need overlap.
both Text plus original page fidelity More disk space; may duplicate boundary pages.

For PDF output, conceptual chunks are decided by element boundaries, but written PDFs include whole pages. --overlap-pages reduces context loss at boundaries at the cost of duplicated pages between neighbors.

Edge Cases and Limitations

  • Scanned PDFs — OCR is disabled by default. Pages without extractable text are skipped and reported.
  • Password-protected PDFs — not supported.
  • DOCX page numbers — estimated from word count; DOCX has no stable rendered page numbers.
  • Non-Latin filenames — semantic slugs are ASCII-folded; fallback is section-N.
  • Very short documents — may produce fewer or smaller chunks than the 5–10 page target.
  • Very long concepts — the host agent should choose extend until a coherent cut appears.
  • Tables and lists — treated atomically; the tool avoids cutting through them.
  • OpenDataLoader failures — parsing continues with pymupdf4llm; recorded in reconciliation notes.
  • PDF boundary precision — PDF chunks are page-level extracts, not element-level visual crops.

Troubleshooting

Problem Likely Cause Fix
Unsupported file format Input is not .pdf or .docx. Convert or use a supported extension.
Password-protected PDFs are not supported PDF requires a password. Save an unlocked copy and rerun.
Java 11+ is required for OpenDataLoader Java missing or not on PATH. Install a JDK; confirm java -version.
OpenDataLoader skipped in report OpenDataLoader failed; fallback succeeded. Review reconciliation notes; fix Java if layout fidelity matters.
Verification fails (missing elements) Chunks or manifest inconsistent. Re-run write; inspect verification-report.json.
Verification fails (word-count mismatch) Parser and written chunks diverged. Inspect Markdown around tables/images; file an issue with sample input.
PDF output is only supported for PDF inputs --output-format pdf or both with DOCX. Use --output-format markdown for DOCX.
Missing content analyses during index Not every chunk has committed analysis. Run analysis-context and commit-analysis for each chunk.
Chunk files not yet read by the agent during commit-index Index committed without reading all chunk files via get_chunk. Call get_chunk for every unread chunk ID listed in the error; the CLI tracks reads automatically.
Boundary reason must be a conceptual decision Reason contains auto-cut or similar auto-generated pattern. Write a real conceptual reason explaining where the topic ends and why.
auto from section_headings is not acceptable Analysis reason is auto-generated. Read the chunk and provide your own coherence assessment.
auto-generated study-focus template in index Index contains template like Study X: core definitions, mechanisms. Write unique educational study focus for each session.
MCP server cannot import Python package Wrong Python interpreter. Set DOC_SPLITTER_PYTHON to the venv Python path.
Temporary-file errors No writable temp directory. Set TMPDIR to a writable directory.

Development

ducsplit/
├── server.js                         # MCP server
├── pyproject.toml                    # Python package metadata
├── package.json                      # Node/MCP dependencies
├── scripts/install-mcp.sh            # MCP registration helper
├── src/doc_splitter/
│   ├── cli.py                        # CLI entry point
│   ├── orchestrator.py               # Pipeline coordination
│   ├── config.py                     # SplitConfig defaults
│   ├── format_detector.py            # PDF/DOCX detection
│   ├── ir/                           # Intermediate representation
│   ├── parsers/                      # PDF/DOCX parsers and reconciliation
│   ├── boundary/                     # Safe candidates and boundary session
│   ├── writers/                      # Markdown and PDF writers
│   ├── content/                      # Chunk analysis workflow
│   ├── verifier.py                   # Integrity verification
│   └── index_generator.py            # Agent-authored index context/commit
└── tests/

Run tests:

source .venv/bin/activate
python -m pytest -q

Run the MCP server directly (waits for stdio MCP protocol messages):

node server.js

Recommended workflow:

  1. Add or update parser/writer behavior.
  2. Add focused tests under tests/.
  3. Run python -m pytest -q.
  4. Test a small real PDF or DOCX through the CLI.
  5. Inspect ir.json, manifest.json, and verification-report.json.
  6. If MCP behavior changed, test through an MCP host with DOC_SPLITTER_PYTHON pointing at the local venv.

Design Principles

  • LLM judgment is constrained — the agent decides among safe options; it does not rewrite parser state freely.
  • Agent laziness is rejected — auto-generated reasons (auto-cut, auto from section_headings), template study-focus, and index commits without reading chunk files are caught by validators and refused.
  • Verification is mandatory — generated chunks are auditable and checked for loss or duplication.
  • Concepts beat page counts — 5–10 pages is a target, not a hard rule.
  • No bundled LLMducsplit does not call an external LLM API; the host agent does.
  • PDF fidelity and semantic precision differ — Markdown is best for semantic processing; PDF output is best for visual study continuity.

License

No license file is currently included. Until one is added, the repository is public but not explicitly open-source licensed. Recommended next step: add an OSI-approved license (MIT or Apache-2.0).

推荐服务器

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 模型以安全和受控的方式获取实时的网络信息。

官方
精选