skills/markitdown/references/mcp_and_plugins.md
The Microsoft monorepo publishes markitdown-mcp. As of July 23, 2026, the package version is 0.0.1a4; it depends on markitdown[all]>=0.1.1,<0.2.0.
Pin both packages to ensure the documented converter version:
uv pip install \
"markitdown==0.1.6" \
"markitdown-mcp==0.0.1a4"
The server exposes exactly one tool:
convert_to_markdown(uri: str) -> str
Accepted URI schemes are http:, https:, file:, and data:.
STDIO is the default and preferred local transport:
markitdown-mcp
Generic MCP client configuration:
{
"mcpServers": {
"markitdown": {
"command": "markitdown-mcp",
"args": []
}
}
}
The MCP client launches the server with the same filesystem and network permissions as the client process unless additional sandboxing is applied.
markitdown-mcp --http --host 127.0.0.1 --port 3001
Endpoints:
http://127.0.0.1:3001/mcphttp://127.0.0.1:3001/sse--sse is a deprecated alias for --http.
The server:
file: URIsRequirements:
127.0.0.1 or localhost.0.0.0.0, a LAN interface, or the public Internet without a separately designed authenticated gateway and strict input policy.Localhost is not authentication: other processes or users on the same machine may still reach the port.
The MCP process disables MarkItDown plugins by default. It enables them only when the named variable is explicitly set to a truthy value:
MARKITDOWN_ENABLE_PLUGINS=true markitdown-mcp
Do this only for installed, reviewed plugins. Enabling plugins loads Python entry points into the server process, expanding both code-execution and file/network capabilities.
The official guide recommends Docker for desktop-agent use. A secure deployment should:
v0.1.6 source checkout.Example runtime shape after building a trusted image:
docker run --rm -i \
--read-only \
--cap-drop ALL \
-v "/absolute/path/to/documents:/workdir:ro" \
markitdown-mcp:0.1.6
The conversion URI inside the container would use a path under /workdir.
Plugins are Python distributions registered under the markitdown.plugin entry-point group.
List discovered plugins without enabling them:
markitdown --list-plugins
python scripts/inspect_installation.py
Enable plugins for one CLI conversion:
markitdown --use-plugins input.rtf -o output.md
Enable in Python:
from markitdown import MarkItDown
converter = MarkItDown(enable_plugins=True)
result = converter.convert_local("input.rtf")
print(result.markdown)
Before installing a plugin:
pyproject.toml, entry points, dependencies, and install hooks.Do not install arbitrary packages merely because they use the #markitdown-plugin tag.
from typing import Any, BinaryIO
from markitdown import (
DocumentConverter,
DocumentConverterResult,
StreamInfo,
)
class ExampleConverter(DocumentConverter):
def accepts(
self,
file_stream: BinaryIO,
stream_info: StreamInfo,
**kwargs: Any,
) -> bool:
return (stream_info.extension or "").lower() == ".example"
def convert(
self,
file_stream: BinaryIO,
stream_info: StreamInfo,
**kwargs: Any,
) -> DocumentConverterResult:
payload = file_stream.read()
return DocumentConverterResult(
markdown=payload.decode("utf-8", errors="replace")
)
accepts() must restore the stream position if it reads any bytes.
from markitdown import MarkItDown
__plugin_interface_version__ = 1
def register_converters(markitdown: MarkItDown, **kwargs) -> None:
markitdown.register_converter(ExampleConverter())
pyproject.toml[project.entry-points."markitdown.plugin"]
example = "example_markitdown_plugin"
MarkItDown calls register_converters() when a plugin-enabled instance is constructed and forwards the constructor keywords.
Lower values run first:
-1.00.010.0Registering a converter before built-ins can change the parser selected for existing formats. Treat priority as part of the plugin's security and compatibility review.
markitdown-ocr==0.1.0 is an official plugin from the Microsoft monorepo:
uv pip install \
"markitdown==0.1.6" \
"markitdown-ocr==0.1.0" \
"openai==2.41.1"
It sends document images/pages to the configured OpenAI-compatible vision provider. Configuration and disclosure requirements are in cloud_and_ocr.md.