عاجلًا أم آجلًا، سيضع أحدهم صورة جواز سفر في محادثة مع مساعد ويطلب منه «أن يملأ النموذج فحسب». سيحاول نموذج الرؤية العام ذلك. وقد يصيب الاسم أيضًا. لكنه لن يخبرك هل اجتازت أرقام التحقق في منطقة القراءة الآلية (MRZ) الفحص، ولن يعيد التواريخ بصيغة واحدة في كل مرة، ولن يقول «لم أتمكن من قراءة هذا» بدلًا من التخمين.

هذه الفجوة تسدّها أداة على نحو مناسب. يتيح Model Context Protocol للوكيل استدعاء أداة كهذه، ويشرح هذا المقال كيف تمنح Claude Desktop وClaude Code وCursor وعملاء آخرين أداة للتعرّف على الوثائق، وما الذي يحصل عليه الوكيل، وكيف تُبقي التكلفة محدودة، وما الذي ينبغي التفكير فيه قبل أن توجّه وكيلًا نحو وثائق الهوية أصلًا.

هذه مدونة doc.cheap، واجهة API التي يقوم عليها خادم MCP المستخدم هنا. الخادم مرخّص بـMIT، وأسئلة الإعداد تنطبق على أي أداة من هذا النوع.

ما الذي يحصل عليه الوكيل

الخادم هو @doc-cheap/mcp على npm (بترخيص MIT، ويتطلب Node 20 أو أحدث)، ويعرض ثلاث أدوات:

الأداة ماذا تفعل هل تستهلك رصيدًا؟
scan_document تتعرّف على جواز سفر أو بطاقة هوية وطنية أو رخصة قيادة من صورة أو مسح ضوئي وتعيد النتيجة المنظمة نعم، فقط حين يُتعرَّف على وثيقة
check_balance تقرأ الرصيد المتبقي وعدّادات الشهر الحالي لا (للقراءة فقط)
search_docs تبحث في توثيق API المرفق بالخادم، دون اتصال بالإنترنت لا (للقراءة فقط)

تحمل كل أداة عنوانًا، ووصفًا (والأداتان اللتان تمسّان الحساب تذكران السعر في وصفهما)، وتلميحات سلوك MCP التي يقرؤها العميل قبل أن يقرر هل يسألك أولًا: scan_document موسومة بأنها ليست للقراءة فقط، والأخريان للقراءة فقط. ويرسل الخادم أيضًا تعليمات يقرؤها النموذج قبل أي استدعاء، تذكر ما يتعرّف عليه وكم يكلّف الاستدعاء. وإلى جانب الأدوات هناك أربعة قوالب طلبات (prompts): scan_document_to_json وcheck_document_expiry وbatch_scan وexplain_error، وكل صفحة من التوثيق معروضة كمورد للقراءة فقط، مثل doccheap://docs/reference/fields.

تجيب scan_document بالنتيجة الكاملة بصيغة JSON منظمة مع ملخص من سطر واحد، على سبيل المثال:

Scan 01a0af18-cd8d-7a61-9f2d-4c7b8e105da3: recognized · passport (GRC) · PARADEIGMA ELENI SOFIA · billed · 684 ms

(صاحب الوثيقة عيّنة مختلقة من التوثيق.) يحتوي JSON الذي يقف خلف هذا السطر على صاحب الوثيقة، ورقم الوثيقة، والتواريخ بصيغة ISO 8601، وكل حقل مع نطاق الثقة الخاص به، وأسطر MRZ مع حكم passed / failed / absent، ومؤشر billed. وهذه البنية هي جوهر الأمر: لا يضطر الوكيل إلى تفسير البكسلات، بل يقرأ حقولًا.

التثبيت: الخادم المحلي

كل العملاء أدناه يشغّلون الخادم باستخدام npx. إذا لم يُضبط مفتاح، يستخدم الخادم مفتاح الـsandbox العام، الذي يمنح 10 وثائق مُتعرَّف عليها مجانًا لكل عنوان IP إجمالًا، و10 طلبات في الساعة كحد أقصى. وهذا يكفي للتجربة. والتسجيل يمنح 20 رصيدًا مجانيًا؛ وبعدها تكلّف الوثيقة المُتعرَّف عليها $0.01.

Claude Desktop وCursor وWindsurf تقرأ الكتلة نفسها، في claude_desktop_config.json و~/.cursor/mcp.json و~/.codeium/windsurf/mcp_config.json على التوالي:

{
  "mcpServers": {
    "doc-cheap": {
      "command": "npx",
      "args": ["-y", "@doc-cheap/mcp"],
      "env": { "DOC_CHEAP_API_KEY": "sk_live_your_key" }
    }
  }
}

احذف سطر env لتعمل بمفتاح الـsandbox.

Claude Code:

claude mcp add-json doc-cheap '{"command":"npx","args":["-y","@doc-cheap/mcp"],"env":{"DOC_CHEAP_API_KEY":"sk_live_your_key"}}'

VS Code:

code --add-mcp '{"name":"doc-cheap","command":"npx","args":["-y","@doc-cheap/mcp"]}'

يستخدم Gemini CLI وKiro كتلة mcpServers نفسها في ملفات الإعدادات الخاصة بهما؛ ويذكر دليل MCP مسار كل منها. أعد تشغيل العميل بعد التعديل: لا يلتقط الخادم متغيرات البيئة المعدّلة إلا عند تشغيل جديد.

التثبيت: الخادم المستضاف

إذا كان عميلك يتصل بعنوان URL بدلًا من تشغيل أمر، فالأدوات الثلاث نفسها مستضافة على https://mcp.doc.cheap/mcp عبر Streamable HTTP، دون تسجيل دخول. يوضع المفتاح في ترويسة، X-Doc-Cheap-Api-Key أو Authorization: Bearer (والغلبة للترويسة المسمّاة إذا أُرسلت الاثنتان)؛ ومن دون مفتاح يُستخدم مفتاح الـsandbox.

Claude Code:

claude mcp add --transport http doc-cheap https://mcp.doc.cheap/mcp --header "Authorization: Bearer sk_live_your_key"

Cursor:

{
  "mcpServers": {
    "doc-cheap": {
      "url": "https://mcp.doc.cheap/mcp",
      "headers": { "Authorization": "Bearer sk_live_your_key" }
    }
  }
}

في Claude Desktop وclaude.ai، أضفه من Settings → Connectors بوصفه connector مخصصًا بهذا العنوان.

لا يستطيع الخادم المستضاف رؤية الملفات على جهازك، لذا تأخذ scan_document هناك الصورة بصيغة image_base64 أو كعنوان عام image_url.

الملفات المحلية والعناوين مسيّجة عن قصد

وسيط الأداة يختاره نموذج، ويمكن إقناع النموذج بأشياء كثيرة. لذلك لا يقرأ الخادم المحلي مسارات عشوائية:

  • image_path معطّل إلى أن تضبط DOC_CHEAP_IMAGE_ROOT على مجلد واحد. تُحلّ المسارات عبر الروابط الرمزية (symlinks) أولًا، ويُرفض .. أو أي رابط يشير إلى خارج المجلد. الملف غير الموجود والملف الواقع خارج الحدود يحصلان على الرسالة نفسها، فلا يمكن استخدام الأداة لمعرفة هل ملف ما موجود.
  • يجب أن يبدأ image_url بـhttps:، وأن يُحلّ فقط إلى عناوين عامة (تُرفض نطاقات loopback والعناوين الخاصة وlink-local وما شابهها)، ولا يتبع أكثر من ثلاث عمليات إعادة توجيه مع إعادة فحص كل قفزة، وحدّه الأقصى 25 MB.

إذا سبق أن ربطت أداة لقراءة الملفات بوكيل، فقارنها بهذه القائمة. عبارة «النموذج لن يمرر إلا مسارات معقولة» ليست حدًا أمنيًا.

إبقاء التكلفة محدودة

خاصيتان تجعلان استخدام الوكيل قابلًا للتنبؤ:

  1. لا يُحتسب إلا ما يُتعرَّف عليه من وثائق. يُخصم الاستدعاء حين يُحدَّد نوع الوثيقة وتُستخرج بيانات فعلًا: منطقة MRZ تجتاز أرقام تحققها، أو خمسة حقول مطبوعة على الأقل، أو رمز شريطي فُكّ ترميزه بشكل صحيح. عدم العثور على وثيقة، أو صورة غير مقروءة، أو نوع غير مدعوم، أو خطأ داخلي، أو انتهاء المهلة: كل ذلك لا يكلّف شيئًا. ويبيّن مؤشر billed في النتيجة ما حدث، في كل مرة. ومع مفتاح الـsandbox لا يُخصم أي شيء إطلاقًا، ويبيّن المؤشر حينها هل كان المسح نفسه سيُحتسب على مفتاح حقيقي.
  2. يمكن جعل إعادة المحاولة مجانية. تقبل scan_document الوسيط idempotency_key؛ ومع مفتاح حقيقي، يعيد التكرار بالمفتاح نفسه النتيجة الأولى المخزّنة بدلًا من الخصم مرة أخرى. أما إعادة المحاولة دون مفتاح فهي عملية مسح ثانية. والتكرار يعيد النتيجة المخزّنة، لذا فإما retain_hours: 0 وإما إعادة محاولات تسترجع النتيجة المخزّنة، لا الاثنان معًا.

عمليًا:

  • اجعل الوكيل يستدعي check_balance قبل أي دفعة. تعليمات الخادم نفسها تطلب من النموذج فعل ذلك، وقالب الطلب batch_scan يبدأ به. ومع مفتاح الـsandbox يكون الرصيد null، وتقول الأداة إنه لا يوجد رصيد بدلًا من عرض أصفار.
  • اجعل الموافقة التلقائية للأدوات المخصصة للقراءة فقط وحدها. إعدادات Kiro، مثلًا، تدعم "autoApprove": ["check_balance", "search_docs"]. أبقِ scan_document خلف طلب تأكيد، لأنها الأداة التي تنفق.
  • دع الوكيل يبحث بنفسه. تعمل search_docs دون اتصال على التوثيق المرفق، فسؤال «ماذا يعني unsupported_document» لا يكلّف شيئًا ولا يعتمد على ذاكرة النموذج.

الخصوصية: أسئلة تطرحها قبل أن تفعل هذا

وثائق الهوية من أكثر البيانات حساسية على الإطلاق، والوكيل يضيف أطرافًا إلى مسار البيانات. إليك ما هو صحيح من جهة الواجهة، وما يعتمد على إعدادك أنت.

من جهة الواجهة (كما هو موثّق):

  • تُحفظ الصورة المرفوعة في الذاكرة طوال مدة الطلب ولا تُكتب أبدًا إلى تخزين دائم.
  • تُحفظ نتيجة التعرّف لكي يمكن قراءتها لاحقًا، لمدة تُضبط على مستوى الحساب (24 ساعة أو 7 أيام أو 30 يومًا أو سنة واحدة). القيمة الافتراضية للحساب الجديد سنة واحدة. ولكل استدعاء، لا يكتب retain_hours: 0 أي صف إطلاقًا، وscan_document تقبل retain_hours أيضًا. إذا كان الوكيل يحتاج إلى الإجابة مرة واحدة فقط، فاضبطه.
  • تجري المعالجة في الاتحاد الأوروبي. ولا تُستخدم البيانات لتدريب النماذج.
  • return_portrait: false يستبعد images.main_photo، أي قصاصة صورة صاحب الوثيقة. أما قصاصة الصفحة كاملة فما زالت تعود، وكذلك النسخة الثانية الباهتة من الوجه التي تطبعها بعض الوثائق داخل الصفحة.

من جهتك أنت:

  • النتيجة تدخل في سياق النموذج. كل ما تعيده scan_document (الأسماء والأرقام والتواريخ) يصبح جزءًا من المحادثة، ويعالجه مزوّد النموذج اللغوي الكبير (LLM) الذي يشغّل عميلك، وفق شروط ذلك المزوّد. وهذا متأصل في أي أداة MCP، وليس خاصًا بهذه الأداة.
  • طريقة انتقال الصورة مهمة. مع image_path على الخادم المحلي، يقرأ الخادم الملف ويرسله مباشرة إلى الواجهة. ومع image_base64، تكون بايتات الصورة ضمن وسائط استدعاء الأداة التي يكتبها النموذج. إذا أردت أن تبقى البكسلات خارج سياق النموذج، فاستخدم مجلدًا محليًا مسيّجًا.
  • هذا تعرّف على البيانات، لا تحقق من الهوية. قيمة مجموعة authenticity في النتيجة هي not_checked. اجتياز MRZ يعني أن المنطقة قُرئت وأنها متسقة داخليًا، لا أن الوثيقة أصلية. لا توجد خطوة للتحقق من الحيوية (liveness) أو لمطابقة الوجه. إذا كانت حالة استخدامك KYC (اعرف عميلك)، فهذا مُدخل واحد، لا القرار.
  • استخدم وثائق اصطناعية أثناء البناء. العيّنات ومناطق MRZ المولَّدة تكفي لربط كل شيء.

جلسة قصيرة

بعد تثبيت الخادم، يكفي طلب مثل «اقرأ صورة جواز السفر هذه وأخبرني هل تنتهي صلاحيته خلال الأشهر الستة القادمة» مع إرفاق عيّنة اصطناعية. الوكيل حسن السلوك يستدعي scan_document، ويقرأ document.expiry_date وdocument.days_remaining من النتيجة، ويجيب من هذه الحقول لا من انطباعه عن الصورة. وإذا عاد المسح بحالة unreadable، فعليه أن يقول ذلك ويطلب صورة أفضل، ولن يُخصم منك شيء مقابله.

هذا السلوك الأخير هو السبب الحقيقي لاستخدام أداة هنا: يحصل الوكيل على «تعذّرت القراءة» صريحة بدلًا من إغراء ملء الفجوة بالتخمين.

روابط

إذا بنيت شيئًا باستخدامه، أو وجدت عميلًا لا يعمل معه الإعداد أعلاه، فاكتب إلى admin@doc.cheap.

كل عبارة عن doc.cheap وخادم MCP الخاص بها جرى التحقق منها مقابل شيفرتهما.