AI Architecture

بناء MCP Gateway آمن للذكاء الاصطناعي في العقارات

تعلّم كيف نفّذنا خادم MCP (Model Context Protocol) من الدرجة الأولى و OAuth gateway لمنصة الذكاء الاصطناعي العقارية لدينا، مع تكامل Azure AD B2C للمصادقة على مستوى المؤسسات.

بقلم Ahmed Abdelhamid
MCP Gateway for Real Estate AI

في هذا المقال، سنستعرض كيف نفّذنا خادم MCP (Model Context Protocol) من الدرجة الأولى و OAuth gateway لمنصتنا العقارية المدعومة بالذكاء الاصطناعي. الهدف هو تمكين عملاء LLM من استدعاء أدوات النطاق بأمان (Kadaster، تصنيفات الطاقة، تحليل الموقع، تقييمات المستخدمين) بعقود واضحة وجلسات عديمة الحالة ومصادقة على مستوى المؤسسات، دون المساس بسرعة التطوير.

إليك ما نركز عليه: سنستعرض معمارية MCP العامة، ثم نتعمق في المصادقة وتكاملنا مع Azure AD B2C، وهو الجانب الأكثر تعقيدًا والأكثر أهمية حين تتعامل الأدوات مع بيانات خاصة بالمستخدم. إذا أردت التخطي إلى الأمام، انظر قسم تدفق المصادقة (Sequence) ونقاط نهاية OAuth Proxy وتعيينها على Azure AD B2C.

رحلة المستخدم

  1. يفتح المستخدم عميل MCP مدعومًا (مثل Claude.ai أو ChatGPT أو طرفية Claude Code مخصصة) ويتصل بخادم MCP الخاص بنا.
  2. يُوجَّه العميل عبر OAuth gateway الذي يعمل كوسيط لـ Azure AD B2C لتسجيل الدخول.
  3. عند النجاح، يُصدر MCP gateway رمز وصول موقَّعًا ويُدرج user_id في سياق الطلب.
  4. بعد المصادقة، يسرد العميل الأدوات المتاحة وسكيمات المدخلات الخاصة بها. الأدوات العامة تشمل:
    • Get_Addresses_for_Postcode
    • Analyze_Property_Location
    • Get_Property_Energy_Label
    • Get_Property_Data
    يمكن للمستخدم أيضًا طلب الأدوات المحمية التي تستلزم مصادقة:
    • Quick_Assess_Property
    • Get_Assessed_Properties
    • Get_Property_Assessments
  5. عند استدعاء الأداة من عميل MCP بتوجيه من LLM، تعمل الأداة من جانب الخادم، وتستعلم من تكامل Kadaster والخدمات الأخرى، وتُعيد مخرجات JSON منظمة.
  6. يعرض العميل النتائج في المحادثة، ويمكنه ربطها بأدوات أخرى عند الحاجة.

يُبقي هذا التصميم تجربة LLM بسيطة مع تطبيق قواعد الوصول إلى البيانات وإنتاج مخرجات متسقة وصديقة للأدوات.

معمارية الحل

نظرة عامة

MCP Architecture Diagram

نظرة عامة على معمارية MCP Gateway

المكونات التقنية الفعلية

  • تطبيق ASGI (Starlette + Uvicorn) مع نواة خادم MCP.
  • StreamableHTTPSessionManager في الوضع عديم الحالة لتقديم MCP عبر HTTP.
  • نقاط نهاية OAuth تُقدَّم من نفس التطبيق: /.well-known/oauth-authorization-server و/oauth/authorize و/oauth/token و/oauth/callback و/oauth/jwks، بالإضافة إلى .well-known/oauth-protected-resource لاكتشاف الموارد.
  • عقود الأدوات مُعرَّفة مركزيًا في ملف all_tools_schema.json ومسجَّلة ديناميكيًا عبر list_tools().
  • تُوزّع call_tool() حسب الاسم إلى تطبيقات مُحكمة النوع وتستدعي الأداة المقابلة.

المصادقة: OAuth Gateway يعمل كوسيط لـ Azure AD B2C

إذا سبق لك العمل مع Azure AD B2C، فأنت تعرف أن إدارة redirect URI يمكن أن تُبطئك. احتجنا إلى تأهيل ديناميكي للعملاء وعدم تغيير البوابة عند الاختبار مع عملاء MCP جدد. لهذا السبب طبّقنا نمط الـ gateway.

  • نعرض بيانات تعريف الموارد المحمية على /.well-known/oauth-protected-resource ليتمكن العملاء من اكتشاف النطاقات وخوادم التفويض.
  • ندعم نقطة نهاية DCR (Dynamic Client Registration) بسيطة تُعيد بيانات اعتماد العميل الثابتة لتبسيط التطوير.
  • في Azure AD B2C، نسجّل رابط callback واحدًا يُعيد التوجيه إلى خادم مصادقة MCP بعد نجاح المصادقة.
  • في نقطة نهاية الـ callback، نُشفّر redirect URI الأصلي للعميل (والسياق) في OAuth state.
  • عند الـ callback، نتبادل الكود مع B2C، ونستخرج هوية المستخدم، ثم نُصدر رمز الوصول الخاص بنا (JWT) مرتبطًا بـ audience لعنوان URL لمورد MCP.

يحافظ هذا على نقاط قوة Azure AD B2C (المصادقة والسياسات) مع منحنا المرونة لتأهيل عملاء MCP جدد فورًا.

لماذا Gateway: التطور والمبررات

قصة موجزة عن سبب وضعنا وسيطًا أمام Azure AD B2C.

المقاربة الأولية: تكامل مباشر مع Azure AD B2C

  • نقاط نهاية OAuth (authorize, token, callback, JWKS) تُشير مباشرةً إلى Azure AD B2C.
  • تُسجَّل العملاء في Azure AD B2C بـ redirect URIs ثابتة.
  • يعمل خادم MCP فقط كخادم موارد، يتحقق من الرموز الصادرة عن Azure عبر JWKS الخاص بـ Azure.

المزايا

  • أمان قوي وامتثال للمعايير من البداية.
  • تتولى Azure إدارة طبقة الهوية وتوسيعها.

العيوب

  • إدارة redirect URI لكل عميل/بيئة أبطأتنا.
  • التأهيل الديناميكي للعملاء والتدفقات المخصصة كانت محرجة أو استلزمت تغييرات في البوابة.

المشكلة: صرامة redirect URI

احتياجات العمل:

  • تأهيل عملاء وبيئات جديدة بسرعة، كثيرًا ما تكون بـ redirect URIs فريدة.
  • دعم سيناريوهات متعددة المستأجرين والنماذج الأولية السريعة دون إرهاق البوابة.

التحدي التقني:

  • يتحقق Azure AD B2C بصرامة من redirect URIs؛ أي شيء غير مسجّل مسبقًا يُرفض.

الحل: OAuth proxy/gateway

  • يعرض MCP gateway سطح OAuth للعملاء ويعمل كوسيط لـ Azure AD B2C باستخدام callback واحد مسجّل مسبقًا.
  • نُشفّر redirect URI الأصلي للعميل والسياق في OAuth state.
  • عند الـ callback، نتبادل الكود مع Azure، ونستخرج معلومات المستخدم، ثم نُصدر رموز الوصول الخاصة بنا لمورد MCP.
  • نستضيف نقطة نهاية JWKS (انتقل إلى المفاتيح غير المتماثلة للإنتاج) للتحقق من الرموز.

لماذا التغيير؟

  • فضّلنا التكامل المباشر مع Azure للبساطة، لكن متطلبات العمل وتعدد المستأجرين استلزمت المرونة.
  • نمط الـ gateway كان الطريقة العملية للحفاظ على Azure AD B2C للمصادقة مع منح MCP المرونة للتطور.

نقاط نهاية OAuth Proxy وتعيينها على Azure AD B2C

فكّر في هذه النقاط باعتبارها "الباب الأمامي" الذي يعرضه MCP gateway لأي عميل قادر على OAuth. تُمكّن معًا من ثلاث لحظات: الاكتشاف وتسجيل دخول المستخدم وإصدار الرمز (بالإضافة إلى اكتشاف المفاتيح للتحقق). فيما يلي نصف كل نقطة نهاية بلغة بسيطة، ثم نُظهر كيف تتوافق مع Azure AD B2C كمزود هوية.

1) GET /.well-known/oauth-protected-resource

  • ما هي: وثيقة بيانات تعريف الموارد (RFC 9728) تخبر العملاء بالـ "resource" الذي يحاولون الوصول إليه، وأي خوادم تفويض يمكنها إصدار رموز له، وما هي النطاقات الموجودة.
  • لماذا تهم: تتيح لعميل MCP اكتشاف آلية الأمان دون ترميز النقاط الثابتة. يمكن للعميل معرفة "من يمكنه منحي رمزًا لهذا الخادم وما النطاقات المتاحة؟"
  • الحقول النموذجية: معرّف المورد (URL)، قائمة خوادم التفويض، رابط مستندات اختياري والنطاقات.
  • في gateway الخاص بنا: المورد هو عنوان URL الأساسي لخادم MCP؛ قائمة خوادم التفويض تحتوي على issuer الـ gateway العام. تعكس النطاقات قدرات الأدوات الواسعة.

2) GET /.well-known/oauth-authorization-server

  • ما هي: اكتشاف OAuth/OIDC القياسي (فهرس قابل للقراءة آليًا لنقاط نهاية المصادقة والميزات).
  • لماذا تهم: تتعلم العملاء برمجيًا أين يرسلون المتصفح للتفويض، وأين يُرسلون POST لتبادل الكود، وطرق code challenge (PKCE) المدعومة، وأين تُجلب مفاتيح التوقيع (JWKS).
  • في gateway الخاص بنا: الـ issuer هو نطاقنا العام؛ نقاط نهاية التفويض والرمز هي /oauth/authorize و/oauth/token الخاصة بالـ gateway؛ JWKS URI يُشير إلى /oauth/jwks الخاص بنا.

تدفق المصادقة (Sequence)

MCP OAuth Sequence Diagram

تسلسل مصادقة MCP OAuth

فيما يلي التسلسل الدقيق الذي يتبعه النظام عندما يحتاج عميل MCP للوصول إلى الأدوات المحمية:

  1. يكتشف العميل نقاط نهاية OAuth
    • يقرأ عميل MCP /.well-known/oauth-protected-resource على MCP gateway لاكتشاف النطاقات المدعومة وخادم التفويض.
    • يقرأ أيضًا /.well-known/oauth-authorization-server للتعرف على authorization_endpoint ونقطة نهاية الرمز وjwks_uri.
  2. طلب التفويض (وسيط لـ Azure AD B2C)
    • يستدعي العميل /oauth/authorize في MCP gateway مع: client_id وredirect_uri (الخاص بالعميل) وstate وcode_challenge الاختياري وscope.
    • يُشفّر الـ gateway حالة JSON تحتوي على state وredirect_uri وclient_id وscope وcode_challenge.
    • يُعيد الـ gateway توجيه المتصفح إلى نقطة نهاية authorize في Azure AD B2C، باستخدام redirect_uri واحد مسجَّل مسبقًا يُشير إلى MCP gateway.
  3. يُصادق المستخدم مع Azure AD B2C
    • يُكمل المستخدم تسجيل الدخول والسياسات على Azure AD B2C.
    • يستدعي Azure AD B2C MCP gateway على /oauth/callback?code=...&state=....
    • يفكّ الـ gateway تشفير الحالة، ويتبادل code مع نقطة نهاية رمز Azure للحصول على الرموز (بما فيها id_token).
    • يستخرج الـ gateway sub (subject) للمستخدم من id_token، يخزّن كود تفويض وسيط للعميل الأصلي، ويُعيد توجيه المتصفح إلى redirect_uri الأصلي للعميل مع ?code=...&state=....
  4. يتبادل العميل الكود مع MCP gateway
    • يستدعي عميل MCP /oauth/token في الـ gateway مع grant_type=authorization_code والكود المُستلَم وclient_id وcode_verifier الاختياري.
    • يتحقق الـ gateway من الكود (وPKCE إن وُجد)، يُعلّمه مستخدَمًا، ويُصدر رمز وصول MCP عبر create_access_token(). يتضمن الرمز:
      • aud = MCP_SERVER_URL (مرتبط بالـ audience)
      • scp = مصفوفة النطاقات
      • sub = subject المستخدم (إن وُجد) أو معرّف العميل (client credentials)
  5. استدعاء أدوات MCP المحمية
    • يرسل العميل الطلبات مع Authorization: Bearer <access_token> إلى جذر خادم MCP حيث تُركَّب نقاط نهاية MCP.
    • تتحقق برمجية التفويض الوسيطة من الرمز (الـ issuer والـ audience)، وتُدرج user_id في نطاق ASGI، وتُعيّن current_user_id في contextvars.ContextVar لوظائف الأدوات التالية.
    • تقرأ وظائف الأدوات مثل Get_Assessed_Properties وGet_Property_Assessments معرّف المستخدم الحالي عبر get_current_user_id() وتُطبّق وصول البيانات لكل مستخدم.

تفاصيل Azure AD B2C التي يجب تهيئتها:

  • تسجيل التطبيق مع AZURE_B2C_CLIENT_ID والسر؛ اضبط AZURE_B2C_REDIRECT_URI على عنوان URL لـ callback الوسيط.
  • اسم تدفق/سياسة المستخدم (AZURE_B2C_POLICY) المستخدم في نقاط نهاية authorize/token.
  • تأكد من أن نطاق الوسيط (OAUTH_DOMAIN) قابل للوصول ومتسق (يُستخدم كـ iss في رموز MCP ومدرج في البيانات التعريفية).

الخلاصة

جعل MCP الأمر بسيطًا لعرض قدراتنا في النطاق العقاري بطريقة يستطيع LLMs فهمها وتنسيقها. مع OAuth gateway أمام Azure AD B2C، نستوفي متطلبات الأمان على مستوى المؤسسات دون إعاقة سرعة المطوّرين. النتيجة هي مسار سريع وآمن وقابل للتوسع نحو سير عمل وكيل جاهز للإنتاج.