Aracılığıyla paylaş


Öğretici: Azure Container Apps'e Python MCP sunucusu dağıtma

Bu öğreticide, FastAPI ve MCP Python SDK'sını kullanarak görev yönetimi araçlarını kullanıma sunan bir Model Bağlam Protokolü (MCP) sunucusu oluşturacaksınız. Sunucuyu Azure Container Apps'e dağıtır ve VS Code'da GitHub Copilot Sohbeti'nden bu sunucuya bağlanırsınız.

Bu eğitimde, siz:

  • MCP araçlarını kullanıma sunan bir FastAPI uygulaması oluşturma
  • MCP sunucusunu GitHub Copilot ile yerel olarak test etme
  • Uygulamayı kapsayıcıya alma ve Azure Container Apps'e dağıtma
  • GitHub Copilot'ı dağıtılan MCP sunucusuna bağlama

Önkoşullar

Uygulama iskelesini oluşturma

Bu bölümde FastAPI ve MCP Python SDK'sı ile yeni bir Python projesi oluşturacaksınız.

  1. Proje dizinini oluşturun ve bir sanal ortam ayarlayın:

    mkdir tasks-mcp-server && cd tasks-mcp-server
    python -m venv .venv
    source .venv/bin/activate
    
  2. Oluştur requirements.txt:

    fastapi>=0.115.0
    uvicorn>=0.30.0
    mcp[cli]>=1.2.0
    
  3. Bağımlılıkları yükleyin:

    pip install -r requirements.txt
    
  4. Bellek içi veri deposu için oluşturun task_store.py :

    from dataclasses import dataclass, field
    from datetime import datetime, timezone
    
    
    @dataclass
    class TaskItem:
        id: int
        title: str
        description: str
        is_complete: bool = False
        created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    
        def to_dict(self) -> dict:
            return {
                "id": self.id,
                "title": self.title,
                "description": self.description,
                "is_complete": self.is_complete,
                "created_at": self.created_at.isoformat(),
            }
    
    
    class TaskStore:
        def __init__(self):
            self._tasks: list[TaskItem] = [
                TaskItem(1, "Buy groceries", "Milk, eggs, bread"),
                TaskItem(2, "Write docs", "Draft the MCP tutorial", True),
            ]
            self._next_id = 3
    
        def get_all(self) -> list[dict]:
            return [t.to_dict() for t in self._tasks]
    
        def get_by_id(self, task_id: int) -> dict | None:
            task = next((t for t in self._tasks if t.id == task_id), None)
            return task.to_dict() if task else None
    
        def create(self, title: str, description: str) -> dict:
            task = TaskItem(self._next_id, title, description)
            self._next_id += 1
            self._tasks.append(task)
            return task.to_dict()
    
        def toggle_complete(self, task_id: int) -> dict | None:
            task = next((t for t in self._tasks if t.id == task_id), None)
            if task is None:
                return None
            task.is_complete = not task.is_complete
            return task.to_dict()
    
        def delete(self, task_id: int) -> bool:
            task = next((t for t in self._tasks if t.id == task_id), None)
            if task is None:
                return False
            self._tasks.remove(task)
            return True
    
    
    # For demonstration only — not thread-safe.
    store = TaskStore()
    

    TaskItem dataclass, to_dict() yöntemiyle veri modelini seri hale getirir. sınıfı, TaskStore örnek verilerle önceden doldurulmuş bir bellek içi listeyi yönetir ve CRUD yöntemleri sağlar. Modül düzeyindeki store tekil nesne, basitlik sağlamak için uygulama genelinde paylaşılır.

MCP araçlarını tanımlama

Bu bölümde, yapay zeka modelinin FastAPI uygulamanıza MCP sunucusunu çağırabileceği ve bağlayabileceği MCP araçlarını tanımlarsınız.

  1. Oluştur mcp_server.py:

    from mcp.server.fastmcp import FastMCP
    from task_store import store
    
    mcp = FastMCP("TasksMCP", stateless_http=True)
    
    
    @mcp.tool()
    async def list_tasks() -> list[dict]:
        """List all tasks with their ID, title, description, and completion status."""
        return store.get_all()
    
    
    @mcp.tool()
    async def get_task(task_id: int) -> dict | None:
        """Get a single task by its numeric ID.
    
        Args:
            task_id: The numeric ID of the task to retrieve.
        """
        return store.get_by_id(task_id)
    
    
    @mcp.tool()
    async def create_task(title: str, description: str) -> dict:
        """Create a new task with the given title and description. Returns the created task.
    
        Args:
            title: A short title for the task.
            description: A detailed description of what the task involves.
        """
        return store.create(title, description)
    
    
    @mcp.tool()
    async def toggle_task_complete(task_id: int) -> str:
        """Toggle a task's completion status between complete and incomplete.
    
        Args:
            task_id: The numeric ID of the task to toggle.
        """
        task = store.toggle_complete(task_id)
        if task:
            status = "complete" if task["is_complete"] else "incomplete"
            return f"Task {task['id']} is now {status}."
        return f"Task with ID {task_id} not found."
    
    
    @mcp.tool()
    async def delete_task(task_id: int) -> str:
        """Delete a task by its numeric ID.
    
        Args:
            task_id: The numeric ID of the task to delete.
        """
        if store.delete(task_id):
            return f"Task {task_id} deleted."
        return f"Task with ID {task_id} not found."
    

    Önemli noktalar:

    • FastMCP("TasksMCP", stateless_http=True) Python SDK'sında durum bilgisi olmayan HTTP desenini kullanarak bir MCP sunucusu oluşturur. Akışlanabilir HTTP uç noktası varsayılan olarak /mcp alt yoluna yönlendirilir.
    • Her @mcp.tool() işlev çağrılabilen bir araç haline gelir. İşlev metni ve parametre açıklamaları, yapay zeka modelinin her aracı nasıl kullanacağını anlamasına yardımcı olur.
  2. oluşturun app.py. Bu dosya, MCP sunucusunu bağlayan FastAPI uygulamasını tanımlar:

    from contextlib import AsyncExitStack, asynccontextmanager
    
    from fastapi import FastAPI
    from fastapi.responses import JSONResponse
    
    from mcp_server import mcp
    
    
    @asynccontextmanager
    async def lifespan(app: FastAPI):
        async with AsyncExitStack() as stack:
            await stack.enter_async_context(mcp.session_manager.run())
            yield
    
    
    app = FastAPI(lifespan=lifespan)
    app.mount("/", mcp.streamable_http_app())
    
    
    @app.get("/health")
    async def health():
        return JSONResponse({"status": "healthy"})
    

    MCP sunucu uygulaması köke (/) bağlanır. SDK'nın akışla aktarılabilir HTTP uç noktası varsayılan olarak /mcpkullanılır, bu nedenle tam uç nokta yolu şeklindedir /mcp.

    Container Apps sistem durumu yoklamaları için ayrı /health bir uç nokta kullanılır. MCP uç noktaları JSON-RPC POST istekleri bekler ve sistem durumu denetimleri olarak uygun değildir.

MCP sunucusunu yerel olarak test edin

Azure'a dağıtmadan önce MCP sunucusunun yerel olarak çalıştırıp GitHub Copilot'tan bağlanarak çalıştığını doğrulayın.

  1. Uygulamayı başlatın:

    uvicorn app:app --reload --port 8080
    
  2. VS Code'ı açın, ardından Copilot Sohbet'i açın ve Aracı modu'nu seçin.

  3. Araçlar düğmesini ve ardından Daha Fazla Araç Ekle... öğesini seçin.>MCP Sunucusu ekleyin.

  4. HTTP (HTTP veya Server-Sent Olayları) öğesini seçin.

  5. Sunucu URL'sini girin: http://localhost:8080/mcp

  6. Bir sunucu kimliği girin: tasks-mcp

  7. Çalışma Alanı Ayarları'nı seçin.

  8. Yeni bir Copilot Sohbet isteminde şunu yazın: "Bana tüm görevleri göster"

  9. Copilot MCP aracı onayı isterken Devam'ı seçin.

Bellek içi deponuzdan döndürülen görev listesini görmeniz gerekir.

Tavsiye

"PR'yi gözden geçirmek için bir görev oluştur", "Görev 1'i tamamlanmış olarak işaretle" veya "Görev 2'yi sil" gibi diğer istemleri deneyin.

Uygulamayı kapsayıcılı hale getirme

Uygulamayı Docker kapsayıcısı olarak paketleyerek Azure'a dağıtmadan önce yerel olarak test edebilirsiniz.

  1. DockerfileOluştur

    FROM python:3.12-slim
    
    WORKDIR /app
    
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY . .
    
    EXPOSE 8080
    CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
    

    Dockerfile, hafif bir Python 3.12 temel görüntüsü kullanır, requirements.txt öğesinden bağımlılıkları yükler ve ardından uygulama kodunu kopyalar. Uvicorn, 8080 numaralı bağlantı noktasında FastAPI uygulamasına hizmet verir.

  2. Kapsayıcının yerel olarak derlendiğini ve çalıştığını doğrulayın:

    docker build -t tasks-mcp-server .
    docker run -p 8080:8080 tasks-mcp-server
    

    Sağlık uç noktasının yanıt verdiğini onaylayın: curl http://localhost:8080/health

Azure Container Apps'a dağıtım

Uygulamayı kapsayıcıya aldıktan sonra Azure CLI kullanarak Azure Container Apps'e dağıtın. komutu az containerapp up kapsayıcı görüntüsünü bulutta oluşturur, bu nedenle bu adım için makinenizde Docker'a ihtiyacınız yoktur.

  1. Ortam değişkenlerini ayarlama:

    RESOURCE_GROUP="mcp-tutorial-rg"
    LOCATION="eastus"
    ENVIRONMENT_NAME="mcp-env"
    APP_NAME="tasks-mcp-server-py"
    
  2. Kaynak grubu ve Container Apps ortamı oluşturma:

    az group create --name $RESOURCE_GROUP --location $LOCATION
    
    az containerapp env create \
        --name $ENVIRONMENT_NAME \
        --resource-group $RESOURCE_GROUP \
        --location $LOCATION
    
  3. Kapsayıcı uygulamasını dağıtma:

    az containerapp up \
        --name $APP_NAME \
        --resource-group $RESOURCE_GROUP \
        --environment $ENVIRONMENT_NAME \
        --source . \
        --ingress external \
        --target-port 8080
    
  4. CORS'yi yapılandırma:

    az containerapp ingress cors enable \
        --name $APP_NAME \
        --resource-group $RESOURCE_GROUP \
        --allowed-origins "*" \
        --allowed-methods "GET,POST,DELETE,OPTIONS" \
        --allowed-headers "*"
    

    Uyarı

    Üretim için joker karakter çıkış noktalarını belirli güvenilir kaynaklarla değiştirin. Bkz . Container Apps'te MCP sunucularının güvenliğini sağlama.

  5. Dağıtımı doğrulayın:

    APP_URL=$(az containerapp show \
        --name $APP_NAME \
        --resource-group $RESOURCE_GROUP \
        --query "properties.configuration.ingress.fqdn" -o tsv)
    
    curl https://$APP_URL/health
    

GitHub Copilot'ı dağıtılan sunucuya bağlama

MCP sunucusu Azure'da çalıştığına göre VS Code'u GitHub Copilot'ı dağıtılan uç noktaya bağlamak için yapılandırın.

  1. oluşturun veya güncelleştirin .vscode/mcp.json:

    {
        "servers": {
            "tasks-mcp-server": {
                "type": "http",
                "url": "https://<your-app-fqdn>/mcp"
            }
        }
    }
    

    <your-app-fqdn> değerini dağıtım çıktısından FQDN ile değiştirin.

  2. VS Code'da Aracı modunda Copilot Sohbet'i açın.

  3. Doğrula tasks-mcp-server , Araçlar listesinde görünür. Gerekirse Başlat'ı seçin.

  4. "Hazırlama ortamını dağıtmak için görev oluşturma" gibi bir istemle test edin.

Etkileşimli kullanım için ölçeklendirmeyi yapılandırma

Azure Container Apps, varsayılan olarak sıfır kopyaya ölçeklendirilebilir. Copilot gibi etkileşimli istemcilere hizmet veren MCP sunucuları için soğuk başlatmalar fark edilebilir gecikmelere neden olur. En az bir örneğin çalışmasını sağlamak için en düşük çoğaltma sayısını ayarlayın:

az containerapp update \
    --name $APP_NAME \
    --resource-group $RESOURCE_GROUP \
    --min-replicas 1

Güvenlik konuları

Bu öğreticide basitlik için kimliği doğrulanmamış bir MCP sunucusu kullanılır. Üretimde bir MCP sunucusu çalıştırmadan önce aşağıdaki önerileri gözden geçirin. Büyük dil modelleri (LLM) tarafından desteklenen bir aracı MCP sunucunuzu aradığında, istem ekleme saldırılarına dikkat edin.

  • Kimlik doğrulaması ve yetkilendirme: Microsoft Entra Id ile MCP sunucunuzun güvenliğini sağlayın. Bkz . Container Apps'te MCP sunucularının güvenliğini sağlama.
  • Giriş doğrulama: Araç parametrelerini her zaman doğrulayın. Araç girişlerinde veri doğrulamayı zorlamak için Pydantic kullanın.
  • HTTPS: Azure Container Apps, otomatik TLS sertifikaları ile varsayılan olarak HTTPS'nin zorunlu kılınmasını sağlar.
  • En az ayrıcalık: Yalnızca kullanım örneğinizin gerektirdiği araçları kullanıma sunma. Onay olmadan yıkıcı işlemler gerçekleştiren araçlardan kaçının.
  • CORS: İzin verilen çıkış noktalarını üretimdeki güvenilen etki alanlarıyla kısıtlayın.
  • Günlük kaydı ve izleme: Denetim amaçlı MCP aracı çağrılarını günlüğe kaydetme. Azure İzleyici ve Log Analytics'i kullanın.

Kaynakları temizle

Bu uygulamayı kullanmaya devam etmek istemiyorsanız, bu öğreticide oluşturduğunuz tüm kaynakları kaldırmak için kaynak grubunu silin:

az group delete --resource-group $RESOURCE_GROUP --yes --no-wait

Sonraki adım