۱. مقدمه
در این codelab، یاد خواهید گرفت که چگونه از Google Cloud Agent Registry و Agent Development Kit (ADK) برای کشف و فراخوانی پویا سرورهای Model Context Protocol (MCP) ثبتشده در زمان اجرا استفاده کنید و نیاز به پیکربندیهای ابزار و نقاط پایانی کدگذاریشده را ازبین ببرید.
این آزمایشگاه از ADK و زبان برنامهنویسی Python برای ساختن برنامه استفاده میکند. همین اصول را میتوان در زبانهای برنامهنویسی دیگر و بااستفاده از چارچوبهای توسعه عامل دیگر اعمال کرد.
آنچه انجام خواهید داد
- فعال و پیکربندی کردن Google Cloud Agent Registry در پروژه شما
- مستقر کردن سرور MCP در Cloud Run و ثبت کردن آن در Agent Registry
- ساختن عامل ADK که سرور MCP را بااستفاده از نشانی وب کدگذاریشده فراخوانی میکند
- عامل را تغییر دهید تا سرور MCP را در «دفتر ثبت عامل» براساس هویت آن کاوش کند
- تغییر دادن عامل برای کشف سرورهای MCP در زمان اجرا بااستفاده از جستجوی معنایی
آنچه نیاز خواهید داشت
- مرورگر وب مدرن (مانند Chrome)
- پروژه Google Cloud با صورتحساب فعالشده
- حسابی با اجازههای ایجاد و مدیریت منابع و پیکربندی خطمشیهای IAM در پروژه Google Cloud
۲. راهاندازی محیط
دستورالعملهای این codelab فرض میکنند که شما فرمانها را در Cloud Shell در کنسول Google Cloud اجرا میکنید. Cloud Shell محیطی با خط فرمان است که در Google Cloud اجرا میشود و ابزارهای لازم ازقبل در آن بار شده است. اگر gcloud CLI، git و Python 3 را در محیط محلی خود نصب کردهاید، میتوانید فرمانها را در آنجا نیز اجرا کنید.
ایجاد پروژه Google Cloud
- در کنسول Google Cloud، در صفحه انتخابگر پروژه، پروژه Google Cloud ایجاد کنید.
- مطمئن شوید که صورتحساب برای پروژه Cloud شما فعال باشد. با نحوه بررسی فعال بودن صورتحساب در پروژه آشنا شوید.
راهاندازی پایانه Cloud Shell
- بااستفاده از انتخابگر منبع پروژه Google Cloud را که ایجاد کردهاید انتخاب کنید.
- روی فعالسازی Cloud Shell
در بالای کنسول Google Cloud کلیک کنید.
- پساز اتصال به Cloud Shell، اصالتسنجیتان را درستیسنجی کنید:
gcloud auth list - تأیید کنید که پروژهتان پیکربندی شده است:
gcloud config get project - اگر پروژه شما طبق انتظار تنظیم نشده است یا اگر بهجای Cloud Shell از محیطی در دستگاه محلیتان استفاده میکنید، شناسه پروژه را تنظیم کنید:
export GOOGLE_CLOUD_PROJECT=<YOUR_PROJECT_ID> gcloud config set project "${GOOGLE_CLOUD_PROJECT}"
انتخاب پروژه Google Cloud و تنظیم متغیرهای محیطی
- میاناهای برنامهسازی کاربردی Google Cloud موردنیاز را فعال کنید:
gcloud services enable \ agentregistry.googleapis.com \ aiplatform.googleapis.com \ cloudbuild.googleapis.com \ run.googleapis.com \ --project="${GOOGLE_CLOUD_PROJECT}"
راهاندازی محیط Python
- محیط مجازی ایجاد و فعال کنید و وابستگیهای لازم را نصب کنید:
mkdir -p adk-dynamic-discovery && cd adk-dynamic-discovery python3 -m venv .venv source .venv/bin/activate pip install "fastmcp<5.0.0" "google-adk[mcp,a2a,agent-identity]>=2.5.0,<3.0.0"
۳. ایجاد و ثبت کردن سرور Zoo MCP
در این مرحله، سرور Zoo MCP را ایجاد و ثبت میکنید. سرور سه ابزار را ارائه میدهد: list_species ‒ فهرست کردن همه گونههایی که در باغوحش زندگی میکنند، get_animals_by_species ‒ فهرست کردن حیوانات یک گونه خاص، و get_animal_details ‒ دریافت اطلاعات بیشتر درباره یک حیوان خاص.
میتوانید همه فایلهای این مرحله را در GitHub پیدا کنید.
سرور MCP را ایجاد کنید
- راهاندازی پوشه و پروژه Python برای سرور MCP
mkdir mcp-on-cloudrun && cd mcp-on-cloudrun uv init --description "Example of deploying an MCP server on Cloud Run" --bare --python 3.13 uv add "fastmcp<5.0.0" --no-sync - کد سرور MCP را بارگیری کنید:
curl -fsSL https://raw.githubusercontent.com/GoogleCloudPlatform/devrel-demos/main/codelabs/agent-registry-dynamic-discovery-with-adk/steps/step3/server.py -o server.py
مستقر کردن سرور MCP در Cloud Run و ثبت کردن در Agent Registry
سپس، Dockerfile را برای سرور ایجاد میکنید و سرور را در Cloud Run مستقر میکنید.
- ایجاد کردن
Dockerfile:cat << EOF > 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 # Run the FastMCP server CMD ["uv", "run", "server.py"] EOF - حساب سرویس تعیینشدهای برای سرور ایجاد کنید:
gcloud iam service-accounts create zoo-mcp-server-sa \ --display-name="Zoo MCP Server Service Account" - سرور را در منطقه
us-west1پیادهسازی کنید. اگر پیامواره زیر را میبینید، ایجاد مخزن Artifact Registry جدید را تأیید کنید. اگر مخزن Artifact Registry در پروژه شما برای منطقهgcloud run deploy zoo-mcp-server \ --service-account=zoo-mcp-server-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --region=us-west1 \ --source=. \ --labels=dev-tutorial=codelab-dynamic-mcp-discovery \ --invoker-iam-check \ --no-allow-unauthenticatedus-west1وجود نداشته باشد، این پیامواره نشان داده خواهد شد: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)? - ثبت کردن سرور MCP در «دفتر ثبت عامل» در مکان «جهانی»:
این فرمانهاfastmcp inspect server.py --format mcp | jq 'del(..|nulls) | del(.tools[]?._meta?)' > toolspec.json MCP_URL=$(gcloud run services describe zoo-mcp-server --region=us-west1 --format='value(status.url)') gcloud agent-registry services create zoo-mcp-server \ --display-name="zoo-mcp-server" \ --project="${GOOGLE_CLOUD_PROJECT}" \ --location=global \ --mcp-server-spec-type="tool-spec" \ --mcp-server-spec-content="toolspec.json" \ --interfaces="url=${MCP_URL}/mcp,protocolBinding=jsonrpc"toolspec.jsonرا با مانیفست ابزار تولید میکنند و برای ثبت سرور، Agent Registry API را فراخوانی میکنند. - تأیید کنید که نماینده در دفتر ثبت ظاهر میشود:
برونداد YAML را با اطلاعات سرور MCP بهاینصورت خواهید دید:gcloud agent-registry mcp-servers list \ --location=global \ --filter="display_name=zoo-mcp-server"--- attributes: agentregistry.googleapis.com/system/RuntimeReference: uri: //agentregistry.googleapis.com/projects/[PROJECT_NUMBER]/locations/global/services/zoo-mcp-server createTime: '<create time datetime in ISO 8601>' displayName: zoo-mcp-server interfaces: - protocolBinding: JSONRPC url: https://zoo-mcp-server-[PROJECT_NUMBER].us-west1.run.app/mcp mcpServerId: urn:mcp:projects-[PROJECT_NUMBER]:projects:[PROJECT_NUMBER]:locations:global:agentregistry:services:zoo-mcp-server name: projects/[PROJECT_ID]/locations/global/mcpServers/agentregistry-00000000-0000-0000-1234-56789abcdef tools: - annotations: idempotentHint: true readOnlyHint: true description: |- Returns every species in the zoo. Use it first for zoo-wide questions such as counting all animals or listing everything the zoo has. name: list_species - annotations: idempotentHint: true readOnlyHint: true description: |- 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. name: get_animals_by_species - annotations: idempotentHint: true readOnlyHint: true description: Retrieves the details of a specific animal by its name. name: get_animal_details updateTime: '<last updated datetime in ISO 8601>'
۴. ایجاد کردن عامل ADK پایه برای استفاده از سرور Zoo MCP
در این مرحله، یک عامل ADK ایجاد میکنید تا با کمک نشانی وب کدگذاریشده سرور Zoo MCP به درخواستهای کاربر درباره باغوحش پاسخ دهد. کدگذاری سخت شما را ملزم میکند که URL سرور MCP را پیشاز استقرار عامل بدانید.
فایلهای منبع این مرحله را میتوانید در GitHub پیدا کنید.
ایجاد برنامه عامل
یک داربست از پروژه ADK و عامل Zoo که از سرور Zoo MCP استفاده میکند ایجاد کنید.
- پوشه و پروژهای برای عامل Zoo راهاندازی کنید:
mkdir ../sample-agent && cd ../sample-agent uv init --description "Example of ADK agent to showcase dynamic MCP discovery" --bare --python 3.13 uv add "google-adk[mcp,a2a,agent-identity]>=2.5.0,<3.0.0" --no-sync - پوشه بسته عامل را ایجاد کنید و فایل
__init__.pyرا بارگیری کنید:mkdir zoo_agent curl -fsSL https://raw.githubusercontent.com/GoogleCloudPlatform/devrel-demos/main/codelabs/agent-registry-dynamic-discovery-with-adk/steps/step4/zoo_agent/__init__.py -o zoo_agent/__init__.py - فایل
.envرا ایجاد کنید و آن را با متغیرهای محیطی که در این مرحله و مراحل بعدی استفاده میشوند پر کنید: این فرمان همه متغیرهای محیطی موردنیاز در این مرحله و مراحل اکتشاف بعدی را درMCP_URL=$(gcloud run services describe zoo-mcp-server --region=us-west1 --format='value(status.url)') cat << EOF > zoo_agent/.env GOOGLE_GENAI_USE_ENTERPRISE=TRUE GOOGLE_CLOUD_LOCATION=global GOOGLE_CLOUD_PROJECT="${GOOGLE_CLOUD_PROJECT}" GOOGLE_CLOUD_PROJECT_NUMBER=$(gcloud projects describe ${GOOGLE_CLOUD_PROJECT} \ --format='value(projectNumber)') MCP_SERVER_URL="${MCP_URL}" EOFzoo_agent/.envمینویسد، بنابراین نیازی نیست بعداً فایل را دوباره ایجاد کنید. در این مرحله، از متغیرهای زیر استفاده میشود:GOOGLE_GENAI_USE_ENTERPRISE،GOOGLE_CLOUD_PROJECT، وGOOGLE_CLOUD_LOCATION: بهطور ضمنی توسط ADK و Google GenAI SDK برای مسیریابی تماسهای مدل Gemini ازطریق Vertex AI در پروژه و مکان Google Cloud شما (global) استفاده میشود. همچنین مکان Agent Registry را که سرور MCP در آن ثبت شده است ذخیره میکند.-
GOOGLE_CLOUD_PROJECT_NUMBER: در این مرحله استفاده نمیشود؛ در اینجا ازپیش تکمیل شده است تا در مرحله بعدی استفاده شود. -
MCP_SERVER_URL: مستقیماً درzoo_agent/agent.pyبخوانید تاMcpToolsetرا با URL کدگذاریشده Cloud Run سرور Zoo MCP پیکربندی کنید.
agent.pyرا با کد مربوط به عامل Zoo که به سرور MCP Zoo متصل میشود بارگیری کنید:curl -fsSL https://raw.githubusercontent.com/GoogleCloudPlatform/devrel-demos/main/codelabs/agent-registry-dynamic-discovery-with-adk/steps/step4/zoo_agent/agent.py -o zoo_agent/agent.py
نحوه عملکرد صدور مجوز سرور MCP
چون سرویس Cloud Run zoo-mcp-server با پرچمهای --invoker-iam-check و --no-allow-unauthenticated مستقر شده است، هر درخواست HTTP به سرور MCP باید شامل یک شناسه کاربری امضاشده توسط Google در سرصفحه Authorization باشد. این توکن باید تماسگیرندهای را شناسایی کند که در سرویس اجازه run.routes.invoke دارد.
در zoo_agent/agent.py، کلاس _GoogleAuthHeaders اعتبارنامه توکن شناسه را به یکی از دو روش دریافت میکند. ابتدا fetch_id_token_credentials() را فراخوانی میکند تا یک شناسه برای نشانی وب سرویس از سرور فراداده یا کلید حساب سرویس دریافت کند. اگر این کار ناموفق باشد، از شناسه ژتون اعتبارنامه پیشفرض برنامه (ADC) کاربر شما استفاده میکند. هربار که نمونه فراخوانی میشود، درصورت لزوم کد را بازآوری میکند و سرایند Authorization را برمیگرداند:
class _GoogleAuthHeaders:
def __init__(self, audience: str):
self._request = Request()
self._id_token = False
try:
self._credentials = id_token.fetch_id_token_credentials(audience, request=self._request)
except exceptions.DefaultCredentialsError:
self._credentials, _ = google.auth.default()
self._id_token = True
if not isinstance(self._credentials, credentials.Credentials):
raise
def __call__(self, unused_context: ReadonlyContext | None = None) -> dict[str, str]:
if not self._credentials.valid or (self._id_token and not self._credentials.id_token):
self._credentials.refresh(self._request)
token = self._credentials.id_token if self._id_token else self._credentials.token
return {"Authorization": f"Bearer {token}"}
عامل نمونهای از کلاس را بهعنوان آرگومان header_provider به McpToolset ارسال میکند. ADK ارائهدهنده سرایند را فراخوانی میکند و سرایندهایی را که برمیگرداند به هر درخواست به سرور MCP پیوست میکند. چون کارخواه HTTP توسط ADK ایجاد میشود، همان کد بدون توجه به اینکه کدام نسخه از MCP Python SDK و کتابخانه HTTP آن نصب شده است کار میکند:
zoo_mcp_toolset = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url=f"{MCP_SERVER_URL}/mcp",
timeout=30.0,
),
header_provider=_GoogleAuthHeaders(MCP_SERVER_URL),
)
مخاطب درخواستشده نشانی وب سرویس (MCP_SERVER_URL) است، درحالیکه نشانی وب اتصال شامل مسیر /mcp است که سرور FastMCP پروتکل MCP را ارائه میدهد. مهلت ۳۰ ثانیهای برای شروع سرد Cloud Run فضا ایجاد میکند.
آزمایش کردن عامل بااستفاده از زمین بازی ADK در محیط محلی
قبلاز آزمایش کردن نماینده، مطمئن شوید که حساب کاربریتان میتواند سرور MCP را فراخوانی کند.
- فقط پایانه محلی (از این مرحله در Cloud Shell رد شوید): ADC را با اطلاعات کاربری کاربرتان مقداردهی اولیه کنید:
دستورالعملها را برای تکمیل مقداردهی اولیه ADC دنبال کنید.gcloud auth application-default login - (اختیاری) به حساب کاربریتان اجازه دهید سرور MCP راه دور را فراخوانی کند:
gcloud run services add-iam-policy-binding zoo-mcp-server \ --region=us-west1 \ --project=${GOOGLE_CLOUD_PROJECT} \ --member=user:$(gcloud config get-value account) \ --role='roles/run.invoker' - عاملتان را با فرمان
adk runاجرا کنید: یا میانای وب ADK را با فرمانadk run zoo_agentadk webاجرا کنید: و سپس نشانی وبی را که فرمان در مرورگر چاپ میکند باز کنید.اگر از Cloud Shell استفاده میکنید، آرگومانadk web --port 8080--allow_originsرا اضافه کنید تا باز کردن میانای وب از Cloud Shell مجاز شود: پساز اجرای فرمان، نماد پیشنمایش وبadk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"
را در نوار ابزار Cloud Shell (سمت راست) پیدا کنید. روی آن کلیک کنید و پیشنمایش در درگاه ۸۰۸۰ را انتخاب کنید. Cloud Shell زبانه مرورگر جدیدی باز میکند که میانای وب ADK را نمایش میدهد. - گپ زدن با نماینده را شروع کنید. برای مثال، درباره حیوانات باغوحش از آن بپرسید:
عاملHow many animals are in the zoo?list_speciesو سپسget_animals_by_speciesرا برای هر گونه فراخوانی میکند تا پاسخ را محاسبه کند.
میانای وب ADK به شما امکان میدهد نحوه عملکرد عامل را کاوش کنید، ازجمله تماسهای آن با سرور MCP باغوحش. برای آشنایی با نحوه انجام این کار، به اسناد میانای کاربری وب مراجعه کنید.
۵. نقطه پایان سرور MCP را بهطور پویا پیدا کنید
در این مرحله، عامل را تغییر میدهید تا نقطه پایان سرور Zoo MCP ثبتشده در Agent Registry را بهجای کدگذاری سخت نشانی وب نقطه پایان آن کشف کند.
میتوانید همه فایلهای این مرحله را در GitHub پیدا کنید.
برای پیدا کردن و بازیابی نشانی وب سرور، از ادغام ADK با Agent Registry استفاده میکنید. برای پیادهسازی آن به اطلاعات زیر نیاز دارید:
- شماره پروژه و مکان Agent Registry که سرور MCP شما در آن ثبت شده است (
global). - شناسه سرویسی که برای ثبت سرور MCP استفاده کردید (
zoo-mcp-server).
بهروزرسانی نماینده برای استفاده از «دفتر ثبت نماینده»
- فایل
agent.pyبهروزشده را از GitHub بارگیری کنید تا نسخه اول نماینده را لغو کنید:curl -fsSL https://raw.githubusercontent.com/GoogleCloudPlatform/devrel-demos/main/codelabs/agent-registry-dynamic-discovery-with-adk/steps/step5/zoo_agent/agent.py -o zoo_agent/agent.pyمتغیرهای محیط در این مرحله
با این بهروزرسانی، عامل به متغیرهای محیطی زیر ازzoo_agent/.envمتکی است:GOOGLE_CLOUD_PROJECT_NUMBER: اکنون برای ساختن URN هویت سرور MCP (MCP_SERVER_URN) لازم است.-
GOOGLE_CLOUD_PROJECT،GOOGLE_GENAI_USE_ENTERPRISE، وGOOGLE_CLOUD_LOCATION: ADK از این نقشها برای پیکربندی دسترسی به Vertex AI استفاده میکند. از مکان برای پیدا کردن سرور MCP نیز استفاده میشود. - دیگر لازم نیست:
MCP_SERVER_URLدیگر استفاده نمیشود زیرا عامل نشانی وب نقطه پایانی سرور MCP را از «دفتر ثبت عامل» بازیابی میکند و آن را از محیط نمیخواند.
نحوه عملکرد هویت و کاوش سرور MCP در
در «دفتر ثبت عامل»، هر سرور MCP ثبتشده دارای یک شناسه منحصربهفرد است که در فیلدAgentRegistrymcpServerIdآن ذخیره شده و بهصورت «نام منبع یکسان» (URN) قالببندی شده است. میتوانید آن را در خروجی فرمانgcloud agent-registry mcp-servers listدر «مرحله ۳» ببینید. عامل این شناسه را از متغیرهای محیطی بازسازی میکند: URN شماره پروژه دفتر ثبت (PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] PROJECT_NUMBER = os.environ["GOOGLE_CLOUD_PROJECT_NUMBER"] LOCATION = os.environ.get("GOOGLE_CLOUD_LOCATION", "global") MCP_SERVER_URN = f"urn:mcp:projects-{PROJECT_NUMBER}:projects:{PROJECT_NUMBER}:locations:{LOCATION}:agentregistry:services:zoo-mcp-server"projects-{PROJECT_NUMBER})، شماره پروژه و مکانی که سرور در آن ثبت شده است (projects:{PROJECT_NUMBER}:locations:{LOCATION})، و شناسه سرویسی را که در فرمانgcloud agent-registry services createاستفاده کردهاید (agentregistry:services:zoo-mcp-server) کدگذاری میکند. عامل سرورهای MCP ثبتشده را باregistry.list_mcp_servers()فهرست میکند وmcpServerIdهر سرور را باMCP_SERVER_URNمطابقت میدهد. سپس منبع سرور منطبقname(projects/.../locations/.../mcpServers/...) را بهregistry.get_mcp_toolset()ارسال میکند، که نشانی وب نقطه پایان را از میانای ثبتشده سرور (https://...run.app/mcp) میخواند و یکMcpToolsetمتصل به آن نشانی وب برمیگرداند:header_provider = _GoogleAuthHeaders() registry = AgentRegistry( project_id=PROJECT_ID, location=LOCATION, header_provider=header_provider, ) mcp_server_name = next( ( s["name"] for s in registry.list_mcp_servers().get("mcpServers", []) if s.get("mcpServerId") == MCP_SERVER_URN ), None, ) if not mcp_server_name: raise RuntimeError(f"MCP server '{MCP_SERVER_URN}' not found in Agent Registry.") zoo_mcp_toolset = registry.get_mcp_toolset(mcp_server_name=mcp_server_name) header_provider.bind(zoo_mcp_toolset.connection_params.url) zoo_mcp_toolset.connection_params.timeout = 30.0get_mcp_toolset()نام نمایشی سرور را بهعنوان پیشوند به نام ابزارها اضافه میکند، بنابراین نماینده ابزارها را بهصورتzoo_mcp_server_list_species،zoo_mcp_server_get_animals_by_species، وzoo_mcp_server_get_animal_detailsمیبیند. این پیشوند از تداخل نامها در زمانی که عامل از ابزارهای چند سرور MCP استفاده میکند جلوگیری میکند. خط آخر زمان اتمام اتصال را از مقدار پیشفرض ۵ ثانیه افزایش میدهد تا فضایی برای راهاندازی سرد Cloud Run باقی بماند.نحوه تغییر مجوز با
AgentRegistryAgentRegistryفراخوانیهای میانای برنامهسازی کاربردی خود را، مانندlist_mcp_servers()، با ADC اصالتسنجی میکند، بنابراین ارائهدهنده سرصفحه فقط برای فراخوانیهای سرور MCP کشفشده لازم است. چونAgentRegistryبهطور داخلیMcpToolsetرا ایجاد میکند، ارائهدهنده سرصفحه را به سازندهAgentRegistryارسال میکنید.در مرحله قبل، مخاطب مقدارMCP_SERVER_URLبود که ازقبل میدانستید. اکنون نشانی وب فقط پساز کاوش شناخته میشود. وقتی عامل درخواستی به سرور MCP ارسال میکند، ADK ارائهدهنده سرایند را فراخوانی میکند، نه وقتی کهAgentRegistryایجاد میشود. این کار به نماینده اجازه میدهد ابتدا ارائهدهنده را ایجاد کند و پساز بازگشتget_mcp_toolset()آن را به نقطه پایانی کشفشده متصل کند. روشbind()اطلاعات کاربری را به همان روش سازنده در مرحله قبلی دریافت میکند، با مخاطبی که از نشانی وب نقطه پایانی کشفشده بدون مسیر/mcpگرفته شده است: روشdef bind(self, endpoint_url: str) -> None: parsed = urlparse(endpoint_url) audience = f"{parsed.scheme}://{parsed.netloc}" try: self._credentials = id_token.fetch_id_token_credentials(audience, request=self._request) except exceptions.DefaultCredentialsError: self._credentials, _ = google.auth.default() self._id_token = True if not isinstance(self._credentials, credentials.Credentials): raise__call__همانند مرحله قبلی است، با این تفاوت که اگر قبلازbind()فراخوانی شود، خطایی ایجاد میکند. - نمایندهتان را اجرا کنید تا تغییر را آزمایش کنید. از فرمان
adk runاستفاده کنید: یا میانای وب ADK را با فرمانadk run zoo_agentadk webاجرا کنید: و سپس نشانی وبی را که فرمان در مرورگر چاپ میکند باز کنید.اگر از Cloud Shell استفاده میکنید، آرگومانadk web --port 8080--allow_originsرا اضافه کنید تا باز کردن میانای وب از Cloud Shell مجاز شود: همان سؤال مرحله قبل را از نماینده بپرسید. پاسخ یکسان است، اما در میانای وب ADK، فراخوانیهای ابزار اکنون بهصورتadk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"zoo_mcp_server_list_speciesوzoo_mcp_server_get_animals_by_speciesنشان داده میشوند.
این تغییر به شما امکان میدهد نیاز به URL صریح سرور MCP را دور بزنید. بااینحال، همچنان باید شماره پروژه، مکان ثبت، و شناسه سرویس مورداستفاده برای ثبت سرور MCP را بدانید و فرایند کشف بهصورت ایستا درطول مقداردهی اولیه کارگزار انجام میشود.
۶. استفاده از جستجوی معنایی برای سرور MCP در اکتشاف پویا
در این مرحله، کاوش پویای سرور MCP را با جایگزین کردن تطابق دقیق URN در راهاندازی با جستجوی معنایی زمان اجرا بهبود میبخشید. این رویکرد نیاز به دانستن شماره پروژه محل استقرار سرور یا هویت دقیق سرور (MCP_SERVER_URN) را ازبین میبرد و کاوش ابزار را مستقیماً در گردش کار زمان اجرای استاندارد عامل ادغام میکند، بهجای اینکه آن را در مرحله مقداردهی اولیه مدیریت کند.
میتوانید همه فایلهای این مرحله را در GitHub پیدا کنید.
بهروزرسانی عامل برای استفاده از کاوش معنایی در زمان اجرا
- فایل
agent.pyبهروزشده را از GitHub بارگیری کنید تا روی پیادهسازی موجود بازنویسی شود:curl -fsSL https://raw.githubusercontent.com/GoogleCloudPlatform/devrel-demos/main/codelabs/agent-registry-dynamic-discovery-with-adk/steps/step6/zoo_agent/agent.py -o zoo_agent/agent.pyمتغیرهای محیط در این مرحله
چون نماینده دیگر URN سرور MCP را نمیسازد، پیکربندی موردنیاز بیشتر ساده میشود:-
GOOGLE_CLOUD_PROJECT،GOOGLE_GENAI_USE_ENTERPRISE، وGOOGLE_CLOUD_LOCATION: ADK از این نقشها برای پیکربندی دسترسی به Vertex AI استفاده میکند. از مکان برای پیدا کردن سرور MCP نیز استفاده میشود. - دیگر لازم نیست:
GOOGLE_CLOUD_PROJECT_NUMBERدیگر لازم نیست (علاوهبرMCP_SERVER_URLکه قبلاً در مرحله قبل برداشته شده است).
تغییر از تطبیق دقیق به جستجوی معنایی
بهجای فراخوانیregistry.list_mcp_servers()درطول مقداردهی اولیه ماژول و مقایسه هر ورودی باMCP_SERVER_URNساختهشده،agent.pyاکنون تابع ابزار اکتشافdiscover_zoo_mcp_serversرا تعریف میکند کهregistry.search_mcp_servers()را باsearch_type="SEMANTIC"فراخوانی میکند: این کار به عامل اجازه میدهد تا در زمان اجرا بااستفاده از شرح زبان طبیعی قابلیتهای موردنیازش (برای مثال،def discover_zoo_mcp_servers(query: str, tool_context: ToolContext) -> dict[str, Any]: """Discovers Zoo MCP server(s) matching the query using semantic search. Args: query: Semantic description of zoo capabilities needed (e.g. 'zoo animal info') """ cached = _fresh_discovery(tool_context.state) if cached: return { "status": "already_discovered", "message": "Zoo MCP servers are already discovered.", "servers": cached["servers"], } try: response = registry.search_mcp_servers( search_string=query, search_type="SEMANTIC", page_size=5, ) except Exception as e: return { "status": "error", "message": f"Agent Registry search failed: {e}", } found_servers = response.get("mcpServers", []) if not found_servers: return { "status": "not_found", "message": f"No MCP servers found in Agent Registry at {LOCATION} matching '{query}'.", } valid_servers = [s["name"] for s in found_servers if "name" in s] tool_context.state[DISCOVERY_STATE_KEY] = { "servers": valid_servers, "discovered_at": time.time(), } return { "status": "discovered", "message": f"Successfully discovered {len(valid_servers)} Zoo MCP server(s).", "servers": valid_servers, }"zoo animals, exhibits, habitat, care, feeding schedule") در Agent Registry جستجو کند و نامهای منبع سرور کشفشده را در وضعیت جلسه ADK ذخیره کند (tool_context.state).نحوه ادغام کاوش پویا در گردش کار نماینده
برای سوار کردن ابزارها از سرورهای کشفشده در زمان اجرا و راهنمایی کردن نماینده در جریان کشف و سپس فراخوانی،agent.pyپیادهسازیBaseToolsetسفارشی (RegistryDiscoveredToolset) را با ارائهدهنده دستورالعمل پویا (zoo_guide_instruction) ترکیب میکند:- مجموعه ابزار پویا (
RegistryDiscoveredToolset): زیرکلاسهایBaseToolsetو مجموعههایself._use_invocation_cache = Falseبهطوریکه ADK بلافاصله پساز اینکهdiscover_zoo_mcp_serversوضعیت جلسه را بهروز کرد، ابزارهای دردسترس را مجدداً ارزیابی میکند، بهجای اینکه فهرست ابزار خالی اولیه را ذخیره کند. وقتیget_tools()فراخوانی میشود، نامهای سرور کشفشده را از وضعیت میخواند، یکMcpToolsetاصالتسنجیشده برای هر سرور در رشته عامل میسازد، و همه ابزارهای فعال را برمیگرداند. اگر یک سرور دردسترس نباشد، بر سرورهای دیگر تأثیری نمیگذارد. _build_toolset()عملیات ورودی/خروجی مسدودکننده انجام میدهد، بنابراین_tools_of()آن را در رشته عامل اجرا میکند.class RegistryDiscoveredToolset(BaseToolset): def __init__(self, agent_registry: AgentRegistry): super().__init__() self._registry = agent_registry self._toolsets: dict[str, McpToolset] = {} self._use_invocation_cache = False def _build_toolset(self, server_name: str) -> McpToolset: header_provider = _GoogleAuthHeaders() server_registry = AgentRegistry( project_id=self._registry.project_id, location=self._registry.location, header_provider=header_provider, ) toolset = server_registry.get_mcp_toolset(server_name) header_provider.bind(toolset.connection_params.url) toolset.connection_params.timeout = 30.0 return toolset async def _tools_of(self, server_name: str, ctx: ReadonlyContext) -> list[BaseTool]: try: if server_name not in self._toolsets: self._toolsets[server_name] = await asyncio.to_thread( self._build_toolset, server_name ) return await self._toolsets[server_name].get_tools_with_prefix(ctx) except Exception as e: print(f"Skipping MCP server {server_name}: {e}") return [] async def get_tools(self, readonly_context: ReadonlyContext | None = None) -> list[BaseTool]: if not readonly_context: return [] record = _fresh_discovery(readonly_context.state) if not record or not record.get("servers"): if self._toolsets: await self.close() return [] per_server = await asyncio.gather( *(self._tools_of(name, readonly_context) for name in record["servers"]) ) return [tool for tools in per_server for tool in tools] - دستورالعمل پویای نماینده (
zoo_guide_instruction): وضعیت جلسه را قبلاز هر نوبت مدل ارزیابی میکند. وقتی هنوز هیچ سروری شناسایی نشده است،_DISCOVERY_PROMPTرا اضافه میکند و به نماینده دستور میدهد ابتداdiscover_zoo_mcp_serversرا فراخوانی کند. پساز موفقیتآمیز بودن کاوش، پیامواره را بهروز میکند تا سرورهای فعال MCP را فهرست کند و به عامل دستور میدهد که مستقیماً از ابزارهای باغوحش سوارشده استفاده کند، بدون اینکه کاوش را دوباره اجرا کند:def zoo_guide_instruction(ctx: ReadonlyContext) -> str: record = _fresh_discovery(ctx.state) if record is None: return _ROLE + _DISCOVERY_PROMPT return _ROLE + ( f"\nYour active Zoo MCP servers: {', '.join(record['servers'])}. " "Do not run discovery again; use the active zoo tools directly to fulfill the visitor's request." )
صدور مجوز برای سرورهای کشفشده بهصورت پویا
جستجوی معنایی میتواند چندین سرور را برگرداند و ADK یک ارائهدهنده سرصفحه را بدون اینکه به آن بگوید درخواست به کدام سرور میرود فراخوانی میکند. بنابراین،_build_toolset()برای هر سرور کشفشده یک_GoogleAuthHeadersوAgentRegistryاختصاصی ایجاد میکند و ارائهدهنده را به نقطه پایانی آن سرور متصل میکند. ارائهدهنده همان ارائهدهنده مرحله قبلی است، با پرچم_boundکه باعث میشود اگر قبلازbind()استفاده شود، ناموفق باشد.منطق نگهداری و بازآوری
برای جلوگیری از پرسمان «دفتر ثبت عامل» در هر نوبت و درعینحال بازآوری دورهای نقاط پایانی کشفشده،agent.pyحفظ وضعیت را با «زمان بقا» (TTL) پیادهسازی میکند:DISCOVERY_STATE_KEY = "app:zoo_mcp_servers" DISCOVERY_TTL_SECONDS = 24 * 60 * 60 def _fresh_discovery(state: Any) -> dict[str, Any] | None: if not state: return None record = state.get(DISCOVERY_STATE_KEY) if not record or not record.get("servers"): return None if time.time() - record.get("discovered_at", 0) > DISCOVERY_TTL_SECONDS: return None return record- حفظ داده در محدوده برنامه: نامهای سرور کشفشده و مُهر زمان
discovered_atدر وضعیت جلسه تحت کلیدapp:zoo_mcp_serversذخیره میشوند. استفاده از پیشوندapp:ADK، سابقه کاوش ذخیرهشده در حافظه نهان را در سراسر اجرای برنامه محدود میکند. - اعتبارسنجی TTL و بازآوری خودکار:
_fresh_discovery()تأیید میکند که سابقه ذخیرهشده وجود دارد و عمر آن ازDISCOVERY_TTL_SECONDS(۲۴ ساعت) بیشتر نیست. تا زمانی که رکورد تازه باشد،RegistryDiscoveredToolsetاز اتصالاتMcpToolsetذخیرهشده در حافظه نهان (self._toolsets) مجدداً استفاده میکند،zoo_guide_instructionپیامواره اکتشاف را حذف میکند، و هر تماس تکراری باdiscover_zoo_mcp_serversبلافاصله"already_discovered"را برمیگرداند. پساز منقضی شدن TTL ۲۴ ساعته،_fresh_discovery()مقدارNoneرا برمیگرداند که باعث میشودRegistryDiscoveredToolset.get_tools()جلسههای کارخواه MCP موجود (await self.close()) را ببندد وzoo_guide_instructionاز نماینده بخواهد که کاوش جدیدی انجام دهد.
-
- عاملتان را اجرا کنید تا گردش کار کاوش معنایی را آزمایش کنید. از فرمان
adk runاستفاده کنید: یا میانای وب ADK را با فرمانadk run zoo_agentadk webاجرا کنید: و سپس نشانی وبی را که فرمان در مرورگر چاپ میکند باز کنید.اگر از Cloud Shell استفاده میکنید، آرگومانadk web --port 8080--allow_originsرا اضافه کنید تا باز کردن میانای وب از Cloud Shell مجاز شود: وقتی از عامل سؤالی درباره باغوحش میپرسید (برای مثال،adk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"How many animals are in the zoo?)، مشاهده میکنید که ابتداdiscover_zoo_mcp_serversرا فراخوانی میکند، ابزارها را بهطور پویا از سرور MCP کشفشده سوار میکند، و سپس ابزارهای باغوحش، مانندzoo_mcp_server_list_speciesوzoo_mcp_server_get_animals_by_species، را برای پاسخ دادن به سؤال شما فراخوانی میکند.یک سؤال تکمیلی بپرسید، برای مثالWhich is the oldest lion?. نماینده بااستفاده از ابزارهای باغوحش که ازقبل سوار شدهاند پاسخ میدهد و دوبارهdiscover_zoo_mcp_serversرا فراخوانی نمیکند، زیرا سابقه کاوش در وضعیت جلسه هنوز تازه است.
۷. مرتبسازی
گزینه ۱: حذف پروژه
اگر پروژه اختصاصی برای این codelab ایجاد کردهاید، سادهترین راه برای حذف صورتحساب، حذف پروژه است:
gcloud projects delete "${GOOGLE_CLOUD_PROJECT}" --quiet
گزینه ۲: حذف منابع بهصورت تکی
اگر از پروژه موجودی استفاده کردهاید و میخواهید آن را نگه دارید، منابع تکی ایجادشده درطول این codelab را حذف کنید:
- ثبت سرور MCP را از «ثبت عامل» حذف کنید. چون سرور را بهصورت دستی ثبت کردهاید، حذف کردن سرویس Cloud Run ثبت را برنمیدارد:
gcloud agent-registry services delete zoo-mcp-server \ --location=global \ --project="${GOOGLE_CLOUD_PROJECT}" \ --quiet - سرویس سرور Cloud Run MCP را حذف کنید:
gcloud run services delete zoo-mcp-server \ --region=us-west1 \ --project="${GOOGLE_CLOUD_PROJECT}" \ --quiet - حساب سرویس ایجادشده برای سرور MCP را حذف کنید:
gcloud iam service-accounts delete \ "zoo-mcp-server-sa@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --project="${GOOGLE_CLOUD_PROJECT}" \ --quiet - اگر مخزن
cloud-run-source-deployArtifact Registry بهطور خاص درطول این codelab ایجاد شده است، آن را حذف کنید تا از هزینههای ذخیرهسازی تصویر محتوی جلوگیری شود:gcloud artifacts repositories delete cloud-run-source-deploy \ --location=us-west1 \ --project="${GOOGLE_CLOUD_PROJECT}" \ --quiet - درصورت تمایل، دایرکتوری پروژه محلی ایجادشده در Cloud Shell را بردارید:
cd ~ && rm -rf adk-dynamic-discovery
۸. تبریک میگوییم
در این codelab، نحوه کشف و استفاده پویا از سرورهای MCP با Google Cloud Agent Registry و Agent Development Kit (ADK) را یاد گرفتید:
- ثبت سرور MCP: یک سرور MCP امن را در Cloud Run مستقر کردید و آن را در Agent Registry ثبت کردید.
- کشف سرور MCP براساس هویت: نقطه پایان سرور MCP را بهجای کدگذاری ثابت نشانی وب آن، از «دفتر ثبت عامل» حل کرد.
- سرورهای MCP را بهصورت معنایی کشف کرد: به عامل اجازه میدهد ابزارهای MCP را در زمان اجرا بااستفاده از جستجوی زبان طبیعی، با حفظ و بازآوری، پیدا و سوار کند.