Home

MCP Tools

The server exposes five tools. Four are read-only; to_markdown writes to disk.

The intended loop: parse a document, read the headings that look relevant, search when none of them do, get_outline if the outline scrolls out of context, and to_markdown when the user wants the document itself rather than an answer drawn from it.


parse

Parse a document and return its heading outline. Call this first.

Accepts a local path or an http(s) URL; the format is detected automatically.

ParameterTypeDefaultDescription
sourcestrFile path or URL to parse
passwordstr | NoneNoneFor an encrypted document
refreshboolFalseRe-parse even if an identical parse is cached

Returns

FieldDescription
doc_idHandle to pass to every other tool
titleDocument title from metadata
pagesPage count
headingsNumber of headings in the hierarchy
document_tokensSize of the whole document — what reading everything would cost, not the size of this response
outlineHeading outline, each line marked with its read cost
is_completefalse when an outline was returned, true when the full text was
textPresent only when is_complete is true — the whole document
rendererHTML sources only: "static" means no browser rendered the page

A short document comes back as text with is_complete: true instead of an outline. There is nothing left to fetch — read and search on it would return only what the model already holds. The threshold is controlled by DOCSLICER_MCP_FULL_TEXT.

renderer: "static" means Playwright was not available, so scripts never ran and heading detection is weaker. A thin outline on a static render may be incomplete rather than accurate — see Installation.


get_outline

Re-fetch a parsed document's outline, with per-heading read costs. For when the outline has scrolled out of context. Cheap — no re-parse.

ParameterTypeDescription
doc_idstrHandle from parse

Returns doc_id, title, and outline.


read

Return the text under one or more headings, chosen from the outline.

ParameterTypeDescription
doc_idstrHandle from parse
headingslist[str]Exact outline headings, or "Parent > Heading"

Pass heading text exactly as the outline prints it, and pass every heading you want in a single call. A heading includes its subsections, so it returns roughly the tokens the outline printed against it — prefer a subsection when the parent is large.

Disambiguation. Where a heading appears in more than one place, prefix any ancestor with > to pick one — "Notes > Revenue". The full chain is never required. Unqualified, every match is returned.

Nesting. Asking for a heading and one nested under it returns the ancestor alone, since its text already carries the other. The folded-in headings come back under already_included with the parent they were returned under — nothing is missing.

Returns

FieldDescription
doc_idEchoed back
textThe section text, with [Page X] markers
tokens_returnedThe same per-heading figures the outline quoted
already_includedHeadings folded into an ancestor, if any
noteExplains already_included when present

A [Page X] line means the text below it is on page X until the next such line, numbered as the document numbers it (S-23, iv). Cite the nearest marker above the quote — sections run over several pages, so the page a section opens on is right only for its first part.


Find where something is discussed. Use when the outline is not enough.

ParameterTypeDefaultDescription
doc_idstrHandle from parse
querystrA term, a phrase, or a description
limitint8Most sections to return, each a distinct place

Try the outline first — it is faster. Search is for when it does not settle the question: headings that name nothing useful (Note 14, Item 7A), a figure buried in a table no heading mentions, or a section too big to read whole.

Two matchers run together. A whole-word literal match catches NCT03785249, €1.2m, a surname — the things a tokenizer would split or BM25's idf would misjudge. BM25 over the chunks finds sections about a topic the query only describes. Literal hits rank first: naming a string exactly is a stronger signal of intent than resembling one. One hit per heading — the same place twice is a wasted slot, not a stronger match.

Returns doc_id, query, hits, a note, and unmatched_terms when the query contained words the document does not have. Each hit:

FieldDescription
headingPass this to read
pagePage reference for the matching chunk
snippetA window cut around the match
snippet_is_partialPresent when the snippet was cut from something longer
read_tokensWhat reading that heading costs

Search returns places, not answers. Stop at a snippet only when it answers the question alone and depends on nothing outside the window. A partial snippet is missing what sat around it — often a table's header row, so figures appear without the column naming them. Never infer a truncated table's columns.

unmatched_terms exists because score magnitude cannot tell a good query from a bad one: a nonsense query whose one real word happens to be rare will outscore a sensible query about a common topic. Listing the words that appear nowhere makes that recognisable.


to_markdown

Write the whole document to disk as markdown. Returns a path, not the text.

ParameterTypeDefaultDescription
sourcestr | NoneNoneFile path or URL. Omit if passing doc_id
doc_idstr | NoneNoneHandle from a previous parse — reuses it instead of parsing again
passwordstr | NoneNoneFor an encrypted document. Ignored with doc_id
output_pathstr | NoneNoneWhere to write it

For when the user wants the document as a file rather than an answer drawn from it. Nothing enters the model's context, so document size stops mattering. Tables, charts, page markers, and structure are all preserved.

Output path resolution. Absolute paths are used as given; relative paths resolve against the source file's directory. The default is the source filename with a .md extension, written next to the source — for a URL source, to a temp directory. Parent directories are created.

Returns doc_id, title, pages, output_path (always absolute), markdown_size_bytes, overwrote, and document_tokens.

An existing file at the destination is overwritten without prompting. The response sets overwrote: true when that happened — worth surfacing to the user.


Chunking options

Every parse on the server uses one fixed set of options, chosen for reading rather than embedding — larger chunks, no headers/footers, no comments, tables as markdown, and exact token counts via tiktoken. They are not model-facing and cannot be set per call. To control chunking yourself, use the Python API.


Next steps

  • Configuration — transports, sandboxing, cache limits
  • MCP Server — install and how the outline-first design works