Перейти к содержимому

Python MCP-сервер

Python SDK NextPDF включает сервер Model Context Protocol (MCP), который предоставляет операции извлечения из PDF как нативные инструменты для агентов. Агент с поддержкой MCP, например Claude Code, регистрирует сервер один раз, а затем вызывает инструменты NextPDF так же, как любые другие инструменты.

Сервер представляет собой тонкий адаптер. Каждый инструмент читает PDF с локального диска, через асинхронный клиент обращается к вашей конечной точке NextPDF Connect и возвращает результат в виде строки JSON. Сервер не содержит бизнес-логики и не хранит данные между вызовами.

Установите SDK с дополнительным пакетом MCP:

Окно терминала
pip install nextpdf[mcp]

Дополнительный пакет mcp устанавливает основной пакет mcp (ограничение mcp>=1.0,<2.0). Серверу требуется Python 3.10 или новее.

Запустите модуль сервера из конфигурации вашего MCP-клиента. В примере ниже оба параметра подключения считываются из окружения хоста, а не хранятся как секрет в файле конфигурации (см. Безопасность):

{
"mcpServers": {
"nextpdf": {
"command": "python",
"args": ["-m", "nextpdf.mcp"],
"env": {
"NEXTPDF_BASE_URL": "https://connect.example.com",
"NEXTPDF_API_KEY": "${NEXTPDF_API_KEY}"
}
}
}
}

Точка входа python -m nextpdf.mcp вызывает main(), который запускает сервер через стандартные потоки ввода-вывода (stdio) с помощью asyncio.run(serve()). Не путайте её с python -m nextpdf, которая запускает интерфейс командной строки (CLI), а не MCP-сервер.

NEXTPDF_BASE_URL и NEXTPDF_API_KEY обязательны. Сервер создаёт клиент лениво — при первом вызове инструмента. Если хотя бы одна из переменных пуста, он вызывает RuntimeError и возвращает исключение агенту как ошибку инструмента, а не аварийно завершает процесс.

Каталог инструментов и сопоставление с SDK

Заголовок раздела «Каталог инструментов и сопоставление с SDK»

Сервер регистрирует восемь инструментов. В имени каждого инструмента используется префикс nextpdf_. Каждый инструмент сопоставляется с методом из пространства имён ast асинхронного клиента (AsyncNextPDF.ast), за исключением двух составных инструментов, отмеченных ниже. Сервер формирует их из вызовов более низкого уровня.

Инструмент MCPВызов SDKПримечания
nextpdf_extract_textast.extract_cited_text(pdf_data, page_index=..., headings_only=...)Возвращает список CitedTextBlock.
nextpdf_extract_tablesast.extract_cited_tables(pdf_data, page_range=...)Возвращает ExtractCitedTablesResponse.
nextpdf_get_astast.get_document_ast(pdf_data, page_range_start=0, page_range_end=..., token_budget=...)Возвращает AstDocument.
nextpdf_infoast.get_document_ast(pdf_data)Сервер формирует сводку метаданных; выделенной конечной точки нет.
nextpdf_healthнетПроверяет только переменные окружения; сетевых вызовов не выполняет.
nextpdf_searchast.search_ast_nodes(pdf_data, node_type=..., page_index=..., text_query=..., max_results=...)Возвращает SearchAstNodesResponse.
nextpdf_get_outlineast.search_ast_nodes(pdf_data, node_type="heading", max_results=500)Сервер преобразует узлы заголовков в структуру оглавления.
nextpdf_diffast.get_ast_diff(original_pdf_data, modified_pdf_data)Возвращает GetAstDiffResponse.

Учитывайте следующие детали входных данных инструментов, прежде чем подключать агента:

  • Все входные пути (pdf_path, original_pdf_path, modified_pdf_path) — это абсолютные пути к файлам на машине, где работает сервер. Агент передаёт путь, а сервер читает байты локально. Отдельного инструмента загрузки нет.
  • nextpdf_extract_text объявляет поле max_pages в своей входной схеме, но обработчик текста не передаёт его в SDK. Для текста ограничение по страницам задаётся через page_index (одна страница с отсчётом от 0). Используйте nextpdf_get_ast с max_pages, когда нужно ограничить обход всего документа.
  • nextpdf_get_ast преобразует max_pages во включительный диапазон страниц [0, max_pages - 1] (значение max_pages по умолчанию — 50). Передайте token_budget, чтобы ограничить размер возвращаемого дерева.
  • nextpdf_info возвращает schema_version, source_hash, page_count, estimated_tokens, root_node_type и root_children_count. Эти значения берутся из модели AstDocument, где estimated_tokens — вычисляемое свойство (примерно четыре символа на токен).
  • nextpdf_get_outline возвращает по одной записи для каждого заголовка с полями id, page_index, text и depth (значение берётся из attributes["level"] узла, по умолчанию 1), а также heading_count, total_matches и truncated.

Инструменты извлечения с цитированием прикрепляют CitationAnchor к каждому результату. Каждый якорь включает node_id, page_index, нормализованный bbox (координаты в диапазоне от 0.0 до 1.0) и оценку уверенности confidence (от 0.0 до 1.0). Агенты, которым нужны сведения о происхождении результата, должны показывать эти поля, а не только необработанный текст.

Сервер никогда не пропускает исключения на транспортный уровень агента. Диспетчер call_tool перехватывает каждую ошибку и возвращает её в виде JSON TextContent, поэтому при неудачном вызове инструмент возвращает структурированную полезную нагрузку, которую агент может прочитать, вместо разрыва соединения. Форматы полезной нагрузки:

УсловиеВозвращаемый JSON
Неизвестное имя инструмента{"error": "Unknown tool: <name>"}
Отсутствует входной файл{"error": "PDF file not found: <path>"}
Любой NextPDFError или его подкласс{"error": "<message>", "error_type": "<class>", "status_code": <int?>}
Любое другое исключение{"error": "Unexpected error: <message>"}

status_code появляется, только если он есть у базовой ошибки. SDK сопоставляет ответы HTTP с типизированной иерархией исключений, корнем которой является NextPDFError:

ИсключениеСтатус HTTPerror_codeКогда
NextPDFLicenseError402license/tier-requiredДля этой операции конечной точке требуется более высокий уровень лицензии на стороне сервера.
AstNoStructTreeError422ast/no-struct-treePDF не размечен, а эвристический резервный механизм на сервере не включён.
QuotaExceededError429quota/exceededДостигнут лимит частоты запросов или квота. Содержит retry_after (в секундах), когда сервер отправляет заголовок Retry-After.
AstBuildTimeoutError504ast/build-timeoutПостроение AST превысило бюджет времени сервера. Уменьшите диапазон страниц.
NextPDFAPIErrorдругие 4xx/5xxпредоставляется серверомЛюбой другой сбой на уровне API.

Используйте эти рекомендации для интеграций с агентами:

  • Тайм-ауты. HTTP-клиент использует фиксированные тайм-ауты по умолчанию: 60 секунд в сумме и 10 секунд на подключение. Медленный или большой документ приводит либо к AstBuildTimeoutError (сервер прекратил построение AST), либо, если истёк тайм-аут самого клиента, к полезной нагрузке Unexpected error от транспортного уровня. Когда вы видите ast/build-timeout, попросите агента сузить область: уменьшите max_pages в nextpdf_get_ast или задайте page_index / page_start и page_end в инструментах извлечения.
  • Квоты и пауза перед повтором. При 429 инструмент возвращает error_type со значением QuotaExceededError и status_code 429. Значение retry_after хранится в объекте исключения. Поскольку сервер сериализует только error, error_type и status_code, агенту следует расценивать 429 как сигнал сделать паузу и повторить позже, а не пытаться получить заголовок повтора из вывода инструмента. Контролируйте соблюдение квот на конечной точке Connect, а не в агенте.
  • Неразмеченные PDF. 422 ast/no-struct-tree означает, что у исходного PDF нет дерева структуры. Включите эвристический режим на сервере для таких документов или отправьте их на этап разметки перед извлечением.

Безопасность: ограничение области API-ключа и принцип наименьших привилегий

Заголовок раздела «Безопасность: ограничение области API-ключа и принцип наименьших привилегий»

Относитесь к API-ключу как к секрету и обращайтесь с ним так же осторожно, как с паролем базы данных.

  • Никогда не встраивайте ключ в файл конфигурации MCP. Приведённый выше пример JSON ссылается на ${NEXTPDF_API_KEY}, чтобы значение подставлялось из окружения хоста или менеджера секретов во время запуска. Файл конфигурации может быть помещён в систему контроля версий; секрет — нет.
  • Ограничьте область действия ключа извлечением только для чтения. MCP-сервер использует только интерфейс извлечения AST (extract_cited_text, extract_cited_tables, get_document_ast, search_ast_nodes, get_ast_diff). Он не отрисовывает, не подписывает, не редактирует и не изменяет документы. Выдайте агенту ключ, область действия которого на стороне сервера ограничена этими путями чтения, чтобы скомпрометированный агент не мог получить доступ к операциям записи или операциям более высокого уровня.
  • Используйте отдельный ключ для каждого агента. Отдельный ключ для каждого агента позволяет отзывать или менять одну интеграцию, не затрагивая другие, и делает журналы конечной точки привязанными к конкретному агенту.
  • Ограничьте файловую систему. Поскольку каждый инструмент читает абсолютный путь с локального диска, сервер может прочитать любой файл, доступный процессу хоста. Запускайте его от имени непривилегированного пользователя, ограничьте его рабочий каталог папкой с документами и никогда не запускайте его от привилегированной учётной записи.
  • Предпочитайте Transport Layer Security (TLS). Указывайте NEXTPDF_BASE_URL на https://-конечную точку для любого нелокального развёртывания. SDK отправляет ключ в виде токена Bearer в заголовке Authorization, поэтому передача открытым текстом раскрыла бы его в канале.

См. Безопасность и эксплуатация Connect для средств управления на стороне конечной точки, которые поддерживают эти клиентские практики.

Локальное тестирование сервера перед подключением агента

Заголовок раздела «Локальное тестирование сервера перед подключением агента»

Проверьте сервер отдельно, прежде чем подключать агента. Самая быстрая проверка не требует ни PDF, ни сети:

Окно терминала
python -c "from nextpdf.mcp import _tool_definitions; print(len(_tool_definitions()))"

Корректная установка выводит 8. Если вы видите ImportError с упоминанием дополнительного пакета mcp, значит необязательная зависимость отсутствует. Переустановите с помощью pip install nextpdf[mcp].

Затем проверьте через CLI те же кодовые пути SDK, которые используют инструменты. CLI обращается к вашей конечной точке с теми же двумя переменными окружения. Задайте их один раз:

Окно терминала
export NEXTPDF_BASE_URL="https://connect.example.com"
export NEXTPDF_API_KEY="$(cat /run/secrets/nextpdf_api_key)"

Затем проверьте версию, соединение и реальное извлечение:

Окно терминала
nextpdf version
nextpdf info /path/to/sample.pdf
nextpdf extract text /path/to/sample.pdf --headings-only

nextpdf version выполняется без учётных данных и подтверждает, что пакет импортируется. nextpdf info задействует get_document_ast — тот же вызов, на котором основаны nextpdf_get_ast и nextpdf_info. Если оба вызова успешны, учётные данные и конечная точка корректны, и соответствующие инструменты MCP будут работать.

Чтобы управлять протоколом MCP напрямую, используйте основной MCP Inspector (поставляется с пакетом mcp). Укажите ему ту же команду и окружение, которые будет использовать ваш агент, затем вручную получите список инструментов и вызовите их. Убедитесь, что nextpdf_health сообщает status: "ok". Он возвращает misconfigured всякий раз, когда NEXTPDF_BASE_URL или NEXTPDF_API_KEY не задана, и это самый быстрый способ обнаружить отсутствующее значение окружения, прежде чем агент вызовет реальный инструмент.

Мониторинг и отладка вызовов инструментов

Заголовок раздела «Мониторинг и отладка вызовов инструментов»

MCP-сервер обменивается данными через стандартные потоки ввода-вывода (stdio), поэтому по стандартному выводу идёт поток протокола, и он должен оставаться чистым. Сервер не настраивает собственное журналирование приложения. Ваши основные каналы наблюдаемости — это структурированные полезные нагрузки с ошибками инструментов, CLI и собственные журналы вашей конечной точки.

  • Полезные нагрузки с ошибками инструментов — основной сигнал. Каждый неудачный вызов возвращает объект JSON с полем error и, для ошибок SDK, error_type и status_code (см. Обработка ошибок). Настройте хост агента на запись этих полезных нагрузок. По ним видно, какой инструмент отказал и почему, без дополнительного инструментирования сервера.
  • Воспроизведите через CLI с отладочным журналированием. Сам MCP-сервер не выдаёт журналов, но CLI задействует те же вызовы SDK и ведёт журнал. Воспроизведите отказавший инструмент через соответствующую команду CLI с --log-level debug. CLI пишет журнал в stderr с метками времени и записывает полные трассировки для непредвиденных ошибок, что является самым прямым способом увидеть, что делает обработчик, без подключения отладчика.
  • Проверка работоспособности как зонд. Вызовите nextpdf_health, чтобы подтвердить, что сервер видит базовый URL и API-ключ. Результат сообщает sdk_version, server_url, api_key_configured (булево значение, никогда не сам ключ) и status.
  • Наблюдаемость на стороне конечной точки. Поскольку каждый инструмент сопоставляется с одним запросом Connect, сопоставляйте активность инструментов с журналами доступа конечной точки по API-ключу и метке времени. Размещайте конечную точку за теми же средствами аутентификации, квотирования и наблюдаемости, что вы используете для других клиентов сервиса.

Устранение типичных проблем интеграции с агентами

Заголовок раздела «Устранение типичных проблем интеграции с агентами»
СимптомВероятная причинаРешение
Сервер не запускается с ImportError о дополнительном пакете mcp (extra)Необязательная зависимость mcp не установленаУстановите с помощью pip install nextpdf[mcp].
Первый вызов инструмента возвращает {"error": "NEXTPDF_BASE_URL environment variable is required..."}Блок env MCP не передал базовый URL, или оболочка не развернула ${NEXTPDF_BASE_URL}Задайте переменную в окружении хоста агента и убедитесь, что средство запуска её разворачивает.
nextpdf_health сообщает "status": "misconfigured"Одна из двух обязательных переменных пустаУкажите обе переменные: NEXTPDF_BASE_URL и NEXTPDF_API_KEY.
Каждый инструмент с путём возвращает {"error": "PDF file not found: <path>"}Агент передал относительный путь или путь на стороне хоста, который процесс сервера не видитПередайте абсолютный путь, доступный для чтения пользователю сервера; проверьте с помощью nextpdf info <path>.
Инструмент возвращает error_typeNextPDFLicenseError (статус 402)Для операции нужен более высокий уровень лицензии на стороне сервераИспользуйте конечную точку и ключ, дающие право на эту операцию.
Инструмент возвращает error_typeAstNoStructTreeError (статус 422)PDF не размечен, а эвристический резервный механизм отключёнВключите эвристический режим на конечной точке или сначала разметьте PDF.
Инструмент возвращает error_typeQuotaExceededError (статус 429)Достигнут предел частоты запросов или квотаСделайте паузу и повторите попытку; повысьте квоту конечной точки, если предел слишком низок.
Инструмент возвращает error_typeAstBuildTimeoutError (статус 504) или тайм-аут транспортаДокумент слишком велик для бюджета времениСузьте область с помощью max_pages, page_index или page_start/page_end.
Агент не регистрирует ни одного инструмента NextPDFАгент вызвал python -m nextpdf (CLI) вместо python -m nextpdf.mcpИспользуйте python -m nextpdf.mcp в качестве command/args.

Сведения об отказах на уровне конечной точки и проверках развёртывания см. в разделе Устранение неполадок Connect. Об операциях SDK, на которых построены эти инструменты, см. в справочнике CLI и в обзоре SDK.