MCP-сервер для интеграции с self-hosted MinerU через протокол Model Context Protocol (MCP) с транспортом Streamable HTTP. https://git.maydayoffice.kz/maydayoffice/mineru-mcp-server
  • Python 89.8%
  • Dockerfile 10.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
akalagov 47a9f4f39b
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 19s
Обновить .forgejo/workflows/wiki-gen.yml
2026-07-26 16:49:54 +05:00
.forgejo/workflows Обновить .forgejo/workflows/wiki-gen.yml 2026-07-26 16:49:54 +05:00
src/mineru_mcp feature: Добавлена поддержка Bearer-авторизации 2026-07-22 08:59:48 +00:00
tests dev (#1) 2026-07-21 19:10:13 +05:00
.gitignore Initial commit 2026-07-21 15:06:15 +05:00
AGENTS.md Добавить AGENTS.md 2026-07-24 17:30:12 +05:00
CHANGELOG.md Обновить CHANGELOG.md 2026-07-24 13:28:43 +05:00
docker-compose.yml feature: Добавлена поддержка Bearer-авторизации 2026-07-22 08:59:48 +00:00
Dockerfile chore(deps): update python docker tag to v3.14 2026-07-24 07:56:37 +00:00
LICENSE Initial commit 2026-07-21 15:06:15 +05:00
pyproject.toml Обновить pyproject.toml 2026-07-24 13:29:27 +05:00
pytest.ini dev (#1) 2026-07-21 19:10:13 +05:00
README.md Обновить README.md 2026-07-25 21:41:06 +05:00
renovate.json Add renovate.json 2026-07-24 06:45:40 +00:00
requirements.txt feature: Добавлена поддержка Bearer-авторизации 2026-07-22 08:59:48 +00:00

MinerU MCP Server

Python Version MCP SDK Docker License Vibe Coding Powered by Qwen

Gitea Stars Gitea Forks Gitea Issues Gitea Issues Gitea Last Commit (branch) Gitea Release

MCP-сервер для интеграции с self-hosted MinerU через протокол Model Context Protocol (MCP) с транспортом Streamable HTTP.

🤖 Разработка с участием ИИ (Vibe Coding)

Этот проект создается с активным использованием ИИ-инструментов (включая модели семейства Qwen). ИИ берет на себя генерацию кода и рутину, а архитектура, ревью и тестирование остаются под полным контролем человека для гарантии качества и безопасности.

Описание

MinerU MCP Server — это микросервис, который предоставляет LLM-агентам возможность извлекать текст и структурированные данные из документов (PDF, изображения, DOCX, PPTX, XLSX) через стандартизированный протокол MCP.

Сервер абстрагирует сложность асинхронного API MinerU, предоставляя агенту единый атомарный инструмент parse_document, который внутри себя управляет загрузкой файлов, отправкой задач, опросом статуса и возвратом результата.

Возможности

  • Streamable HTTP транспорт — современный стандарт MCP
  • Асинхронная обработка — внутренний поллинг задач MinerU, для LLM выглядит как один вызов
  • Гибкая передача файлов — поддержка публичных URL и Base64 для локальных файлов
  • Настраиваемые параметры — таймауты, бэкенд парсинга, уровень детализации через переменные окружения
  • Оптимизация контекста — по умолчанию возвращает только Markdown, структурированные данные опциональны
  • Надежная обработка ошибок — понятные сообщения для LLM с рекомендациями по исправлению
  • Автоматическая очистка — временные файлы удаляются после обработки
  • Готовность к развертыванию — разделение ответственности, тесты, Docker, non-root пользователь
  • CI/CD интеграция — тесты выполняются при сборке Docker-образа

📁 Структура проекта

mineru-mcp-server/
├── .gitignore
├── docker-compose.yml          # Оркестрация контейнеров
├── Dockerfile                  # Сборка образа с автоматическим запуском тестов
├── pyproject.toml              # Конфигурация Python-пакета (src layout)
├── pytest.ini                  # Конфигурация pytest
├── README.md                   # Документация
├── requirements.txt            # Зависимости проекта
├── src/
│   └── mineru_mcp/             # Папка приложения
│       ├── __init__.py         # Делает директорию Python-пакетом
│       ├── config.py           # Управление переменными окружения
│       ├── file_handler.py     # Логика работы с файлами (URL, base64, temp)
│       ├── mineru_client.py    # Клиент MinerU API (отправка, поллинг, парсинг)
│       ├── mcp_tools.py        # Определение MCP инструментов
│       └── main.py             # Точка входа (запуск Uvicorn)
└── tests/
    ├── __init__.py             # Делает директорию тестов Python-пакетом
    ├── conftest.py             # Фикстуры и моки (respx)
    ├── test_file_handler.py    # Тесты обработки файлов
    └── test_mineru_client.py   # Тесты клиента MinerU

🚀 Быстрый старт

Предварительные требования

  • Docker и Docker Compose
  • Self-hosted экземпляр MinerU (или доступ к нему по сети)
  • (Опционально) Python 3.11+ для локальной разработки

1. Клонирование репозитория

git clone https://git.maydayoffice.kz/maydayoffice/mineru-mcp-server.git
cd mineru-mcp-server

2. Настройка переменных окружения

Отредактируйте docker-compose.yml и укажите адрес вашего MinerU:

environment:
  - MINERU_URL=http://mineru:8000  # Замените на адрес вашего MinerU
  - MINERU_BACKEND=hybrid-engine
  - MCP_TIMEOUT_SECONDS=600
  - MCP_POLL_INTERVAL_SECONDS=5
  - MCP_PORT=8001
  - DEFAULT_EFFORT=medium
  - LOG_LEVEL=INFO
  - MCP_API_KEY=your-super-secret-api-key-12345

3. Запуск через Docker Compose

# Сборка и запуск всех сервисов
docker-compose up -d

# Просмотр логов
docker-compose logs -f mineru-mcp

MCP-сервер будет доступен по адресу: http://localhost:8001/mcp

⚙️ Конфигурация

Все параметры настраиваются через переменные окружения в docker-compose.yml:

Переменная Описание Пример / По умолчанию
MINERU_URL Адрес self-hosted MinerU API http://mineru:8000
MINERU_BACKEND Бэкенд парсинга hybrid-engine (также: pipeline, vlm-engine, vlm-http-client, hybrid-http-client)
MINERU_LANG_LIST Список языков для улучшения OCR (через запятую) cyrillic (также: east_slavic, ch, korean, arabic, devanagari и др.)
MCP_TIMEOUT_SECONDS Максимальное время ожидания задачи (сек) 600 (10 минут)
MCP_POLL_INTERVAL_SECONDS Интервал опроса статуса задачи (сек) 5
MCP_PORT Порт MCP-сервера 8001
DEFAULT_EFFORT Уровень детализации (только для hybrid-бэкендов) medium (или high для максимальной точности)
LOG_LEVEL Уровень логирования INFO (или DEBUG, WARNING, ERROR)

💡 Совет: Параметр lang_list наиболее эффективен при использовании бэкенда pipeline, но может быть указан для любого бэкенда. Для документов на русском и казахском языках оптимально использовать cyrillic или east_slavic.

Использование

Инструмент parse_document

Основной инструмент для извлечения текста и структуры из документов.

Параметры

Параметр Тип Обязательный Описание
source_type string Да Тип источника: "url" или "base64"
source string Да URL файла или base64-строка с содержимым
filename string Да Имя файла с расширением (например, report.pdf)
include_structured_data boolean Нет Если true, возвращает также структурированные данные (по умолчанию false)

Пример 1: Парсинг по публичному URL

{
  "source_type": "url",
  "source": "https://example.com/document.pdf",
  "filename": "document.pdf",
  "include_structured_data": false
}

Пример 2: Парсинг локального файла через Base64

{
  "source_type": "base64",
  "source": "JVBERi0xLjQKJeLjz9M...",
  "filename": "local-document.pdf",
  "include_structured_data": true
}

Важные замечания

Передача файлов:

  • Если вы используете source_type="url", URL должен быть публичным и доступным из интернета.
  • Если файл находится на вашей локальной машине или в закрытой сети, обязательно используйте source_type="base64".
  • Если вы не уверены, доступен ли URL, сразу используйте source_type="base64" — это гарантированно сработает.

⚠️ Формат ответа:

  • По умолчанию возвращается только Markdown (return_md=true), что оптимально для LLM.
  • Если вам нужны структурированные данные (таблицы, списки контента), установите include_structured_data=true.

🔗 Интеграция с LiteLLM

LiteLLM выступает как MCP Server Gateway, проксируя запросы от агентов к вашему MCP-серверу.

Конфигурация LiteLLM

Добавьте в ваш litellm_config.yaml:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY

mcp_servers:
  - name: mineru_parser
    url: http://host.docker.internal:8001
    transport: streamable_http

Примечание:

  • Если LiteLLM запущен на хосте (не в Docker), используйте http://localhost:8001
  • Если LiteLLM в Docker-контейнере, используйте http://host.docker.internal:8001
  • LiteLLM автоматически управляет сессиями MCP (Mcp-Session-Id)

🧪 Тестирование

Локальный запуск тестов

# Установка зависимостей
pip install -r requirements.txt

# Запуск тестов
PYTHONPATH=src pytest tests/ -v

Тестирование через Docker

Тесты автоматически выполняются при сборке Docker-образа. Если тесты падают, сборка прерывается:

docker-compose build --no-cache mineru-mcp

Ручное тестирование через curl

Шаг 1: Инициализация сессии

curl -v -X POST http://localhost:8001/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "capabilities": {},
      "clientInfo": {
        "name": "curl-test",
        "version": "1.0"
      }
    }
  }'

Скопируйте Mcp-Session-Id из заголовков ответа.

Шаг 2: Вызов инструмента

curl -X POST http://localhost:8001/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: ВАШ_SESSION_ID" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "parse_document",
      "arguments": {
        "source_type": "url",
        "source": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
        "filename": "dummy.pdf",
        "include_structured_data": false
      }
    }
  }'

🏗 Архитектура

Поток данных

[Агент / LLM]
       │
       ▼ (JSON-RPC через Streamable HTTP)
[LiteLLM Gateway]
       │
       ▼ (проксирование с Mcp-Session-Id)
[MCP Сервер] ← этот проект
       │
       ├─► Скачивает файл по URL или декодирует Base64
       ├─► Сохраняет во временный файл
       ├─► Отправляет задачу в MinerU (/tasks)
       ├─► Опрашивает статус (/tasks/{id}) каждые N секунд
       ├─► Получает результат (/tasks/{id}/result)
       ├─► Парсит ответ (учитывает структуру dict в MinerU v3.x)
       └─► Удаляет временный файл
              │
              ▼
       [MinerU API]

Ключевые решения

  1. Атомарный инструмент с внутренним поллингом
    Агент видит один вызов parse_document, хотя внутри происходит множество HTTP-запросов к MinerU. Это упрощает логику агента и избегает таймаутов.

  2. Гибридная передача файлов (URL + Base64)

    • URL: для публичных файлов, экономит память и трафик
    • Base64: для локальных файлов, гарантированно работает за NAT
  3. Обработка структуры ответа MinerU v3.x
    MinerU возвращает results как словарь (dict), где ключи — имена файлов. Код корректно распаковывает эту структуру.

  4. Без SSRF-проверок
    Вместо попыток валидации URL (что ненадежно), сервер честно пытается скачать файл и возвращает понятную ошибку с рекомендацией использовать base64, если URL недоступен.

🔧 Разработка

Локальный запуск без Docker

# Установка зависимостей
pip install -r requirements.txt

# Установка переменных окружения
export MINERU_URL=http://localhost:8000
export MINERU_BACKEND=hybrid-engine
export MCP_PORT=8001

# Запуск сервера
PYTHONPATH=src python -m mineru_mcp.main

Добавление новых инструментов

  1. Откройте src/mineru_mcp/mcp_tools.py
  2. Добавьте новую функцию с декоратором @mcp.tool()
  3. Реализуйте логику в соответствующем модуле (mineru_client.py или file_handler.py)
  4. Напишите тесты в tests/
  5. Запустите тесты: PYTHONPATH=src pytest tests/ -v

🐛 Troubleshooting

Проблема: ImportError: cannot import name 'StreamableHTTPServer'

Решение: Убедитесь, что используется MCP SDK версии 1.x. В requirements.txt указано mcp>=1.0.0,<2.0.0.

Проблема: TypeError: FastMCP.run() got an unexpected keyword argument 'host'

Решение: В MCP SDK 1.x метод run() не принимает host и port. Используйте uvicorn для запуска ASGI-приложения, как показано в main.py.

Проблема: Bad Request: Missing session ID

Решение: Протокол MCP Streamable HTTP требует инициализации сессии. При ручном тестировании через curl сначала выполните initialize, получите Mcp-Session-Id и передавайте его в заголовке. LiteLLM делает это автоматически.

Проблема: Not Acceptable: Client must accept both application/json and text/event-stream

Решение: В заголовке Accept укажите оба формата: application/json, text/event-stream.

Проблема: Парсинг завершен, но текст не найден

Решение: Проверьте логи сервера (docker-compose logs -f mineru-mcp). Убедитесь, что:

  • MinerU доступен по адресу MINERU_URL
  • Файл корректно скачался или декодирован
  • Структура ответа MinerU соответствует ожидаемой (словарь results)

Проблема: Таймаут при парсинге больших документов

Решение: Увеличьте MCP_TIMEOUT_SECONDS в docker-compose.yml (по умолчанию 600 секунд = 10 минут).

📊 Производительность

  • Время парсинга: зависит от размера файла и настроек MinerU (обычно 5-30 секунд для PDF до 100 страниц)
  • Потребление памяти: минимальное, временные файлы удаляются сразу после обработки
  • Масштабируемость: каждый запрос обрабатывается асинхронно, поддерживается параллельная обработка нескольких документов

🔒 Безопасность

  • Контейнер запускается от имени non-root пользователя (mcpuser)
  • Временные файлы создаются в /tmp с уникальными UUID-именами
  • Нет SSRF-проверок, но есть понятные ошибки при недоступности URL
  • Все зависимости фиксируются в requirements.txt с версиями

Лицензия

MIT

Полезные ссылки

🤝 Вклад в проект

  1. Fork репозитория
  2. Создайте ветку для фичи (git checkout -b feature/amazing-feature)
  3. Закоммитьте изменения (git commit -m 'Add amazing feature')
  4. Запустите тесты (PYTHONPATH=src pytest tests/ -v)
  5. Запушьте ветку (git push origin feature/amazing-feature)
  6. Откройте Pull Request

📧 Контакты

По вопросам и предложениям обращайтесь к автору проекта.