Ir al contenido

Servidor MCP de Python

El SDK de Python de NextPDF incluye un servidor de Model Context Protocol (MCP) que expone las operaciones de extracción de PDF como herramientas nativas para agentes. Un agente compatible con MCP —por ejemplo, Claude Code— registra el servidor una sola vez y luego invoca las herramientas de NextPDF del mismo modo que cualquier otra herramienta.

El servidor funciona como un adaptador ligero. Cada herramienta lee un PDF del disco local, llama al cliente asíncrono en el punto de conexión configurado de NextPDF Connect y devuelve el resultado como una cadena JSON. El servidor en sí no contiene lógica de negocio ni almacena datos entre llamadas.

Instalar el SDK con el extra de MCP:

Ventana de terminal
pip install nextpdf[mcp]

El extra mcp añade el paquete upstream mcp (restricción mcp>=1.0,<2.0). El servidor requiere Python 3.10 o posterior.

Ejecutar el módulo del servidor desde la configuración del cliente MCP. El ejemplo de abajo lee ambos valores de conexión desde el entorno del host en lugar de incrustar un secreto en el archivo de configuración (véase Seguridad):

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

El punto de entrada python -m nextpdf.mcp ejecuta main(), que inicia el servidor sobre la entrada/salida estándar (stdio) mediante asyncio.run(serve()). No confundir esto con python -m nextpdf, que ejecuta la interfaz de línea de comandos (CLI), no el servidor MCP.

Tanto NEXTPDF_BASE_URL como NEXTPDF_API_KEY son obligatorias. El servidor construye su cliente de forma diferida en la primera llamada a una herramienta. Si cualquiera de las dos variables está vacía, genera un RuntimeError que se devuelve al agente como un error de herramienta en vez de hacer fallar el proceso.

Catálogo de herramientas y correspondencia con el SDK

Sección titulada «Catálogo de herramientas y correspondencia con el SDK»

El servidor registra ocho herramientas. El nombre de cada herramienta lleva el prefijo nextpdf_. Cada una se corresponde con un método del espacio de nombres ast del cliente asíncrono (AsyncNextPDF.ast), excepto las dos herramientas compuestas que se indican más abajo, que se componen dentro del servidor a partir de llamadas de nivel inferior.

Herramienta MCPLlamada al SDKNotas
nextpdf_extract_textast.extract_cited_text(pdf_data, page_index=..., headings_only=...)Devuelve una lista de CitedTextBlock.
nextpdf_extract_tablesast.extract_cited_tables(pdf_data, page_range=...)Devuelve ExtractCitedTablesResponse.
nextpdf_get_astast.get_document_ast(pdf_data, page_range_start=0, page_range_end=..., token_budget=...)Devuelve AstDocument.
nextpdf_infoast.get_document_ast(pdf_data)El servidor proyecta un resumen de metadatos; no tiene un punto de conexión dedicado.
nextpdf_healthningunoSolo inspecciona las variables de entorno; no realiza ninguna llamada de red.
nextpdf_searchast.search_ast_nodes(pdf_data, node_type=..., page_index=..., text_query=..., max_results=...)Devuelve SearchAstNodesResponse.
nextpdf_get_outlineast.search_ast_nodes(pdf_data, node_type="heading", max_results=500)El servidor reorganiza los nodos de encabezado en un esquema.
nextpdf_diffast.get_ast_diff(original_pdf_data, modified_pdf_data)Devuelve GetAstDiffResponse.

Antes de conectar un agente, conviene tener en cuenta estas notas sobre la entrada de las herramientas:

  • Todos los campos de ruta (pdf_path, original_pdf_path, modified_pdf_path) son rutas absolutas a archivos en la máquina que ejecuta el servidor. El agente pasa una ruta; el servidor lee los bytes de forma local. No hay ninguna herramienta de carga.
  • nextpdf_extract_text declara un campo max_pages en su esquema de entrada, pero el controlador de texto no se lo pasa al SDK. La limitación por páginas para el texto se hace mediante page_index (una sola página basada en 0). Usar nextpdf_get_ast con max_pages cuando sea necesario acotar un recorrido del documento completo.
  • nextpdf_get_ast traduce max_pages a un rango de páginas inclusivo de [0, max_pages - 1] (el valor predeterminado de max_pages es 50). Pasar token_budget para limitar el tamaño del árbol devuelto.
  • nextpdf_info devuelve schema_version, source_hash, page_count, estimated_tokens, root_node_type y root_children_count. Estos provienen del modelo AstDocument, donde estimated_tokens es una propiedad calculada (aproximadamente cuatro caracteres por token).
  • nextpdf_get_outline devuelve una entrada por cada encabezado con id, page_index, text y depth (leído desde el attributes["level"] del nodo, con 1 como valor predeterminado), además de heading_count, total_matches y truncated.

Las herramientas de extracción con citas añaden un CitationAnchor a cada resultado. Cada ancla incluye node_id, page_index, un bbox normalizado (coordenadas en el rango de 0.0 a 1.0) y una puntuación de confidence (de 0.0 a 1.0). Los agentes que necesiten la procedencia deberían exponer estos campos, no solo el texto sin procesar.

Manejo de errores, tiempos de espera y cuota

Sección titulada «Manejo de errores, tiempos de espera y cuota»

El servidor nunca permite que una excepción se propague al transporte del agente. El despachador call_tool captura cada error y lo devuelve como TextContent JSON, de modo que una llamada de herramienta fallida produce una carga útil estructurada que el agente puede leer, en lugar de una conexión interrumpida. Las formas de la carga útil son:

CondiciónJSON devuelto
Nombre de herramienta desconocido{"error": "Unknown tool: <name>"}
Archivo de entrada no encontrado{"error": "PDF file not found: <path>"}
Cualquier NextPDFError o subclase{"error": "<message>", "error_type": "<class>", "status_code": <int?>}
Cualquier otra excepción{"error": "Unexpected error: <message>"}

status_code se incluye solo cuando el error subyacente lleva uno. El SDK asigna las respuestas HTTP a una jerarquía de excepciones tipadas, todas con raíz en NextPDFError:

ExcepciónEstado HTTPerror_codeCuándo
NextPDFLicenseError402license/tier-requiredEl punto de conexión requiere un nivel de licencia más alto del lado del servidor para la operación.
AstNoStructTreeError422ast/no-struct-treeEl PDF está sin etiquetar y el modo heurístico de respaldo no está habilitado en el servidor.
QuotaExceededError429quota/exceededSe alcanzó un límite de tasa o una cuota. Lleva retry_after (en segundos) cuando el servidor envía un encabezado Retry-After.
AstBuildTimeoutError504ast/build-timeoutLa construcción del AST superó el presupuesto de tiempo del servidor. Reduce el rango de páginas.
NextPDFAPIErrorotros 4xx/5xxproporcionado por el servidorCualquier otro fallo a nivel de API.

Orientación práctica para las integraciones de agentes:

  • Tiempos de espera. El cliente HTTP usa un tiempo de espera predeterminado fijo: 60 segundos en total, con un tiempo de espera de conexión de 10 segundos. Un documento lento o grande se manifiesta como un AstBuildTimeoutError (el servidor desistió de construir el AST) o, si el propio cliente agota su tiempo de espera, como una carga útil de Unexpected error de la capa de transporte. Cuando aparezca ast/build-timeout, indicar al agente que reduzca el alcance: reducir max_pages en nextpdf_get_ast, o establecer page_index / page_start y page_end en las herramientas de extracción.
  • Cuota y reintentos progresivos. Ante un 429, la herramienta devuelve un error_type de QuotaExceededError con status_code 429. El valor de retry_after reside en el objeto de excepción. Como el servidor solo serializa error, error_type y status_code, el agente debería tratar el 429 como una señal para pausar y reintentar más tarde, en lugar de analizar un encabezado de reintento de la salida de la herramienta. Aplicar las cuotas en el punto de conexión de Connect, no en el agente.
  • PDF sin etiquetar. Un 422 ast/no-struct-tree significa que el PDF de origen no tiene árbol de estructura. Habilitar el modo heurístico en el servidor para esos documentos, o enviarlos a un paso de etiquetado antes de la extracción.

Seguridad: alcance de la clave de API y privilegio mínimo

Sección titulada «Seguridad: alcance de la clave de API y privilegio mínimo»

Tratar la clave de API como un secreto, con el mismo cuidado que la contraseña de una base de datos.

  • No incrustar nunca la clave en el archivo de configuración de MCP. El ejemplo JSON de arriba hace referencia a ${NEXTPDF_API_KEY}, de modo que el valor se resuelve desde el entorno del host o desde un gestor de secretos en el momento del arranque. Un archivo de configuración se registra en el control de versiones; un secreto no debe hacerlo.
  • Acotar la clave a la extracción de solo lectura. El servidor MCP solo llama a la superficie de extracción del AST (extract_cited_text, extract_cited_tables, get_document_ast, search_ast_nodes, get_ast_diff). No realiza renderizado, firma, redacción ni mutación de documentos. Entregar al agente una clave cuyo alcance del lado del servidor esté limitado a esas rutas de lectura, para que un agente comprometido no pueda alcanzar operaciones de escritura ni de nivel superior.
  • Usar una clave dedicada por agente. Una clave por agente permite revocar o rotar una integración sin afectar a las demás, y hace que los registros del punto de conexión sean atribuibles a un agente concreto.
  • Restringir el sistema de archivos. Como cada herramienta lee una ruta absoluta del disco local, el servidor puede leer cualquier archivo que el proceso del host pueda leer. Ejecutarlo como un usuario sin privilegios, restringir su directorio de trabajo a una carpeta de documentos y nunca ejecutarlo como una cuenta con privilegios.
  • Preferir la seguridad de la capa de transporte (TLS). Apuntar NEXTPDF_BASE_URL a un punto de conexión https:// en cualquier despliegue que no sea local. El SDK envía la clave como un token Bearer en el encabezado Authorization, por lo que un transporte sin cifrar la expondría en la red.

Consultar Seguridad y operaciones de Connect para conocer los controles del lado del punto de conexión que respaldan estas prácticas del lado del cliente.

Probar el servidor de forma local antes de conectar un agente

Sección titulada «Probar el servidor de forma local antes de conectar un agente»

Validar el servidor de forma aislada antes de conectar un agente. La comprobación más rápida no necesita ningún PDF ni red:

Ventana de terminal
python -c "from nextpdf.mcp import _tool_definitions; print(len(_tool_definitions()))"

Una instalación correcta imprime 8. Si aparece un ImportError que menciona el extra mcp, falta la dependencia opcional: reinstalar con pip install nextpdf[mcp].

A continuación, probar mediante la CLI las mismas rutas del SDK que usan las herramientas. La CLI se comunica con el punto de conexión usando las mismas dos variables de entorno. Definirlas una sola vez:

Ventana de terminal
export NEXTPDF_BASE_URL="https://connect.example.com"
export NEXTPDF_API_KEY="$(cat /run/secrets/nextpdf_api_key)"

Luego, confirmar la versión, la conectividad y una extracción real:

Ventana de terminal
nextpdf version
nextpdf info /path/to/sample.pdf
nextpdf extract text /path/to/sample.pdf --headings-only

nextpdf version se ejecuta sin credenciales y confirma que el paquete se importa. nextpdf info prueba get_document_ast, la misma llamada que hay detrás de nextpdf_get_ast y nextpdf_info. Si ambas tienen éxito, las credenciales y el punto de conexión son correctos y las herramientas MCP correspondientes funcionarán.

Para manejar el protocolo MCP directamente, usar el MCP Inspector original (incluido con el paquete mcp). Apuntarlo al mismo comando y entorno que usará el agente, y luego enumerar e invocar las herramientas a mano. Verificar que nextpdf_health informe status: "ok". Devuelve misconfigured siempre que NEXTPDF_BASE_URL o NEXTPDF_API_KEY no esté definida, que es la forma más rápida de detectar un valor de entorno ausente antes de que un agente llegue a llamar a una herramienta real.

Supervisión y depuración de las llamadas a herramientas

Sección titulada «Supervisión y depuración de las llamadas a herramientas»

El servidor MCP se comunica por stdio, por lo que su salida estándar transporta el flujo del protocolo y debe mantenerse limpia. El servidor no configura su propio registro de aplicación, por lo que los canales principales de observabilidad son las cargas útiles estructuradas de error de herramienta, la CLI y los propios registros del punto de conexión.

  • Las cargas útiles de error de herramienta son la señal. Cada llamada fallida devuelve un objeto JSON con error y, en el caso de los errores del SDK, error_type y status_code (véase Manejo de errores). Configurar el host del agente para que registre estas cargas útiles; identifican la herramienta que falla y la causa precisa sin ninguna instrumentación adicional en el servidor.
  • Reproducir a través de la CLI con registro de depuración. El servidor MCP en sí no emite registros, pero la CLI ejecuta las mismas llamadas al SDK y sí emite registros. Reproducir una herramienta que falla a través del comando de la CLI correspondiente con --log-level debug. La CLI registra en stderr con marcas de tiempo y guarda las trazas de pila completas de los errores inesperados, lo que es la forma más directa de ver qué hace un controlador sin conectar un depurador.
  • Health como sonda. Llamar a nextpdf_health para confirmar que el servidor ve una URL base y una clave de API. El resultado informa sdk_version, server_url, api_key_configured (un valor booleano, nunca la clave en sí) y status.
  • Observabilidad del lado del punto de conexión. Como cada herramienta se corresponde con una solicitud de Connect, correlacionar la actividad de las herramientas con los registros de acceso del punto de conexión por clave de API y marca de tiempo. Ejecutar el punto de conexión detrás de los mismos controles de autenticación, cuota y observabilidad que se usan para otros clientes de servicio.

Solución de problemas comunes de integración con agentes

Sección titulada «Solución de problemas comunes de integración con agentes»
SíntomaCausa probableResolución
El servidor no arranca y devuelve un ImportError sobre el extra mcpLa dependencia opcional mcp no está instaladaInstalar con pip install nextpdf[mcp].
La primera llamada a una herramienta devuelve {"error": "NEXTPDF_BASE_URL environment variable is required..."}El bloque env de MCP no pasó la URL base, o el shell no expandió ${NEXTPDF_BASE_URL}Definir la variable en el entorno del host del agente y confirmar que el lanzador la expande.
nextpdf_health informa "status": "misconfigured"Una de las dos variables obligatorias está vacíaProporcionar ambas, NEXTPDF_BASE_URL y NEXTPDF_API_KEY.
Cada herramienta basada en rutas devuelve {"error": "PDF file not found: <path>"}El agente pasó una ruta relativa o del lado del host que el proceso del servidor no puede verPasar una ruta absoluta legible por el usuario del servidor; confirmarlo con nextpdf info <path>.
La herramienta devuelve error_typeNextPDFLicenseError (estado 402)La operación necesita un nivel de licencia más alto del lado del servidorUsar un punto de conexión y una clave con derecho a la operación.
La herramienta devuelve error_typeAstNoStructTreeError (estado 422)El PDF está sin etiquetar y el respaldo heurístico está desactivadoHabilitar el modo heurístico en el punto de conexión, o etiquetar primero el PDF.
La herramienta devuelve error_typeQuotaExceededError (estado 429)Se alcanzó un límite de tasa o una cuotaPausar y reintentar; aumentar la cuota del punto de conexión si el límite es demasiado bajo.
La herramienta devuelve error_typeAstBuildTimeoutError (estado 504), o un tiempo de espera del transporteEl documento es demasiado grande para el presupuesto de tiempoReducir el alcance con max_pages, page_index o page_start/page_end.
El agente no registra ninguna herramienta de NextPDFEl agente invocó python -m nextpdf (la CLI) en lugar de python -m nextpdf.mcpUsar python -m nextpdf.mcp como command/args.

Para los fallos a nivel del punto de conexión y las comprobaciones de despliegue, consultar Solución de problemas de Connect. Para las operaciones del SDK subyacente que envuelven estas herramientas, consultar la Referencia de la CLI y la Introducción al SDK.