okraPDF PDF MCP server
OfficialServer Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OKRA_MCP_URL | No | Override the okraPDF MCP endpoint URL (default: https://okrapdf.com/mcp) |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| resources | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| view_htmlA | Drop a PDF (by public URL) and get back a LIVE, streaming, screen-reader-friendly HTML twin of the document — the same accessible rendering okrapdf.com serves. Returns a viewer_url that progressively streams semantic HTML (headings, lists, tables, figure alt text) as the page is parsed, plus an SSE events_url and a static download_url. Use this to make any PDF readable by assistive tech. (Reserved: policy="wcag" will add the WCAG 2.2 AA / PDF-UA / Section 508 conformance audit — not yet implemented.) |
| verify_sourceA | Verify a source for a PDF-backed claim and show the result as an inline citation state card. Default mode is high-level: pass document_id, claim, and any rough locator/pages/quote/number; Okra searches parsed nodes, handles not-found and multiple-candidate states, and when a confident source is found mints a durable link.okrapdf.com proof card with quote, page image, bbox focus, confidence, and reasons. For lawfully-reachable PDFs (permitted source or a doc the user has rights to; not paywalled/license-gated) that should not go through full upload/parse yet, pass pdf_url plus page/pages and the tool uses eager_url mode to fetch only that PDF page. verification_requirement defines what counts as verified and defaults to "bbox": eager_url must resolve coordinate evidence before proof is minted, and the API fails rather than returning a proof without bbox. Pass verification_requirement="text_match" only when a deterministic page-text/text-layer match is enough; that returns a found state without a durable proof link, page-image proof, or bbox-backed confidence claim. Use mode="exact_node" with nodes only when the agent is already grounded in exact query rows or node ids. This is the one model-facing source-verification tool; the result also includes create_view arguments for arranging returned card(s) in a custom view. |
| upload_documentA | Upload a PDF from a lawfully-reachable URL or base64 PDF bytes for Gemini Flash VLM extraction when later okraPDF tool calls need a document_id for SQL/search/docs.read, render_ui, view_document/review_extraction, parsed-node verification, or workflow runs. URL ingest is corpus-gated (see internal/content-rights-policy.md): open/public-record sources or docs the user has rights to — not paywalled/license-gated. For such URLs, prefer resolve_pdf_url so the D1 URL registry can reuse prior ingests. If you only need to read or understand PDF content for reasoning, use normal web_fetch/browser reading first; for arXiv papers, prefer arxiv.org/html/... when available. Do not use this for "verify", "cite", "prove", "source", or "where in the PDF" requests; call verify_source directly with pdf_url + page/pages instead. Opens a live document viewer immediately; the app polls status, page images, and extracted blocks as they arrive. Set wait=true only for legacy blocking status behavior. |
| resolve_pdf_urlA | Resolve a lawfully-reachable PDF URL to a stable okraPDF document_id using the D1 URL registry when later okraPDF tool calls need that document_id: execute_code SQL/search/docs.read, render_ui, view_document/review_extraction, verify_source with parsed-node evidence, or workflow runs. Intended for open/public-record sources (SEC EDGAR, gov, public-domain, permissively-licensed arXiv) and for documents the user supplies or has the rights to process. Do NOT use it to fetch behind a paywall, login, or anti-bot wall, and do NOT treat the resulting derivative as a public mirror of a copyrighted source — see internal/content-rights-policy.md (mirror levels). If you only need to read or understand the PDF content for reasoning, use normal web_fetch/browser reading first; for arXiv papers, prefer the arxiv.org/html/... page when available because it is cleaner and cheaper than OCR. Do not use this for "verify", "cite", "prove", "source", or "where in the PDF" requests; call verify_source directly with pdf_url + page/pages instead. Opens the live document viewer immediately while ingest/parse/page previews finish. Do not set wait_for/wait_ms unless the very next tool call depends on query/page/visual readiness. |
| describe_collectionA | Call this FIRST, before any execute_code or render_ui SQL. Returns collection metadata, the document list, the SQLite schema, the node data model (what a node / table / cell is, that cell values are raw strings and that row/column headers are positional sibling cells, not labels), and example queries — the context you need to write a working query on the first try. |
| execute_codeA | Execute JavaScript against Code Mode namespaces — the primary tool for exploring, querying, grepping, reading, and citing documents (results come back here). For a finished chart, table, metric, or HTML display, pass the working query to render_ui instead. Code Mode API: docs.list() → [{id, file_name, status, total_pages}] docs.status({ docId }) → {phase, totalPages, totalNodes, ...} docs.read({ docId, pages? }) → {markdown, page_count, total_pages, truncated?} docs.ask({ docId, question }) → {answer, citations, trace_id} (LLM — slow, use sparingly) docs.extract({ docId, prompt, jsonSchema }) → {data, trace_id} (LLM — slow, use sparingly) sql.query({ docId, sql }) → {rows, count} — read-only SQL on one doc; rows include document_id sql.queryMany({ docIds, sql }) → {results:[{docId, rows, count}], count} — run the same query across docs sql.search({ query, docId?, docIds? }) → FTS5 keyword/phrase search across one doc or the current collection sql.grep({ query, docId?, docIds?, pages? }) → literal substring search across node values; useful when FTS tokenization is too strict citation.create({ claim, nodes, docId?, minQuality? }) → {id, url, verification} — mint a shareable link.okrapdf.com/c/{id} proof card; minQuality defaults to "high". citation.batch({ items }) → {citations:[{id,url,...}], count} — mint many proof links from multi-doc results. SQLite tables per doc: nodes (id, parent_id, type, label, value, status, page_number, confidence, metadata, sort_order) nodes_fts — FTS5 on label+value (use MATCH) meta (key, value) page_ledger (page_number, status, pass, vendor, attempt, confidence, error) Node data model — the
Prefer SQL/FTS for discovery, filtering, keyword search, counting, and reading content. SQL is fast, free, and deterministic. Only fall back to reading full pages when SQL doesn't have what you need. When answering numerical or factual questions, use sql.query() to find exact values, then compute the answer step by step. If the first query doesn't return what you need, try a different query — iterate rather than guessing from partial data. IMPORTANT: nodes_fts rows contain full page text (5KB+ each). Always use substr() and JOIN nodes for page_number: SELECT n.page_number, substr(n.value, 1, 200) as excerpt FROM nodes_fts f JOIN nodes n ON n.id = f.node_id WHERE nodes_fts MATCH 'keyword' LIMIT 10 High-grade citation workflow:
Page images: https://api.okrapdf.com/v1/documents/{docId}/pg_{N}.png |
| view_documentA | Show the VISUAL extraction of a parsed okraPDF document: page images with colored bounding-box overlays over the extracted blocks that have bbox data (a bounded set per page), plus a clickable block list (click a box to highlight its text, and vice versa). Use after upload_document to let the user see and verify the extraction. Pass document_id and optional pages. For the structured text output instead (parsed nodes as plain reading HTML, no images), use inspect_html. |
| view_pdfA | Open the document as a PDF reader/navigation surface inside the MCP host. Shows page images and, when available, extracted bounding boxes. Use this for quick visual page inspection; use review_extraction when the user is specifically verifying parser output. |
| review_extractionA | Open the extraction review workflow: page images with bbox overlays and clickable extracted blocks that can be verified or flagged. This is the bbox/provenance workflow surface, not a PDF editor. |
| verify_blockA | Mark an extracted block as verified (✓) or wrong (✗), persisted to the document. Called by the view_document viewer when the user clicks a block; also usable directly with document_id + node_id. |
| interactA | Drive the document viewer the user already has open (from view_document): navigate, highlight a node, or auto-highlight text with the pdf-server-style highlight_text arguments query/page/color/content. Pass document_id plus view_uuid or viewUUID from the view_document result. Use commands or actions for ordered batches. Do NOT call view_document again to navigate — that opens a separate viewer. |
| poll_document_viewA | Internal: the viewer widget refreshes upload/parse/render status, page images, and extracted blocks. Not for direct agent use. |
| poll_view_commandsA | Internal: the viewer widget drains queued interact commands. Not for direct agent use. |
| inspect_htmlA | Show the STRUCTURED text output of a parsed document: the canonical extracted nodes rendered as plain webpage-like HTML pages — no page images, no bounding boxes. Omit page to render the available pages together (capped, ~50 pages for long docs); pass page for one specific page. Uses canonical DocumentAgent nodes (not vendor playground facets) and returns status="ready" only when node-backed HTML exists, else a not-ready state. For the visual extraction (page images + bounding-box overlays) instead, use view_document. |
| view_structuredA | Open the parsed structured text/HTML view inside the MCP host. Use this for reading extracted document content as HTML without page images or bbox overlays; use view_pdf/review_extraction for visual source pages. |
| render_uiA | Run codemode against docs/sql/citation and render the returned visualization as an MCP App. Use for charts, tables, metrics, and small dashboards derived from PDFs after you know the schema. Call describe_collection first, and validate exploratory SQL with execute_code before embedding it here; SQL failures are returned as codemode errors. The codemode sandbox includes the preinstalled "okra-render-ui" module with querySql() plus prebuilt component helpers like TimeSeriesLineChart(), DataTable(), MetricCards(), dashboard(), and chart/table/html specs; keep query code separate from reusable UI helpers, return compact data, not screenshots, and do not rely on CDN scripts such as Chart.js inside html(). |
| create_viewA | Render a model-authored chart, table, metric, proof card, or dashboard as an MCP App and progressively preview safe component JSON while tool arguments stream. Use when you already have the data. For document-backed SQL/codemode work, use render_ui instead. Input view is a compact JSON string; top-level arrays are dashboard items. Do not pass HTML, scripts, iframes, or CDN-dependent payloads. |
| get_render_payloadA | Internal: the render_ui viewer fetches a large visualization payload that was stashed out-of-band. Not for direct agent use. |
| play_music_scoreA | Render and play a PDF music-score extraction from semantic note events with normalized page bboxes. Use this when demonstrating non-text PDF accessibility: each note has page coordinates, pitch, timing, and an accessible label; the UI synchronizes the source bbox overlay with a playable score. If no input is provided, it opens a seeded public-domain Beethoven Moonlight Sonata excerpt from Mutopia. For real OMR output, pass abc_notation plus notes[]. |
| list_workflowsA | List workflows you authored, newest first, so you can recover workflow_id values from prior MCP sessions before calling view_workflow or run_workflow. |
| list_workflow_runsA | List workflow runs you started, newest first, so you can recover run_id values from prior MCP sessions before calling view_workflow_run. |
| view_workflow_runA | Monitor a workflow run. For agent workflow scripts, returns status, stats, controller_output, per-agent outputs, event stream, logs, and failed-agent details. For step-definition workflows (e.g. invoice extraction), returns overall status, per-document rows, exceptions, dropped docs, stats, and the human-approval state. Pass the run_id from POST /v1/runs. |
| view_workflowA | Confirm a workflow as it is being built: finite definitions return visualization + validation, while agent workflow scripts return parse/readiness state and a best-effort plan estimate. Accepts a catalog name (e.g. staff.table-ingest) or a workflow id you authored. |
| approve_runA | Approve or reject a run that is waiting_for_review (the human-in-the-loop gate). Approving emits the validated rows; rejecting discards the run. Returns the refreshed run snapshot. |
| draft_workflowA | Author, create, build, or draft a workflow. For custom/agentic work, pass |
| run_workflowA | Start a run of a runnable workflow you authored (the write counterpart to view_workflow_run). Pass the |
| submit_usage_feedbackA | Submit detailed feedback about using the okraPDF MCP server. Use this only when the user asks to report feedback or when a reproducible MCP tool/app issue, confusing workflow, missing affordance, or useful agent-DX note should be sent to the okraPDF team. Pass the long feedback string in |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| okraPDF accessible HTML twin | |
| okraPDF accessibility report | |
| okraPDF Viewer | |
| Parsed HTML Pages | |
| Render UI | |
| Playable Music Score |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/okrapdf/pdf-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server