콘텐츠로 이동

Python MCP 서버

NextPDF Python SDK는 PDF 추출 작업을 네이티브 에이전트 도구로 노출하는 Model Context Protocol(MCP) 서버를 제공합니다. MCP를 지원하는 에이전트(예: Claude Code)는 서버를 한 번 등록한 뒤, 다른 도구를 호출할 때와 같은 방식으로 NextPDF 도구를 호출합니다.

이 서버는 가벼운 어댑터 역할을 합니다. 각 도구는 로컬 디스크에서 PDF를 읽고, NextPDF Connect 엔드포인트에 비동기 클라이언트를 호출한 다음, 결과를 JSON 문자열로 반환합니다. 서버 자체에는 비즈니스 로직이 없으며 호출 사이에 어떤 데이터도 저장하지 않습니다.

MCP extra와 함께 SDK를 설치하십시오:

Terminal window
pip install nextpdf[mcp]

mcp extra는 업스트림 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()을 실행하며, asyncio.run(serve())를 통해 표준 입출력(stdio)으로 서버를 시작합니다. 이를 python -m nextpdf와 혼동하지 마십시오. python -m nextpdf는 MCP 서버가 아니라 명령줄 인터페이스(CLI)를 실행합니다.

NEXTPDF_BASE_URLNEXTPDF_API_KEY는 둘 다 필수입니다. 서버는 첫 번째 도구 호출 시 클라이언트를 지연 생성합니다. 두 변수 중 하나라도 비어 있으면 RuntimeError를 발생시키며, 프로세스를 중단시키는 대신 도구 오류로 에이전트에 반환됩니다.

서버는 여덟 개의 도구를 등록합니다. 모든 도구 이름에는 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_astmax_pages와 함께 사용하십시오.
  • nextpdf_get_astmax_pages[0, max_pages - 1]의 양끝을 포함하는 페이지 범위로 변환합니다(기본값 max_pages는 50). 반환되는 트리의 크기를 제한하려면 token_budget을 전달하십시오.
  • nextpdf_infoschema_version, source_hash, page_count, estimated_tokens, root_node_typeroot_children_count를 반환합니다. 이들은 AstDocument 모델에서 가져오며, 여기서 estimated_tokens는 계산된 속성입니다(토큰당 대략 4자).
  • nextpdf_get_outline는 각 제목에 대해 id, page_index, textdepth(노드의 attributes["level"]에서 읽으며, 기본값은 1)를 포함하는 항목 하나를 반환하고, 여기에 더해 heading_count, total_matchestruncated를 반환합니다.

인용 추출 도구는 모든 결과에 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를 루트로 하는 타입화된 예외 계층 구조에 매핑합니다:

예외HTTP 상태error_code상황
NextPDFLicenseError402license/tier-required엔드포인트가 해당 작업에 대해 더 높은 서버 측 라이선스 등급을 요구합니다.
AstNoStructTreeError422ast/no-struct-treePDF 에 태그가 없고 서버에서 휴리스틱 폴백이 활성화되어 있지 않습니다.
QuotaExceededError429quota/exceeded속도 제한 또는 할당량에 도달했습니다. retry_after(초)를 포함하며, 서버가 Retry-After 헤더를 보낼 때 제공됩니다.
AstBuildTimeoutError504ast/build-timeoutAST 빌드가 서버의 시간 예산을 초과했습니다. 페이지 범위를 줄이십시오.
NextPDFAPIError기타 4xx/5xx서버 제공기타 모든 API 수준 실패.

에이전트 통합을 위한 실용적 지침:

  • 타임아웃. HTTP 클라이언트는 고정된 기본 타임아웃을 사용합니다. 총 60초, 연결 타임아웃 10초입니다. 느리거나 큰 문서는 AstBuildTimeoutError(서버가 AST 빌드를 포기함)로 나타나거나, 클라이언트 자체가 타임아웃되는 경우 전송 계층에서 Unexpected error 페이로드로 나타납니다. ast/build-timeout가 보이면 에이전트에 범위를 좁히도록 지시하십시오: nextpdf_get_ast에서 max_pages를 낮추거나, 추출 도구에 page_index / page_startpage_end를 설정하십시오.
  • 할당량 및 백오프. 429에서 도구는 error_type으로 QuotaExceededError를, status_code로 429를 반환합니다. 예외 객체에는 retry_after 값이 있습니다. 서버는 error, error_typestatus_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)만 호출합니다. 렌더링, 서명, 편집(redaction), 문서 변경은 수행하지 않습니다. 서버 측 범위가 해당 읽기 경로로 제한된 키를 에이전트에 발급하여, 침해된 에이전트가 쓰기 또는 더 높은 등급의 작업에 도달할 수 없도록 하십시오.
  • 에이전트별 전용 키를 사용하십시오. 에이전트별 키를 사용하면 다른 통합에 영향을 주지 않고 한 통합을 폐기하거나 교체할 수 있으며, 엔드포인트 로그를 특정 에이전트에 귀속시킬 수 있습니다.
  • 파일 시스템을 제한하십시오. 모든 도구가 로컬 디스크에서 절대 경로를 읽으므로, 서버는 호스트 프로세스가 읽을 수 있는 모든 파일을 읽을 수 있습니다. 권한이 낮은 사용자로 실행하고, 작업 디렉터리를 문서 폴더로 제한하며, 고권한 계정으로 절대 실행하지 마십시오.
  • 전송 계층 보안(TLS)을 선호하십시오. 로컬이 아닌 모든 배포에서 NEXTPDF_BASE_URLhttps:// 엔드포인트로 지정하십시오. SDK는 키를 Bearer 토큰으로 Authorization 헤더에 담아 보내므로, 평문 전송은 키를 통신 경로에 노출시킵니다.

이러한 클라이언트 측 실무 지침을 뒷받침하는 엔드포인트 측 제어에 대해서는 Connect 보안 및 운영을 참조하십시오.

에이전트를 연결하기 전에 로컬에서 서버 테스트하기

섹션 제목: “에이전트를 연결하기 전에 로컬에서 서버 테스트하기”

에이전트를 연결하기 전에 서버를 독립적으로 검증하십시오. 가장 빠른 점검에는 PDF도 네트워크도 필요하지 않습니다:

Terminal window
python -c "from nextpdf.mcp import _tool_definitions; print(len(_tool_definitions()))"

올바르게 설치되었다면 8을 출력합니다. ImportErrormcp extra를 언급하며 나타나면, 선택적 의존성이 누락된 것입니다. pip install nextpdf[mcp]로 다시 설치하십시오.

다음으로, 도구가 사용하는 것과 동일한 SDK 경로를 CLI를 통해 실행하십시오. CLI는 동일한 두 환경 변수로 엔드포인트와 통신합니다. 한 번 설정하십시오:

Terminal window
export NEXTPDF_BASE_URL="https://connect.example.com"
export NEXTPDF_API_KEY="$(cat /run/secrets/nextpdf_api_key)"

그런 다음 버전, 연결성 및 실제 추출을 확인하십시오:

Terminal window
nextpdf version
nextpdf info /path/to/sample.pdf
nextpdf extract text /path/to/sample.pdf --headings-only

nextpdf version은 자격 증명 없이 실행되며 패키지 가져오기를 확인합니다. nextpdf infoget_document_ast를 실행하며, 이는 nextpdf_get_astnextpdf_info 뒤에 있는 동일한 호출입니다. 후자의 두 명령이 모두 성공하면 자격 증명과 엔드포인트가 올바르며 해당 MCP 도구가 작동합니다.

MCP 프로토콜을 직접 구동하려면 업스트림 MCP Inspector(mcp 패키지에 포함됨)를 사용하십시오. 에이전트가 사용할 것과 동일한 명령 및 환경을 가리키도록 설정한 다음, 도구를 수동으로 나열하고 호출하십시오. nextpdf_healthstatus: "ok"를 보고하는지 확인하십시오. misconfigured를 반환하는 경우는 NEXTPDF_BASE_URL 또는 NEXTPDF_API_KEY가 설정되지 않았다는 뜻이며, 이는 에이전트가 실제 도구를 호출하기 전에 누락된 환경 값을 잡아내는 가장 빠른 방법입니다.

MCP 서버는 stdio를 통해 통신하므로, 표준 출력은 프로토콜 스트림을 전달하며 깨끗하게 유지되어야 합니다. 서버는 자체 애플리케이션 로깅을 구성하지 않으므로, 주요 관측 가능성 채널은 구조화된 도구 오류 페이로드, CLI 및 엔드포인트 자체의 로그입니다.

  • 도구 오류 페이로드가 신호입니다. 모든 실패한 호출은 error를, SDK 오류의 경우 error_typestatus_code를 포함하는 JSON 객체를 반환합니다(오류 처리 참조). 에이전트 호스트가 이러한 페이로드를 기록하게 하십시오. 이 페이로드는 서버에 추가 계측을 하지 않고도 실패한 도구와 정확한 원인을 식별할 수 있게 합니다.
  • 디버그 로깅과 함께 CLI를 통해 재현하십시오. MCP 서버 자체는 로그를 내보내지 않지만, CLI는 동일한 SDK 호출을 실행하며 로그를 남깁니다. 실패한 도구를 해당 CLI 명령으로 --log-level debug와 함께 재현하십시오. CLI는 타임스탬프와 함께 stderr에 로그를 남기고 예기치 않은 오류에 대해 전체 트레이스백을 기록하므로, 디버거를 연결하지 않고도 핸들러가 무엇을 하고 있는지 확인하는 가장 직접적인 방법입니다.
  • 프로브로 사용하는 상태 점검. 서버가 기본 URL과 API 키를 인식하는지 확인하려면 nextpdf_health를 호출하십시오. 결과는 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..."}MCP env 블록이 기본 URL을 전달하지 않았거나, 셸이 ${NEXTPDF_BASE_URL}을 확장하지 않음에이전트 호스트 환경에서 변수를 설정하고 런처가 이를 확장하는지 확인하십시오.
nextpdf_health"status": "misconfigured"를 보고함두 필수 변수 중 하나가 비어 있음NEXTPDF_BASE_URLNEXTPDF_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.mcpcommand/args로 사용하십시오.

엔드포인트 수준 실패 및 배포 점검에 대해서는 Connect 문제 해결을 참조하십시오. 이러한 도구가 래핑하는 기반 SDK 작업에 대해서는 CLI 참조SDK 개요를 참조하십시오.