Serveur MCP Python
Serveur MCP Python
Section intitulée « 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 :
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 MCP | Appel SDK | Notes |
|---|---|---|
nextpdf_extract_text | ast.extract_cited_text(pdf_data, page_index=..., headings_only=...) | Renvoie une liste de CitedTextBlock. |
nextpdf_extract_tables | ast.extract_cited_tables(pdf_data, page_range=...) | Renvoie ExtractCitedTablesResponse. |
nextpdf_get_ast | ast.get_document_ast(pdf_data, page_range_start=0, page_range_end=..., token_budget=...) | Renvoie AstDocument. |
nextpdf_info | ast.get_document_ast(pdf_data) | Le serveur projette un résumé des métadonnées ; aucun endpoint dédié. |
nextpdf_health | aucun | Inspecte uniquement les variables d’environnement ; n’effectue aucun appel réseau. |
nextpdf_search | ast.search_ast_nodes(pdf_data, node_type=..., page_index=..., text_query=..., max_results=...) | Renvoie SearchAstNodesResponse. |
nextpdf_get_outline | ast.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_diff | ast.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_textdéclare un champmax_pagesdans 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 viapage_index(une seule page indexée à partir de 0). Utilisenextpdf_get_astavecmax_pagesquand tu dois borner un parcours de tout le document.nextpdf_get_asttraduitmax_pagesen une plage de pages inclusive de[0, max_pages - 1](la valeur par défaut demax_pagesest 50). Passetoken_budgetpour limiter la taille de l’arbre renvoyé.nextpdf_inforenvoieschema_version,source_hash,page_count,estimated_tokens,root_node_type, etroot_children_count. Ces valeurs proviennent du modèleAstDocument, oùestimated_tokensest une propriété calculée (environ quatre caractères par token).nextpdf_get_outlinerenvoie une entrée par titre avecid,page_index,text, etdepth(lu depuis l’attributattributes["level"]du nœud, avec 1 par défaut), plusheading_count,total_matches, ettruncated.
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.
Gestion des erreurs, délais d’attente et quota
Section intitulée « Gestion des erreurs, délais d’attente et quota »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 :
| Condition | JSON 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 :
| Exception | Statut HTTP | error_code | Quand |
|---|---|---|---|
NextPDFLicenseError | 402 | license/tier-required | L’endpoint exige un niveau de licence côté serveur supérieur pour cette opération. |
AstNoStructTreeError | 422 | ast/no-struct-tree | Le PDF n’est pas balisé et le repli heuristique n’est pas activé sur le serveur. |
QuotaExceededError | 429 | quota/exceeded | Une 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. |
AstBuildTimeoutError | 504 | ast/build-timeout | La construction de l’AST a dépassé le budget de temps du serveur. Réduis la plage de pages. |
NextPDFAPIError | autres 4xx/5xx | fourni par le serveur | Tout 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 utileUnexpected errorprovenant de la couche de transport. Quand tu voisast/build-timeout, demande à l’agent de restreindre la portée : baissemax_pagessurnextpdf_get_ast, ou définispage_index/page_startetpage_endsur les outils d’extraction. - Quota et temporisation. En cas de 429, l’outil renvoie un
error_typeégal àQuotaExceededErroravec unstatus_code429. La valeurretry_afterse trouve sur l’objet exception. Comme le serveur ne sérialise queerror,error_type, etstatus_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-treesignifie 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_URLvers un endpointhttps://dans tout déploiement non local. Le SDK envoie la clé sous forme de jetonBearerdans l’en-têteAuthorization, 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 :
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 :
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 :
nextpdf versionnextpdf info /path/to/sample.pdfnextpdf extract text /path/to/sample.pdf --headings-onlynextpdf 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.
Surveillance et débogage des appels d’outils
Section intitulée « Surveillance et débogage des appels d’outils »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
erroret, pour les erreurs du SDK,error_typeetstatus_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_healthpour confirmer que le serveur voit une URL de base et une clé API. Le résultat indiquesdk_version,server_url,api_key_configured(un booléen, jamais la clé elle-même), etstatus. - 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ôme | Cause probable | Résolution |
|---|---|---|
Le serveur ne démarre pas et lève une ImportError liée à l’extra mcp | La dépendance optionnelle mcp n’est pas installée | Installe 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 vide | Fournis à 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 voir | Transmets 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é atteint | Mets 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 temps | Restreins la portée avec max_pages, page_index, ou page_start/page_end. |
| L’agent n’enregistre aucun outil NextPDF | L’agent a invoqué python -m nextpdf (la CLI) au lieu de python -m nextpdf.mcp | Utilise 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.