Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Markitdown Mcp Skill

CSecurity

markitdown MCP reference — local docs-to-Markdown (PDF, DOCX, PPTX, XLSX, HTML, EPUB): config, decision tree, fallbacks.

6 stars
0 votes
0 copies
0 views
Added 9/20/2026
devopspythonrustgobashdockerazuregitapi

Works with

cliapimcp

Security Analysis

C71/100
criticalPipes output to a shell interpreter
mediumInstalls packages at runtime which could introduce malicious dependencies

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add darellchua2/opencode-config-template --skill markitdown-mcp-skill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Markitdown Mcp Skill?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Markitdown Mcp Skill
[![Security: C — Skills Directory](https://www.skillsdirectory.com/api/skills/darellchua2-markitdown-mcp-skill/badge)](https://www.skillsdirectory.com/skills/darellchua2-markitdown-mcp-skill)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: markitdown-mcp-skill
description: "markitdown MCP reference — local docs-to-Markdown (PDF, DOCX, PPTX, XLSX, HTML, EPUB): config, decision tree, fallbacks."
license: Apache-2.0
compatibility: opencode
metadata:
  pattern: mcp-document-reading
category: Configuration
---

## What this skill does

- Documents the `markitdown` MCP server and its single tool `convert_to_markdown`
- Provides `opencode.json` configuration (the `mcp.servers` entry and `permissions` rule)
- Prescribes a decision tree for choosing markitdown vs `image-analyzer-subagent` vs `pdf-specialist-skill` vs `pdftotext` vs built-in `Read`
- Covers usage patterns (large docs, batch conversion, table post-processing)
- Documents privacy guarantees for company-internal document handling
- Provides fallback strategies when the MCP is unavailable

**Reference:** [markitdown-local-mcp launcher README](../../opencode_app/mcp-servers/markitdown-local-mcp/README.md) · [Upstream microsoft/markitdown](https://github.com/microsoft/markitdown)

## Requirements & Honesty Note

| Requirement                                                          | Status                                                  |
| -------------------------------------------------------------------- | ------------------------------------------------------- |
| `markitdown` MCP server in `opencode.json` `mcp.servers` block        | Required for MCP tool access                            |
| `markitdown-local-mcp` binary on PATH                                | Installed via `./deploy/setup.sh` (pip) or baked into Docker |
| `mcp.servers.markitdown.disabled: false` in `opencode.json`          | **Ships `disabled: true`** — user must opt in (#262)     |
| `permissions` rule `{ "action": "markitdown*", "resource": "*", "effect": "allow" }` | **No rule by default** — user must opt in (#262) |

If any requirement is unmet, MCP tool calls return connection errors. Fall back to `pdftotext`, `image-analyzer-subagent`, or built-in `Read` (see **Fallback Strategy** below).

**Privacy note:** markitdown is privacy-safe for local files — the `markitdown-local-mcp` fork's `pyproject.toml` trust boundary installs only `markitdown[pdf,docx,pptx,xlsx,xls,outlook]` (no azure/speech/youtube extras), so conversion is fully local with zero phone-home network calls. Opt-in (`disabled: true` by default per #262) is a choice of minimal default footprint, not a privacy concern.

## opencode.json Configuration

The markitdown MCP server ships as opt-in (`disabled: true`) per [#262](https://github.com/darellchua2/opencode-config-template/issues/262). To enable:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "markitdown": {
        "type": "local",
        "command": ["markitdown-local-mcp"],
        "environment": {
          "MARKITDOWN_ENABLE_PLUGINS": "false"
        },
        "disabled": false
      }
    }
  },
  "permissions": [
    { "action": "markitdown*", "resource": "*", "effect": "allow" }
  ]
}
```

**Both flips are required:**
1. `mcp.servers.markitdown.disabled: false` — starts the server process
2. `permissions` rule `{ "action": "markitdown*", "resource": "*", "effect": "allow" }` — grants tool-calling permission. Rules live in the top-level `permissions` array (last matching rule wins); a legacy `permission` map key is ignored by opencode v2.

The sanctioned path does both flips and installs the launcher in one step: `./deploy/setup.sh --enable-pack markitdown` (Linux/macOS) or `.\deploy\setup.ps1 --enable-pack markitdown` (Windows). Manual editing of the deployed config works too. Docker users get the launcher baked in at build time.

Verify: `opencode mcp list` shows `markitdown` as `connected` — after restarting opencode (MCP servers connect at session start; config edits need a restart).

## Available MCP Tools

| Tool                       | Description                                                                          | Use Case                                       |
| -------------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------- |
| `convert_to_markdown(uri)` | Convert a document at the given URI to Markdown. Accepts `file:`, `data:`, `http:`, `https:` schemes. | Extract text from binary office docs, fetch remote URLs |

**Tool name is exactly `convert_to_markdown` (snake_case).** The skill name uses kebab-case (`markitdown-mcp-skill`); the MCP tool uses snake_case. Don't confuse them.

### Input schema

```json
{
  "name": "convert_to_markdown",
  "arguments": {
    "uri": "file:///absolute/path/to/document.pdf"
  }
}
```

Returns: `{ "content": [{ "type": "text", "text": "<markdown>" }] }`

## Format Coverage

All converters below are **100% local** (no network calls, verified via `ss -tnp`):

| Format        | Local library                  | Output characteristic                                              |
| ------------- | ------------------------------ | ----------------------------------------------------------------- |
| PDF           | pdfminer.six, pdfplumber       | Page-separated text; tables best-effort                           |
| DOCX          | mammoth, lxml                  | Headings, paragraphs, lists; tables as Markdown tables            |
| PPTX          | python-pptx                    | `<!-- Slide number: N -->` separators per slide                   |
| XLSX / XLS    | openpyxl, pandas, xlrd         | Multi-sheet → `## Sheet N` headers; cells as Markdown tables      |
| Outlook MSG   | olefile, extract-msg           | Headers, body, attachment list                                    |
| HTML          | beautifulsoup4, markdownify    | Cleaned Markdown (scripts/styles stripped)                        |
| CSV / JSON / XML | stdlib / pandas             | Direct conversion to Markdown tables / fenced blocks              |
| EPUB          | zipfile + html parsing         | Chapter-by-chapter                                                |
| IPYNB         | nbformat                       | Code cells as fenced blocks; outputs inline                       |
| ZIP           | zipfile                        | Iterates contents; converts each member                          |
| Images        | local EXIF (exiftool)          | **Metadata only** (camera, GPS, timestamp). No LLM description.   |

**NOT supported (cloud/extra deps deliberately excluded — see Privacy Guarantees):**
- Audio transcription (Google Speech API — excluded)
- YouTube transcripts (YouTube API — excluded)
- Azure Document Intelligence layout analysis (excluded)
- LLM-generated image descriptions (excluded — `llm_client` never passed)

## Decision Tree

Choose the right tool for the job. **Read this before calling `convert_to_markdown`.**

```
Need to understand a binary/office document?
│
├─ Is it PLAIN TEXT (.md, .txt, .json, .yaml, source code)?
│  └─ YES → Use built-in Read tool. markitdown adds nothing.
│
├─ Is it a BORN-DIGITAL office doc (.docx, .pptx, .xlsx, .xls, .msg)
│  or born-digital PDF (text-selectable, not scanned)?
│  └─ YES → Use markitdown.convert_to_markdown(uri).
│           Fast (~1s/50 pages), preserves text fidelity, no cloud calls.
│
├─ Did markitdown return EMPTY / GARBAGE / missing tables (complex layout,
│  multi-column, heavy formatting)?
│  └─ YES → Escalate to docling (layout-aware — see AGENTS.md routing rule
│           + docling-mcp-skill). CLI-on-demand: detect → ask consent →
│           pip install docling → docling convert. MCP: --enable-pack docling.
│
├─ Is the PDF SCANNED / image-only (no selectable text)?
│  └─ YES → pdftoppm (bash, if available) → image-analyzer-subagent.
│           markitdown will return empty/garbage for scanned PDFs.
│
├─ Do you need STRUCTURED PDF data (forms, tables as data, fillable fields,
│   OCR-as-purpose, post-edit)?
│  └─ YES → Use pdf-specialist-skill (purpose-built for structured PDF).
│           markitdown gives best-effort text dumps only.
│
├─ Do you need VISUAL UNDERSTANDING (charts, diagrams, screenshots,
│   layout, "what does this look like")?
│  └─ YES → image-analyzer-subagent. markitdown returns text only.
│
├─ Is the document at a REMOTE URL?
│  └─ TWO OPTIONS (equivalent, pick one):
│     • webfetch first → save locally → markitdown.convert_to_markdown(file://)
│     • markitdown.convert_to_markdown(https://...) directly
│       (single requests.get(), no telemetry, equivalent to webfetch)
│
└─ None of the above → Ask the user to clarify format/intent.
```

**PDF routing note:** markitdown and `pdf-specialist-skill` overlap on `.pdf`. Use markitdown for **fast text dumps of born-digital PDFs**. Use `pdf-specialist-skill` for **structured extraction, forms, OCR-as-purpose, or editing**. When unsure, start with markitdown (cheap) and escalate to pdf-specialist-skill if the output is insufficient.

## Usage Patterns

### Large documents (50+ pages)

Pass the URI directly — markitdown handles streaming internally. Don't pre-split. If the result exceeds context, post-process with `head`/`tail`/`grep` via bash, or ask for specific page ranges.

### Table fidelity

XLSX and CSV convert cleanly to Markdown tables. Complex PDF tables (merged cells, nested headers) may need re-alignment — verify before using in critical paths.

### Multi-sheet XLSX

Output uses `## Sheet N` headers (one per sheet). When querying for a specific sheet, grep the output for the sheet name.

### Batch conversion

No batch API. Loop over URIs:
```python
results = [call_tool("convert_to_markdown", {"uri": u}) for u in uris]
```

### Following up with visual analysis

After markitdown conversion, if the document contains charts/diagrams referenced as images, follow up with `image-analyzer-subagent` on those specific elements. markitdown extracts text; it does not interpret visuals.

## Troubleshooting

### MCP not connected / tool returns "server not found"

Three gates, all required:
- `markitdown-local-mcp` binary on PATH (`--enable-pack markitdown` installs it)
- `mcp.servers.markitdown.disabled: false` in the deployed config
- `permissions` rule `{ "action": "markitdown*", "resource": "*", "effect": "allow" }` (last matching rule wins)

Missing any one leaves the MCP unreachable or its tools denied. Verify with `opencode mcp list` (should show `markitdown` connected) and restart opencode after config edits — there is no hot-reload.

### Tool denied after upgrading from pre-#370 deploys

Earlier releases carried the opt-in denies under a nested `permission.tool` key, which opencode's permission engine never read — so hand-enabled servers worked despite the "deny". Under v2 the denies are `permissions`-array rules and **enforce**. If you enable markitdown/docling/next-devtools by hand, make sure no later deny rule shadows your allow (last matching rule wins) — or re-run `--enable-pack <name>`.

### `markitdown-local-mcp: command not found`

The launcher binary isn't on PATH. Fix:
- Linux/macOS: run `./deploy/setup.sh` (installs via `pip install --user`); ensure `~/.local/bin` is on PATH
- Windows: run `.\deploy\setup.ps1`; ensure `%APPDATA%\Python\Scripts` is on PATH
- Docker: launcher is baked into the image at `/opt/python-env/bin/markitdown-local-mcp` (already on PATH)

### `ImportError: No module named 'youtube_transcript_api'` / `'azure'` / `'speech_recognition'`

**This is expected, not a bug.** It means a cloud-only converter was invoked on a YouTube URL, audio file, or with explicit Azure kwargs — paths this privacy-hardened launcher structurally excludes. If you need those capabilities, install upstream `markitdown[all]` (NOT recommended for company-internal docs).

### Conversion times out for very large file

Split the source:
- PDF: use `pdftk` or `pdfseparate` to split into ranges, convert each
- PPTX: convert slide-by-slide if needed (no native batch)

### `convert_to_markdown` returns empty/garbage for a PDF

The PDF is likely scanned/image-only. Markitdown cannot OCR — switch to `pdftoppm` + `image-analyzer-subagent`.

## Fallback Strategy (No MCP)

When markitdown MCP is disabled, unavailable, or you choose not to enable it:

| Priority | Approach                                                            | When to use                                          |
| -------- | ------------------------------------------------------------------- | ---------------------------------------------------- |
| 1        | bash `pdftotext input.pdf -` (if installed)                          | Born-digital PDFs, fast                             |
| 2        | bash `pdftoppm` → `image-analyzer-subagent`                          | Scanned/image-only PDFs                              |
| 3        | Direct Python libs: `python-docx`, `openpyxl`, `python-pptx`         | If agent has `bash: allow` + Python + the lib         |
| 4        | `image-analyzer-subagent`                                           | Universal fallback (slower, vision-based)            |
| 5        | Tell user: "Please enable markitdown MCP for better results" + setup steps | When conversion quality matters and MCP is missing |

For company-internal docs, option 5 is preferred over option 4 (cheaper, preserves text fidelity, no vision-token cost).

## Privacy Guarantees

This MCP is the **privacy-hardened** fork of upstream `markitdown-mcp`, vendored at `opencode_app/mcp-servers/markitdown-local-mcp/`. See [launcher README](../../opencode_app/mcp-servers/markitdown-local-mcp/README.md) for the full trust-boundary analysis.

| Guarantee                                                | Mechanism                                                              |
| -------------------------------------------------------- | ---------------------------------------------------------------------- |
| No Azure SDK on disk                                     | `pyproject.toml` excludes `markitdown[all]` — installs only `[pdf,docx,pptx,xlsx,xls,outlook]` extras |
| No Google Speech / YouTube API                           | Same — `SpeechRecognition`, `youtube-transcript-api` not installed      |
| No LLM image description (cloud)                         | Launcher never passes `llm_client`; image converter runs EXIF-only      |
| No plugin converters (3rd-party)                         | `enable_plugins=False` hard-coded in constructor (env var belt-and-suspenders) |
| No telemetry / Application Insights                       | Confirmed absent in markitdown source; defense-in-depth via dep exclusion |
| Version drift protection                                 | markitdown pinned `>=0.1.1,<0.2.0` — bumps require explicit audit       |
| Local file conversions                                   | Zero TCP calls (verifiable via `ss -tnp` during conversion)             |
| User-supplied `http:`/`https:` URIs                      | Single `requests.get()` — no Microsoft endpoints, no telemetry headers. Equivalent to built-in `webfetch`. |

**Safe for company-internal documents.** No data leaves the host unless the user explicitly passes an `http:`/`https:` URI (in which case the fetch is identical to what `webfetch` would do).

Attribution

darellchua2darellchua2
View sourceMore from darellchua2 →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Terraform Module Library

Build reusable Terraform modules for AWS, Azure, and GCP infrastructure following infrastructure-as-code best practices. Use when creating infrastructure modules, standardizing cloud provisioning, or implementing reusable IaC components.

393431 votes

sematext-otel

Wire a service's OpenTelemetry output to Sematext Cloud. Walks through region, App-type, instrumentation flow (managed OTLP endpoint vs Sematext Agent), and signal selection (traces/metrics/logs), then produces the exact env-var block and points at a runnable reference example in this repo. Invoke when instrumenting a new app for Sematext.

01 votes

Deployment Patterns

Deployment workflows, CI/CD pipeline patterns, Docker containerization, health checks, rollback strategies, and production readiness checklists for web applications. Use when setting up deployment infrastructure or planning releases.

2459130 votes

Babysit

Watch a pull request or review cycle until it is ready to merge. Use when asked to babysit, monitor, or keep checking PR comments, reviews, and CI until all actionable issues are resolved.

942310 votes

V7 Roster

Interact with the Paperclip control plane API for task coordination and governance. Use when checking assignments, updating issue status, posting comments, delegating work, managing routines, or calling Paperclip API endpoints.

805540 votes
View all in devops →