Integrera en App Service-app som en MCP-server för GitHub Copilot Chat (Python)

I den här självstudien får du lära dig hur du exponerar en FastAPI-apps funktioner via Model Context Protocol (MCP), lägger till den som ett verktyg i GitHub Copilot och interagerar med din app med naturligt språk i Copilot Chat-agentläge.

Skärmbild som visar att svaret från MCP-verktyget anropar i GitHub Copilot Chat-fönstret.

Om ditt webbprogram redan har användbara funktioner, till exempel shopping, hotellbokning eller datahantering, är det enkelt att göra dessa funktioner tillgängliga för:

Genom att lägga till en MCP-server i webbappen gör du det möjligt för en agent att förstå och använda appens funktioner när den svarar på användarfrågor. Det innebär att allt din app kan göra kan agenten också göra.

  • Lägg till en MCP-server i webbappen.
  • Testa MCP-servern lokalt i GitHub Copilot Chat-agentläge.
  • Distribuera MCP-servern till Azure App Service och anslut till den i GitHub Copilot Chat.

Förutsättningar

Den här självstudien förutsätter att du arbetar med exemplet som används i Distribuera en Python FastAPI-webbapp med PostgreSQL i Azure.

Öppna minst exempelprogrammet i GitHub Codespaces och distribuera appen genom att köra azd up.

Öppna i GitHub Codespaces

Lägga till MCP-server i webbappen

  1. I codespace Explorer öppnar du src/pyproject.toml, lägger till mcp[cli] i listan över beroenden, som du ser i följande exempel:

    dependencies = [
        ...
        "mcp[cli]",
    ]
    
  2. I src/fastapi_app skapar du en fil med namnet mcp_server.py och klistrar in följande MCP-serverinitieringskod i filen:

    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)
    

    Initiatorn FastMCP() skapar en MCP-server med mönstret tillståndslöst läge i MCP Python SDK. Som standard är dess strömmande HTTP-slutpunkt inställd på /mcp undersökvägen.

    • Dekoratören @mcp.tool() lägger till ett verktyg till MCP-servern med dess implementering.
    • Verktygsfunktionens beskrivning hjälper anropande agenten att förstå hur verktyget och dess parametrar används.

    Verktygen duplicerar befintliga funktioner för restauranggranskning i det formulärbaserade FastAPI-webbprogrammet. Om du vill kan du lägga till fler verktyg för uppdaterings- och borttagningsfunktioner.

  3. Leta upp raden för (rad 24) i app = FastAPI() och ersätt den med följande kod:

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

    Den här koden monterar MCP-serverns strömmande HTTP-slutpunkt till den befintliga FastAPI-appen på sökvägen /mcp. Tillsammans med standardsökvägen för den strömmande HTTP-slutpunkten är /mcp/mcpden fullständiga sökvägen .

Testa MCP-servern lokalt

  1. Kör programmet med följande kommandon i codespace-terminalen:

    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älj Öppna i webbläsare och lägg sedan till några restauranger och recensioner.

    Lämna uvicorn igång. McP-servern körs nu http://localhost:8000/mcp/mcp .

  3. Gå tillbaka till kodområdet, öppna Copilot Chat och välj sedan Agentläge i promptrutan.

  4. Välj knappen Verktyg och välj sedan ikonen Lägg till MCP Server i popup-fönstrets övre högra hörn.

    Skärmbild som visar hur du lägger till en MCP-server i GitHub Copilot Chat-agentläge.

  5. Välj HTTP (HTTP eller Server-Sent-händelser).

  6. I Ange server-URL skriver du http://localhost:8000/mcp/mcp.

  7. I Ange server-ID skriver du restaurant_ratings eller valfritt namn som du vill.

  8. Välj Inställningar för arbetsyta.

  9. I ett nytt Copilot Chat-fönster skriver du något i stil med "Visa mig restaurangbetygen".

  10. Som standard visar GitHub Copilot en säkerhetsbekräftelse när du anropar en MCP-server. Välj Fortsätt.

    Skärmbild som visar standardsäkerhetsmeddelandet från ett MCP-anrop i GitHub Copilot Chat.

    Nu bör du se ett svar som anger att MCP-verktygsanropet lyckas.

    Skärmbild som visar att svaret från MCP-verktyget anropar i GitHub Copilot Chat-fönstret.

Distribuera MCP-servern till App Service

  1. Tillbaka i kodområdesterminalen distribuerar du dina ändringar genom att genomföra dina ändringar (GitHub Actions-metod) eller köra azd up (Azure Developer CLI-metod).

  2. Leta reda på appens URL i AZD-utdata. URL:en ser ut så här i AZD-utdata:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <app-url>
     
  3. När du är azd up klar öppnar du .vscode/mcp.json. Ändra URL:en till <app-url>/mcp/mcp.

  4. Välj Starta ovanför den ändrade MCP-serverkonfigurationen.

    Skärmbild som visar hur du startar en MCP-server manuellt från den lokala mcp.json filen.

  5. Starta ett nytt GitHub Copilot Chat-fönster. Du bör kunna visa restaurangklassificeringar, samt skapa nya restauranger och nya betyg i Copilot-agenten.

Metodtips för säkerhet

När MCP-servern anropas av en agent som drivs av stora språkmodeller (LLM) bör du vara medveten om snabba inmatningsattacker . Överväg följande metodtips för säkerhet:

  • Autentisering och auktorisering: Skydda MCP-servern med Microsoft Entra-autentisering för att säkerställa att endast behöriga användare eller agenter kan komma åt dina verktyg. En stegvis guide finns i Secure Model Context Protocol-anrop till Azure App Service från Visual Studio Code med Microsoft Entra-autentisering .
  • Validering och sanering av indata: Verifiera alltid inkommande data för att förhindra ogiltiga eller skadliga indata. För Python-appar använder du bibliotek som Pydantic för att framtvinga dataverifieringsregler med dedikerade indatamodeller (till exempel RestaurangSkapa och GranskaSkapa). Mer information om metodtips och implementering finns i dokumentationen.
  • HTTPS: Exemplet förlitar sig på Azure App Service, som framtvingar HTTPS som standard och tillhandahåller kostnadsfria TLS/SSL-certifikat för att kryptera data under överföring.
  • Lägsta behörighetsprincip: Exponera endast nödvändiga verktyg och data som krävs för ditt användningsfall. Undvik att exponera känsliga åtgärder om det inte behövs.
  • Hastighetsbegränsning och begränsning: Använd API Management eller anpassade mellanprogram för att förhindra missbruk och överbelastningsattacker.
  • Loggning och övervakning: Loggåtkomst och användning av MCP-slutpunkter för granskning och avvikelseidentifiering. Övervaka misstänkt aktivitet.
  • CORS-konfiguration: Begränsa begäranden mellan ursprung till betrodda domäner om MCP-servern nås från webbläsare. Mer information finns i Aktivera CORS.
  • Regelbundna uppdateringar: Håll dina beroenden uppdaterade för att minimera kända sårbarheter.

Fler resurser

Integrera AI i dina Azure App Service-program