איך פורסים שרת MCP מאובטח ב-Cloud Run

1. מבוא

סקירה כללית

בשיעור ה-Lab הזה תבנו ותפרסו שרת Model Context Protocol‏ (MCP). שרתי MCP שימושיים למתן גישה למודלים מסוג LLM לכלים ולשירותים חיצוניים. תגדירו אותו כשירות מאובטח ומוכן לייצור ב-Cloud Run, שאפשר לגשת אליו מכמה לקוחות. לאחר מכן מתחברים לשרת ה-MCP המרוחק מ-Antigravity CLI.

הפעולות שתבצעו:

נשתמש ב-FastMCP כדי ליצור שרת MCP של גן חיות עם שני כלים: get_animals_by_species ו-get_animal_details. ‫FastMCP מספק דרך מהירה ופשוטה ליצור שרתי MCP ולקוחות.

גרפיקה של שרת MCP של גן חיות

מה תלמדו

  • פורסים את שרת ה-MCP ב-Cloud Run.
  • כדי לאבטח את נקודת הקצה של השרת, צריך לדרוש אימות לכל הבקשות, כדי להבטיח שרק לקוחות וסוכנים מורשים יוכלו לתקשר איתו.
  • חיבור לנקודת הקצה המאובטחת של שרת ה-MCP מ-Antigravity CLI

2. הגדרת הפרויקט

  1. אם עדיין אין לכם חשבון Google, אתם צריכים ליצור חשבון Google.
    • משתמשים בחשבון לשימוש אישי במקום בחשבון לצורכי עבודה או בחשבון בית ספרי. יכול להיות שבחשבונות לצורכי עבודה או בחשבונות בית ספריים יש הגבלות שימנעו מכם להפעיל את ממשקי ה-API שנדרשים למעבדה הזו.
  2. נכנסים למסוף Google Cloud.
  3. יוצרים פרויקט חדש או בוחרים להשתמש בפרויקט קיים.
    • אם מופיעה שגיאה לגבי מכסת הפרויקט, צריך לעשות שימוש חוזר בפרויקט קיים או למחוק פרויקט קיים כדי ליצור פרויקט חדש.

3. פתיחת Cloud Shell Editor

  1. כדי לעבור ישירות אל Cloud Shell Editor, לוחצים על הקישור הזה.
  2. אם תתבקשו לאשר בשלב כלשהו היום, תצטרכו ללחוץ על אישור כדי להמשיך. לוחצים כדי לתת הרשאה ל-Cloud Shell
  3. אם הטרמינל לא מופיע בתחתית המסך, פותחים אותו:
    • לוחצים על הצגה.
    • לוחצים על Terminal (טרמינל)פתיחת טרמינל חדש ב-Cloud Shell Editor.
  4. בטרמינל, מגדירים את הפרויקט באמצעות הפקודה הבאה:
    • פורמט:
      gcloud config set project [PROJECT_ID]
      
    • דוגמה:
      gcloud config set project lab-project-id-example
      
    • אם אתם לא זוכרים את מזהה הפרויקט:
      • כדי להציג רשימה של כל מזהי הפרויקטים:
        gcloud projects list | awk '/PROJECT_ID/{print $2}'
        
      הגדרת מזהה הפרויקט בטרמינל של Cloud Shell Editor
  5. תוצג ההודעה הבאה:
    Updated property [core/project].
    
    אם מופיע WARNING ומוצגת השאלה Do you want to continue (Y/n)?, כנראה שהזנתם את מזהה הפרויקט בצורה שגויה. לוחצים על n, לוחצים על Enter ומנסים להריץ שוב את הפקודה gcloud config set project.

4. הפעלת ממשקי ה-API

בטרמינל, מפעילים את ממשקי ה-API:

gcloud services enable \
  run.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com

אם מתבקשים לאשר, לוחצים על אישור כדי להמשיך. לוחצים כדי לתת הרשאה ל-Cloud Shell

הפקודה הזו עשויה להימשך כמה דקות, אבל בסופו של דבר היא אמורה להפיק הודעה דומה לזו:

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

5. הכנת פרויקט Python

  1. יוצרים תיקייה בשם mcp-on-cloudrun לאחסון קוד המקור לפריסה:
    mkdir mcp-on-cloudrun && cd mcp-on-cloudrun
    
  2. יוצרים פרויקט Python באמצעות הכלי uv כדי ליצור קובץ pyproject.toml:
    uv init --description "Example of deploying an MCP server on Cloud Run" --bare --python 3.13
    
    הפקודה uv init יוצרת קובץ pyproject.toml לפרויקט.כדי להציג את תוכן הקובץ, מריצים את הפקודה הבאה:
    cat pyproject.toml
    
    הפלט אמור להיראות כך:
    [project]
    name = "mcp-on-cloudrun"
    version = "0.1.0"
    description = "Example of deploying an MCP server on Cloud Run"
    requires-python = ">=3.13"
    dependencies = []
    

6. יצירת שרת MCP של גן החיות

כדי לספק הקשר חשוב לשיפור השימוש במודלים גדולים של שפה (LLM) עם MCP, צריך להגדיר שרת MCP של גן חיות עם FastMCP – מסגרת סטנדרטית לעבודה עם Model Context Protocol. ‫FastMCP מספק דרך מהירה לבניית שרתי MCP ולקוחות באמצעות Python. שרת ה-MCP הזה מספק נתונים על בעלי חיים בגן חיות דמיוני. לשם פשטות, אנחנו מאחסנים את הנתונים בזיכרון. בשרת MCP לייצור, כדאי לספק נתונים ממקורות כמו מסדי נתונים או ממשקי API.

  1. מריצים את הפקודה הבאה כדי להוסיף את FastMCP כתלות בקובץ pyproject.toml:
    uv add fastmcp==2.12.4 --no-sync
    
    הפעולה הזו תוסיף קובץ uv.lock לפרויקט.
  2. יוצרים ופותחים קובץ server.py חדש בשביל קוד המקור של שרת ה-MCP:
    cloudshell edit ~/mcp-on-cloudrun/server.py
    
    הפקודה cloudshell edit תפתח את הקובץ server.py בכלי העריכה שמעל הטרמינל.
  3. מוסיפים את קוד המקור הבא של שרת ה-MCP של גן החיות לקובץ server.py:
    import asyncio
    import logging
    import os
    from typing import List, Dict, Any
    
    from fastmcp import FastMCP
    
    logger = logging.getLogger(__name__)
    logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)
    
    mcp = FastMCP("Zoo Animal MCP Server 🦁🐧🐻")
    
    # Dictionary of animals at the zoo
    ZOO_ANIMALS = [
        {
            "species": "lion",
            "name": "Leo",
            "age": 7,
            "enclosure": "The Big Cat Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "lion",
            "name": "Nala",
            "age": 6,
            "enclosure": "The Big Cat Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "lion",
            "name": "Simba",
            "age": 3,
            "enclosure": "The Big Cat Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "lion",
            "name": "King",
            "age": 8,
            "enclosure": "The Big Cat Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "penguin",
            "name": "Waddles",
            "age": 2,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "penguin",
            "name": "Pip",
            "age": 4,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "penguin",
            "name": "Skipper",
            "age": 5,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "penguin",
            "name": "Chilly",
            "age": 3,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "penguin",
            "name": "Pingu",
            "age": 6,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "penguin",
            "name": "Noot",
            "age": 1,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "elephant",
            "name": "Ellie",
            "age": 15,
            "enclosure": "The Pachyderm Sanctuary",
            "trail": "Savannah Heights"
        },
        {
            "species": "elephant",
            "name": "Peanut",
            "age": 12,
            "enclosure": "The Pachyderm Sanctuary",
            "trail": "Savannah Heights"
        },
        {
            "species": "elephant",
            "name": "Dumbo",
            "age": 5,
            "enclosure": "The Pachyderm Sanctuary",
            "trail": "Savannah Heights"
        },
        {
            "species": "elephant",
            "name": "Trunkers",
            "age": 10,
            "enclosure": "The Pachyderm Sanctuary",
            "trail": "Savannah Heights"
        },
        {
            "species": "bear",
            "name": "Smokey",
            "age": 10,
            "enclosure": "The Grizzly Gulch",
            "trail": "Polar Path"
        },
        {
            "species": "bear",
            "name": "Grizzly",
            "age": 8,
            "enclosure": "The Grizzly Gulch",
            "trail": "Polar Path"
        },
        {
            "species": "bear",
            "name": "Barnaby",
            "age": 6,
            "enclosure": "The Grizzly Gulch",
            "trail": "Polar Path"
        },
        {
            "species": "bear",
            "name": "Bruin",
            "age": 12,
            "enclosure": "The Grizzly Gulch",
            "trail": "Polar Path"
        },
        {
            "species": "giraffe",
            "name": "Gerald",
            "age": 4,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "giraffe",
            "name": "Longneck",
            "age": 5,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "giraffe",
            "name": "Patches",
            "age": 3,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "giraffe",
            "name": "Stretch",
            "age": 6,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "antelope",
            "name": "Speedy",
            "age": 2,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "antelope",
            "name": "Dash",
            "age": 3,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "antelope",
            "name": "Gazelle",
            "age": 4,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "antelope",
            "name": "Swift",
            "age": 5,
            "enclosure": "The Tall Grass Plains",
            "trail": "Savannah Heights"
        },
        {
            "species": "polar bear",
            "name": "Snowflake",
            "age": 7,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "polar bear",
            "name": "Blizzard",
            "age": 5,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "polar bear",
            "name": "Iceberg",
            "age": 9,
            "enclosure": "The Arctic Exhibit",
            "trail": "Polar Path"
        },
        {
            "species": "walrus",
            "name": "Wally",
            "age": 10,
            "enclosure": "The Walrus Cove",
            "trail": "Polar Path"
        },
        {
            "species": "walrus",
            "name": "Tusker",
            "age": 12,
            "enclosure": "The Walrus Cove",
            "trail": "Polar Path"
        },
        {
            "species": "walrus",
            "name": "Moby",
            "age": 8,
            "enclosure": "The Walrus Cove",
            "trail": "Polar Path"
        },
        {
            "species": "walrus",
            "name": "Flippers",
            "age": 9,
            "enclosure": "The Walrus Cove",
            "trail": "Polar Path"
        }
    ]
    
    @mcp.tool()
    def get_animals_by_species(species: str) -> List[Dict[str, Any]]:
        """
        Retrieves all animals of a specific species from the zoo.
        Can also be used to collect the base data for aggregate queries
        of animals of a specific species - like counting the number of penguins
        or finding the oldest lion.
    
        Args:
            species: The species of the animal (e.g., 'lion', 'penguin').
    
        Returns:
            A list of dictionaries, where each dictionary represents an animal
            and contains details like name, age, enclosure, and trail.
        """
        logger.info(f">>> 🛠️ Tool: 'get_animals_by_species' called for '{species}'")
        return [animal for animal in ZOO_ANIMALS if animal["species"].lower() == species.lower()]
    
    @mcp.tool()
    def get_animal_details(name: str) -> Dict[str, Any]:
        """
        Retrieves the details of a specific animal by its name.
    
        Args:
            name: The name of the animal.
    
        Returns:
            A dictionary with the animal's details (species, name, age, enclosure, trail)
            or an empty dictionary if the animal is not found.
        """
        logger.info(f">>> 🛠️ Tool: 'get_animal_details' called for '{name}'")
        for animal in ZOO_ANIMALS:
            if animal["name"].lower() == name.lower():
                return animal
        return {}
    
    if __name__ == "__main__":
        port = int(os.getenv("PORT", 8080))
        logger.info(f"🚀 MCP server started on port {port}")
        asyncio.run(
            mcp.run_async(
                transport="http",
                host="0.0.0.0",
                port=port,
            )
        )
    

הקוד שלך הושלם! הגיע הזמן לפרוס את שרת ה-MCP ב-Cloud Run.

7. פריסה ב-Cloud Run

עכשיו פורסים שרת MCP ל-Cloud Run ישירות מקוד המקור.

  1. יוצרים ופותחים קובץ Dockerfile חדש לפריסה ב-Cloud Run:
    cloudshell edit ~/mcp-on-cloudrun/Dockerfile
    
  2. כדי להשתמש בכלי uv להרצת הקובץ server.py, צריך לכלול את הקוד הבא ב-Dockerfile:
    # Use the official Python image
    FROM python:3.13-slim
    
    # Install uv
    COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
    
    # Install the project into /app
    COPY . /app
    WORKDIR /app
    
    # Allow statements and log messages to immediately appear in the logs
    ENV PYTHONUNBUFFERED=1
    
    # Install dependencies
    RUN uv sync
    
    EXPOSE $PORT
    
    # Run the FastMCP server
    CMD ["uv", "run", "server.py"]
    
  3. יוצרים חשבון שירות בשם mcp-server-sa:
    gcloud iam service-accounts create mcp-server-sa --display-name="MCP Server Service Account"
    
  4. מריצים את הפקודה gcloud כדי לפרוס את האפליקציה ב-Cloud Run
    cd ~/mcp-on-cloudrun
    gcloud run deploy zoo-mcp-server \
        --service-account=mcp-server-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
        --no-allow-unauthenticated \
        --region=us-west1 \
        --source=. \
        --labels=dev-tutorial=codelab-mcp
    
    משתמשים בדגל --no-allow-unauthenticated כדי לדרוש אימות. הדבר חשוב מטעמי אבטחה. אם לא נדרש אימות, כל אחד יכול להתקשר לשרת ה-MCP שלכם ולגרום נזק למערכת.
  5. מאשרים את היצירה של מאגר חדש ב-Artifact Registry. מכיוון שזו הפעם הראשונה שאתם פורסים ל-Cloud Run מקוד מקור, תופיע ההודעה:
    Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named
    [cloud-run-source-deploy] in region [us-west1] will be created.
    
    Do you want to continue (Y/n)?
    
    מקלידים Y ולוחצים על Enter. כך ייצור מאגר Artifact Registry לפריסה. הפעולה הזו נדרשת כדי לאחסן את קונטיינר ה-Docker של שרת ה-MCP בשירות Cloud Run.
  6. אחרי כמה דקות, תופיע הודעה כמו:
    Service [zoo-mcp-server] revision [zoo-mcp-server-12345-abc] has been deployed and is serving 100 percent of traffic.
    

פרסתם את שרת ה-MCP. עכשיו אפשר להשתמש בו.

8. הוספת שרת MCP מרוחק ל-Antigravity CLI

אחרי שפרסתם בהצלחה שרת MCP מרוחק, אתם יכולים להתחבר אליו באמצעות אפליקציות שונות כמו Google Code Assist או Antigravity CLI. בקטע הזה נסביר איך ליצור חיבור לשרת MCP מרוחק חדש באמצעות Antigravity CLI.

  1. נותנים לחשבון המשתמש הרשאה להתקשר לשרת MCP מרוחק
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member=user:$(gcloud config get-value account) \
        --role='roles/run.invoker'
    
  2. שומרים את פרטי הכניסה ל-Google Cloud ואת מספר הפרויקט במשתני סביבה לשימוש בקובץ ההגדרות של Antigravity:
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    export ID_TOKEN=$(gcloud auth print-identity-token)
    
  3. יוצרים תיקייה בשם .gemini/antigravity-cli אם היא עדיין לא נוצרה
    mkdir -p ~/.gemini/antigravity-cli
    
  4. כותבים את שרת ה-MCP המרוחק לקובץ התצורה של MCP ב-Antigravity CLI:
    cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF
    {
        "mcpServers": {
            "zoo-remote": {
                "serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp",
                "headers": {
                    "Authorization": "Bearer ${ID_TOKEN}"
                }
            }
        }
    }
    EOF
    
  5. מפעילים את Antigravity CLI:
    agy
    
  1. אימות באמצעות Antigravity CLI: נדרש אימות במהלך ההפעלה הראשונית. בוחרים באפשרות OAuth (לוחצים על Enter).מסך אימות של Antigravity
  2. לוחצים על הקישור (אם אי אפשר ללחוץ עליו, מדגישים את כתובת ה-URL ב-Cloud Shell כדי להעתיק אותה, ואז מדביקים אותה בדפדפן).
  3. כניסה לחשבון Google
  4. להעתיק את הקוד
  5. מדביקים את הקוד בטרמינל של Cloud Shell Editor.
  6. לוחצים על Enter.הנחיה להזנת קוד אבטחה ב-Antigravity
  7. כדי לאשר חלק מהגדרות ברירת המחדל, לוחצים על Enter.
  8. הצגת רשימת הכלים של MCP שזמינים ל-Antigravity CLI בהקשר שלו
    /mcp
    
    כדי לחזור לתיבת הפרומפט, לוחצים על ESC.
  9. מבקשים מ-Antigravity CLI למצוא משהו בגן החיות
    Where can I find penguins?
    
    ממשק Antigravity CLI אמור לדעת להשתמש בשרת zoo-remote MCP ולשאול אם רוצים לאפשר את ההפעלה של MCP.
  10. משתמשים בחץ למטה ואז מקישים על Enter כדי לבחור
    Yes, always allow all tools from server "zoo-remote"
    
    Antigravity CLI allow zoo remote tools

הפלט צריך להציג את התשובה הנכונה ותיבת תצוגה שמראה שהיה שימוש בשרת MCP.

‫Antigravity CLI show zoo mcp server result

הצלחתם! הצלחתם לפרוס שרת MCP מרוחק ל-Cloud Run ולבדוק אותו באמצעות Antigravity CLI.

כשמוכנים לסיים את הסשן, מקלידים /exit ואז לוחצים על Enter כדי לצאת מ-Antigravity CLI.

ניפוי באגים

אם מופיעה שגיאה כמו זו:

🔍 Attempting OAuth discovery for 'zoo-remote'...
❌ 'zoo-remote' requires authentication but no OAuth configuration found
Error connecting to MCP server 'zoo-remote': MCP server 'zoo-remote' requires authentication. Please configure OAuth or check server settings.

סביר להניח שפג התוקף של אסימון המזהה וצריך להגדיר שוב את ID_TOKEN.

  1. מקלידים /exit ואז מקישים על Enter כדי לצאת מ-Antigravity CLI.
  2. הגדרת הפרויקט במסוף
    gcloud config set project [PROJECT_ID]
    
  3. מריצים מחדש את הפקודה של פרטי הכניסה ל-Google Cloud כדי לקבל ID_TOKEN חדש, כי יכול להיות שהתוקף שלכם פג, וכותבים מחדש את קובץ ההגדרות:
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    export ID_TOKEN=$(gcloud auth print-identity-token)
    
    cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF
    

‪{ "mcpServers": { "zoo-remote": { "serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp", "headers": { "Authorization": "Bearer ${ID_TOKEN}" } } } } EOF ```

9. (אופציונלי) אימות של קריאות לכלים ביומני השרת

כדי לוודא ששרת ה-MCP של Cloud Run נקרא, בודקים את יומני השירות.

gcloud run services logs read zoo-mcp-server --region us-west1 --limit=5

אמור להופיע יומן פלט שמאשר שהתבצעה קריאה לכלי. 🛠️

2025-08-05 19:50:31 INFO:     169.254.169.126:39444 - "POST /mcp HTTP/1.1" 200 OK
2025-08-05 19:50:31 [INFO]: Processing request of type CallToolRequest
2025-08-05 19:50:31 [INFO]: >>> 🛠️ Tool: 'get_animals_by_species' called for 'penguin'

10. (אופציונלי) הוספת הנחיה ל-MCP לשרת

הנחיה של MCP יכולה לזרז את תהליך העבודה שלכם בהנחיות שאתם מריצים לעיתים קרובות, על ידי יצירת קיצור להנחיה ארוכה יותר.

ה-Antigravity CLI ממיר באופן אוטומטי פרומפטים של MCP לפקודות סלאש מותאמות אישית, כך שאפשר להפעיל פרומפט של MCP על ידי הקלדת /prompt_name, כאשר prompt_name הוא השם של הפרומפט של MCP.

יוצרים הנחיה ל-MCP כדי למצוא במהירות חיה בגן החיות על ידי הקלדת /find animal ב-Antigravity CLI.

  1. מוסיפים את הקוד הזה לקובץ server.py מעל השומר הראשי (if __name__ == "__main__":)
    @mcp.prompt()
    def find(animal: str) -> str:
        """
        Find which exhibit and trail a specific animal might be located.
        """
    
        return (
            f"Please find the exhibit and trail information for {animal} in the zoo. "
            f"Respond with '[animal] can be found in the [exhibit] on the [trail].'"
            f"Example: Penguins can be found in The Arctic Exhibit on the Polar Path."
        )
    
  2. פריסה מחדש של האפליקציה ב-Cloud Run
    gcloud run deploy zoo-mcp-server \
        --region=us-west1 \
        --source=. \
        --labels=dev-tutorial=codelab-mcp
    
  3. מרעננים את ID_TOKEN ויוצרים מחדש את קובץ ההגדרות:
    export ID_TOKEN=$(gcloud auth print-identity-token)
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    
    cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF
    

‪{ "mcpServers": { "zoo-remote": { "serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp", "headers": { "Authorization": "Bearer ${ID_TOKEN}" } } } } EOF ```

  1. אחרי שפורסתם את הגרסה החדשה של האפליקציה, מפעילים את Antigravity CLI.
    agy
    
  2. בהנחיה, משתמשים בפקודה החדשה בהתאמה אישית שיצרתם:
    /find lions
    

אפשר לראות ש-Antigravity CLI קורא לכלי get_animals_by_species ומעצב את התגובה לפי ההוראות בהנחיה של MCP.

╭───────────────────────────╮
│  > /find lions            │
╰───────────────────────────╯

 ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✔  get_animals_by_species (zoo-remote MCP Server) get_animals_by_species (zoo-remote MCP Server)  │
 │                                                                                                   │
 │    [{"species":"lion","name":"Leo","age":7,"enclosure":"The Big Cat                               │
 │    Plains","trail":"Savannah                                                                      │
 │    Heights"},{"species":"lion","name":"Nala","age":6,"enclosure":"The Big Cat                     │
 │    Plains","trail":"Savannah                                                                      │
 │    Heights"},{"species":"lion","name":"Simba","age":3,"enclosure":"The Big Cat                    │
 │    Plains","trail":"Savannah                                                                      │
 │    Heights"},{"species":"lion","name":"King","age":8,"enclosure":"The Big Cat                     │
 │    Plains","trail":"Savannah Heights"}]                                                           │
 ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Lions can be found in The Big Cat Plains on the Savannah Heights.

11. (אופציונלי) שימוש ב-Gemini Flash Lite לקבלת תשובות מהירות יותר

ב-Antigravity CLI אפשר לבחור את המודל ואת רמת המאמץ שבהם משתמשים.

מכיוון שהבקשות שקשורות למציאת חיות בגן החיות לא דורשות חשיבה רציונלית, כדאי לנסות להשתמש במודל מהיר יותר כדי לזרז את התהליך.

בקטע הקודם יצרתם הנחיית MCP כדי למצוא במהירות חיה בגן החיות על ידי הקלדת /find animal בממשק Antigravity CLI.

  1. אחרי שפורסתם את הגרסה החדשה של האפליקציה, מפעילים את Antigravity CLI.
    agy --model=gemini-3.6-flash --effort=low
    
  2. בהנחיה, משתמשים בפקודה החדשה בהתאמה אישית שיצרתם:
    /find lions
    

עדיין תראו שהכלי Antigravity CLI קורא לכלי get_animals_by_species ומעצב את התשובה לפי ההנחיות בהנחיה של MCP, אבל התשובה אמורה להופיע הרבה יותר מהר.

╭───────────────────────────╮
│  > /find lions            │
╰───────────────────────────╯

 ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✔  get_animals_by_species (zoo-remote MCP Server) get_animals_by_species (zoo-remote MCP Server)  │
 │                                                                                                   │
 │    [{"species":"lion","name":"Leo","age":7,"enclosure":"The Big Cat                               │
 │    Plains","trail":"Savannah                                                                      │
 │    Heights"},{"species":"lion","name":"Nala","age":6,"enclosure":"The Big Cat                     │
 │    Plains","trail":"Savannah                                                                      │
 │    Heights"},{"species":"lion","name":"Simba","age":3,"enclosure":"The Big Cat                    │
 │    Plains","trail":"Savannah                                                                      │
 │    Heights"},{"species":"lion","name":"King","age":8,"enclosure":"The Big Cat                     │
 │    Plains","trail":"Savannah Heights"}]                                                           │
 ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Lions can be found in The Big Cat Plains on the Savannah Heights.

ניפוי באגים

אם מופיעה שגיאה כמו זו:

✕ Unknown command: /find lions

מנסים להריץ את הפקודה /mcp. אם הפלט הוא zoo-remote - Disconnected, יכול להיות שתצטרכו לפרוס מחדש או להריץ שוב את הפקודות הבאות:

 gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
   --member=user:$(gcloud config get-value account) \
   --role='roles/run.invoker'

export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export ID_TOKEN=$(gcloud auth print-identity-token)

cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF
{
   "mcpServers": {
       "zoo-remote": {
           "serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp",
           "headers": {
               "Authorization": "Bearer ${ID_TOKEN}"
           }
       }
   }
}
EOF

12. סיכום

מעולה! הצלחתם לפרוס ולהתחבר לשרת MCP מרוחק ומאובטח.

המשך ל-Lab הבא

שיעור ה-Lab הזה הוא הראשון בסדרה של שלושה שיעורי Lab. במעבדה השנייה, תשתמשו בשרת ה-MCP שיצרתם עם סוכן ADK.

שימוש בשרת MCP ב-Cloud Run עם סוכן ADK

(אופציונלי) ניקוי

אם אתם לא ממשיכים למעבדה הבאה ורוצים לנקות את מה שיצרתם, אתם יכולים למחוק את פרויקט בענן כדי להימנע מחיובים נוספים.

ב-Cloud Run לא מחויבים כשלא משתמשים בשירות, אבל יכול להיות שתחויבו על אחסון קובץ האימג' של הקונטיינר ב-Artifact Registry. כשמוחקים פרויקט בענן, החיוב על כל המשאבים שנעשה בהם שימוש באותו פרויקט נפסק.

אם רוצים, אפשר למחוק את הפרויקט:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

מומלץ גם למחוק משאבים מיותרים מהדיסק של Cloud Shell. אתם יכולים:

  1. מוחקים את ספריית הפרויקט של ה-codelab:
    rm -rf ~/mcp-on-cloudrun
    
  2. אזהרה! אי אפשר לבטל את הפעולה הבאה! אם רוצים למחוק את כל מה שיש ב-Cloud Shell כדי לפנות מקום, אפשר למחוק את כל ספריית הבית. חשוב לוודא שכל מה שרוצים לשמור נשמר במקום אחר.
    sudo rm -rf $HOME