1. מבוא
סקירה כללית
בשיעור ה-Lab הזה תבנו ותפרסו שרת Model Context Protocol (MCP). שרתי MCP שימושיים כדי לספק למודלים מסוג LLM גישה לכלים ולשירותים חיצוניים. תגדירו אותו כשירות מאובטח ומוכן לייצור ב-Cloud Run, שאפשר לגשת אליו מכמה לקוחות. לאחר מכן תתחברו לשרת ה-MCP המרוחק מ-Gemini CLI.
הפעולות שתבצעו:
נשתמש ב-FastMCP כדי ליצור שרת MCP של zoo עם שני כלים: get_animals_by_species
ו-get_animal_details
. FastMCP מספק דרך מהירה ופייתונית לבניית שרתים ולקוחות של MCP.
מה תלמדו
- פורסים את שרת ה-MCP ב-Cloud Run.
- כדי להגן על נקודת הקצה של השרת, צריך לדרוש אימות לכל הבקשות, כדי שרק לקוחות ונציגים מורשים יוכלו לתקשר איתו.
- התחברות לנקודת הקצה של שרת ה-MCP המאובטח מ-Gemini CLI
2. הגדרת הפרויקט
- אם אין לכם חשבון Google, אתם צריכים ליצור חשבון Google.
- משתמשים בחשבון לשימוש אישי במקום בחשבון לצורכי עבודה או בחשבון בית ספרי. יכול להיות שבחשבונות לצורכי עבודה או בחשבונות בית ספריים יש הגבלות שלא מאפשרות להפעיל את ממשקי ה-API שנדרשים למעבדה הזו.
- נכנסים למסוף Google Cloud.
- מפעילים את החיוב במסוף Cloud.
- העלות של השלמת שיעור ה-Lab הזה צריכה להיות פחות מ-1 $ על משאבי Cloud.
- כדי למחוק משאבים ולמנוע חיובים נוספים, אפשר לפעול לפי השלבים בסוף שיעור ה-Lab הזה.
- משתמשים חדשים זכאים לתקופת ניסיון בחינם בשווי 300$.
- יוצרים פרויקט חדש או בוחרים להשתמש בפרויקט קיים.
3. פתיחת Cloud Shell Editor
- כדי לעבור ישירות אל Cloud Shell Editor, לוחצים על הקישור הזה.
- אם תתבקשו לאשר את הפעולה בשלב כלשהו היום, תצטרכו ללחוץ על אישור כדי להמשיך.
- אם הטרמינל לא מופיע בתחתית המסך, פותחים אותו:
- לוחצים על תצוגה.
- לוחצים על Terminal (מסוף)
.
- בטרמינל, מגדירים את הפרויקט באמצעות הפקודה הבאה:
- פורמט:
gcloud config set project [PROJECT_ID]
- דוגמה:
gcloud config set project lab-project-id-example
- אם אתם לא זוכרים את מזהה הפרויקט:
- כדי לראות את כל מזהי הפרויקטים, מריצים את הפקודה:
gcloud projects list | awk '/PROJECT_ID/{print $2}'
- כדי לראות את כל מזהי הפרויקטים, מריצים את הפקודה:
- פורמט:
- תוצג ההודעה:
אם מופיע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
אם מתבקשים לאשר, לוחצים על אישור כדי להמשיך.
השלמת הפקודה עשויה להימשך כמה דקות, אבל בסופו של דבר אמורה להתקבל הודעה על הצלחה שדומה להודעה הבאה:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
5. הכנת פרויקט Python
- יוצרים תיקייה בשם
mcp-on-cloudrun
לאחסון קוד המקור לפריסה:mkdir mcp-on-cloudrun && cd mcp-on-cloudrun
- יוצרים פרויקט 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 של zoo באמצעות FastMCP – מסגרת סטנדרטית לעבודה עם פרוטוקול הקשר של המודל. FastMCP היא דרך מהירה לבנות שרתי MCP ולקוחות באמצעות Python. שרת ה-MCP הזה מספק נתונים על בעלי חיים בגן חיות פיקטיבי. לשם פשטות, אנחנו מאחסנים את הנתונים בזיכרון. בשרת MCP של סביבת ייצור, כדאי לספק נתונים ממקורות כמו מסדי נתונים או ממשקי API.
- מריצים את הפקודה הבאה כדי להוסיף את FastMCP כתלות בקובץ
pyproject.toml
: כך יתווסף קובץuv add fastmcp==2.11.1 --no-sync
uv.lock
לפרויקט. - יוצרים ופותחים קובץ
server.py
חדש לקוד המקור של שרת ה-MCP: הפקודהcloudshell edit server.py
cloudshell edit
תפתח את הקובץserver.py
בכלי העריכה מעל הטרמינל. - מוסיפים את קוד המקור הבא של שרת ה-MCP של zoo לקובץ
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__": logger.info(f"🚀 MCP server started on port {os.getenv('PORT', 8080)}") asyncio.run( mcp.run_async( transport="http", host="0.0.0.0", port=os.getenv("PORT", 8080), ) )
הקוד שלך הושלם! הגיע הזמן לפרוס את שרת ה-MCP ב-Cloud Run.
7. פריסה ב-Cloud Run
עכשיו פורסים שרת MCP ב-Cloud Run ישירות מקוד המקור.
- יוצרים ופותחים קובץ
Dockerfile
חדש לפריסה ב-Cloud Run:cloudshell edit Dockerfile
- כדי להשתמש בכלי
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"]
- מריצים את הפקודה
gcloud
כדי לפרוס את האפליקציה ב-Cloud Run. משתמשים בדגלgcloud run deploy zoo-mcp-server \ --no-allow-unauthenticated \ --region=europe-west1 \ --source=. \ --labels=dev-tutorial=codelab-mcp
--no-allow-unauthenticated
כדי לדרוש אימות. הדבר חשוב מטעמי אבטחה. אם לא נדרש אימות, כל אחד יכול להתקשר לשרת ה-MCP שלכם ולגרום נזק למערכת. - מאשרים את היצירה של מאגר חדש ב-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 [europe-west1] will be created. Do you want to continue (Y/n)?
Y
ולוחצים עלEnter
. כך ייצור מאגר Artifact Registry לפריסה. ההרשאה הזו נדרשת כדי לאחסן את קונטיינר Docker של שרת ה-MCP בשירות Cloud Run. - אחרי כמה דקות, תופיע הודעה כמו:
Service [zoo-mcp-server] revision [zoo-mcp-server-12345-abc] has been deployed and is serving 100 percent of traffic.
פרסתם את שרת ה-MCP. עכשיו אפשר להשתמש בו.
8. הוספת שרת MCP מרוחק ל-Gemini CLI
אחרי שפרסתם בהצלחה שרת MCP מרוחק, אתם יכולים להתחבר אליו באמצעות אפליקציות שונות כמו Google Code Assist או Gemini CLI. בקטע הזה נסביר איך ליצור חיבור לשרת MCP המרוחק החדש באמצעות Gemini CLI.
- נותנים לחשבון המשתמש הרשאה להתקשר לשרת MCP המרוחק
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member=user:$(gcloud config get-value account) \ --role='roles/run.invoker'
- שומרים את פרטי הכניסה ל-Google Cloud ואת מספר הפרויקט במשתני סביבה לשימוש בקובץ ההגדרות של Gemini:
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)") export ID_TOKEN=$(gcloud auth print-identity-token)
- פותחים את קובץ ההגדרות של Gemini CLI.
cloudshell edit ~/.gemini/settings.json
- החלפת קובץ ההגדרות של Gemini CLI כדי להוסיף את שרת ה-MCP של Cloud Run
{ "mcpServers": { "zoo-remote": { "httpUrl": "https://zoo-mcp-server-$PROJECT_NUMBER.europe-west1.run.app/mcp/", "headers": { "Authorization": "Bearer $ID_TOKEN" } } }, "selectedAuthType": "cloud-shell", "hasSeenIdeIntegrationNudge": true }
- הפעלת Gemini CLI ב-Cloud Shell
יכול להיות שתצטרכו ללחוץ עלgemini
Enter
כדי לאשר כמה הגדרות ברירת מחדל. - מבקשים מ-Gemini לרשום את כלי ה-MCP שזמינים לו בהקשר שלו
/mcp
- אפשר לבקש מ-Gemini למצוא משהו בגן החיות
Gemini CLI אמור לדעת להשתמש בשרתWhere can I find penguins?
zoo-remote
MCP וישאל אם רוצים לאפשר את ההפעלה של MCP. - משתמשים בחץ למטה ומקישים על
Enter
כדי לבחור.Yes, always allow all tools from server "zoo-remote"
הפלט צריך להציג את התשובה הנכונה ותיבת תצוגה שמראה שהשתמשו בשרת MCP.
הצלחתם! הצלחתם לפרוס שרת MCP מרוחק ב-Cloud Run ולבדוק אותו באמצעות Gemini CLI.
כשמוכנים לסיים את הסשן, מקלידים /quit
ואז לוחצים על Enter
כדי לצאת מ-Gemini 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 וצריך להגדיר שוב את ID_TOKEN
.
- מקלידים
/quit
ואז מקישים עלEnter
כדי לצאת מ-Gemini CLI. - הגדרת הפרויקט במסוף
gcloud config set project [PROJECT_ID]
- מתחילים מחדש משלב 2 שלמעלה
9. (אופציונלי) אימות של קריאות לכלים ביומני השרת
כדי לוודא שהשרת של Cloud Run MCP נקרא, בודקים את יומני השירות.
gcloud run services logs read zoo-mcp-server --region europe-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 יכולה לזרז את תהליך העבודה שלכם בהנחיות שאתם מריצים לעיתים קרובות, על ידי יצירת קיצור להנחיה ארוכה יותר.
ממשק ה-CLI של Gemini ממיר באופן אוטומטי הנחיות של MCP לפקודות סלאש מותאמות אישית, כך שאפשר להפעיל הנחיה של MCP על ידי הקלדת /prompt_name
, כאשר prompt_name
הוא השם של ההנחיה של MCP.
יוצרים הנחיה ל-MCP כדי למצוא במהירות חיה בגן החיות על ידי הקלדת /find animal
ב-Gemini CLI.
- מוסיפים את הקוד הזה לקובץ
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." )
- פריסה מחדש של האפליקציה ב-Cloud Run
gcloud run deploy zoo-mcp-server \ --no-allow-unauthenticated \ --region=europe-west1 \ --source=. \ --labels=dev-tutorial=codelab-mcp
- רענון של ID_TOKEN עבור שרת MCP מרוחק
export ID_TOKEN=$(gcloud auth print-identity-token)
- אחרי שפורסתם את הגרסה החדשה של האפליקציה, מפעילים את Gemini CLI.
gemini
- בהנחיה, משתמשים בפקודה החדשה בהתאמה אישית שיצרתם:
/find --animal="lions"
אפשר לראות ש-Gemini CLI קורא לכלי get_animals_by_species
ומעצב את התשובה לפי ההוראות בהנחיה של MCP.
╭───────────────────────────╮ │ > /find --animal="lion" │ ╰───────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ✔ 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.
יעדים שאפתניים לבדיקה עצמית
כדי להוסיף אתגר, נסו לבצע את אותם השלבים כדי ליצור הנחיה להחזרת עובדות מעניינות על מינים ספציפיים של בעלי חיים בגן החיות.
או, כדי לבחון את מה שלמדתם, אפשר להעלות רעיון לכלי שבו תשתמשו לעיתים קרובות ולפרוס שרת MCP מרוחק שני. לאחר מכן מוסיפים אותו להגדרות של Gemini CLI כדי לבדוק אם הוא פועל.
11. סיכום
מעולה! הצלחתם לפרוס ולהתחבר לשרת MCP מרוחק ומאובטח.
המשך לשיעור ה-Lab הבא
שיעור ה-Lab הזה הוא הראשון בסדרה של שלושה שיעורי Lab. בשיעור ה-Lab השני, תשתמשו בשרת ה-MCP שיצרתם באמצעות סוכן ADK.
שימוש בשרת MCP ב-Cloud Run עם סוכן ADK
(אופציונלי) ניקוי
אם אתם לא ממשיכים למעבדה הבאה ורוצים לנקות את מה שיצרתם, אתם יכולים למחוק את פרויקט Cloud כדי להימנע מחיובים נוספים.
ב-Cloud Run לא מחויבים כשלא משתמשים בשירות, אבל יכול להיות שתחויבו על אחסון קובץ האימג' של הקונטיינר ב-Artifact Registry. כשמוחקים פרויקט ב-Cloud, החיוב על כל המשאבים שנעשה בהם שימוש באותו פרויקט נפסק.
אם רוצים, מוחקים את הפרויקט:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
מומלץ גם למחוק משאבים מיותרים מהדיסק של Cloud Shell. אתם יכולים:
- מוחקים את ספריית הפרויקט של ה-codelab:
rm -rf ~/mcp-on-cloudrun
- אזהרה! אי אפשר לבטל את הפעולה הבאה! אם אתם רוצים למחוק את כל מה שיש ב-Cloud Shell כדי לפנות מקום, אתם יכולים למחוק את כל ספריית הבית. חשוב לוודא שכל מה שרוצים לשמור נשמר במקום אחר.
sudo rm -rf $HOME