1. مقدمة
نظرة عامة
في هذا الدرس التطبيقي، ستنشئ خادم Model Context Protocol (MCP) وتنشره. تفيد خوادم MCP في منح النماذج اللغوية الكبيرة إمكانية الوصول إلى الأدوات والخدمات الخارجية. ستعمل على إعدادها كخدمة آمنة وجاهزة للإنتاج على Cloud Run يمكن الوصول إليها من أجهزة عملاء متعددة. بعد ذلك، ستتصل بخادم MCP البعيد من واجهة سطر الأوامر في Gemini.
الإجراءات التي ستنفذّها
سنستخدم FastMCP لإنشاء خادم MCP لحديقة الحيوانات يتضمّن أداتَين: get_animals_by_species
وget_animal_details
. يوفر FastMCP طريقة سريعة تستند إلى لغة Python لإنشاء خوادم وعملاء MCP.
أهداف الدورة التعليمية
- انشر خادم MCP على Cloud Run.
- يمكنك تأمين نقطة نهاية الخادم من خلال طلب المصادقة لجميع الطلبات، ما يضمن إمكانية تواصل العملاء والوكلاء المصرّح لهم فقط معها.
- الاتصال بنقطة نهاية خادم MCP الآمنة من واجهة سطر الأوامر في Gemini
2. إعداد المشروع
- إذا لم يكن لديك حساب على Google، عليك إنشاء حساب على Google.
- استخدام حساب شخصي بدلاً من حساب عمل أو حساب تديره مؤسسة تعليمية قد تتضمّن حسابات العمل والحسابات التي تديرها المؤسسة التعليمية قيودًا تمنعك من تفعيل واجهات برمجة التطبيقات اللازمة لهذا الدرس التطبيقي.
- سجِّل الدخول إلى Google Cloud Console.
- فعِّل الفوترة في Cloud Console.
- يجب أن تكلّف إكمال هذا المختبر أقل من دولار أمريكي واحد من موارد السحابة الإلكترونية.
- يمكنك اتّباع الخطوات في نهاية هذا المختبر لحذف الموارد وتجنُّب تحمّل المزيد من الرسوم.
- يمكن للمستخدمين الجدد الاستفادة من الفترة التجريبية المجانية بقيمة 300 دولار أمريكي.
- أنشئ مشروعًا جديدًا أو اختَر إعادة استخدام مشروع حالي.
3- فتح Cloud Shell Editor
- انقر على هذا الرابط للانتقال مباشرةً إلى محرّر Cloud Shell
- إذا طُلب منك منح الإذن في أي وقت اليوم، انقر على منح الإذن للمتابعة.
- إذا لم تظهر النافذة الطرفية في أسفل الشاشة، افتحها باتّباع الخطوات التالية:
- انقر على عرض.
- انقر على 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. تفعيل واجهات برمجة التطبيقات
في الوحدة الطرفية، فعِّل واجهات برمجة التطبيقات:
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 الخاص بحديقة الحيوانات
لتوفير سياق قيّم لتحسين استخدام النماذج اللغوية الكبيرة مع بروتوكول MCP، يمكنك إعداد خادم بروتوكول MCP في Zoo باستخدام FastMCP، وهو إطار عمل عادي للتعامل مع بروتوكول سياق النموذج. توفّر FastMCP طريقة سريعة لإنشاء خوادم وعملاء MCP باستخدام Python. يوفّر خادم MCP هذا بيانات حول الحيوانات في حديقة حيوانات وهمية. لتبسيط الأمر، نخزّن البيانات في الذاكرة. بالنسبة إلى خادم MCP للإنتاج، من المحتمل أنّك تريد تقديم بيانات من مصادر مثل قواعد البيانات أو واجهات برمجة التطبيقات.
- نفِّذ الأمر التالي لإضافة 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 الخاص بحديقة الحيوانات التالية في ملف
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
- أدرِج الرمز التالي في Dockerfile لاستخدام أداة
uv
لتشغيل ملفserver.py
:# 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
بعد أن تمكّنت من نشر خادم 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 في Cloud Shell
قد تحتاج إلى الضغط علىgemini
Enter
لقبول بعض الإعدادات التلقائية. - اطلب من Gemini إدراج أدوات MCP المتاحة له ضمن سياقه
/mcp
- اطلب من Gemini العثور على شيء في حديقة الحيوانات
يجب أن تعرف واجهة سطر الأوامر في Gemini كيفية استخدام خادم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_TOKEN
مرة أخرى.
- اكتب
/quit
ثم اضغط علىEnter
للخروج من Gemini CLI. - ضبط مشروعك في نافذة الأوامر
gcloud config set project [PROJECT_ID]
- أعِد بدء العملية من الخطوة 2 أعلاه.
9- (اختياري) التحقّق من استدعاءات الأدوات في سجلّات الخادم
للتأكّد من أنّه تم استدعاء خادم MCP في Cloud Run، راجِع سجلّات الخدمة.
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 إلى تسريع سير عملك للطلبات التي تنفّذها غالبًا من خلال إنشاء اختصار لطلب أطول.
يحوّل Gemini CLI تلقائيًا طلبات 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 بعيد وآمن والاتصال به.
المتابعة إلى المختبر التالي
هذا المختبر هو المختبر الأول في سلسلة من ثلاثة أجزاء. في الدرس التطبيقي الثاني، ستستخدم خادم MCP الذي أنشأته مع "وكيل حزمة تطوير البرامج الإعلانية".
استخدام خادم MCP على Cloud Run مع وكيل ADK
(اختياري) التنظيف
إذا لم تكن ستنتقل إلى المختبر التالي وأردت تنظيف ما أنشأته، يمكنك حذف مشروعك على السحابة الإلكترونية لتجنُّب تكبُّد رسوم إضافية.
على الرغم من أنّ Cloud Run لا يفرض رسومًا عندما لا تكون الخدمة قيد الاستخدام، قد يتم تحصيل رسوم منك مقابل تخزين صورة الحاوية في Artifact Registry. يؤدي حذف مشروعك على السحابة الإلكترونية إلى إيقاف الفوترة لجميع الموارد المستخدَمة في هذا المشروع.
إذا أردت، يمكنك حذف المشروع باتّباع الخطوات التالية:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
يمكنك أيضًا حذف الموارد غير الضرورية من قرص cloudshell. يمكنك إجراء ما يلي:
- احذف دليل مشروع الدرس البرمجي:
rm -rf ~/mcp-on-cloudrun
- تحذير! لا يمكن التراجع عن هذا الإجراء. إذا أردت حذف كل المحتوى على Cloud Shell لإخلاء بعض المساحة، يمكنك حذف دليلالمنزل بأكمله. يُرجى التأكّد من حفظ كل ما تريد الاحتفاظ به في مكان آخر.
sudo rm -rf $HOME