Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

# Keep this environment free of optional converters to exercise the base install.
- name: Install packages
run: pip install "./packages/markitdown[all]" ./packages/markitdown-mcp pytest
run: pip install ./packages/markitdown ./packages/markitdown-mcp pytest

- name: Run tests
working-directory: packages/markitdown-mcp
Expand Down
2 changes: 1 addition & 1 deletion packages/markitdown-mcp/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ RUN apt-get update \

COPY . /app

RUN pip install --no-cache-dir /app
RUN pip install --no-cache-dir "/app[all]"

WORKDIR /workdir

Expand Down
28 changes: 27 additions & 1 deletion packages/markitdown-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,38 @@ It exposes one tool: `convert_to_markdown(uri)`, where uri can be any `http:`, `

## Installation

To install the package, use pip:
The base installation includes the MCP server and MarkItDown's core converters,
such as text and HTML. Optional document and media converters are installed
separately. This avoids requiring platform-specific dependencies for formats
you do not use.

To install the base package, use pip:

```bash
pip install markitdown-mcp
```

To install every optional converter (the previous default), use:

```bash
pip install "markitdown-mcp[all]"
```

For selected formats, install the corresponding MarkItDown extras alongside the
server. For example, to add PDF support:

```bash
pip install markitdown-mcp "markitdown[pdf]"
```

With `uvx`, select the extra explicitly when full converter support is needed:

```bash
uvx --from "markitdown-mcp[all]" markitdown-mcp
```

The provided Docker image continues to include all optional converters.

## Usage

To run the MCP server, using STDIO (default), use the following command:
Expand Down
5 changes: 4 additions & 1 deletion packages/markitdown-mcp/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ classifiers = [
]
dependencies = [
"mcp>=2.1.1,<3.0.0",
"markitdown[all]>=0.1.1,<0.2.0",
"markitdown>=0.1.1,<0.2.0",
"requests>=2.0.0,<3.0.0",
]

[project.optional-dependencies]
all = ["markitdown[all]>=0.1.1,<0.2.0"]

[project.urls]
Documentation = "https://github.com/microsoft/markitdown#readme"
Issues = "https://github.com/microsoft/markitdown/issues"
Expand Down
48 changes: 48 additions & 0 deletions packages/markitdown-mcp/tests/test_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import asyncio
from importlib.metadata import requires

from packaging.requirements import Requirement


def markitdown_requirements():
return [
requirement
for value in requires("markitdown-mcp") or []
if (requirement := Requirement(value)).name == "markitdown"
]


def test_base_install_does_not_require_optional_converters():
requirements = [
requirement
for requirement in markitdown_requirements()
if requirement.marker is None or requirement.marker.evaluate({"extra": ""})
]
assert len(requirements) == 1
assert requirements[0].extras == set()


def test_all_extra_enables_converters_with_the_same_version_range():
requirements = markitdown_requirements()
base = next(
requirement for requirement in requirements if requirement.marker is None
)
optional = [
requirement
for requirement in requirements
if requirement.marker is not None
and requirement.marker.evaluate({"extra": "all"})
]
assert len(optional) == 1
assert optional[0].extras == {"all"}
assert optional[0].specifier == base.specifier


def test_mcp_tool_converts_html_without_optional_converters():
from markitdown_mcp.__main__ import convert_to_markdown

result = asyncio.run(convert_to_markdown("data:text/html,%3Ch1%3EHello%3C%2Fh1%3E"))
assert result.strip() == "# Hello"