Aller au contenu

Serveur MCP Python

Le SDK Python de NextPDF fournit un serveur Model Context Protocol (MCP) qui expose les opérations d’extraction PDF sous forme d’outils natifs pour les agents. Un agent compatible MCP — par exemple Claude Code — enregistre le serveur une seule fois, puis appelle les outils NextPDF comme n’importe quel autre outil.

Le serveur est un adaptateur léger. Chaque outil lit un PDF sur le disque local, utilise le client asynchrone configuré pour ton endpoint NextPDF Connect, puis renvoie le résultat sous forme de chaîne JSON. Le serveur lui-même ne contient aucune logique métier et ne conserve aucune donnée d’un appel à l’autre.

Installe le SDK avec l’extra MCP :

Fenêtre de terminal
pip install nextpdf[mcp]

L’extra mcp ajoute le paquet amont mcp (contrainte mcp>=1.0,<2.0). Le serveur requiert Python 3.10 ou une version plus récente.

Lance le module serveur depuis la configuration de ton client MCP. L’exemple ci-dessous lit les deux valeurs de connexion dans l’environnement de l’hôte, au lieu d’intégrer un secret dans le fichier de configuration (voir Sécurité) :

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

Le point d’entrée python -m nextpdf.mcp exécute main(), qui démarre le serveur sur les flux standard d’entrée/sortie (stdio) via asyncio.run(serve()). Ne le confonds pas avec python -m nextpdf, qui lance l’interface en ligne de commande (CLI), pas le serveur MCP.

NEXTPDF_BASE_URL et NEXTPDF_API_KEY sont tous deux requis. Le serveur initialise son client à la demande lors du premier appel d’outil. Si l’une des deux variables est vide, il lève une RuntimeError renvoyée à l’agent comme une erreur d’outil, au lieu de faire planter le processus.

Catalogue des outils et correspondance avec le SDK

Section intitulée « Catalogue des outils et correspondance avec le SDK »

Le serveur enregistre huit outils. Chaque nom d’outil porte le préfixe nextpdf_. Chaque outil correspond à une méthode de l’espace de noms ast du client asynchrone (AsyncNextPDF.ast), sauf les deux outils composites mentionnés plus bas, qui sont assemblés dans le serveur à partir d’appels de plus bas niveau.

Outil MCPAppel SDKNotes
nextpdf_extract_textast.extract_cited_text(pdf_data, page_index=..., headings_only=...)Renvoie une liste de CitedTextBlock.
nextpdf_extract_tablesast.extract_cited_tables(pdf_data, page_range=...)Renvoie ExtractCitedTablesResponse.
nextpdf_get_astast.get_document_ast(pdf_data, page_range_start=0, page_range_end=..., token_budget=...)Renvoie AstDocument.
nextpdf_infoast.get_document_ast(pdf_data)Le serveur projette un résumé des métadonnées ; aucun endpoint dédié.
nextpdf_healthaucunInspecte uniquement les variables d’environnement ; n’effectue aucun appel réseau.
nextpdf_searchast.search_ast_nodes(pdf_data, node_type=..., page_index=..., text_query=..., max_results=...)Renvoie SearchAstNodesResponse.
nextpdf_get_outlineast.search_ast_nodes(pdf_data, node_type="heading", max_results=500)Le serveur remodèle les nœuds de titre en une table des matières.
nextpdf_diffast.get_ast_diff(original_pdf_data, modified_pdf_data)Renvoie GetAstDiffResponse.

Quelques points sur les entrées des outils à connaître avant de câbler un agent :

  • Toutes les entrées de chemin (pdf_path, original_pdf_path, modified_pdf_path) sont des chemins absolus vers des fichiers présents sur la machine qui exécute le serveur. L’agent transmet un chemin ; le serveur lit les octets localement. Aucun outil de téléversement n’est fourni.
  • nextpdf_extract_text déclare un champ max_pages dans son schéma d’entrée, mais le gestionnaire de texte ne le transmet pas au SDK. Pour le texte, la sélection des pages se fait via page_index (une seule page indexée à partir de 0). Utilise nextpdf_get_ast avec max_pages quand tu dois borner un parcours de tout le document.
  • nextpdf_get_ast traduit max_pages en une plage de pages inclusive de [0, max_pages - 1] (la valeur par défaut de max_pages est 50). Passe token_budget pour limiter la taille de l’arbre renvoyé.
  • nextpdf_info renvoie schema_version, source_hash, page_count, estimated_tokens, root_node_type, et root_children_count. Ces valeurs proviennent du modèle AstDocument, où estimated_tokens est une propriété calculée (environ quatre caractères par token).
  • nextpdf_get_outline renvoie une entrée par titre avec id, page_index, text, et depth (lu depuis l’attribut attributes["level"] du nœud, avec 1 par défaut), plus heading_count, total_matches, et truncated.

Les outils d’extraction citée associent un CitationAnchor à chaque résultat. Chaque ancre porte node_id, page_index, une bbox normalisée (coordonnées comprises entre 0.0 et 1.0), et un score de confidence (0.0 à 1.0). Les agents qui ont besoin de la provenance devraient faire remonter ces champs plutôt que le seul texte brut.

Le serveur ne laisse jamais une exception s’échapper vers le transport de l’agent. Le dispatcher call_tool intercepte chaque erreur et la renvoie sous forme de TextContent JSON, si bien qu’un appel d’outil échoué produit une charge utile structurée que l’agent peut lire, plutôt qu’une connexion interrompue. Les formes de charge utile sont les suivantes :

ConditionJSON renvoyé
Nom d’outil inconnu{"error": "Unknown tool: <name>"}
Fichier d’entrée manquant{"error": "PDF file not found: <path>"}
Toute sous-classe de NextPDFError{"error": "<message>", "error_type": "<class>", "status_code": <int?>}
Toute autre exception{"error": "Unexpected error: <message>"}

status_code n’est inclus que lorsque l’erreur sous-jacente en fournit un. Le SDK fait correspondre les réponses HTTP à une hiérarchie d’exceptions typées, toutes enracinées dans NextPDFError :

ExceptionStatut HTTPerror_codeQuand
NextPDFLicenseError402license/tier-requiredL’endpoint exige un niveau de licence côté serveur supérieur pour cette opération.
AstNoStructTreeError422ast/no-struct-treeLe PDF n’est pas balisé et le repli heuristique n’est pas activé sur le serveur.
QuotaExceededError429quota/exceededUne limite de débit ou un quota a été atteint. Contient retry_after (en secondes) quand le serveur envoie un en-tête Retry-After.
AstBuildTimeoutError504ast/build-timeoutLa construction de l’AST a dépassé le budget de temps du serveur. Réduis la plage de pages.
NextPDFAPIErrorautres 4xx/5xxfourni par le serveurTout autre échec côté API.

Conseils pratiques pour les intégrations d’agents :

  • Délais d’attente. Le client HTTP utilise un délai d’attente par défaut fixe — 60 secondes au total avec un délai de connexion de 10 secondes. Un document lent ou volumineux se manifeste soit par une AstBuildTimeoutError (le serveur a renoncé à construire l’AST), soit, si le client lui-même dépasse son délai, par une charge utile Unexpected error provenant de la couche de transport. Quand tu vois ast/build-timeout, demande à l’agent de restreindre la portée : baisse max_pages sur nextpdf_get_ast, ou définis page_index / page_start et page_end sur les outils d’extraction.
  • Quota et temporisation. En cas de 429, l’outil renvoie un error_type égal à QuotaExceededError avec un status_code 429. La valeur retry_after se trouve sur l’objet exception. Comme le serveur ne sérialise que error, error_type, et status_code, l’agent devrait traiter le 429 comme un signal de pause et de nouvelle tentative ultérieure, plutôt que d’analyser un en-tête de retry depuis la sortie de l’outil. Applique les quotas sur l’endpoint Connect, pas dans l’agent.
  • PDF non balisés. Un 422 ast/no-struct-tree signifie que le PDF source n’a pas d’arbre de structure. Active le mode heuristique sur le serveur pour ces documents, ou achemine-les vers une étape de balisage avant l’extraction.

Sécurité : restriction de la clé API et moindre privilège

Section intitulée « Sécurité : restriction de la clé API et moindre privilège »

Traite la clé API comme un secret, avec autant de soin qu’un mot de passe de base de données.

  • N’intègre jamais la clé dans le fichier de configuration MCP. L’exemple JSON ci-dessus référence ${NEXTPDF_API_KEY} afin que la valeur soit résolue depuis l’environnement de l’hôte ou un gestionnaire de secrets au moment du lancement. Un fichier de configuration est versionné dans le contrôle de source ; un secret ne doit pas l’être.
  • Restreins la clé à l’extraction en lecture seule. Le serveur MCP n’appelle que la surface d’extraction de l’AST (extract_cited_text, extract_cited_tables, get_document_ast, search_ast_nodes, get_ast_diff). Il n’effectue aucun rendu, signature, caviardage ni mutation de document. Délivre à l’agent une clé dont la portée côté serveur est limitée à ces chemins de lecture, afin qu’un agent compromis ne puisse pas atteindre les opérations d’écriture ou de niveau supérieur.
  • Utilise une clé dédiée par agent. Une clé par agent te permet de révoquer ou de renouveler une intégration sans affecter les autres, et rend les journaux de l’endpoint attribuables à un agent précis.
  • Restreins le système de fichiers. Comme chaque outil lit un chemin absolu depuis le disque local, le serveur peut lire n’importe quel fichier lisible par le processus hôte. Exécute-le en tant qu’utilisateur non privilégié, restreins son répertoire de travail à un dossier de documents, et ne l’exécute jamais sous un compte privilégié.
  • Privilégie le chiffrement de la couche de transport (TLS). Fais pointer NEXTPDF_BASE_URL vers un endpoint https:// dans tout déploiement non local. Le SDK envoie la clé sous forme de jeton Bearer dans l’en-tête Authorization, donc un transport en clair l’exposerait sur le réseau.

Consulte Sécurité et exploitation de Connect pour les contrôles côté endpoint qui soutiennent ces pratiques côté client.

Tester le serveur en local avant de câbler un agent

Section intitulée « Tester le serveur en local avant de câbler un agent »

Valide le serveur isolément avant de connecter un agent. La vérification la plus rapide ne nécessite ni PDF ni réseau :

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

Une installation correcte affiche 8. Si tu vois une ImportError mentionnant l’extra mcp, la dépendance optionnelle est absente — réinstalle avec pip install nextpdf[mcp].

Ensuite, exécute avec la CLI les mêmes appels du SDK que ceux qu’empruntent les outils. La CLI dialogue avec ton endpoint via les deux mêmes variables d’environnement. Définis-les une fois :

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

Confirme ensuite la version, la connectivité et une extraction réelle :

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

nextpdf version s’exécute sans identifiants et confirme que le paquet s’importe. nextpdf info exerce get_document_ast, le même appel que celui derrière nextpdf_get_ast et nextpdf_info. Si les deux réussissent, les identifiants et l’endpoint sont corrects, et les outils MCP correspondants fonctionneront.

Pour piloter directement le protocole MCP, utilise l’inspecteur MCP amont (fourni avec le paquet mcp). Fais-le pointer vers la même commande et le même environnement que ceux qu’utilisera ton agent, puis liste et invoque les outils à la main. Vérifie que nextpdf_health signale status: "ok". Il renvoie misconfigured dès que NEXTPDF_BASE_URL ou NEXTPDF_API_KEY n’est pas défini, ce qui en fait le moyen le plus rapide de détecter une valeur d’environnement manquante avant même qu’un agent n’appelle un vrai outil.

Le serveur MCP communique via stdio : sa sortie standard transporte donc le flux du protocole et doit rester propre. Le serveur ne configure pas sa propre journalisation applicative, ce qui signifie que tes principaux canaux d’observabilité sont les charges utiles d’erreur d’outil structurées, la CLI et les journaux de ton endpoint.

  • Les charges utiles d’erreur d’outil sont le signal. Chaque appel échoué renvoie un objet JSON avec error et, pour les erreurs du SDK, error_type et status_code (voir Gestion des erreurs). Fais en sorte que l’hôte de l’agent enregistre ces charges utiles ; elles identifient l’outil en échec et la cause précise sans aucune instrumentation supplémentaire dans le serveur.
  • Reproduis via la CLI avec la journalisation de débogage. Le serveur MCP lui-même n’émet aucun journal, mais la CLI exerce les mêmes appels du SDK et produit des journaux. Reproduis un outil en échec via la commande CLI correspondante avec --log-level debug. La CLI journalise vers stderr avec des horodatages et enregistre les traces complètes pour les erreurs inattendues, ce qui est le moyen le plus direct de voir ce que fait un gestionnaire sans attacher de débogueur.
  • La santé comme sonde. Appelle nextpdf_health pour confirmer que le serveur voit une URL de base et une clé API. Le résultat indique sdk_version, server_url, api_key_configured (un booléen, jamais la clé elle-même), et status.
  • Observabilité côté endpoint. Comme chaque outil correspond à une requête Connect, corrèle l’activité des outils avec les journaux d’accès de l’endpoint par clé API et horodatage. Exécute l’endpoint derrière les mêmes contrôles d’authentification, de quota et d’observabilité que ceux que tu utilises pour tes autres clients de service.

Résolution des problèmes courants d’intégration d’agent

Section intitulée « Résolution des problèmes courants d’intégration d’agent »
SymptômeCause probableRésolution
Le serveur ne démarre pas et lève une ImportError liée à l’extra mcpLa dépendance optionnelle mcp n’est pas installéeInstalle avec pip install nextpdf[mcp].
Le premier appel d’outil renvoie {"error": "NEXTPDF_BASE_URL environment variable is required..."}Le bloc env MCP n’a pas transmis l’URL de base, ou le shell n’a pas développé ${NEXTPDF_BASE_URL}Définis la variable dans l’environnement de l’hôte de l’agent et confirme que le lanceur la développe.
nextpdf_health signale "status": "misconfigured"L’une des deux variables requises est videFournis à la fois NEXTPDF_BASE_URL et NEXTPDF_API_KEY.
Chaque outil basé sur un chemin renvoie {"error": "PDF file not found: <path>"}L’agent a transmis un chemin relatif, ou un chemin côté hôte que le processus serveur ne peut pas voirTransmets un chemin absolu lisible par l’utilisateur du serveur ; confirme avec nextpdf info <path>.
L’outil renvoie error_typeNextPDFLicenseError (statut 402)L’opération nécessite un niveau de licence côté serveur plus élevéUtilise un endpoint et une clé habilités pour l’opération.
L’outil renvoie error_typeAstNoStructTreeError (statut 422)Le PDF n’est pas balisé et le repli heuristique est désactivéActive le mode heuristique sur l’endpoint, ou balise le PDF au préalable.
L’outil renvoie error_typeQuotaExceededError (statut 429)Une limite de débit ou un quota a été atteintMets en pause et réessaie ; augmente le quota de l’endpoint si la limite est trop basse.
L’outil renvoie error_typeAstBuildTimeoutError (statut 504), ou un délai d’attente de transport dépasséLe document est trop volumineux pour le budget de tempsRestreins la portée avec max_pages, page_index, ou page_start/page_end.
L’agent n’enregistre aucun outil NextPDFL’agent a invoqué python -m nextpdf (la CLI) au lieu de python -m nextpdf.mcpUtilise python -m nextpdf.mcp comme command/args.

Pour les défaillances côté endpoint et les vérifications de déploiement, consulte Résolution des problèmes de Connect. Pour les opérations SDK sous-jacentes que ces outils encapsulent, consulte la référence de la CLI et la vue d’ensemble du SDK.