Skip to main content
Glama

Extract plain text from PDF

extract_text
Read-onlyIdempotent

Extracts plain text from PDFs by decoding font mappings, returning per-page and full text in logical order for search, indexing, and analysis.

Instructions

Plain-text extraction: decodes Tj/TJ operands through each font's /ToUnicode CMap, /Encoding /Differences or base encoding and returns pages[] + fullText (positioned runs with includeRuns:true; pages selects 0-based pages). extractable is false only when a page decoded ENTIRELY to U+FFFD (a font with no usable mapping — expected for some subset fonts, not an error; extractableReason explains). Tagged content carrying /ActualText (every pdfA document this server writes) returns that SOURCE text, in logical order; untagged right-to-left and reordered shaped runs (Arabic, Hebrew, Indic, Khmer, Myanmar, …) carry /ActualText since pdfnative 1.9 and come back in logical order too — only a Thai above-vowel + tone-mark pair still reads in drawn order untagged. onStreamError: 'limit' (default) fails only on a stream over the decompression cap (PDF_PARSE_FAILED), 'throw' fails on any undecodable stream, 'skip' returns the page without that stream's text. Encrypted sources: pass password (PASSWORD_REQUIRED / PASSWORD_INVALID otherwise). Token-frugal: verbosity:'summary', fields:[…].

Input Schema

NameRequiredDescriptionDefault
pagesNoOptional 0-based page indices to extract. When omitted, every page is extracted.
fieldsNoOptional dot-path projection applied to the structured result (e.g. ['fullText'] or ['extractable']). Composes after verbosity. Unknown paths are omitted.
passwordNoPassword (user or owner) of an encrypted source. Never logged or echoed.
pdfBase64YesBase64-encoded PDF bytes.
verbosityNoResponse verbosity. 'full' (default) returns the per-page pages[] array and fullText; 'summary' returns a token-frugal { pageCount, extractedPageCount, extractable, charCount } and drops the text payloads.full
includeRunsNoWhen true, each page also carries `runs[]` — positioned text-showing operations `{ text, x, y, fontSize, fontName }` in device space (content-stream order). Useful for layout-aware extraction; larger responses.
maxTextLengthNoHard cap on total extracted characters across all pages (memory bound for adversarial input). Default 16000000. Exceeding it fails with OUTPUT_TOO_LARGE.
onStreamErrorNo'limit' (default): a stream over the decompression cap (PDFNATIVE_MCP_MAX_INFLATE_BYTES) fails with PDF_PARSE_FAILED; other damaged streams are skipped. 'throw': any undecodable stream fails the call (PDF_PARSE_FAILED). 'skip': skip the over-cap stream too and read the rest (1.7.0 behaviour — that page reads as empty).limit

Output Schema

NameRequiredDescriptionDefault
pagesNo
fullTextNo
charCountNosummary only: length of fullText.
pageCountNo
extractableNoFalse when one or more requested pages produced text that is entirely U+FFFD replacement characters — a font with no usable /ToUnicode CMap or base encoding. Blank pages are still considered extractable.
extractableReasonNoPresent when extractable is false: why no text could be decoded.
extractedPageCountNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv1.8.0
    • addedInput schema / properties / onStreamError
      Added value: +{
      +  "default": "limit",
      +  "description": "'limit' (default): a stream over the decompression cap (PDFNATIVE_MCP_MAX_INFLATE_BYTES) fails with PDF_PARSE_FAILED; other damaged streams are skipped. 'throw': any undecodable stream fails the call (PDF_PARSE_FAILED). 'skip': skip the over-cap stream too and read the rest (1.7.0 behaviour — that page reads as empty).",
      +  "enum": [
      +    "limit",
      +    "skip",
      +    "throw"
      +  ],
      +  "type": "string"
      +}
  2. Changed7 schema fields changed
    • changedInput schema / properties / password / description
      Previous value: -"Password to open an encrypted source PDF (user or owner — both are tried). Omit for unencrypted documents. Never logged or echoed back."New value: +"Password (user or owner) of an encrypted source. Never logged or echoed."
    • addedOutput schema / description
      Added value: +"Structured text-extraction result. Every property is optional because the result can be projected: verbosity:'summary' returns only the scalar summary fields, fields:[...] keeps a dot-path subset. Defaults return the full shape."
    • addedOutput schema / properties / charCount
      Added value: +{
      +  "description": "summary only: length of fullText.",
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • changedOutput schema / properties / extractableReason / description
      Previous value: -"Human-readable explanation when extractable=false. Absent when extractable=true."New value: +"Present when extractable is false: why no text could be decoded."
    • removedOutput schema / properties / pages / items / properties / runs / items / required
      Removed value: -[
      -  "text",
      -  "x",
      -  "y",
      -  "fontSize",
      -  "fontName"
      -]
    • removedOutput schema / properties / pages / items / required
      Removed value: -[
      -  "index",
      -  "text"
      -]
    • removedOutput schema / required
      Removed value: -[
      -  "pageCount",
      -  "extractedPageCount",
      -  "extractable",
      -  "pages",
      -  "fullText"
      -]
  3. Changed5 schema fields changedv1.6.0
    • addedInput schema / properties / includeRuns
      Added value: +{
      +  "default": false,
      +  "description": "When true, each page also carries `runs[]` — positioned text-showing operations `{ text, x, y, fontSize, fontName }` in device space (content-stream order). Useful for layout-aware extraction; larger responses.",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / maxTextLength
      Added value: +{
      +  "description": "Hard cap on total extracted characters across all pages (memory bound for adversarial input). Default 16000000. Exceeding it fails with OUTPUT_TOO_LARGE.",
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • addedInput schema / properties / password
      Added value: +{
      +  "description": "Password to open an encrypted source PDF (user or owner — both are tried). Omit for unencrypted documents. Never logged or echoed back.",
      +  "maxLength": 4096,
      +  "minLength": 1,
      +  "type": "string"
      +}
    • changedOutput schema / properties / extractable / description
      Previous value: -"False when one or more requested pages had a non-empty content stream but yielded no extractable text (likely subset fonts without /ToUnicode)."New value: +"False when one or more requested pages produced text that is entirely U+FFFD replacement characters — a font with no usable /ToUnicode CMap or base encoding. Blank pages are still considered extractable."
    • addedOutput schema / properties / pages / items / properties / runs
      Added value: +{
      +  "description": "Positioned text runs (present only when includeRuns is true).",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "fontName": {
      +        "type": "string"
      +      },
      +      "fontSize": {
      +        "type": "number"
      +      },
      +      "text": {
      +        "type": "string"
      +      },
      +      "x": {
      +        "type": "number"
      +      },
      +      "y": {
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "text",
      +      "x",
      +      "y",
      +      "fontSize",
      +      "fontName"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
  4. Changed2 schema fields changedv1.2.0
    • addedInput schema / properties / fields
      Added value: +{
      +  "description": "Optional dot-path projection applied to the structured result (e.g. ['fullText'] or ['extractable']). Composes after verbosity. Unknown paths are omitted.",
      +  "items": {
      +    "minLength": 1,
      +    "type": "string"
      +  },
      +  "maxItems": 16,
      +  "type": "array"
      +}
    • addedInput schema / properties / verbosity
      Added value: +{
      +  "default": "full",
      +  "description": "Response verbosity. 'full' (default) returns the per-page pages[] array and fullText; 'summary' returns a token-frugal { pageCount, extractedPageCount, extractable, charCount } and drops the text payloads.",
      +  "enum": [
      +    "summary",
      +    "full"
      +  ],
      +  "type": "string"
      +}
  5. First observedv1.1.0

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description is unusually rich about semantics the annotations do not cover: `extractable` is false only when a page decoded ENTIRELY to U+FFFD, extractableReason explains it, /ActualText source-text handling, logical-order behavior for RTL/shaped scripts with the one Thai above-vowel caveat, and per-mode onStreamError outcomes with error codes. That is genuine behavioral context beyond the readOnly/idempotent hints, though the CMap/encoding internals are more implementation trivia than agent-relevant behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, and most sentences carry real information, but it is a single dense paragraph thick with backticks, parentheticals, and low-value internals (Tj/TJ operands, /Encoding /Differences, pdfnative 1.9 version trivia). Splitting the font-decoding internals from the parameter/behavior notes would improve scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter extraction tool with an output schema, the description covers the failure modes (PDF_PARSE_FAILED, OUTPUT_TOO_LARGE, PASSWORD_REQUIRED/PASSWORD_INVALID), the partial-success case (extractable=false), encoding/ordering edge cases, and the token-frugal path. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already defines every parameter including the onStreamError enum and verbosity modes; the description largely restates these. The only marginal additions are the framing of runs as "positioned runs" for includeRuns and the note that `pages` is 0-based, both of which the schema also carries.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ("Plain-text extraction") and immediately names the mechanism (decoding Tj/TJ operands via /ToUnicode CMap) plus the outputs (pages[] + fullText). It is clearly distinguishable from mutating siblings like sign_pdf or add_table, though it never explicitly names the closest logical sibling, inspect_layout, even while mentioning positioned runs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: "includeRuns:true ... Useful for layout-aware extraction" hints at a layout use case, and "Encrypted sources: pass `password`" is a precondition. There is no explicit when-to-use-this-vs-alternatives routing (e.g. vs inspect_layout or inspect_pdf), so the agent must infer.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.