Skip to content

Ctx Markitdown

Ctx MarkItDown — mvp.ctx_markitdown

Cluster: Context & Retrieval | Type: component | MCP Tools: 26

Overview

Document-to-Markdown converter backed by the MarkItDown library, supporting PDF, DOCX, HTML, image files, and URLs as input sources. The converted Markdown text is returned in MarkdownOutput.content alongside the source path and character count. If MarkItDown is not installed, infer() returns a clear error rather than silently producing empty output.

Outputs expose the canonical G6 degradation envelope: completion_state, warning_card, evidence, request_id, task_id, and run_id. Conversions that actually extract text are verified; missing MarkItDown, blocked sources, conversion exceptions, and conversions that ran without error but extracted no text (empty or whitespace-only) are surfaced as blocked-escalated with stable G6_E_* warning-card codes rather than cosmetic completion. Batch conversion can be qualified-draft when useful partial work exists but sources were skipped or degraded.

When to use:

  • Converting diverse document formats to Markdown before feeding into an LLM or RAG pipeline
  • Extracting readable text from PDFs or Office files without manual pre-processing
  • Building a normalised text corpus from a mixed-format document collection

Example:

from mvp.ctx_markitdown import CtxMarkitdownBlock, DocumentInput

block = CtxMarkitdownBlock(name="md")
result = block.infer(DocumentInput(source="/reports/q1.pdf"))
# result.value.content → Markdown text of the PDF

Works well with: ctx_langextract, ctx_rag, ctx_scrapling

Launch Readiness Caveat

Pinned runtime dependencies are necessary, not sufficient

ctx_markitdown depends on markitdown==0.1.5 for document conversion and the MCP server path depends on fastmcp==2.14.6. These are pinned in the workspace, development environment, and projects/g6_mcp package metadata. A missing markitdown install returns a clear [MARKITDOWN_ERROR] markitdown is not installed error instead of silently producing empty output.

Before presenting document conversion as part of a first-user workflow, still run a clean-machine MCP smoke test using the deployable MCP requirements: install the server, call md_info, convert one small allow-listed file, and verify the result appears in conversion history. Component tests prove the logic path; they do not prove the user's package environment has no unrelated dependency conflicts.

State Surface and Degradation Envelope

The MCP tier stores conversion history, source names, content previews, errors, templates, jobs, and pipelines in SQLite at $MARKITDOWN_DB_PATH (default ~/.markitdown/markitdown.db). Rows persist until explicit delete or purge operations, or until the database is removed. Adapter-level encryption and content sanitization are not enforced; callers handling sensitive documents should treat the database path as sensitive state.

info, list_formats, resource_check, convert, and batch_convert include capability evidence describing static format support versus live optional dependency availability (markitdown, OCR, transcription, and LLM rerank). This is the component's weakest-link disclosure: conversion usefulness is constrained by source policy, MarkItDown availability, and format-specific optional backends.

Public API

MarkitdownRerankDecision

Validated advisory rerank verdict over a returned search-record set.

Field Type Default
ordered_indices tuple[int, ...] required
dropped_indices tuple[int, ...] ()
rationale str ''
eligible_fingerprint str ''
confidence float 0.0
degraded bool False
raw_response str ''

LLMMarkitdownRerankRuntime

Provider-neutral search-result-rerank runtime backed by G6's LLM caller.

Constructor:

Parameter Type Default
llm LLMCaller \| None None

Methods:

rerank(query: str, records: list[Any]) -> MarkitdownRerankDecision

CtxMarkitdownRerankPatternRuntime

Stateless, load-bearing returned-set-ceiling enforcement.

Methods:

enforce_eligibility(decision: MarkitdownRerankDecision, records: list[Any]) -> tuple[list[Any], bool, bool]

CtxMarkitdownPlanner

Runtime-first advisory result-rerank facade with returned-order fallback.

Constructor:

Parameter Type Default
runtime MarkitdownRerankRuntime \| None None
pattern_runtime CtxMarkitdownRerankPatternRuntime \| None None

Methods:

rerank(query: str, records: list[Any]) -> list[Any]

CtxMarkitdownBlock(AIBlock[DocumentInput, MarkdownOutput, None])

Converts documents (PDF, DOCX, HTML, URLs, images, …) to Markdown text

Field Type Default
name str 'ctx_markitdown'
resource_bounds ResourceBounds \| None None
usage ResourceUsage field(default_factory=ResourceUsage)

Methods:

infer(data: DocumentInput) -> Result[MarkdownOutput]

DocumentInput(BaseModel)

Input for CtxMarkitdownBlock — a path or URL to convert.

Field Type Default
source str required
source_type str ''
extra_options dict[str, str] Field(default_factory=dict)
run_mode Literal['beta', 'production'] 'beta'
reviewer_signature str ''

MarkdownOutput(BaseModel)

Markdown text produced from a document.

Field Type Default
content str required
source str required
char_count int 0
metadata dict[str, str] Field(default_factory=dict)
degraded bool False
degradation_reason str \| None None
completion_state Literal['verified', 'qualified-draft', 'blocked-escalated'] 'qualified-draft'
warning_card dict[str, Any] Field(default_factory=dict)
evidence dict[str, Any] Field(default_factory=dict)
request_id str ''
task_id str ''
run_id str ''

Methods:

model_post_init(__context: Any) -> None

CtxMarkitdownMCPBlock(AIBlock[MCPMarkitdownInput, MCPMarkitdownOutput, dict])

Full-featured markitdown block with SQLite persistence.

Field Type Default
name str 'ctx_markitdown_mcp'
state dict \| None None
db_path str ':memory:'
resource_bounds ResourceBounds \| None None
usage ResourceUsage field(default_factory=ResourceUsage)
agentic_planner CtxMarkitdownPlanner \| None None

Methods:

infer(data: MCPMarkitdownInput) -> Result[MCPMarkitdownOutput]

MCPMarkitdownRecord(BaseModel)

Field Type Default
id str required
record_type str required
key str required
value str required
tags list[str] Field(default_factory=list)
timestamp str required
metadata dict[str, Any] Field(default_factory=dict)

MCPMarkitdownInput(BaseModel)

Field Type Default
op Literal['convert', 'batch_convert', 'detect_type', 'list_formats', 'resource_check', 'record_conversion', 'query_conversions', 'get_conversion_stats', 'delete_conversion', 'export_history', 'purge_old', 'save_template', 'get_template', 'list_templates', 'delete_template', 'submit_job', 'get_job_status', 'list_jobs', 'cancel_job', 'create_pipeline', 'run_pipeline', 'list_pipelines', 'delete_pipeline', 'search', 'info', 'list_patterns'] required
source str ''
source_type str ''
sources_json str ''
llm_model str ''
llm_prompt str ''
max_execution_seconds int 60
max_disk_bytes int 0
max_files int 10
key str ''
value str ''
tags list[str] Field(default_factory=list)
query str ''
limit int 50
top_k int 5
conversion_id str ''
detected_type str ''
content_preview str ''
char_count int 0
success bool True
error_message str ''
engine str 'markitdown'
duration_ms int 0
metadata_json str ''
days int 30
name str ''
description str ''
source_type_filter str ''
extra_options_json str ''
job_id str ''
status str ''
pipeline_name str ''
steps_json str ''
agentic_rerank bool \| None None
run_mode Literal['beta', 'production'] 'beta'
reviewer_signature str ''

MCPMarkitdownOutput(BaseModel)

Field Type Default
op str required
key str ''
value str ''
found bool False
count int 0
records list[MCPMarkitdownRecord] Field(default_factory=list)
retrieved list[str] Field(default_factory=list)
scores list[float] Field(default_factory=list)
summary str ''
message str ''
content str ''
metadata dict[str, Any] Field(default_factory=dict)
degraded bool False
degradation_reason str ''
completion_state Literal['verified', 'qualified-draft', 'blocked-escalated'] 'qualified-draft'
warning_card dict[str, Any] Field(default_factory=dict)
evidence dict[str, Any] Field(default_factory=dict)
request_id str ''
task_id str ''
run_id str ''
agentic_evidence dict[str, Any] Field(default_factory=dict)
capabilities dict[str, bool] Field(default_factory=lambda: {'markitdown': False, 'sklearn': False, 'llm': False, 'ocr': False, 'transcription': False})

Methods:

model_post_init(__context: Any) -> None

MarkitdownStore

Sync SQLite markitdown store with 5 tables.

Constructor:

Parameter Type Default
db_path str ':memory:'

Methods:

add_conversion(source: str, source_type: str, detected_type: str, content_preview: str, char_count: int, success: bool, error_message: str, engine: str, llm_model: str, duration_ms: int, tags: list[str], metadata_json: str) -> str

query_conversions(source_type: str = '', success: bool | None = None, limit: int = 50) -> list[dict[str, Any]]

get_conversion_stats() -> dict[str, Any]

delete_conversion(conversion_id: str) -> bool

export_history(limit: int = 1000) -> list[dict[str, Any]]

purge_old(days: int = 30) -> int

add_error(conversion_id: str, source: str, source_type: str, error_type: str, error_message: str, engine: str) -> str

upsert_template(name: str, description: str, source_type_filter: str, engine: str, llm_model: str, llm_prompt: str, max_execution_seconds: int, extra_options_json: str, tags: list[str]) -> str

get_template(name: str) -> dict[str, Any] | None

list_templates(tag: str = '', limit: int = 50) -> list[dict[str, Any]]

delete_template(name: str) -> bool

increment_template_use(name: str) -> None

create_job(input_sources_json: str, engine: str, total_files: int) -> str

get_job(job_id: str) -> dict[str, Any] | None

update_job(job_id: str, **kwargs: Any) -> bool

list_jobs(status: str = '', limit: int = 50) -> list[dict[str, Any]]

upsert_pipeline(name: str, description: str, steps_json: str, tags: list[str]) -> str

get_pipeline(name: str) -> dict[str, Any] | None

list_pipelines(limit: int = 50) -> list[dict[str, Any]]

delete_pipeline(name: str) -> bool

increment_pipeline_use(name: str) -> None

text_search(query: str, top_k: int = 5) -> list[dict[str, Any]]

TF-IDF search across conversions, templates, pipelines, and errors.

count_all() -> dict[str, int]

Functions

agentic_planner_enabled(default_enabled: bool) -> bool

Decide whether the agentic search-result-rerank planner should be used.

eligible_fingerprint(records: list[Any]) -> str

sha256 over the returned record texts (order-sensitive).

validate_markitdown_rerank_decision(decision: MarkitdownRerankDecision, n_eligible: int, expected_fingerprint: str) -> None

Returned-set / anti-injection guard for a search-result-rerank decision.

planner_is_llm_trusted(planner: Any) -> bool

Whether the BLOCK may report llm_used=True for planner.

MCP Tools

Operation Source
convert markitdown_mcp
batch_convert markitdown_mcp
detect_type markitdown_mcp
list_formats markitdown_mcp
resource_check markitdown_mcp
record_conversion markitdown_mcp
query_conversions markitdown_mcp
get_conversion_stats markitdown_mcp
delete_conversion markitdown_mcp
export_history markitdown_mcp
purge_old markitdown_mcp
save_template markitdown_mcp
get_template markitdown_mcp
list_templates markitdown_mcp
delete_template markitdown_mcp
submit_job markitdown_mcp
get_job_status markitdown_mcp
list_jobs markitdown_mcp
cancel_job markitdown_mcp
create_pipeline markitdown_mcp
run_pipeline markitdown_mcp
list_pipelines markitdown_mcp
delete_pipeline markitdown_mcp
search markitdown_mcp
info markitdown_mcp
list_patterns markitdown_mcp