Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions docs/HEADERLESS_TABLES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Header-neutral table conversion

`convert_pdf_to_markdown` accepts the explicit, default-off
`allow_headerless_tables: true` option. The selected renderer profile is
`1.22.0`; ordinary calls and explicit `false` retain profile `1.21.0` and
the previous complete result envelope.

This addresses a narrow representational limit: GFM assigns header semantics
to its first row, so the default converter refuses a grid whose source does
not distinguish a header. The opt-in profile can preserve that grid as an
HTML table containing only escaped `<td>` data cells. It creates no `<th>`,
spans, inherited values or semantic blank values. Header roles remain
unestablished and a typed conversion gap remains visible.

The fallback applies only to complete source-covered ruled-rectangle cell
grids. Every cell must have rectangle evidence, every relevant source line
and item must be accounted for, and each text advance box must fit its one
cell. Missing/competing rectangles, overlapping items, cross-cell text,
truncated evidence, suspect text and ordinary aligned prose do not qualify.
This does not broaden the captioned/solid-mask, segmented-rule, or unruled
table paths. Those and existing GFM tables keep their prior rules. Source
text is HTML-escaped, never interpreted as markup or an attribute.

Example tool arguments:

```json
{
"pdf_path": "/absolute/local/document.pdf",
"allow_headerless_tables": true
}
```

The option composes with `compact` and `emit_table_proposals`. Table cells
are excluded from compact normalizations; if proposal emission is requested,
the unresolved-header region remains source-bound and available for review.
No OCR, model call or automatic verification is introduced. Empty cells
represent retained text coverage, not proof that the source's data is blank.

The earlier full corpus score belongs to the default text-only profile and
has not been improved, replaced or rescored by this option. Synthetic table
success does not establish general table accuracy, scan quality, unique
semantic topology or competitive benchmark performance. The broader
equation, scanned-document and uncertain-topology gaps remain separate work.
6 changes: 6 additions & 0 deletions docs/MCP_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ means persistence; each result retains its own verification or uncertainty statu
`review_extraction_workspace` is a read-only, source- and generation-bound viewer
entrypoint with bounded value, history, citation, and page-coverage views.

`convert_pdf_to_markdown` has a default-off `allow_headerless_tables` option
for narrowly qualified complete ruled-rectangle grids. The opted-in renderer
profile `1.22.0` emits escaped HTML data cells without assigning header roles;
typed uncertainty remains. Omitted or false retains the unchanged default
profile `1.21.0`. See [Header-neutral tables](HEADERLESS_TABLES.md).

`get_pdf_identity` provides parser-independent artifact binding for planning
and provenance. It streams at most 250 MiB from one read-only descriptor,
returns the canonical local path, exact byte length, and SHA-256, and rejects
Expand Down
6 changes: 5 additions & 1 deletion pdf-toolkit-mcp-share/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3772,7 +3772,7 @@ async function listTools(request) {
},
{
name: "convert_pdf_to_markdown",
description: "Convert a bounded page range of a local PDF into deterministic Markdown from the source-validated PDF Tools Extraction IR. Headings and lists require geometry or literal marker evidence. A table requires a complete recurring text grid, a clean ruled-rectangle grid, or a complete closed painted grid, with every item in one cell and real header evidence. A link requires a source-validated external http or https annotation target covering one contiguous text run. Unsupported tables and link targets, including merged cells, internal destinations, actions, and other schemes, stay escaped text with typed gaps. Compact extreme-margin page numbers and provenance furniture, plus same-band text repeated across selected pages, are removed with typed counts by default; detected headings and all source-evidenced table-region lines are preserved, and removal can be disabled. No OCR or external model. Optionally enable compact mode for counted dot-leader and spaced-hyphen normalizations. Optionally saves transactional UTF-8 Markdown. Use absolute or ~/ local paths, not Claude container paths (/mnt/...).",
description: "Convert a bounded page range of a local PDF into deterministic Markdown from the source-validated PDF Tools Extraction IR. Headings and lists require geometry or literal marker evidence. By default, a table requires a complete recurring text grid, a clean ruled-rectangle grid, or a complete closed painted grid, with every item in one cell and real header evidence. A link requires a source-validated external http or https annotation target covering one contiguous text run. Unsupported tables and link targets, including merged cells, internal destinations, actions, and other schemes, stay escaped text with typed gaps. Compact extreme-margin page numbers and provenance furniture, plus same-band text repeated across selected pages, are removed with typed counts by default; detected headings and all source-evidenced table-region lines are preserved, and removal can be disabled. No OCR or external model. Optionally enable compact mode for counted dot-leader and spaced-hyphen normalizations. Optionally saves transactional UTF-8 Markdown. Use absolute or ~/ local paths, not Claude container paths (/mnt/...).",
inputSchema: {
type: "object",
additionalProperties: false,
Expand All @@ -3788,6 +3788,7 @@ async function listTools(request) {
compact: { type: "boolean", description: "Opt into counted dot-leader, isolated page-number, and Unicode-letter spaced-hyphen normalizations. Default: false." },
remove_page_furniture: { type: "boolean", description: "Remove only source-evidenced extreme-margin page furniture and report every removed line by typed gap and counts. Set false to preserve all source lines. Default: true." },
emit_table_proposals: { type: "boolean", description: "Opt into emitting one bounded, deterministic table_proposals packet per abandoned table region (TABLE_TOPOLOGY_UNKNOWN or TABLE_RULING_UNSUPPORTED), carrying the region's text items, ruled and painted evidence, header hints, page, bbox, coordinate_space, and a source-and-IR-bound proposal_token so a host model can propose a structure for later read-only verification. Additive: the abstention gap is unchanged and default output stays byte-identical. Default: false." },
allow_headerless_tables: { type: "boolean", description: "Opt into header-neutral HTML data cells for a complete source-covered ruled-rectangle cell grid without header evidence. No header roles, spans or blank data values are inferred; incomplete, ambiguous and cross-cell geometry remains text with typed gaps. Uses renderer profile 1.22.0; default false keeps profile 1.21.0 and unchanged output. No OCR or model." },
output_path: { type: "string", description: "Optional absolute .md path, or ~/ path. The file is written only after complete bytes are staged and verified." },
overwrite: { type: "boolean", description: "Replace an existing output_path only when its exact expected_output_identity is also supplied. Default: false." },
expected_output_identity: EXPECTED_MARKDOWN_OUTPUT_IDENTITY_INPUT_SCHEMA
Expand Down Expand Up @@ -5867,6 +5868,7 @@ async function handleToolCall(request) {
"compact",
"remove_page_furniture",
"emit_table_proposals",
"allow_headerless_tables",
"output_path",
"overwrite",
"expected_output_identity",
Expand All @@ -5884,6 +5886,7 @@ async function handleToolCall(request) {
true,
);
const emitTableProposals = optionalBooleanArgument(markdownArgs.emit_table_proposals, "emit_table_proposals", false);
const allowHeaderlessTables = optionalBooleanArgument(markdownArgs.allow_headerless_tables, "allow_headerless_tables", false);
const overwrite = optionalBooleanArgument(markdownArgs.overwrite, "overwrite", false);
const expectedOutputIdentity = normalizeExpectedOutputIdentity(
markdownArgs.expected_output_identity,
Expand Down Expand Up @@ -5944,6 +5947,7 @@ async function handleToolCall(request) {
compact,
removePageFurniture,
emitTableProposals,
allowHeaderlessTables,
});
const pagesNeedingVision = deriveMarkdownVisionRouting(layout);

Expand Down
Loading
Loading