تخطَّ إلى المحتوى

خادم MCP للغة Python

تتضمّن حزمة تطوير ⁨NextPDF⁩ للغة ⁨Python⁩ خادم ⁨Model Context Protocol⁩ (⁨MCP⁩) يتيح عمليات استخراج ⁨PDF⁩ على هيئة أدوات أصلية للوكلاء. يسجّل الوكيل الداعم لـ ⁨MCP⁩، مثل ⁨Claude Code⁩، الخادم مرة واحدة، ثم يستدعي أدوات ⁨NextPDF⁩ بالطريقة نفسها التي يستدعي بها أي أداة أخرى.

الخادم طبقة مواءمة خفيفة. تقرأ كل أداة ملف ⁨PDF⁩ من القرص المحلي، وتستدعي العميل غير المتزامن لنقطة نهاية ⁨NextPDF Connect⁩ الخاصة بك، ثم تُعيد النتيجة بوصفها سلسلة ⁨JSON.⁩ لا يحتفظ الخادم بأي منطق أعمال، ولا يخزّن أي بيانات بين الاستدعاءات.

ثبّت حزمة التطوير مع إضافة ⁨MCP⁩:

Terminal window
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()، التي تبدأ الخادم عبر الإدخال/الإخراج القياسي ⁨input/output⁩ (⁨stdio⁩) باستخدام asyncio.run(serve()). لا تخلط بينها وبين python -m nextpdf، فهي تُشغّل واجهة سطر الأوامر (⁨CLI⁩)، لا خادم ⁨MCP.⁩

المتغيّران NEXTPDF_BASE_URL وNEXTPDF_API_KEY مطلوبان. يُنشئ الخادم العميل عند الحاجة، وذلك عند أول استدعاء لأداة. إذا كان أيٌّ من المتغيّرين فارغاً، فإنه يطلق RuntimeError ويُعيده إلى الوكيل بوصفه خطأ أداة، بدلاً من التسبب في انهيار العملية.

فهرس الأدوات وربطها بحزمة التطوير

قسم بعنوان «فهرس الأدوات وربطها بحزمة التطوير»

يسجّل الخادم ثماني أدوات. يستخدم اسم كل أداة البادئة nextpdf_. تُربَط كل أداة بطريقة في فضاء الأسماء ast الخاص بالعميل غير المتزامن (AsyncNextPDF.ast)، باستثناء الأداتين المركّبتين المذكورتين أدناه. يكوّن الخادم هاتين الأداتين من استدعاءات منخفضة المستوى.

أداة ⁨MCP⁩استدعاء حزمة التطويرملاحظات
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 في مخطّط مُدخلاتها، لكن مُعالج النص لا يمرّره إلى حزمة التطوير. يُحدَّد نطاق الصفحات للنص عبر page_index (صفحة واحدة مفهرسة من الصفر). استخدم 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 فقط عندما يحمل الخطأ الأساسي هذه القيمة. تربط حزمة التطوير استجابات ⁨HTTP⁩ بتسلسل هرمي من الاستثناءات المُصنَّفة، وجذرها جميعاً NextPDFError:

الاستثناءحالة ⁨HTTP⁩error_codeمتى
NextPDFLicenseError402license/tier-requiredتتطلّب نقطة النهاية فئة ترخيص أعلى على جانب الخادم لإجراء العملية.
AstNoStructTreeError422ast/no-struct-treeملف ⁨PDF⁩ غير موسوم والاحتياط الاستدلالي غير مُفعَّل على الخادم.
QuotaExceededError429quota/exceededجرى تجاوز حدّ معدّل أو حصة. يحمل retry_after (بالثواني) عندما يرسل الخادم ترويسة Retry-After.
AstBuildTimeoutError504ast/build-timeoutتجاوز بناء ⁨AST⁩ ميزانية الوقت لدى الخادم. قلّل نطاق الصفحات.
NextPDFAPIErrorحالة 4⁨xx/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). لا يعرض المستندات، ولا يوقّعها، ولا يُنقّحها، ولا يُعدّلها. أصدِر للوكيل مفتاحاً يقتصر نطاقه في الخادم على مسارات القراءة تلك، حتى لا يستطيع وكيل مُخترَق بلوغ عمليات الكتابة أو العمليات ذات الفئة الأعلى.
  • استخدم مفتاحاً مخصّصاً لكل وكيل. يتيح لك المفتاح المخصّص لكل وكيل إبطال تكامل واحد أو تدويره دون التأثير في غيره، ويجعل سجلّات نقطة النهاية منسوبة إلى وكيل بعينه.
  • قيّد نظام الملفات. لأن كل أداة تقرأ مساراً مطلقاً من القرص المحلي، يستطيع الخادم قراءة أي ملف تستطيع عملية المضيف قراءته. شغّله بوصفه مستخدماً غير مميَّز، وقيّد دليل عمله بمجلّد مستندات، ولا تشغّله أبداً بحساب مميَّز.
  • فضّل أمان طبقة النقل (⁨TLS⁩). وجّه NEXTPDF_BASE_URL إلى نقطة نهاية https:// لأي نشر غير محلي. ترسل حزمة التطوير المفتاح بوصفه رمز Bearer في ترويسة Authorization، فالنقل بالنص الصريح يكشفه أثناء النقل.

راجِع أمان ⁨Connect⁩ وعملياته للاطّلاع على ضوابط جانب نقطة النهاية التي تدعم هذه الممارسات على جانب العميل.

اختبار الخادم محلياً قبل توصيل وكيل

قسم بعنوان «اختبار الخادم محلياً قبل توصيل وكيل»

تحقّق من الخادم بمعزل عن الوكيل قبل توصيله به. لا يحتاج الفحص الأسرع إلى ملف ⁨PDF⁩ ولا إلى شبكة:

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

يطبع التثبيت السليم 8. إذا رأيت ImportError يذكر الإضافة mcp، فهذا يعني أن التبعية الاختيارية مفقودة. أعِد التثبيت بـpip install nextpdf[mcp].

بعد ذلك، اختبر عبر واجهة سطر الأوامر (⁨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 info استدعاء get_document_ast نفسه الذي يقف خلف nextpdf_get_ast وnextpdf_info. إذا نجح nextpdf info والاستخراج، فهذا يعني أن بيانات الاعتماد ونقطة النهاية صحيحة، وأن أدوات ⁨MCP⁩ المقابلة ستعمل.

لقيادة بروتوكول ⁨MCP⁩ مباشرةً، استخدم ⁨MCP Inspector⁩ الأصلي من المنبع (المُرفق مع حزمة mcp). وجّهه إلى الأمر والبيئة نفسيهما اللذين سيستخدمهما وكيلك، ثم اسرد الأدوات واستدعِها يدوياً. تحقّق من أن nextpdf_health يُبلّغ status: "ok". يُعيد misconfigured عندما يكون NEXTPDF_BASE_URL أو NEXTPDF_API_KEY غير مضبوط، وهذه أسرع طريقة لاكتشاف قيمة بيئة مفقودة قبل أن يستدعي الوكيل أداة فعلية.

مراقبة استدعاءات الأدوات وتنقيحها

قسم بعنوان «مراقبة استدعاءات الأدوات وتنقيحها»

يتواصل خادم ⁨MCP⁩ عبر الإدخال/الإخراج القياسي ⁨input/output⁩ (⁨stdio⁩)، لذا يحمل خرجه القياسي دفق البروتوكول ويجب أن يبقى نظيفاً. لا يهيّئ الخادم أي تسجيل تطبيق خاص به. قنوات المراقبة الأساسية لديك هي حمولات أخطاء الأدوات المُهيكلة، وواجهة سطر الأوامر، وسجلّات نقطة النهاية الخاصة بك.

  • حمولات أخطاء الأدوات هي الإشارة. يُعيد كل استدعاء فاشل كائن ⁨JSON⁩ يتضمّن error، وفي حال أخطاء حزمة التطوير، error_type وstatus_code (انظر معالجة الأخطاء). اجعل مضيف الوكيل يسجّل هذه الحمولات؛ فهي تحدّد الأداة الفاشلة والسبب الدقيق دون أدوات قياس إضافية على الخادم.
  • أعِد الإنتاج عبر واجهة سطر الأوامر مع تسجيل التنقيح. لا يصدر خادم ⁨MCP⁩ نفسه أي سجلّات، لكن واجهة سطر الأوامر تستخدم استدعاءات حزمة التطوير نفسها وتُسجّل بالفعل. أعِد إنتاج أداة فاشلة عبر أمر واجهة سطر الأوامر المقابل مع --log-level debug. تُسجّل واجهة سطر الأوامر إلى ⁨stderr⁩ مع طوابع زمنية، وتُدوّن آثار تتبّع كاملة للأخطاء غير المتوقّعة. هذه هي الطريقة الأكثر مباشرةً لمعرفة ما يفعله المُعالج دون إرفاق مُنقّح.
  • الصحة بوصفها مسباراً. استدعِ nextpdf_health لتأكيد أن الخادم يرى عنوان ⁨URL⁩ أساسياً ومفتاح ⁨API.⁩ تُبلّغ النتيجة sdk_version وserver_url وapi_key_configured (قيمة منطقية، لا المفتاح نفسه أبداً)، وstatus.
  • المراقبة على جانب نقطة النهاية. لأن كل أداة تُربَط بطلب ⁨Connect⁩ واحد، اربط نشاط الأدوات بسجلّات وصول نقطة النهاية بحسب مفتاح الـ ⁨API⁩ والطابع الزمني. شغّل نقطة النهاية خلف ضوابط المصادقة والحصص والمراقبة نفسها التي تستخدمها لعملاء الخدمة الآخرين.

استكشاف مشكلات تكامل الوكلاء الشائعة وإصلاحها

قسم بعنوان «استكشاف مشكلات تكامل الوكلاء الشائعة وإصلاحها»
العَرَضالسبب المرجَّحالحل
يفشل الخادم في البدء مع ImportError بخصوص الإضافة mcpالتبعية الاختيارية 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 (واجهة سطر الأوامر) بدلاً من python -m nextpdf.mcpاستخدم python -m nextpdf.mcp بوصفه command/args.

للاطّلاع على الإخفاقات على مستوى نقطة النهاية وفحوص النشر، راجِع استكشاف أخطاء ⁨Connect⁩. وللاطّلاع على عمليات حزمة التطوير التي تغلّفها هذه الأدوات، راجِع مرجع واجهة سطر الأوامر ونظرة عامة على حزمة التطوير.