خادم MCP

خادم MCP

استخدم FourA من أي عميل Model Context Protocol (مثل Claude Desktop، Claude Code، Cursor، Windsurf، VS Code) كأربع أدوات أصلية وست مطالبات لمسارات العمل. بدون كود تكامل، وبدون عميل HTTP مخصص.

مفتوح المصدر على GitHub؛ وعلى npm باسم @fouradata/mcp. الإصدار الحالي: 0.5.0.

البدء السريع: stdio المحلي (موصى به لـ Claude Desktop)

احصل على مفتاح من foura.ai/dashboard#api-keys (بنقرة واحدة، يُعرض مرة واحدة عند الإنشاء، بالتنسيق pk_live_...). أضف هذا إلى إعدادات عميل MCP الخاص بك:

{
  "mcpServers": {
    "foura": {
      "command": "npx",
      "args": ["-y", "@fouradata/mcp"],
      "env": { "FOURA_API_KEY": "pk_live_..." }
    }
  }
}

تنبيه حول Claude Desktop: تأكد من إغلاق Claude Desktop بالكامل (Cmd+Q في نظام macOS) قبل تعديل ملف التكوين. إذا كان التطبيق لا يزال قيد التشغيل، فسيقوم بالكتابة فوق تعديلاتك باستخدام التكوين الموجود في الذاكرة عند الإغلاق.

يقوم الأمر npx بتنزيل @fouradata/mcp عند التشغيل الأول ويقوم بتشغيله كعملية فرعية لعميل MCP الخاص بك. لا حاجة إلى تثبيت عام.

العميل موقع ملف التكوين
Claude Desktop (macOS) ~/Library/Application Support/Claude/claude_desktop_config.json
Claude Desktop (Windows) %APPDATA%\Claude\claude_desktop_config.json
Claude Code claude mcp add foura -- npx -y @fouradata/mcp (قم بتعيين FOURA_API_KEY في متغيرات البيئة أولا)
Cursor ~/.cursor/mcp.json
Windsurf ~/.codeium/windsurf/mcp_config.json
VS Code (إضافة MCP) .vscode/mcp.json

أعد تشغيل العميل. ستظهر الأدوات (foura_auto، foura_single، foura_proxy، foura_browser) والست مطالبات في قائمة الأدوات الخاصة بك.

البدء السريع: مستضاف (Streamable HTTP)

للعملاء الذين يدعمون النقل عبر Streamable HTTP (مثل Cursor، وWindsurf، وVS Code، وClaude Code مع --transport http)، قم بتوجيههم إلى الـ endpoint المستضاف بدلا من تشغيل عملية فرعية محلية:

{
  "mcpServers": {
    "foura": {
      "url": "https://mcp.foura.ai/mcp",
      "headers": {
        "Authorization": "Bearer pk_live_..."
      }
    }
  }
}

بالنسبة لـ Claude Desktop، استخدم تكوين stdio أعلاه أو قم بتوصيل endpoint المستضاف عبر mcp-remote:

{
  "mcpServers": {
    "foura": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://mcp.foura.ai/mcp", "--header", "Authorization: Bearer pk_live_..."]
    }
  }
}

مرجع الـ endpoint المستضاف

الخاصية القيمة
URL https://mcp.foura.ai/mcp
النقل Streamable HTTP (POST /mcp, SSE responses)
المصادقة Authorization: Bearer pk_live_... لكل request
إصدار بروتوكول MCP لكل @modelcontextprotocol/sdk (حاليًا 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07)
تحدي 401 WWW-Authenticate: Bearer realm="foura-mcp", resource_metadata="https://foura.ai/docs/mcp/server#auth"

الخادم المستضاف لا يحفظ الحالة (stateless). كل request يحمل مفتاحه الخاص، والذي يوجهه الخادم إلى FourA API كـ X-API-Key. مفتاح واحد يفتح جميع الأدوات الأربعة.

للحماية من إعادة ربط DNS (CVE-2025-66414)، يتحقق الخادم من صحة header Host (يجب أن يكون mcp.foura.ai أو localhost) و header Origin عند وجوده (المسموح بها: mcp.foura.ai, claude.ai, app.cursor.sh, app.cursor.com). المتصلون من خادم إلى خادم (curl, عملاء MCP في وضع stdio bridge) لا يرسلون Origin ويمرون.

الأدوات

جميع الأدوات الأربعة مشروحة بـ readOnlyHint: true و openWorldHint: true وفقًا لـ مواصفات MCP 2025-06-18. العملاء الذين يوافقون تلقائيًا على الأدوات الموثوقة للقراءة فقط يستدعونها بدون نافذة تأكيد لكل request.

foura_auto هو الخيار الافتراضي الذكي: أعطه URL وسيعيد المحتوى، مختارًا طريقة الجلب لك. الثلاثة الآخرون هم العناصر الأساسية الأقل مستوى التي يديرها؛ استخدمهم عندما تريد تحكمًا صريحًا.

foura_auto

أعطه URL عندما تريد من FourA اختيار طريقة الـ request. يقوم بمحاولات محدودة عبر مسارات HTTP، و proxy، والمتصفح المتاحة. مرر validate على الأهداف المحمية بحيث يجب أن يحتوي الـ response على محتوى يحدد الصفحة الحقيقية. إذا لم تنجح أي محاولة في التحقق، ترجع الأداة خطأ بدلاً من تقديم صفحة تحدي كنجاح.

يتضمن الـ response تفاصيل الاكتمال في meta، وافتراضيًا، session قابل لإعادة الاستخدام مع proxy، cookies، و userAgent. لمتابعة عادية، استدعِ foura_single مع session.proxy كـ proxy، قم بتسلسل الـ cookies كـ header Cookie، وأرسل session.userAgent كـ header User-Agent. لتصيير JavaScript، مرر قيم الجلسة إلى حقول foura_browser المطابقة.

foura_single

request HTTP واحد، response راجع. يعكس POST /api/single/ واحد لواحد.

استخدمه للصفحات الثابتة، و JSON APIs، و HTML المصيّر من الخادم.

اختيار المتصفح الذي تقدمه

يقدم الـ request أحدث إصدار من Google Chrome افتراضيًا. عندما يقبل هدف متصفحًا ويرفض آخر، قم بتعيين browser (Chrome, Edge, Safari, Firefox, أو Tor)، os (Windows, macOS, Android, أو iOS)، أو version، أو مرر معرف profile دقيق:

{
  "method": "GET",
  "url": "https://example.com",
  "browser": "Firefox",
  "os": "Windows"
}

تفوز أحدث نسخة عندما تتطابق عدة ملفات تعريف. تُرجع المجموعة غير الموجودة خطأ يسرد ما هو متاح، لذلك لا يتم إرسال request أبدا كمتصفح لم تختره. يحتاج التحديد إلى unblocker، وهو قيد التشغيل افتراضيا. يتم نشر الكتالوج في GET /api/profiles ولا يحتاج إلى مفتاح API.

توجد نفس الحقول الأربعة داخل كائن request الخاص بـ foura_proxy.

foura_proxy

توجيه HTTP request واحد عبر proxies متناوبة مع إعادة المحاولة التلقائية. استخدمه عندما يتم حظر foura_single أو عندما يتطلب الهدف بلد خروج محدد.

قم بتعيين exitCountries إلى قائمة سماح صارمة لرموز البلدان المكونة من حرفين والمرئية للهدف والتي يوفرها المستخدم أو متطلبات الهدف:

{
  "maxTries": 5,
  "exitCountries": ["CZ", "GB"],
  "request": {
    "method": "GET",
    "url": "https://example.com/pricing",
    "browser": "Chrome",
    "os": "Windows"
  }
}

يتم تقليم القيم، وتحويلها إلى أحرف كبيرة، وإزالة التكرار منها. تُستثنى الـ proxies ذات المخارج غير المعروفة، ولا يتراجع الـ request أبدا إلى دولة لم يتم طلبها. يعتمد الاختيار على أحدث بيانات وصفية متاحة للدولة المرئية للهدف، والتي تُحَدَّث عادة خلال عشر دقائق؛ وهو ليس بحثا مباشرا عن الموقع الجغرافي أثناء الـ request. لا تستنتج دولة الخدمة من عنوان مضيف الـ proxy.

يُرجع النجاح المحدد النطاق exitCountry ومعرف proxy القابل لإعادة الاستخدام. تحقق من أن exitCountry ينتمي إلى قائمة السماح المطلوبة. إذا لم يكن هناك تطابق في التجمع الحالي، تُرجع الأداة code: "no_eligible_proxy" مع النطاق الموحد في details.exitCountries. احتفظ بهذا النطاق وأعد المحاولة لاحقا. قم بتغييره أو توسيعه فقط عندما يغير المستخدم المتطلب صراحة.

إذا احتاجت الصفحة المحددة لاحقا إلى JavaScript، فمرر معرف proxy المُرجع إلى foura_browser.proxy حتى يعيد المتصفح استخدام نفس المخرج.

foura_browser

جلسة متصفح كاملة. يتم تشغيل JavaScript، وعرض الـ DOM، وتعود الـ cookies. يطابق POST /api/browser/.

يُستخدم لتطبيقات الصفحة الواحدة، أو المحتوى المُحمّل بتأخير (lazy-loaded)، أو الصفحات المحمية بتحديات مكافحة البوتات التي تحتاج إلى متصفح حقيقي لتجاوزها.

بالنسبة لأشكال الإدخال، والقيم الافتراضية، وقواعد التحقق لكل أداة، راجع مرجع الـ endpoint لـ REST. تتطابق مخططات الأداة مع الـ API الخاصة بـ REST حقلا بحقل، بالإضافة إلى خيار offload_large الخاص بـ MCP فقط (انظر أدناه).

عندما يجري الهدف فحصا للبوتات

يُرجع foura_single و foura_proxy قيمة defense عندما يجري الهدف فحصا للبوتات في الطريق إلى الـ body. تعني defense.solved: true أنه تم اجتياز الفحص وأن data هي الصفحة الحقيقية؛ بينما تعني false أن الـ body قد يكون صفحة تحدٍ. أعد المحاولة باستخدام متصفح، أو نظام تشغيل، أو إصدار مختلف، أو انتقل إلى foura_proxy أو foura_browser، بدلا من التعامل مع صفحة التحدي كمحتوى.

استجابات محددة النوع

تتضمن كل استجابة أداة كلا من content (ملخص نصي قابل للقراءة البشرية) و structuredContent (JSON محدد النوع تم التحقق من صحته مقابل outputSchema الخاص بالأداة). لكل أداة شكلها الفريد:

  • foura_auto: شكل أحادي لـ { status, headers, data } بالإضافة إلى meta ({ rung, solved, attempts, credits }، موجودة دائما، حيث rung هي إحدى القيم cache، أو probe، أو proxy، أو browser، أو fail) و، افتراضيا، session ({ proxy, cookies, userAgent }) لإعادة التشغيل عبر الأدوات ذات المستوى الأدنى. لا يوجد total_time.
  • foura_single: { status, headers, data, total_time, ... } (الـ headers عبارة عن مصفوفة، إدخال واحد لكل قفزة إعادة توجيه)
  • foura_proxy: نفس الشكل الأحادي بالإضافة إلى { proxy, total }؛ يتضمن النجاح المحدد النطاق أيضا exitCountry
  • foura_browser: شكل مميز { status, headers: object, body, cookies, userAgent } (ملاحظة: قد يكون body عبارة عن سلسلة نصية أو كائن بناءً على الـ content-type)

يمكن للعملاء الذين يدعمون structuredContent تمرير الكائن محدد النوع مباشرة إلى الـ LLM بدلا من مطالبته بتحليل الـ JSON من النص.

الـ headers للاستجابة متعددة القيم

الـ headers التي تظهر عدة مرات (Set-Cookie، Link، WWW-Authenticate) تعود في شكل مصفوفات:

{
  "headers": [
    {
      "result": { "version": "HTTP/2", "code": 200, "reason": "" },
      "content-type": "text/html",
      "set-cookie": ["a=1; Path=/", "b=2; Path=/"]
    }
  ]
}

هذا الأمر مهم للمواقع التي تقوم بتعيين ملفات cookies للـ session والتتبع والموافقة في response واحد (معظم مواقع التجارة الإلكترونية).

الـ responses الكبيرة: offload_large (الافتراضي: inline)

بشكل افتراضي (بدءا من الإصدار v0.2.0)، يتم إرجاع أجسام الـ response بالكامل بشكل inline في structuredContent بغض النظر عن الحجم. هذا يعمل في كل عميل MCP مباشرة دون إعدادات إضافية.

إذا كان عميلك يدعم MCP resources/read وكنت ترغب في توفير الـ token في الصفحات الكبيرة، قم بتمرير offload_large: true لكل استدعاء للأداة. بعد ذلك، يتم كتابة الـ responses التي بحجم >= 50 كيلوبايت على القرص، وتُرجع كـ resource_link، ويقوم عميلك بجلب الـ body فقط عندما يحتاج إليه فعليا. تنتهي صلاحية الـ payloads المخزنة مؤقتا بعد 1 ساعة.

{
  "method": "GET",
  "url": "https://en.wikipedia.org/wiki/Web_scraping",
  "offload_large": true
}
العميل offload_large: true
Claude Desktop ليس بعد، اترك الافتراضي false
Claude Code, Cursor, Windsurf مدعوم
إضافة VS Code MCP مدعوم

معزول حسب المستأجر: يحصل كل مفتاح API على مساحة أسماء خاصة به (sha256(apiKey)[:16]). المفتاح الذي قام بتخزين الحمولة هو الوحيد الذي يمكنه قراءتها. تُرجع عمليات القراءة عبر المستأجرين Payload not found دون تسريب وجود البيانات.

المطالبات المضمنة

تظهر ستة قوالب لسير العمل تحت /prompts في أي عميل MCP. يأخذ كل منها وسيطات مسماة ويُرجع رسالة مستخدم كقالب تنسق أداة واحدة أو أكثر.

المطالبة الوسيطات ماذا تفعل
smart_fetch url، اختياري must_contain، extract جلب تلقائي (يختار الطريقة، ويعالج حماية الروبوتات)، ثم يُرجع أو يستخرج المحتوى
scrape_product_page url جلب عبر المتصفح، ثم استخراج عنوان المنتج والسعر والصورة والمخزون وSKU بتنسيق JSON
extract_article url طلب فردي مع خيار التراجع إلى proxy، ثم إزالة التنقل/الإعلانات وإرجاع مقال نظيف بتنسيق JSON
monitor_pricing url، اختياري target_price جلب عبر proxy، استخراج السعر الحالي، ومقارنته بالهدف
check_endpoint_health url، اختياري expected_text طلب فردي مع تحقق صارم، إرجاع إمكانية الوصول والتوقيت
bulk_fetch_urls urls (مفصولة بفواصل) طلب فردي متوازي، خيار تراجع تلقائي إلى proxy لكل URL، إرجاع البيانات الوصفية فقط

لا تكلف المطالبات أي token في وضع الخمول. المطالبات المستدعاة فقط هي التي تدخل في سياق LLM.

النص الكامل بالإضافة إلى مطالبات التراجع اليدوية: وصفات MCP.

غلاف الخطأ

يحمل كل خطأ (isError: true) غلاف structuredContent. الحقول الدنيا في كل خطأ:

{
  "service": "auto | single | proxy | browser",
  "code": "rate_limited",
  "error": "Rate limit exceeded"
}

في أخطاء upstream ذات حالة HTTP، يكون status موجوداً أيضاً. في أخطاء rate-limit والسعة، يضيف upstream envelope retryAfter وcurrent.{concurrency, rpm} وlimits.{maxConcurrency, maxRpm}. راجع API Errors لمعرفة هيكل REST الأساسي.

قيم code المستقرة:

الرمز HTTP المعنى هل إعادة المحاولة آمنة؟
ssrf_blocked غير متوفر عنوان IP الهدف في نطاق خاص أو محجوز (RFC 5735 و6598 وIPv6 المحجوزة) لا، غيّر الـ URL
upstream_non_json يختلف أرجع upstream هيكل body غير صالح ربما، تحقّق
output_validation_failed غير متوفر رفض outputSchema لخادم MCP استجابة upstream (خطأ في الخادم أو هيكل upstream غير متوقع) ربما، أبلغ عنه
bad_request 400 رُفض هيكل الإدخال لا، أصلح الوسائط
auth_failed 401 المفتاح مفقود أو غير صالح أو معطل لا، أصلح المفتاح
forbidden 403 تمت المصادقة ولكنه غير مسموح لا، أو انتقل إلى foura_proxy
not_found 404 الهدف أو הـ endpoint مفقود لا
rate_limited 429 تم الوصول إلى حد RPM نعم، انتظر retryAfter
at_capacity 503 تم الوصول إلى حد التزامن نعم، انتظر retryAfter
service_disabled 503 نافذة الصيانة أو أن خطتك لا تتضمن هذه الأداة تواصل مع الدعم
service_unavailable 503 503 عام نعم، تراجع قصير
upstream_error 500+ Upstream 5xx نعم، تراجع أسي
upstream_client_error 4xx 4xx آخر عادة لا
upstream_unknown آخر دفاعي، يجب ألا يحدث عملياً تحقّق
no_eligible_proxy غير متوفر لا يوجد proxy يطابق نطاق exitCountries الصارم أعد المحاولة لاحقاً؛ غيّر النطاق بشكل صريح فقط

يمكن لوكلاء LLM قراءة code مباشرة لمنطق إعادة المحاولة دون تحليل النص. دليل المصادقة: Authentication.

Limits

  • الـ body المضمن افتراضياً. مع offload_large: true، الاستجابات >= 50 كيلوبايت تنتقل إلى القرص + resource_link (لكل مستأجر، مدة بقاء TTL ساعة واحدة).
  • تُرفض الأهداف الخاصة (RFC 5735 وRFC 6598 وكتل IPv6 المحجوزة) في طبقة MCP. يتم توجيه المضيفين العامين فقط.
  • حد الـ request body يبلغ 256 كيلوبايت في طلبات /mcp الواردة (تكون الـ payloads الحقيقية لـ MCP < 4 كيلوبايت).
  • يفرض FourA API الـ rate limits لكل خدمة. راجع Rate Limits.

Self-Hosting

يتوفر المصدر الكامل للخادم بشكل عام على GitHub ضمن @fouradata/mcp. قم بعمل نسخة (clone) للمستودع، npm install، npm run build، وشغّل node dist/http.js لإنشاء نسختك الخاصة. يعمل بدون حالة (stateless) في حاوية واحدة خلف أي load balancer.

بيئة قابلة للتكوين:

المتغير الافتراضي الغرض
PORT 3076 منفذ استماع HTTP
FOURA_API_BASE https://api.foura.ai/api عنوان URL الأساسي لـ FourA REST للتيار الصاعد
FOURA_MCP_PAYLOADS_DIR /data/payloads حيث يتم تخزين الـ responses التي حجمها >= 50 كيلوبايت مؤقتا على القرص (مع offload_large: true)
FOURA_MCP_ALLOWED_HOSTS mcp.foura.ai,localhost,127.0.0.1,[::1] قائمة السماح لأسماء المضيفين للـ header Host (دفاع ضد DNS-rebinding)
FOURA_MCP_ALLOWED_ORIGINS https://mcp.foura.ai,https://claude.ai,https://app.cursor.sh,https://app.cursor.com قائمة السماح للمصادر (Origin) للمتصلين عبر المتصفح
FOURA_MCP_RESOURCE_METADATA_URL https://foura.ai/docs/mcp/server#auth عنوان URL المُرجع في WWW-Authenticate عند 401

تعمل الحاوية الرسمية كـ uid 1001 (غير root). يجب أن يكون ربط المضيف (bind mount) /data/payloads قابلا للكتابة بواسطة معرف المستخدم (uid) ذلك.

يمكن التوسع أفقيا خلف أي موازن أحمال (load balancer). يقدم العملاء مفتاحهم في كل request، لذلك لا توجد جلسة لاصقة (sticky session).

آخر تحديث: 6 أغسطس 2026