Megosztás a következőn keresztül:


App Service-alkalmazás integrálása MCP-kiszolgálóként a GitHub Copilot Chathez (Python)

Ebben az oktatóanyagban megtanulhatja, hogyan teheti elérhetővé a FastAPI-alkalmazások funkcióit a Model Context Protocol (MCP) használatával, hogyan adhat hozzá eszközt a GitHub Copilothoz, és hogyan használhatja az alkalmazást természetes nyelven a Copilot Csevegőügynök módban.

Képernyőkép arról, hogy az MCP-eszköz hívásának válasza a GitHub Copilot Csevegőablakban.

Ha a webalkalmazás már rendelkezik olyan hasznos funkciókkal, mint a vásárlás, a szállodai foglalás vagy az adatkezelés, könnyen elérhetővé teheti ezeket a képességeket a következő célokra:

Ha mcp-kiszolgálót ad hozzá a webalkalmazáshoz, lehetővé teszi az ügynök számára az alkalmazás képességeinek megértését és használatát, amikor az válaszol a felhasználói kérésekre. Ez azt jelenti, hogy az alkalmazás bármit megtehet, az ügynök is.

  • Adjon hozzá egy MCP-kiszolgálót a webalkalmazáshoz.
  • Tesztelje az MCP-kiszolgálót helyileg a GitHub Copilot Csevegőügynök módban.
  • Telepítse az MCP-kiszolgálót az Azure App Service-ben, és csatlakozzon hozzá a GitHub Copilot Chatben.

Előfeltételek

Ez az oktatóanyag feltételezi, hogy a Python FastAPI-webalkalmazás üzembe helyezéséhez használt mintával dolgozik a PostgreSQL-ben az Azure-ban.

Legalább nyissa meg a mintaalkalmazást a GitHub Codespacesben, és futtassa azd upaz alkalmazást.

Megnyitás a GitHub Codespacesben

MCP-kiszolgáló hozzáadása a webalkalmazáshoz

  1. A kódtérkezelőben nyissa meg az src/pyproject.toml fájlt, adja hozzá mcp[cli] a függőségek listájához az alábbi példában látható módon:

    dependencies = [
        ...
        "mcp[cli]",
    ]
    
  2. Az src/fastapi_app hozzon létre egy mcp_server.py nevű fájlt, és illessze be a következő MCP-kiszolgáló inicializálási kódját a fájlba:

    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)
    

    A FastMCP() inicializáló egy MCP-kiszolgálót hoz létre az MCP Python SDK állapot nélküli módmintájának használatával. Alapértelmezés szerint a streamelhető HTTP-végpontja a /mcp mellékútra van állítva.

    • A @mcp.tool() dekoratőr egy eszközt ad hozzá az MCP-kiszolgálóhoz annak implementálásával.
    • Az eszközfüggvény leírása segít a hívóügynöknek megérteni az eszköz és paramétereinek használatát.

    Az eszközök duplikálják a meglévő étterem felülvizsgálati funkcióit az űrlapalapú FastAPI-webalkalmazásban. Ha szeretné, további eszközöket is hozzáadhat a frissítési és törlési funkciókhoz.

  3. Az src/fastapi_app/app.py területen keresse meg a (24. sor) sorát app = FastAPI() , és cserélje le a következő kódra:

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

    Ez a kód csatlakoztatja az MCP-kiszolgáló streamelhető HTTP-végpontját a meglévő FastAPI-alkalmazáshoz az elérési úton /mcp. A streamelhető HTTP-végpont alapértelmezett elérési útjával együtt a teljes elérési út is ./mcp/mcp

Az MCP-kiszolgáló helyi tesztelése

  1. A kódtér termináljában futtassa az alkalmazást a következő parancsokkal:

    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. Válassza a Megnyitás böngészőben lehetőséget, majd adjon hozzá néhány éttermet és véleményt.

    Hagyja futni uvicorn . Az MCP-kiszolgáló jelenleg http://localhost:8000/mcp/mcp fut.

  3. A kódtérben nyissa meg a Copilot-csevegést, majd válassza az Ügynök mód lehetőséget a parancssorban.

  4. Válassza az Eszközök gombot, majd válassza az MCP-kiszolgáló hozzáadása ikont az előugró ablak jobb felső sarkában.

    Képernyőkép mcp-kiszolgáló hozzáadásáról a GitHub Copilot Csevegőügynök módban.

  5. Válassza a HTTP (HTTP vagy Server-Sent események) lehetőséget.

  6. Írja be az Enter Server URL-címéthttp://localhost:8000/mcp/mcp.

  7. Az Enter Server ID mezőbe írja be a restaurant_ratings vagy a kívánt nevet.

  8. Válassza a Munkaterület beállításai lehetőséget.

  9. Egy új Copilot-csevegőablakban írja be a következőt: "Show me the restaurant ratings".

  10. Alapértelmezés szerint a GitHub Copilot biztonsági megerősítést jelenít meg egy MCP-kiszolgáló meghívásakor. Válassza a Folytatáslehetőséget.

    Képernyőkép egy MCP-hívás alapértelmezett biztonsági üzenetéről a GitHub Copilot Chatben.

    Ekkor megjelenik egy válasz, amely azt jelzi, hogy az MCP-eszköz hívása sikeres.

    Képernyőkép arról, hogy az MCP-eszköz hívásának válasza a GitHub Copilot Csevegőablakban.

Az MCP-kiszolgáló üzembe helyezése az App Service-ben

  1. A kódtér termináljába visszatérve telepítse a módosításokat a módosítások véglegesítésével (GitHub Actions metódus) vagy futtassa azd up (Azure Developer CLI-metódus).

  2. Az AZD-kimenetben keresse meg az alkalmazás URL-címét. Az URL-cím így néz ki az AZD-kimenetben:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <app-url>
     
  3. A befejezés után azd up nyissa meg a .vscode/mcp.json. Módosítsa az URL-címet a következőre <app-url>/mcp/mcp: .

  4. A módosított MCP-kiszolgáló konfigurációja felett válassza a Start lehetőséget.

    Képernyőkép az MCP-kiszolgáló helyi mcp.json fájlból történő manuális indításáról.

  5. Hozzon létre egy új GitHub Copilot-csevegőablakot. Meg kell tudnia tekinteni az éttermi minősítéseket, valamint új éttermeket és új minősítéseket kell létrehoznia a Copilot ügynökben.

Ajánlott biztonsági eljárások

Ha az MCP-kiszolgálót nagy nyelvi modellekkel (LLM) rendelkező ügynök hívja meg, vegye figyelembe a gyors injektálási támadásokat. Vegye figyelembe az alábbi ajánlott biztonsági eljárásokat:

  • Hitelesítés és engedélyezés: Az MCP-kiszolgáló védelme Microsoft Entra-hitelesítéssel annak biztosítása érdekében, hogy csak a jogosult felhasználók vagy ügynökök férhessenek hozzá az eszközeihez. Részletes útmutatót a Visual Studio Code-ból az Azure App Service-be irányuló Biztonságos modell környezeti protokoll hívásai a Microsoft Entra-hitelesítéssel című témakörben talál.
  • Bemenet-ellenőrzés és -tisztítás: Mindig ellenőrizze a bejövő adatokat az érvénytelen vagy rosszindulatú bemenetek elkerülése érdekében. Python-alkalmazások esetén a Pydantichez hasonló kódtárak használatával kényszerítse ki az adatérvényesítési szabályokat dedikált bemeneti modellekkel (például RestaurantCreate és ReviewCreate). Az ajánlott eljárásokról és a megvalósítás részleteiről a dokumentációban olvashat.
  • HTTPS: A minta az Azure App Service-ra támaszkodik, amely alapértelmezés szerint kényszeríti a HTTPS-t, és ingyenes TLS-/SSL-tanúsítványokat biztosít az átvitel közbeni adatok titkosításához.
  • Minimális jogosultság elve: Csak a használati esethez szükséges eszközöket és adatokat tegye elérhetővé. Ha szükséges, kerülje a bizalmas műveletek felfedését.
  • Sebességkorlátozás és szabályozás: Az API Management vagy az egyéni köztes szoftver használata a visszaélések és a szolgáltatásmegtagadásos támadások megelőzésére.
  • Naplózás és figyelés: Az MCP-végpontok naplóhozzáférése és használata naplózáshoz és anomáliadetektáláshoz. Gyanús tevékenységek figyelése.
  • CORS-konfiguráció: Ha az MCP-kiszolgáló böngészőkből érhető el, korlátozza a forrásközi kérelmeket megbízható tartományokra. További információ: CORS engedélyezése.
  • Rendszeres frissítések: A függőségek naprakészen tartása az ismert biztonsági rések csökkentése érdekében.

További erőforrások

AI integrálása az Azure App Service-alkalmazásokba