diff --git a/packages/markitdown-mcp/src/markitdown_mcp/__main__.py b/packages/markitdown-mcp/src/markitdown_mcp/__main__.py index 77ade9974..94b5f89a9 100644 --- a/packages/markitdown-mcp/src/markitdown_mcp/__main__.py +++ b/packages/markitdown-mcp/src/markitdown_mcp/__main__.py @@ -1,3 +1,4 @@ +import asyncio import contextlib import sys import os @@ -20,7 +21,11 @@ @mcp.tool() async def convert_to_markdown(uri: str) -> str: """Convert a resource described by an http:, https:, file: or data: URI to markdown""" - return MarkItDown(enable_plugins=check_plugins_enabled()).convert_uri(uri).markdown + result = await asyncio.to_thread( + MarkItDown(enable_plugins=check_plugins_enabled()).convert_uri, + uri, + ) + return result.markdown def check_plugins_enabled() -> bool: diff --git a/packages/markitdown-mcp/tests/test_main.py b/packages/markitdown-mcp/tests/test_main.py new file mode 100644 index 000000000..e4c18bda1 --- /dev/null +++ b/packages/markitdown-mcp/tests/test_main.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +import threading +from types import SimpleNamespace + +import pytest + +from markitdown_mcp import __main__ as main + + +@pytest.mark.anyio +async def test_convert_to_markdown_runs_conversion_off_event_loop( + monkeypatch: pytest.MonkeyPatch, +) -> None: + event_loop_thread = threading.get_ident() + conversion_thread: list[int] = [] + + class FakeMarkItDown: + def __init__(self, *, enable_plugins: bool) -> None: + self.enable_plugins = enable_plugins + + def convert_uri(self, uri: str) -> SimpleNamespace: + conversion_thread.append(threading.get_ident()) + return SimpleNamespace(markdown=f"converted:{uri}") + + monkeypatch.setattr(main, "MarkItDown", FakeMarkItDown) + + result = await main.convert_to_markdown("https://example.com/test.txt") + + assert result == "converted:https://example.com/test.txt" + assert conversion_thread == [conversion_thread[0]] + assert conversion_thread[0] != event_loop_thread