مشاركة عبر


دمج تطبيق App Service كخادم MCP ل GitHub Copilot Chat (Python)

في هذا البرنامج التعليمي، ستتعلم كيفية عرض وظائف تطبيق FastAPI من خلال بروتوكول سياق النموذج (MCP)، وإضافتها كأداة إلى GitHub Copilot، والتفاعل مع تطبيقك باستخدام لغة طبيعية في وضع وكيل دردشة Copilot.

لقطة شاشة توضح أن الاستجابة من أداة MCP تستدعي في نافذة GitHub Copilot Chat.

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

  • أي تطبيق يدعم تكامل MCP، مثل وضع عامل الدردشة GitHub Copilot في Visual Studio Code أو في GitHub Codespaces.
  • عامل مخصص يصل إلى الأدوات البعيدة باستخدام عميل MCP.

من خلال إضافة خادم MCP إلى تطبيق الويب الخاص بك، فإنك تمكن الوكيل من فهم إمكانات تطبيقك واستخدامها عندما يستجيب لمطالبات المستخدم. هذا يعني أن أي شيء يمكن أن يفعله تطبيقك ، يمكن للوكيل القيام به أيضا.

  • أضف خادم MCP إلى تطبيق الويب الخاص بك.
  • اختبر خادم MCP محليا في وضع عامل الدردشة GitHub Copilot.
  • انشر خادم MCP إلى Azure App Service واتصل به في GitHub Copilot Chat.

المتطلبات

يفترض هذا البرنامج التعليمي أنك تعمل مع النموذج المستخدم في نشر تطبيق ويب Python FastAPI باستخدام PostgreSQL في Azure.

كحد أدنى، افتح نموذج التطبيق في GitHub Codespaces ونشر التطبيق عن طريق تشغيل azd up.

فتح في GitHub Codespaces

إضافة خادم MCP إلى تطبيق الويب الخاص بك

  1. في مستكشف مساحة التعليمات البرمجية، افتح src/pyproject.toml، وأضفه mcp[cli] إلى قائمة التبعيات، كما هو موضح في المثال التالي:

    dependencies = [
        ...
        "mcp[cli]",
    ]
    
  2. في src/fastapi_app، قم بإنشاء ملف يسمى mcp_server.py والصق التعليمات البرمجية التالية لتهيئة خادم MCP في الملف:

    import asyncio
    import contextlib
    from contextlib import asynccontextmanager
    
    from mcp.server.fastmcp import FastMCP
    from sqlalchemy.sql import func
    from sqlmodel import Session, select
    
    from .models import Restaurant, Review, engine
    
    # Create a FastMCP server. Use stateless_http=True for simple mounting. Default path is .../mcp
    mcp = FastMCP("RestaurantReviewsMCP", stateless_http=True)
    
    # Lifespan context manager to start/stop the MCP session manager with the FastAPI app
    @asynccontextmanager
    async def mcp_lifespan(app):
        async with contextlib.AsyncExitStack() as stack:
            await stack.enter_async_context(mcp.session_manager.run())
            yield
    
    # MCP tool: List all restaurants with their average rating and review count
    @mcp.tool()
    async def list_restaurants_mcp() -> list[dict]:
        """List restaurants with their average rating and review count."""
    
        def sync():
            with Session(engine) as session:
                statement = (
                    select(
                        Restaurant,
                        func.avg(Review.rating).label("avg_rating"),
                        func.count(Review.id).label("review_count"),
                    )
                    .outerjoin(Review, Review.restaurant == Restaurant.id)
                    .group_by(Restaurant.id)
                )
                results = session.exec(statement).all()
                rows = []
                for restaurant, avg_rating, review_count in results:
                    r = restaurant.dict()
                    r["avg_rating"] = float(avg_rating) if avg_rating is not None else None
                    r["review_count"] = review_count
                    r["stars_percent"] = (
                        round((float(avg_rating) / 5.0) * 100) if review_count > 0 and avg_rating is not None else 0
                    )
                    rows.append(r)
                return rows
    
        return await asyncio.to_thread(sync)
    
    # MCP tool: Get a restaurant and all its reviews by restaurant_id
    @mcp.tool()
    async def get_details_mcp(restaurant_id: int) -> dict:
        """Return the restaurant and its related reviews as objects."""
    
        def sync():
            with Session(engine) as session:
                restaurant = session.exec(select(Restaurant).where(Restaurant.id == restaurant_id)).first()
                if restaurant is None:
                    return None
                reviews = session.exec(select(Review).where(Review.restaurant == restaurant_id)).all()
                return {"restaurant": restaurant.dict(), "reviews": [r.dict() for r in reviews]}
    
        return await asyncio.to_thread(sync)
    
    # MCP tool: Create a new review for a restaurant
    @mcp.tool()
    async def create_review_mcp(restaurant_id: int, user_name: str, rating: int, review_text: str) -> dict:
        """Create a new review for a restaurant and return the created review dict."""
    
        def sync():
            with Session(engine) as session:
                review = Review()
                review.restaurant = restaurant_id
                review.review_date = __import__("datetime").datetime.now()
                review.user_name = user_name
                review.rating = int(rating)
                review.review_text = review_text
                session.add(review)
                session.commit()
                session.refresh(review)
                return review.dict()
    
        return await asyncio.to_thread(sync)
    
    # MCP tool: Create a new restaurant
    @mcp.tool()
    async def create_restaurant_mcp(restaurant_name: str, street_address: str, description: str) -> dict:
        """Create a new restaurant and return the created restaurant dict."""
    
        def sync():
            with Session(engine) as session:
                restaurant = Restaurant()
                restaurant.name = restaurant_name
                restaurant.street_address = street_address
                restaurant.description = description
                session.add(restaurant)
                session.commit()
                session.refresh(restaurant)
                return restaurant.dict()
    
        return await asyncio.to_thread(sync)
    

    يقوم مهيئ FastMCP() بإنشاء خادم MCP باستخدام نمط الوضع عديم الحالة في MCP Python SDK. بشكل افتراضي، يتم تعيين نقطة نهاية HTTP القابلة للبث إلى المسار الفرعي /mcp .

    • @mcp.tool() يضيف الديكور أداة إلى خادم MCP مع تنفيذه.
    • يساعد وصف وظيفة الأداة وكيل الاتصال على فهم كيفية استخدام الأداة ومعلماتها.

    تقوم الأدوات بتكرار وظيفة مراجعات المطاعم الحالية في تطبيق الويب FastAPI المستند إلى النموذج. إذا كنت ترغب في ذلك ، يمكنك إضافة المزيد من الأدوات لوظيفة التحديث والحذف.

  3. في src/fastapi_app/app.py، أوجد السطر ( app = FastAPI() السطر 24) واستبدله بالرمز التالي:

    from .mcp_server import mcp, mcp_lifespan
    app = FastAPI(lifespan=mcp_lifespan)
    app.mount("/mcp", mcp.streamable_http_app())
    

    تقوم هذه التعليمات البرمجية بتحميل نقطة نهاية HTTP القابلة للبث لخادم MCP إلى تطبيق FastAPI الحالي في المسار /mcp. جنبا إلى جنب مع المسار الافتراضي لنقطة نهاية HTTP القابلة للدفق، يكون المسار الكامل هو /mcp/mcp.

اختبار خادم MCP محليا

  1. في محطة codespace، قم بتشغيل التطبيق باستخدام الأوامر التالية:

    python3 -m venv .venv
    source .venv/bin/activate
    pip install -r src/requirements.txt
    pip install -e src
    python3 src/fastapi_app/seed_data.py
    python3 -m uvicorn fastapi_app:app --reload --port=8000
    
  2. حدد فتح في المتصفح، ثم أضف بعض المطاعم والمراجعات.

    اترك uvicorn الجري. خادم MCP الخاص بك قيد التشغيل http://localhost:8000/mcp/mcp الآن.

  3. مرة أخرى في مساحة التعليمات البرمجية، افتح دردشة Copilot، ثم حدد وضع الوكيل في مربع المطالبة.

  4. حدد الزر "أدوات "، ثم حدد أيقونة إضافة خادم MCP في الزاوية العلوية اليمنى من النافذة المنبثقة.

    لقطة شاشة توضح كيفية إضافة خادم MCP في وضع عامل الدردشة GitHub Copilot.

  5. حدد HTTP (HTTP أو أحداث Server-Sent).

  6. في إدخال عنوان URL للخادم، اكتب http://localhost:8000/mcp/mcp.

  7. في إدخال معرف الخادم، اكتب restaurant_ratings أو أي اسم تريده.

  8. حدد إعدادات مساحة العمل.

  9. في نافذة دردشة مساعد الطيار الجديدة، اكتب شيئا مثل "أرني تقييمات المطعم".

  10. بشكل افتراضي، يعرض لك GitHub Copilot تأكيدا أمنيا عند استدعاء خادم MCP. حدد متابعة.

    لقطة شاشة توضح رسالة الأمان الافتراضية من استدعاء MCP في دردشة GitHub Copilot.

    يجب أن ترى الآن استجابة تشير إلى نجاح استدعاء أداة MCP.

    لقطة شاشة توضح أن الاستجابة من أداة MCP تستدعي في نافذة GitHub Copilot Chat.

نشر خادم MCP الخاص بك إلى App Service

  1. مرة أخرى في المحطة الطرفية لمساحة التعليمات البرمجية، انشر التغييرات عن طريق تنفيذ التغييرات (أسلوب GitHub Actions) أو قم بتشغيل azd up (أسلوب Azure Developer CLI).

  2. في إخراج AZD ، ابحث عن عنوان URL لتطبيقك. يبدو عنوان URL كما يلي في إخراج AZD:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <app-url>
     
  3. بمجرد azd up الانتهاء ، افتح .vscode/mcp.json. قم بتغيير عنوان URL إلى <app-url>/mcp/mcp.

  4. أعلى تكوين خادم MCP المعدل، حدد ابدأ.

    لقطة شاشة توضح كيفية بدء تشغيل خادم MCP يدويا من ملف mcp.json المحلي.

  5. ابدأ نافذة دردشة GitHub Copilot جديدة. يجب أن تكون قادرا على عرض تقييمات المطاعم ، بالإضافة إلى إنشاء مطاعم جديدة وتقييمات جديدة في وكيل Copilot.

أفضل الممارسات الأمنية

عندما يتم استدعاء خادم MCP الخاص بك بواسطة وكيل مدعوم بنماذج لغوية كبيرة (LLM)، كن على دراية بهجمات الحقن الفوري . ضع في اعتبارك أفضل ممارسات الأمان التالية:

  • المصادقة والتفويض: قم بتأمين خادم MCP الخاص بك باستخدام مصادقة Microsoft Entra لضمان وصول المستخدمين أو الوكلاء المصرح لهم فقط إلى أدواتك. انظر استدعاءات بروتوكول السياق الآمن إلى Azure App Service من Visual Studio Code with Microsoft Entra Authentication للحصول على دليل خطوة بخطوة.
  • التحقق من صحة الإدخال والتعقيم: تحقق دائما من صحة البيانات الواردة لمنع الإدخال غير الصالح أو الضار. بالنسبة لتطبيقات Python، استخدم مكتبات مثل Pydantic لفرض قواعد التحقق من صحة البيانات باستخدام نماذج إدخال مخصصة (مثل RestaurantCreate وReviewCreate). راجع وثائقهم للحصول على أفضل الممارسات وتفاصيل التنفيذ.
  • HTTPS: يعتمد النموذج على Azure App Service، الذي يفرض HTTPS بشكل افتراضي ويوفر شهادات TLS/SSL مجانية لتشفير البيانات أثناء النقل.
  • مبدأ الامتياز الأقل: اعرض فقط الأدوات والبيانات الضرورية المطلوبة لحالة الاستخدام الخاصة بك. تجنب تعريض العمليات الحساسة إلا إذا لزم الأمر.
  • تحديد المعدل والتقييد: استخدم إدارة واجهة برمجة التطبيقات أو البرامج الوسيطة المخصصة لمنع هجمات إساءة الاستخدام ورفض الخدمة.
  • التسجيل والمراقبة: الوصول إلى السجل واستخدام نقاط نهاية MCP للتدقيق واكتشاف الحالات الشاذة. مراقبة النشاط المشبوه.
  • تكوين CORS: تقييد الطلبات عبر الأصل بالمجالات الموثوق بها إذا تم الوصول إلى خادم MCP الخاص بك من المستعرضات. لمزيد من المعلومات، راجع تمكين CORS.
  • تحديثات منتظمة: حافظ على تحديث تبعياتك للتخفيف من الثغرات الأمنية المعروفة.

موارد إضافية

دمج الذكاء الاصطناعي في تطبيقات Azure App Service