1. Giriş
Bu codelab'de, çalışma zamanında kayıtlı Model Context Protocol (MCP) sunucularını dinamik olarak keşfetmek ve çağırmak için Google Cloud Agent Registry ve Agent Development Kit'i (ADK) nasıl kullanacağınızı öğreneceksiniz. Böylece, sabit kodlu uç noktaları ve araç yapılandırmalarını ortadan kaldırabilirsiniz.
Bu laboratuvarda, uygulama oluşturmak için ADK ve Python programlama dili kullanılır. Aynı ilkeler diğer programlama dillerinde ve diğer temsilci geliştirme çerçevelerinde de uygulanabilir.
Yapacaklarınız
- Projenizde Google Cloud Agent Registry'yi etkinleştirme ve yapılandırma
- Cloud Run'a MCP sunucusu dağıtma ve Agent Registry'ye kaydetme
- Sabit kodlu bir URL kullanarak MCP sunucusunu çağıran bir ADK temsilcisi oluşturma
- Temsilciyi, Agent Registry'deki MCP sunucusunu kimliğine göre bulacak şekilde değiştirin.
- Temsilciyi, semantik aramayı kullanarak çalışma zamanında MCP sunucularını keşfedecek şekilde değiştirme
İhtiyacınız olanlar
- Modern bir web tarayıcısı (ör. Chrome)
- Faturalandırmanın etkin olduğu bir Google Cloud projesi
- Google Cloud projesinde kaynak oluşturma ve yönetme ile IAM politikalarını yapılandırma izinlerine sahip bir hesap
2. Ortamınızı ayarlama
Bu codelab'deki talimatlarda, komutları Google Cloud Console'daki Cloud Shell'de çalıştırdığınız varsayılır. Cloud Shell, Google Cloud'da çalışan ve gerekli araçların önceden yüklendiği bir komut satırı ortamıdır. Yerel ortamınızda gcloud CLI, git ve Python 3 yüklüyse komutları orada da çalıştırabilirsiniz.
Google Cloud projesi oluşturma
- Google Cloud Console'da, proje seçici sayfasında bir Google Cloud projesi oluşturun.
- Cloud projeniz için faturalandırmanın etkinleştirildiğinden emin olun. Bir projede faturalandırmanın etkin olup olmadığını nasıl kontrol edeceğinizi öğrenin.
Cloud Shell terminali başlatma
- Kaynak seçiciyi kullanarak oluşturduğunuz Google Cloud projesini seçin.
- Google Cloud konsolunun üst kısmından Activate Cloud Shell (Cloud Shell'i etkinleştir)
simgesini tıklayın.
- Cloud Shell'e bağlandıktan sonra kimlik doğrulamanızı doğrulayın:
gcloud auth list - Projenizin yapılandırıldığını doğrulayın:
gcloud config get project - Projeniz beklendiği gibi ayarlanmadıysa veya Cloud Shell yerine yerel makinenizde bir ortam kullanıyorsanız proje kimliğini ayarlayın:
export GOOGLE_CLOUD_PROJECT=<YOUR_PROJECT_ID> gcloud config set project "${GOOGLE_CLOUD_PROJECT}"
Google Cloud projesi seçme ve ortam değişkenlerini ayarlama
- Gerekli Google Cloud API'lerini etkinleştirin:
gcloud services enable \ agentregistry.googleapis.com \ aiplatform.googleapis.com \ cloudbuild.googleapis.com \ run.googleapis.com \ --project="${GOOGLE_CLOUD_PROJECT}"
Python ortamını ayarlama
- Sanal ortam oluşturup etkinleştirin ve gerekli bağımlılıkları yükleyin:
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"
3. Zoo MCP sunucusu oluşturma ve kaydetme
Bu adımda bir Zoo MCP sunucusu oluşturup kaydedeceksiniz. Sunucu üç araç sunar: list_species (hayvanat bahçesinde yaşayan tüm türleri listeler), get_animals_by_species (belirli bir türün hayvanlarını listeler) ve get_animal_details (belirli bir hayvan hakkında ek bilgi alır).
Bu adımla ilgili tüm dosyaları GitHub'da bulabilirsiniz.
MCP sunucusunu oluşturma
- MCP sunucusu için bir klasör ve Python projesi oluşturun
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 sunucu kodunu indirin:
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 sunucusunu Cloud Run'a dağıtma ve Agent Registry'ye kaydetme
Ardından, sunucu için Dockerfile oluşturacak ve sunucuyu Cloud Run'a dağıtacaksınız.
Dockerfileoluşturun: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- Sunucu için özel hizmet hesabı oluşturun:
gcloud iam service-accounts create zoo-mcp-server-sa \ --display-name="Zoo MCP Server Service Account" - Sunucuyu
us-west1bölgesine dağıtın. Aşağıdaki istemi görürseniz yeni bir Artifact Registry deposu oluşturma işlemini onaylayın. Projenizdegcloud 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-west1bölgesi için Artifact Registry deponuz yoksa bu istem gösterilir: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 sunucusunu Agent Registry'de "global" konumda kaydedin:
Bu komutlar, araç manifestiylefastmcp 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.jsonoluşturur ve sunucuyu kaydetmek için Agent Registry API'yi çağırır. - Aracının kayıt defterinde göründüğünü doğrulayın:
MCP sunucusu bilgilerini içeren YAML çıkışını görürsünüz: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>'
4. Zoo MCP sunucusunu kullanmak için temel bir ADK temsilcisi oluşturma
Bu adımda, sabit kodlu Zoo MCP sunucusu URL'sinin yardımıyla kullanıcıların hayvanat bahçesiyle ilgili isteklerini yanıtlamak için bir ADK aracısı oluşturacaksınız. Sabit kodlama, temsilci dağıtılmadan ÖNCE MCP sunucusunun URL'sini bilmenizi gerektirir.
Bu adımın kaynak dosyalarını GitHub'da bulabilirsiniz.
Temsilci uygulamasını oluşturma
ADK projesinin ve Zoo MCP sunucusunu kullanan Zoo temsilcisinin iskeletini oluşturun.
- Hayvanat bahçesi temsilcisi için bir klasör ve proje oluşturun:
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 - Aracı paketi klasörünü oluşturun ve
__init__.pydosyasını indirin: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 .envdosyasını oluşturun ve bu adımda ve sonraki adımlarda kullanılan ortam değişkenleriyle doldurun: Bu komut, bu adımda ve sonraki keşif adımlarında gerekli olan tüm ortam değişkenleriniMCP_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/.envdosyasına yazar. Bu sayede, dosyayı daha sonra yeniden oluşturmanız gerekmez. Bu adımda aşağıdaki değişkenler kullanılır:GOOGLE_GENAI_USE_ENTERPRISE,GOOGLE_CLOUD_PROJECTveGOOGLE_CLOUD_LOCATION: ADK ve Google GenAI SDK tarafından, Gemini model çağrılarını Google Cloud projenizdeki ve konumunuzdaki (global) Vertex AI üzerinden yönlendirmek için dolaylı olarak kullanılır. Ayrıca, MCP sunucusunun kayıtlı olduğu Agent Registry konumunu da depolar.GOOGLE_CLOUD_PROJECT_NUMBER: Bu adımda kullanılmaz. Bir sonraki adımda kullanılmak üzere burada önceden doldurulur.MCP_SERVER_URL:McpToolset'yi Zoo MCP sunucusunun sabit kodlu Cloud Run URL'siyle yapılandırmak için doğrudanzoo_agent/agent.pydosyasını okuyun.
- Hayvanat bahçesi MCP sunucusuna bağlanan hayvanat bahçesi temsilcisinin kodunu içeren
agent.pydosyasını indirin: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 sunucusu yetkilendirmesinin işleyiş şekli
zoo-mcp-server Cloud Run hizmeti --invoker-iam-check ve --no-allow-unauthenticated işaretleriyle dağıtıldığından, MCP sunucusuna gönderilen her HTTP isteği Authorization üstbilgisinde Google tarafından imzalanmış bir kimlik jetonu içermelidir. Jeton, hizmette run.routes.invoke iznine sahip bir arayanı tanımlamalıdır.
zoo_agent/agent.py içinde, _GoogleAuthHeaders sınıfı kimlik jetonu kimlik bilgilerini iki yöntemden biriyle alır. İlk olarak, meta veri sunucusundan veya bir hizmet hesabı anahtarından hizmet URL'si için kimlik jetonu almak üzere fetch_id_token_credentials() çağrılır. Bu işlem başarısız olursa kullanıcı Uygulama Varsayılan Kimlik Bilgilerinizin (ADC) kimlik jetonunu kullanır. Örnek her çağrıldığında, gerekirse jetonu yeniler ve Authorization üstbilgisini döndürür:
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}"}
Temsilci, sınıfın bir örneğini header_provider bağımsız değişkeni olarak McpToolset yöntemine iletir. ADK, başlık sağlayıcıyı çağırır ve döndürdüğü başlıkları MCP sunucusuna gönderilen her isteğe ekler. HTTP istemcisi ADK tarafından oluşturulduğundan, MCP Python SDK'sının ve HTTP kitaplığının hangi sürümünün yüklü olduğuna bakılmaksızın aynı kod çalışır:
zoo_mcp_toolset = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url=f"{MCP_SERVER_URL}/mcp",
timeout=30.0,
),
header_provider=_GoogleAuthHeaders(MCP_SERVER_URL),
)
İstenen kitle, hizmet URL'sidir (MCP_SERVER_URL). Bağlantı URL'si ise FastMCP sunucusunun MCP protokolünü sunduğu /mcp yolunu içerir. 30 saniyelik zaman aşımı, Cloud Run'ın baştan başlatılması için yeterli bir süredir.
Yerel ortamınızda ADK Playground'u kullanarak temsilciyi test etme
Temsilciyi test etmeden önce kullanıcı hesabınızın MCP sunucusunu çağırabildiğinden emin olun.
- Yalnızca yerel terminal (Cloud Shell'de bu adımı atlayın): ADC'yi kullanıcı kimlik bilgilerinizle ilk kullanıma hazırlayın:
ADC başlatma işlemini tamamlamak için talimatları uygulayın.gcloud auth application-default login - (İsteğe bağlı) Kullanıcı hesabınıza uzak MCP sunucusunu çağırma izni verin:
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' - Temsilcinizi
adk runkomutuyla çalıştırın: veya ADK web arayüzünüadk run zoo_agentadk webkomutuyla çalıştırın: ve ardından komutun tarayıcıda yazdırdığı URL'yi açın.Cloud Shell kullanıyorsanız web arayüzünün Cloud Shell'den açılmasına izin vermek içinadk web --port 8080--allow_originsbağımsız değişkenini ekleyin: Komutu çalıştırdıktan sonra Cloud Shell araç çubuğunda (sağ tarafta) Web Önizlemeadk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"
simgesini bulun. Bu simgeyi tıklayın ve Preview on port 8080'i (8080 bağlantı noktasında önizle) seçin. Cloud Shell, ADK web arayüzünü gösteren yeni bir tarayıcı sekmesi açar. - Temsilciyle sohbet etmeye başlayın. Örneğin, hayvanat bahçesindeki hayvanlar hakkında soru sorabilirsiniz:
Temsilci, yanıtı hesaplamak için her tür içinHow many animals are in the zoo?list_speciesve ardındanget_animals_by_speciesaracını çağırır.
ADK web arayüzü, temsilcinin nasıl çalıştığını (hayvanat bahçesi MCP sunucusuna yaptığı çağrılar dahil) keşfetmenize olanak tanır. Nasıl yapılacağını öğrenmek için Web kullanıcı arayüzü belgelerine bakın.
5. MCP sunucusu uç noktasını dinamik olarak keşfetme
Bu adımda, temsilciyi, uç nokta URL'sini sabit kodlamak yerine Agent Registry'de kayıtlı Zoo MCP sunucusu uç noktasını keşfedecek şekilde değiştirirsiniz.
Bu adımla ilgili tüm dosyaları GitHub'da bulabilirsiniz.
Sunucunun URL'sini bulmak ve almak için Agent Registry ile ADK entegrasyonunu kullanırsınız. Bu özelliği uygulamak için aşağıdaki bilgilere ihtiyacınız vardır:
- MCP sunucunuzun kayıtlı olduğu Agent Registry'nin proje numarası ve konumu (
global). - MCP sunucusunu kaydetmek için kullandığınız hizmet kimliği (
zoo-mcp-server).
Temsilciyi, Temsilci Kayıt Defteri'ni kullanacak şekilde güncelleme
- Temsilcinin ilk sürümünü geçersiz kılmak için güncellenmiş
agent.pydosyasını GitHub'dan indirin: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.pyBu adımdaki ortam değişkenleri
Bu güncellemeyle birlikte temsilci,zoo_agent/.envüzerinden aşağıdaki ortam değişkenlerini kullanır:GOOGLE_CLOUD_PROJECT_NUMBER: Artık MCP sunucusunun kimlik URN'sini (MCP_SERVER_URN) oluşturmak için gereklidir.GOOGLE_CLOUD_PROJECT,GOOGLE_GENAI_USE_ENTERPRISEveGOOGLE_CLOUD_LOCATION: ADK tarafından Vertex AI erişimini yapılandırmak için kullanılır. Konum, MCP sunucusunu bulmak için de kullanılır.- Artık gerekli değil: Temsilci, MCP sunucusu uç nokta URL'sini ortamdan okumak yerine Agent Registry'den aldığı için
MCP_SERVER_URLartık kullanılmıyor.
Agent Registry'de, kayıtlı her MCP sunucusununAgentRegistryhizmetinde MCP sunucusu kimliği ve keşfinin işleyiş şeklimcpServerIdalanında depolanan ve Tekdüzen Kaynak Adı (URN) olarak biçimlendirilmiş benzersiz bir tanımlayıcısı vardır. Bu değeri, 3. adımdagcloud agent-registry mcp-servers listkomutunun çıkışında görebilirsiniz. Temsilci, bu tanımlayıcıyı ortam değişkenlerinden yeniden oluşturur: URN; kayıt defterinin proje numarasını (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}), sunucunun kayıtlı olduğu proje numarasını ve konumu (projects:{PROJECT_NUMBER}:locations:{LOCATION}) vegcloud agent-registry services createkomutunda kullandığınız hizmet kimliğini (agentregistry:services:zoo-mcp-server) kodlar. Temsilci, kayıtlı MCP sunucularınıregistry.list_mcp_servers()ile listeler ve her sunucununmcpServerIddeğeriniMCP_SERVER_URNile eşleştirir. Ardından, eşleşen sunucununname(projects/.../locations/.../mcpServers/...) kaynağınıregistry.get_mcp_toolset()'ye iletir.registry.get_mcp_toolset(), sunucunun kayıtlı arayüzünden (https://...run.app/mcp) uç nokta URL'sini okur ve bu URL'ye bağlı birMcpToolsetdöndürür: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(), araç adlarının önüne sunucunun görünen adını ekler. Böylece temsilci, araçlarızoo_mcp_server_list_species,zoo_mcp_server_get_animals_by_speciesvezoo_mcp_server_get_animal_detailsolarak görür. Önek, bir temsilci birden fazla MCP sunucusundaki araçları kullandığında ad çakışmalarını önler. Son satır, Cloud Run soğuk başlatmaları için yer açmak amacıyla bağlantı zaman aşımını varsayılan 5 saniyeden daha yüksek bir değere ayarlar.Yetkilendirme
AgentRegistryile nasıl değişir?AgentRegistry,list_mcp_servers()gibi kendi API çağrılarının kimliğini ADC ile doğrular. Bu nedenle, üstbilgi sağlayıcı yalnızca bulunan MCP sunucusuna yapılan çağrılar için gereklidir.AgentRegistry,McpToolsetöğesini dahili olarak oluşturduğundan üstbilgi sağlayıcıyıAgentRegistryoluşturucusuna iletirsiniz.Önceki adımda kitle, önceden bildiğinizMCP_SERVER_URLdeğeriydi. Artık URL yalnızca keşiften sonra bilinir. ADK, üstbilgi sağlayıcıyıAgentRegistryoluşturulduğunda değil, temsilci MCP sunucusuna istek gönderdiğinde çağırır. Bu sayede temsilci önce sağlayıcıyı oluşturabilir veget_mcp_toolset()döndükten sonra keşfedilen uç noktaya bağlayabilir.bind()yöntemi, kimlik bilgilerini önceki adımdaki oluşturucuyla aynı şekilde alır. Kitle,/mcpyolu olmadan keşfedilen uç nokta URL'sinden alınır: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__yöntemi,bind()yönteminden önce çağrılırsa hata vermesi dışında önceki adımdakiyle aynıdır. - Değişikliği test etmek için temsilcinizi çalıştırın.
adk runkomutunu kullanın: veya ADK web arayüzünüadk run zoo_agentadk webkomutuyla çalıştırın: ve ardından komutun tarayıcıda yazdırdığı URL'yi açın.Cloud Shell kullanıyorsanız web arayüzünün Cloud Shell'den açılmasına izin vermek içinadk web --port 8080--allow_originsbağımsız değişkenini ekleyin: Temsilciye önceki adımda sorduğunuz soruyu sorun. Yanıt aynıdır ancak ADK web arayüzünde araç çağrıları artıkadk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"zoo_mcp_server_list_speciesvezoo_mcp_server_get_animals_by_speciesolarak görünür.
Bu değişiklik sayesinde, açık MCP sunucusu URL'sine gerek kalmadan işlem yapabilirsiniz. Ancak MCP sunucusunu kaydetmek için kullanılan proje numarasını, kayıt konumunu ve hizmet kimliğini bilmeniz gerekir. Keşif, temsilci başlatma sırasında statik olarak gerçekleştirilir.
6. Dinamik keşifte MCP sunucusu için semantik aramayı kullanma
Bu adımda, başlangıçtaki tam URN eşleşmesini çalışma zamanı anlamsal aramasıyla değiştirerek MCP sunucusunun dinamik keşfini iyileştirirsiniz. Bu yaklaşım, sunucunun dağıtıldığı proje numarasını veya sunucunun tam kimliğini (MCP_SERVER_URN) bilme ihtiyacını ortadan kaldırır. Ayrıca, araç keşfini başlatma sırasında ele almak yerine doğrudan temsilcinin standart çalışma zamanı iş akışına entegre eder.
Bu adımla ilgili tüm dosyaları GitHub'da bulabilirsiniz.
Temsilciyi, çalışma zamanında anlamsal keşfi kullanacak şekilde güncelleyin.
- Mevcut uygulamayı geçersiz kılmak için güncellenmiş
agent.pydosyasını GitHub'dan indirin: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.pyBu adımdaki ortam değişkenleri
Temsilci artık MCP sunucusu URN'si oluşturmadığından gerekli yapılandırma daha da basitleştirilmiştir:GOOGLE_CLOUD_PROJECT,GOOGLE_GENAI_USE_ENTERPRISEveGOOGLE_CLOUD_LOCATION: ADK tarafından Vertex AI erişimini yapılandırmak için kullanılır. Konum, MCP sunucusunu bulmak için de kullanılır.- Artık gerekli değil:
GOOGLE_CLOUD_PROJECT_NUMBERartık gerekli değil (önceki adımda kaldırılanMCP_SERVER_URL'e ek olarak).
Tam eşlemeden semantik aramaya geçiş
agent.py, modül başlatma sırasındaregistry.list_mcp_servers()işlevini çağırıp her girişi oluşturulmuş birMCP_SERVER_URNile karşılaştırmak yerine,registry.search_mcp_servers()işlevinisearch_type="SEMANTIC"ile çağıran bir keşif aracı işlevidiscover_zoo_mcp_serverstanımlar: Bu sayede temsilci, çalışma zamanında ihtiyaç duyduğu özelliklerin doğal dildeki açıklamasını (ör.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") kullanarak Agent Registry'de arama yapabilir ve bulunan sunucu kaynak adlarını ADK oturum durumuna (tool_context.state) kaydeder.Dinamik keşif, temsilci iş akışına nasıl entegre edilir?
agent.py, çalışma zamanında keşfedilen sunuculardaki araçları bağlamak ve temsilciyi keşif ve ardından çağırma akışında yönlendirmek için özel birBaseToolsetuygulamasını (RegistryDiscoveredToolset) dinamik bir talimat sağlayıcıyla (zoo_guide_instruction) birleştirir:- Dinamik araç seti (
RegistryDiscoveredToolset):BaseToolsetalt sınıflarını oluşturur veself._use_invocation_cache = Falsedeğerini ayarlar. Böylece ADK, başlangıçta boş bir araç listesini önbelleğe almak yerinediscover_zoo_mcp_serversoturum durumunu güncelledikten hemen sonra mevcut araçları yeniden değerlendirir.get_tools()çağrıldığında, keşfedilen sunucu adlarını durumdan okur, bir çalışan iş parçacığındaki her sunucu için kimliği doğrulanmış birMcpToolsetoluşturur ve tüm etkin araçları döndürür. Bir sunucuya ulaşılamaması diğerlerini etkilemez._build_toolset(), engelleyici G/Ç işlemi gerçekleştirdiğinden_tools_of()bunu bir çalışan iş parçacığında çalıştırır.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] - Dinamik temsilci talimatı (
zoo_guide_instruction): Her model sırasından önce oturum durumunu değerlendirir. Henüz sunucu bulunamadığında_DISCOVERY_PROMPTekleyerek temsilciye öncediscover_zoo_mcp_serversyöntemini çağırmasını söyler. Keşif başarılı olduktan sonra istemi güncelleyerek etkin MCP sunucularını listeler ve temsilciye, keşfi tekrar çalıştırmadan bağlı hayvanat bahçesi araçlarını doğrudan kullanmasını söyler: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." )
Dinamik olarak keşfedilen sunucular için yetkilendirme
Anlamsal arama birkaç sunucu döndürebilir ve ADK, bir isteğin hangi sunucuya gittiğini belirtmeden başlık sağlayıcıyı çağırır. Bu nedenle_build_toolset(), bulunan her sunucu için özel bir_GoogleAuthHeadersveAgentRegistryoluşturur ve sağlayıcıyı bu sunucunun uç noktasına bağlar. Sağlayıcı, önceki adımda kullanılanla aynıdır vebind()tarihinden önce kullanılırsa başarısız olmasına neden olan bir_boundişareti içerir.Saklama ve yenileme mantığı
agent.py, keşfedilen uç noktaları düzenli olarak yenilerken her seferinde Temsilci Kayıt Defteri'ni sorgulamamak için yaşam süresi (TTL) ile durum saklama özelliğini uygular: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- Uygulama kapsamlı saklama: Bulunan sunucu adları ve
discovered_atzaman damgası, oturum durumundaapp:zoo_mcp_serversanahtarı altında saklanır. ADK'ninapp:önekini kullanmak, önbelleğe alınmış keşif kaydını uygulama çalıştırması boyunca kapsar. - TTL doğrulaması ve otomatik yenileme:
_fresh_discovery(), kayıtlı kaydın mevcut olduğunu ve yaşınınDISCOVERY_TTL_SECONDS(24 saat) değerini aşmadığını doğrular. Kayıt güncelkenRegistryDiscoveredToolset, önbelleğe alınmışMcpToolsetbağlantılarını (self._toolsets) yeniden kullanır,zoo_guide_instructionkeşif istemini atlar vediscover_zoo_mcp_serversiçin yapılan tüm tekrarlanan çağrılar hemen"already_discovered"değerini döndürür. 24 saatlik TTL süresi dolduğunda_fresh_discovery(),Nonedeğerini döndürür. Bu durum,RegistryDiscoveredToolset.get_tools()'nin mevcut MCP istemci oturumlarını (await self.close()) kapatmasına vezoo_guide_instruction'nin temsilciyi yeni bir keşif yapmaya yönlendirmesine neden olur.
- Anlamsal keşif iş akışını test etmek için temsilcinizi çalıştırın.
adk runkomutunu kullanın: veya ADK web arayüzünüadk run zoo_agentadk webkomutuyla çalıştırın: ve ardından komutun tarayıcıda yazdırdığı URL'yi açın.Cloud Shell kullanıyorsanız web arayüzünün Cloud Shell'den açılmasına izin vermek içinadk web --port 8080--allow_originsbağımsız değişkenini ekleyin: Temsilciye hayvanat bahçesiyle ilgili bir soru sorduğunuzda (örneğin,adk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"How many animals are in the zoo?) öncediscover_zoo_mcp_serversaracını çağırdığını, keşfedilen MCP sunucusundaki araçları dinamik olarak bağladığını ve ardından sorunuzu yanıtlamak içinzoo_mcp_server_list_speciesvezoo_mcp_server_get_animals_by_speciesgibi hayvanat bahçesi araçlarını çağırdığını göreceksiniz.Which is the oldest lion?gibi bir ek soru sorun. Temsilci, önceden eklenmiş hayvanat bahçesi araçlarını kullanarak yanıt verir ve oturum durumundaki keşif kaydı hâlâ güncel olduğu içindiscover_zoo_mcp_serversaracını tekrar çağırmaz.
7. Temizleme
1. seçenek: Projeyi silme
Bu codelab için özel bir proje oluşturduysanız faturalandırmayı ortadan kaldırmanın en kolay yolu projeyi silmektir:
gcloud projects delete "${GOOGLE_CLOUD_PROJECT}" --quiet
2. seçenek: Kaynakları tek tek silme
Mevcut bir projeyi kullandıysanız ve projeyi saklamak istiyorsanız bu codelab sırasında oluşturulan kaynakları tek tek silin:
- MCP sunucusu kaydını Agent Registry'den silin. Sunucuyu manuel olarak kaydettiğiniz için Cloud Run hizmetini silmek kaydı kaldırmaz:
gcloud agent-registry services delete zoo-mcp-server \ --location=global \ --project="${GOOGLE_CLOUD_PROJECT}" \ --quiet - Cloud Run MCP sunucu hizmetini silin:
gcloud run services delete zoo-mcp-server \ --region=us-west1 \ --project="${GOOGLE_CLOUD_PROJECT}" \ --quiet - MCP sunucusu için oluşturulan hizmet hesabını silin:
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 deposu bu codelab sırasında oluşturulduysa kapsayıcı görüntüsü depolama ücreti ödememek için depoyu silin:gcloud artifacts repositories delete cloud-run-source-deploy \ --location=us-west1 \ --project="${GOOGLE_CLOUD_PROJECT}" \ --quiet- İsterseniz Cloud Shell'de oluşturulan yerel proje dizinini kaldırabilirsiniz:
cd ~ && rm -rf adk-dynamic-discovery
8. Tebrikler
Bu codelab'de, Google Cloud Agent Registry ve Agent Development Kit (ADK) ile MCP sunucularını dinamik olarak keşfetmeyi ve kullanmayı öğrendiniz:
- MCP sunucusu kaydetme: Cloud Run'a güvenli bir MCP sunucusu dağıttınız ve bunu Agent Registry'ye kaydettiniz.
- Kimliğe göre MCP sunucusu keşfedildi: MCP sunucusu uç noktası, URL'si sabit kodlanmak yerine Agent Registry'den çözümlendi.
- Anlamsal olarak keşfedilen MCP sunucuları: Temsilcinin, doğal dilde arama kullanarak çalışma zamanında MCP araçlarını bulup bağlamasına olanak tanır. Bu araçlar saklanır ve yenilenir.