এজেন্ট রেজিস্ট্রি এবং ADK সহ ডায়নামিক MCP সার্ভার ডিসকভারি

১. ভূমিকা

এই কোডল্যাবে, আপনি শিখবেন কীভাবে Google Cloud Agent Registry এবং Agent Development Kit (ADK) ব্যবহার করে রানটাইমে রেজিস্টার করা Model Context Protocol (MCP) সার্ভার ডাইনামিকভাবে খুঁজে বের করা এবং ইনভোক করা যায়, যার ফলে হার্ডকোড করা এন্ডপয়েন্ট এবং টুল কনফিগারেশনের প্রয়োজন হয় না।

এই ল্যাবটি অ্যাপ্লিকেশন তৈরি করতে ADK এবং Python প্রোগ্রামিং ল্যাঙ্গুয়েজ ব্যবহার করে। একই নীতি অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজে এবং অন্যান্য এজেন্ট ডেভেলপমেন্ট ফ্রেমওয়ার্ক ব্যবহার করে প্রয়োগ করা যেতে পারে।

আপনি কী করবেন

  • আপনার প্রোজেক্টে Google Cloud Agent Registry চালু ও কনফিগার করা
  • Cloud Run-এ MCP সার্ভার ডিপ্লয় করা এবং এজেন্ট রেজিস্ট্রিতে এটি রেজিস্টার করা
  • হার্ডকোড করা URL ব্যবহার করে MCP সার্ভার কল করে এমন ADK এজেন্ট তৈরি করা
  • এজেন্ট রেজিস্ট্রিতে MCP সার্ভারকে তার পরিচয় দিয়ে খুঁজে পেতে এজেন্ট পরিবর্তন করুন
  • সিম্যান্টিক সার্চ ব্যবহার করে রানটাইমে MCP সার্ভার খুঁজে পেতে এজেন্ট পরিবর্তন করা

আপনার কী প্রয়োজন হবে

  • একটি আধুনিক ওয়েব ব্রাউজার (যেমন Chrome)
  • বিলিং চালু করা আছে এমন একটি Google Cloud প্রোজেক্ট
  • Google Cloud প্রোজেক্টে রিসোর্স তৈরি ও ম্যানেজ করা এবং IAM নীতি কনফিগার করার অনুমতি সহ একটি অ্যাকাউন্ট

২. আপনার পরিবেশ সেট-আপ করুন

এই কোডল্যাবের নির্দেশাবলী ধরে নেয় যে আপনি Google Cloud কনসোলে Cloud Shell-এ কমান্ড চালান। Cloud Shell হল Google Cloud-এ চলা একটি কমান্ড-লাইন এনভায়রনমেন্ট যা প্রয়োজনীয় টুল সহ প্রিলোড করা থাকে। আপনার লোকাল এনভায়রনমেন্টে gcloud CLI, git এবং Python 3 ইনস্টল করা থাকলে, আপনি সেখানেও কমান্ড রান করতে পারবেন।

Google Cloud প্রোজেক্ট তৈরি করা

  1. Google Cloud Console-এ, প্রোজেক্ট সিলেক্টর পৃষ্ঠায়, Google Cloud প্রোজেক্ট তৈরি করুন।
  2. আপনার Cloud প্রোজেক্টের জন্য বিলিং চালু করা আছে কিনা তা ভাল করে দেখে নিন। প্রোজেক্টে বিলিং চালু করা আছে কিনা তা চেক করবেন কীভাবে তা জানুন।

Cloud Shell টার্মিনাল চালু করুন

  1. রিসোর্স পিকার ব্যবহার করে আপনার তৈরি করা Google Cloud প্রোজেক্ট বেছে নিন।
  2. Google Cloud কনসোলের সবচেয়ে উপরে Cloud Shell চালু করুন Cloud Shell আইকন চালু করুন বিকল্পে ক্লিক করুন।
  3. Cloud Shell-এ কানেক্ট করার পরে, আপনার যাচাইকরণ চেক করুন:
    gcloud auth list
    
  4. আপনার প্রোজেক্ট কনফিগার করা হয়েছে কিনা তা কনফার্ম করুন:
    gcloud config get project
    
  5. আপনার প্রোজেক্ট প্রত্যাশা অনুযায়ী সেট করা না থাকলে অথবা আপনি Cloud Shell-এর পরিবর্তে আপনার লোকাল মেশিনে কোনও এনভায়রনমেন্ট ব্যবহার করলে, প্রোজেক্ট আইডি সেট-আপ করুন:
    export GOOGLE_CLOUD_PROJECT=<YOUR_PROJECT_ID>
    gcloud config set project "${GOOGLE_CLOUD_PROJECT}"
    

Google Cloud প্রোজেক্ট বেছে নিন এবং এনভায়রনমেন্ট ভেরিয়েবল সেট করুন

  1. প্রয়োজনীয় Google Cloud API চালু করুন:
    gcloud services enable \
      agentregistry.googleapis.com \
      aiplatform.googleapis.com \
      cloudbuild.googleapis.com \
      run.googleapis.com \
      --project="${GOOGLE_CLOUD_PROJECT}"
    

Python এনভায়রনমেন্ট সেট-আপ করা

  1. ভার্চুয়াল এনভায়রনমেন্ট তৈরি ও অ্যাক্টিভেট করে প্রয়োজনীয় ডিপেন্ডেন্সি ইনস্টল করুন:
    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 সার্ভার তৈরি করুন

  1. MCP সার্ভারের জন্য একটি ফোল্ডার এবং Python প্রোজেক্ট সেট-আপ করুন
    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
    
  2. 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
    

Cloud Run-এ MCP সার্ভার ডিপ্লয় করা এবং এজেন্ট রেজিস্ট্রিতে রেজিস্টার করা

এরপর, আপনি সার্ভারের জন্য Dockerfile তৈরি করবেন এবং Cloud Run-এ সার্ভার ডিপ্লয় করবেন।

  1. 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
    
  2. সার্ভারের জন্য নির্দিষ্ট পরিষেবা অ্যাকাউন্ট তৈরি করুন:
    gcloud iam service-accounts create zoo-mcp-server-sa \
        --display-name="Zoo MCP Server Service Account"
    
  3. us-west1 অঞ্চলে সার্ভার ডিপ্লয় করুন।
    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-unauthenticated
    
    আপনি নিম্নলিখিত প্রম্পট দেখতে পেলে, নতুন আর্টিফ্যাক্ট রেজিস্ট্রি রিপোজিটরি তৈরি করার বিষয়টি কনফার্ম করুন। us-west1 অঞ্চলের জন্য আপনার প্রোজেক্টে Artifact Registry রিপোজিটরি না থাকলে এই প্রম্পট দেখানো হবে:
    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)?
    
  4. "গ্লোবাল" লোকেশনে এজেন্ট রেজিস্ট্রিতে 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 কল করে।
  5. এজেন্টটি রেজিস্ট্রিতে দেখা যাচ্ছে কিনা তা যাচাই করুন:
    gcloud agent-registry mcp-servers list \
        --location=global \
        --filter="display_name=zoo-mcp-server"
    
    আপনি MCP সার্ভারের তথ্য সহ YAML আউটপুট দেখতে পাবেন, যেমন:
    ---
    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>'
    

৪. Zoo MCP সার্ভার ব্যবহার করার জন্য একটি সাধারণ ADK এজেন্ট তৈরি করা

এই ধাপে, আপনি হার্ডকোড করা চিড়িয়াখানা MCP সার্ভার URL-এর সাহায্যে চিড়িয়াখানা সম্পর্কে ব্যবহারকারীর অনুরোধের উত্তর দেওয়ার জন্য একটি ADK এজেন্ট তৈরি করেন। হার্ডকোড করা থাকলে, এজেন্ট ডিপ্লয় করার আগে আপনাকে MCP সার্ভারের URL জানতে হবে।

আপনি GitHub-এ এই ধাপের জন্য সোর্স ফাইল খুঁজে পেতে পারেন।

এজেন্ট অ্যাপ্লিকেশন তৈরি করুন

ADK প্রোজেক্ট এবং Zoo MCP সার্ভার ব্যবহার করে এমন Zoo এজেন্টের স্ক্যাফোল্ড তৈরি করুন।

  1. 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
    
  2. এজেন্ট প্যাকেজ ফোল্ডার তৈরি করুন এবং __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
    
  3. .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}"
    EOF
    
    এই কমান্ডটি এই ধাপ এবং পরবর্তী ডিসকভারি ধাপ জুড়ে প্রয়োজনীয় সমস্ত এনভায়রনমেন্ট ভেরিয়েবেল zoo_agent/.env-এ লিখে, তাই আপনাকে পরে ফাইলটি আবার তৈরি করতে হবে না। এই ধাপে, নিম্নলিখিত ভেরিয়েবেল ব্যবহার করা হয়:
    • GOOGLE_GENAI_USE_ENTERPRISE, GOOGLE_CLOUD_PROJECT এবং GOOGLE_CLOUD_LOCATION: আপনার Google Cloud প্রোজেক্ট এবং লোকেশনে (global) Vertex AI-এর মাধ্যমে Gemini মডেল কল রুট করার জন্য ADK এবং Google GenAI SDK দ্বারা অন্তর্নিহিতভাবে ব্যবহার করা হয়। এটি এজেন্ট রেজিস্ট্রির লোকেশনও স্টোর করে যেখানে MCP সার্ভার রেজিস্টার করা হয়।
    • GOOGLE_CLOUD_PROJECT_NUMBER: এই ধাপে ব্যবহার করা হয়নি; পরবর্তী ধাপে ব্যবহার করার জন্য এটি এখানে অটো-ফিল করা হয়েছে।
    • MCP_SERVER_URL: Zoo MCP সার্ভারের হার্ডকোড করা Cloud Run URL-এর মাধ্যমে McpToolset কনফিগার করতে সরাসরি zoo_agent/agent.py-এ পড়ুন।
  4. Zoo MCP সার্ভারের সাথে কানেক্ট করে এমন Zoo এজেন্টের কোড সহ agent.py ডাউনলোড করুন:
    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 সার্ভার অনুমোদন কীভাবে কাজ করে

যেহেতু zoo-mcp-server Cloud Run পরিষেবা --invoker-iam-check ও --no-allow-unauthenticated ফ্ল্যাগ সহ ডিপ্লয় করা হয়েছে, তাই MCP সার্ভারে প্রতিটি HTTP অনুরোধে Authorization হেডারে Google-স্বাক্ষরিত ID টোকেন অন্তর্ভুক্ত থাকতে হবে। টোকেনটি অবশ্যই এমন একজন কলারকে শনাক্ত করবে যার কাছে পরিষেবার run.routes.invoke অনুমতি আছে।

zoo_agent/agent.py-এ, _GoogleAuthHeaders ক্লাস দুটি উপায়ের মধ্যে একটিতে আইডি টোকেন ক্রেডেনশিয়াল পায়। প্রথমে এটি মেটাডেটা সার্ভার বা পরিষেবা অ্যাকাউন্ট কী থেকে পরিষেবা URL-এর জন্য আইডি টোকেন পেতে 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),
)

অনুরোধ করা অডিয়েন্স হল পরিষেবা URL (MCP_SERVER_URL), যেখানে কানেকশন URL-এ /mcp পাথ অন্তর্ভুক্ত থাকে যেখানে FastMCP সার্ভার MCP প্রোটোকল পরিবেশন করে। ৩০ সেকেন্ডের টাইমআউট Cloud Run কোল্ড স্টার্টের জন্য জায়গা ছেড়ে দেয়।

আপনার লোকাল এনভায়রনমেন্টে ADK প্লেগ্রাউন্ড ব্যবহার করে এজেন্ট টেস্ট করা

এজেন্ট পরীক্ষা করার আগে, আপনার ব্যবহারকারীর অ্যাকাউন্ট MCP সার্ভারকে কল করতে পারে কিনা তা নিশ্চিত করুন।

  1. শুধুমাত্র লোকাল টার্মিনাল (Cloud Shell-এ এই ধাপটি এড়িয়ে যান): আপনার ব্যবহারকারীর ক্রেডেনশিয়াল দিয়ে ADC শুরু করুন:
    gcloud auth application-default login
    
    ADC ইনিশিয়ালাইজেশন সম্পূর্ণ করতে নির্দেশাবলী অনুসরণ করুন।
  2. (ঐচ্ছিক) রিমোট 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'
    
  3. adk run কমান্ডের সাহায্যে আপনার এজেন্ট রান করান:
    adk run zoo_agent
    
    অথবা adk web কমান্ডের সাহায্যে ADK ওয়েব ইন্টারফেস রান করুন:
    adk web --port 8080
    
    এবং তারপর ব্রাউজারে কমান্ড প্রিন্ট করে এমন URL খুলুন। আপনি Cloud Shell ব্যবহার করলে, Cloud Shell থেকে ওয়েব ইন্টারফেস খোলার অনুমতি দিতে --allow_origins আর্গুমেন্ট যোগ করুন:
    adk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"
    
    কমান্ড রান করার পরে Cloud Shell টুলবারে (ডানদিকে) ওয়েব প্রিভিউওয়েব প্রিভিউ আইকন আইকন খুঁজুন। এটিতে ক্লিক করে পোর্ট ৮০৮০-তে প্রিভিউ দেখুন বিকল্প বেছে নিন। Cloud Shell একটি নতুন ব্রাউজার ট্যাব খুলবে যা ADK ওয়েব ইন্টারফেস দেখাবে।
  4. এজেন্টের সাথে চ্যাট করা শুরু করুন। যেমন, চিড়িয়াখানার পশুদের সম্পর্কে জিজ্ঞাসা করুন:
    How many animals are in the zoo?
    
    এজেন্ট উত্তর গণনা করার জন্য প্রতিটি প্রজাতির জন্য list_species এবং তারপর get_animals_by_species কল করে।

ADK ওয়েব ইন্টারফেস আপনাকে এজেন্ট কীভাবে কাজ করে তা এক্সপ্লোর করতে দেয়, যার মধ্যে Zoo MCP সার্ভারে এর কলও অন্তর্ভুক্ত। কীভাবে করতে হয় তা জানতে ওয়েব UI ডকুমেন্টেশন দেখুন।

৫. ডায়নামিক্যালি MCP সার্ভার এন্ডপয়েন্ট খুঁজে নিন

এই ধাপে, আপনি এজেন্টকে পরিবর্তন করেন যাতে এটি চিড়িয়াখানা MCP সার্ভার এন্ডপয়েন্ট URL হার্ডকোড করার পরিবর্তে এজেন্ট রেজিস্ট্রিতে রেজিস্টার করা এন্ডপয়েন্ট খুঁজে পায়।

আপনি GitHub-এ এই ধাপের জন্য সব ফাইল খুঁজে পাবেন।

সার্ভারের URL খুঁজে পেতে এবং তা ফিরিয়ে আনতে আপনি এজেন্ট রেজিস্ট্রির সাথে ADK ইন্টিগ্রেশন ব্যবহার করেন। এটি প্রয়োগ করতে আপনার নিম্নলিখিত তথ্য প্রয়োজন:

  • এজেন্ট রেজিস্ট্রির প্রোজেক্ট নম্বর ও লোকেশন যেখানে আপনার MCP সার্ভার রেজিস্টার করা আছে (global)।
  • MCP সার্ভার (zoo-mcp-server) রেজিস্টার করার জন্য আপনি যে পরিষেবা আইডি ব্যবহার করেছেন।

এজেন্ট রেজিস্ট্রি ব্যবহার করতে এজেন্ট আপডেট করুন

  1. এজেন্টের প্রথম ভার্সন ওভাররাইড করতে GitHub থেকে আপডেট করা agent.py ফাইল ডাউনলোড করুন:
    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: MCP সার্ভারের পরিচয় URN (MCP_SERVER_URN) তৈরি করার জন্য এখন প্রয়োজন।
    • GOOGLE_CLOUD_PROJECT, GOOGLE_GENAI_USE_ENTERPRISE এবং GOOGLE_CLOUD_LOCATION: Vertex AI অ্যাক্সেস কনফিগার করতে ADK ব্যবহার করে। এছাড়াও, MCP সার্ভার খুঁজে পেতে লোকেশন ব্যবহার করা হয়।
    • আর প্রয়োজন নেই: MCP_SERVER_URL আর ব্যবহার করা হয় না কারণ এজেন্ট এনভায়রনমেন্ট থেকে পড়ার পরিবর্তে এজেন্ট রেজিস্ট্রি থেকে MCP সার্ভার এন্ডপয়েন্ট URL রিট্রিভ করে।

    AgentRegistry-এ MCP সার্ভার পরিচয় ও ডিসকভারি কীভাবে কাজ করে

    এজেন্ট রেজিস্ট্রিতে, প্রতিটি রেজিস্টার করা MCP সার্ভারের একটি অনন্য শনাক্তকারী থাকে যা এর mcpServerId ফিল্ডে স্টোর করা থাকে, যা ইউনিফর্ম রিসোর্স নেম (URN) হিসেবে ফর্ম্যাট করা হয়। আপনি ৩ নম্বর ধাপে gcloud agent-registry mcp-servers list কমান্ডের আউটপুটে এটি দেখতে পাবেন। এজেন্ট এনভায়রনমেন্ট ভেরিয়েবেল থেকে এই শনাক্তকারী আবার তৈরি করে:
    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"
    
    URN-এ রেজিস্ট্রির প্রোজেক্ট নম্বর (projects-{PROJECT_NUMBER}), প্রোজেক্ট নম্বর ও সার্ভার যেখানে রেজিস্টার করা হয়েছে সেই লোকেশন (projects:{PROJECT_NUMBER}:locations:{LOCATION}) এবং gcloud agent-registry services create কমান্ডে (agentregistry:services:zoo-mcp-server) আপনি যে পরিষেবা আইডি ব্যবহার করেছেন তা এনকোড করা থাকে। এজেন্ট registry.list_mcp_servers()-এর মাধ্যমে রেজিস্টার করা MCP সার্ভার তালিকাভুক্ত করে এবং প্রতিটি সার্ভারের mcpServerId-এর সাথে MCP_SERVER_URN ম্যাচ করে। এটি তারপর ম্যাচিং সার্ভারের রিসোর্স name (projects/.../locations/.../mcpServers/...) registry.get_mcp_toolset()-এ পাস করে, যা সার্ভারের রেজিস্টার করা ইন্টারফেস (https://...run.app/mcp) থেকে এন্ডপয়েন্ট URL পড়ে এবং সেই URL-এর সাথে কানেক্ট করা একটি 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.0
    
    get_mcp_toolset() সার্ভারের ডিসপ্লে নামের সাথে টুলের নাম প্রিফিক্স করে, তাই এজেন্ট টুলগুলিকে zoo_mcp_server_list_species, zoo_mcp_server_get_animals_by_species এবং zoo_mcp_server_get_animal_details হিসেবে দেখে। এজেন্ট একাধিক MCP সার্ভার থেকে টুল ব্যবহার করলে, প্রিফিক্স নামের সংঘর্ষ প্রতিরোধ করে। শেষ লাইনটি কানেকশন টাইমআউটকে তার ডিফল্ট ৫ সেকেন্ড থেকে বাড়িয়ে দেয় যাতে Cloud Run কোল্ড স্টার্টের জন্য জায়গা থাকে।

    AgentRegistry-এর সাথে অনুমোদনে কীভাবে পরিবর্তন হয়

    AgentRegistry ADC-এর মাধ্যমে নিজের API কল যাচাই করে, যেমন list_mcp_servers(), তাই খুঁজে পাওয়া MCP সার্ভারে কল করার জন্য শুধু হেডার প্রোভাইডার প্রয়োজন। যেহেতু AgentRegistry ইন্টার্নালি McpToolset তৈরি করে, তাই আপনি হেডার প্রোভাইডারকে AgentRegistry কনস্ট্রাক্টরে পাস করেন। আগের ধাপে, অডিয়েন্স ছিল MCP_SERVER_URL ভ্যালু যা আপনি আগে থেকেই জানতেন। এখন URL শুধুমাত্র ডিসকভারির পরে জানা যায়। এজেন্ট যখন MCP সার্ভারে অনুরোধ পাঠায় তখন ADK হেডার প্রোভাইডারকে কল করে, AgentRegistry তৈরি করার সময় নয়। এটি এজেন্টকে প্রথমে প্রোভাইডার তৈরি করতে এবং get_mcp_toolset() রিটার্ন করার পরে এটিকে ডিসকভার করা এন্ডপয়েন্টে বাইন্ড করতে দেয়। bind() মেথডটি আগের ধাপের কনস্ট্রাক্টরের মতোই ক্রেডেনশিয়াল পায়, যেখানে অডিয়েন্সকে /mcp পাথ ছাড়াই ডিসকভার করা এন্ডপয়েন্ট URL থেকে নেওয়া হয়:
        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()-এর আগে কল করা হলে এটি একটি সমস্যা দেখায়।
  2. পরিবর্তনটি পরীক্ষা করতে আপনার এজেন্ট চালান। adk run কমান্ড ব্যবহার করুন:
    adk run zoo_agent
    
    অথবা adk web কমান্ডের সাহায্যে ADK ওয়েব ইন্টারফেস রান করুন:
    adk web --port 8080
    
    এবং তারপর ব্রাউজারে কমান্ড প্রিন্ট করে এমন URL খুলুন। আপনি Cloud Shell ব্যবহার করলে, Cloud Shell থেকে ওয়েব ইন্টারফেস খোলার অনুমতি দিতে --allow_origins আর্গুমেন্ট যোগ করুন:
    adk web --port 8080 --allow_origins="regex:https://.*\.cloudshell\.dev"
    
    আগের ধাপে যে প্রশ্নটি করেছিলেন, এজেন্টকে সেই একই প্রশ্ন করুন। উত্তর একই, তবে ADK ওয়েব ইন্টারফেসে টুল কল এখন zoo_mcp_server_list_species এবং zoo_mcp_server_get_animals_by_species হিসেবে দেখা যায়।

এই পরিবর্তনের ফলে, আপনাকে আর নির্দিষ্ট MCP সার্ভার URL ব্যবহার করতে হবে না। তবে, আপনাকে এখনও প্রোজেক্ট নম্বর, রেজিস্ট্রি লোকেশন এবং MCP সার্ভার রেজিস্টার করার জন্য ব্যবহৃত পরিষেবা আইডি জানতে হবে এবং এজেন্ট ইনিশিয়ালাইজেশনের সময় স্ট্যাটিক্যালি ডিসকভারি করা হয়।

৬. ডায়নামিক ডিসকভারিতে MCP সার্ভারের জন্য সিম্যান্টিক সার্চ ব্যবহার করুন

এই ধাপে, আপনি রানটাইম সিম্যান্টিক সার্চের মাধ্যমে স্টার্টআপে সঠিক URN ম্যাচিং প্রতিস্থাপন করে MCP সার্ভার ডাইনামিক ডিসকভারি উন্নত করেন। এই পদ্ধতিতে, সার্ভার যেখানে ডিপ্লয় করা হয়েছে সেই প্রোজেক্ট নম্বর বা সার্ভারের সঠিক পরিচয় (MCP_SERVER_URN) জানার প্রয়োজন হয় না এবং টুল ডিসকভারি সরাসরি এজেন্টের স্ট্যান্ডার্ড রানটাইম ওয়ার্কফ্লোতে ইন্টিগ্রেট করা হয়, ইনিশিয়ালাইজেশনের সময় এটি ম্যানেজ করা হয় না।

আপনি GitHub-এ এই ধাপের জন্য সব ফাইল খুঁজে পাবেন।

রানটাইমে সিম্যান্টিক ডিসকভারি ব্যবহার করতে এজেন্ট আপডেট করুন

  1. আগে থেকে থাকা ইমপ্লিমেন্টেশন ওভাররাইট করতে GitHub থেকে আপডেট করা agent.py ফাইল ডাউনলোড করুন:
    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
    

    এই ধাপে এনভায়রনমেন্ট ভেরিয়েবল

    যেহেতু এজেন্ট আর MCP সার্ভার URN তৈরি করে না, তাই প্রয়োজনীয় কনফিগারেশন আরও সহজ করা হয়েছে:
    • GOOGLE_CLOUD_PROJECT, GOOGLE_GENAI_USE_ENTERPRISE এবং GOOGLE_CLOUD_LOCATION: Vertex AI অ্যাক্সেস কনফিগার করতে ADK ব্যবহার করে। এছাড়াও, MCP সার্ভার খুঁজে পেতে লোকেশন ব্যবহার করা হয়।
    • আর প্রয়োজন নেই: GOOGLE_CLOUD_PROJECT_NUMBER-এর আর প্রয়োজন নেই (MCP_SERVER_URL-এর সাথে, যা আগের ধাপে আগেই সরিয়ে দেওয়া হয়েছে)।
    মডিউল ইনিশিয়ালাইজেশনের সময় registry.list_mcp_servers() কল করা এবং তৈরি করা MCP_SERVER_URN-এর সাথে প্রতিটি এন্ট্রি তুলনা করার পরিবর্তে, agent.py এখন একটি ডিসকভারি টুল ফাংশন discover_zoo_mcp_servers সংজ্ঞায়িত করে যা search_type="SEMANTIC"-এর সাথে registry.search_mcp_servers() কল করে:
    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") এবং খুঁজে পাওয়া সার্ভার রিসোর্সের নাম ADK সেশন স্টেটে (tool_context.state) সেভ করে।

    এজেন্ট ওয়ার্কফ্লোতে কীভাবে ডায়নামিক ডিসকভারি ইন্টিগ্রেট করা হয়

    রানটাইমে খুঁজে পাওয়া সার্ভার থেকে টুল মাউন্ট করতে এবং এজেন্টকে ডিসকভারি-তারপর-ইনভোকেশন ফ্লোয়ের মাধ্যমে গাইড করতে, agent.py একটি কাস্টম BaseToolset ইমপ্লিমেন্টেশন (RegistryDiscoveredToolset) এবং একটি ডাইনামিক নির্দেশাবলী প্রদানকারী (zoo_guide_instruction) একত্রিত করে:
    1. ডায়নামিক টুলসেট (RegistryDiscoveredToolset): সাবক্লাস BaseToolset এবং সেট self._use_invocation_cache = False যাতে ADK সেশন স্টেট discover_zoo_mcp_servers আপডেট করার সাথে সাথেই উপলভ্য টুলগুলি পুনরায় মূল্যায়ন করে, প্রাথমিকভাবে খালি টুল তালিকা ক্যাশে করার পরিবর্তে। get_tools() কল করা হলে, এটি স্টেট থেকে খুঁজে পাওয়া সার্ভারের নাম পড়ে, ওয়ার্কার থ্রেডে প্রতিটি সার্ভারের জন্য যাচাই করা McpToolset তৈরি করে এবং সব অ্যাক্টিভ টুল ফিরিয়ে দেয়। একটি সার্ভারের সাথে কানেক্ট করতে না পারলে, অন্য সার্ভারের উপর তার কোনও প্রভাব পড়ে না। _build_toolset(), I/O ব্লক করে, তাই _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]
      
    2. ডায়নামিক এজেন্ট নির্দেশাবলী (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 কী-এর অধীনে সেশন স্টেটে স্টোর করা হয়। ADK-এর app: প্রিফিক্স ব্যবহার করলে, অ্যাপ্লিকেশন রান জুড়ে ক্যাশে করা ডিসকভারি রেকর্ড স্কোপ করা হয়।
    • 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 এজেন্টকে নতুন ডিসকভারি করার জন্য প্রম্পট করে।
  2. সিম্যান্টিক ডিসকভারি ওয়ার্কফ্লো পরীক্ষা করতে আপনার এজেন্ট চালান। adk run কমান্ড ব্যবহার করুন:
    adk run zoo_agent
    
    অথবা adk web কমান্ডের সাহায্যে ADK ওয়েব ইন্টারফেস রান করুন:
    adk web --port 8080
    
    এবং তারপর ব্রাউজারে কমান্ড প্রিন্ট করে এমন URL খুলুন। আপনি Cloud Shell ব্যবহার করলে, Cloud Shell থেকে ওয়েব ইন্টারফেস খোলার অনুমতি দিতে --allow_origins আর্গুমেন্ট যোগ করুন:
    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-কে আবার কল করে না, কারণ সেশন স্টেটে ডিসকভারি রেকর্ড এখনও ফ্রেশ।

৭. অপ্রয়োজনীয়গুলি মুছুন

বিকল্প ১: প্রোজেক্ট মুছে দিন

আপনি যদি এই কোডল্যাবের জন্য একটি ডেডিকেটেড প্রোজেক্ট তৈরি করে থাকেন, তাহলে বিলিং বাদ দেওয়ার সবচেয়ে সহজ উপায় হল প্রোজেক্টটি মুছে ফেলা:

gcloud projects delete "${GOOGLE_CLOUD_PROJECT}" --quiet

বিকল্প ২: আলাদা আলাদা রিসোর্স মুছে ফেলা

আপনি যদি আগে থেকে থাকা কোনও প্রোজেক্ট ব্যবহার করে থাকেন এবং সেটি রাখতে চান, তাহলে এই কোডল্যাব চলাকালীন তৈরি করা আলাদা আলাদা রিসোর্স মুছে দিন:

  1. এজেন্ট রেজিস্ট্রি থেকে MCP সার্ভার রেজিস্ট্রেশন মুছে দিন। আপনি ম্যানুয়ালি সার্ভার রেজিস্টার করেছেন বলে, Cloud Run পরিষেবা মুছে দিলেও রেজিস্ট্রেশন মুছে যায় না:
    gcloud agent-registry services delete zoo-mcp-server \
        --location=global \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --quiet
    
  2. Cloud Run MCP সার্ভার পরিষেবা মুছুন:
    gcloud run services delete zoo-mcp-server \
        --region=us-west1 \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --quiet
    
  3. MCP সার্ভারের জন্য তৈরি করা পরিষেবা অ্যাকাউন্ট মুছে দিন:
    gcloud iam service-accounts delete \
        "zoo-mcp-server-sa@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --quiet
    
  4. এই কোডল্যাব চলাকালীন cloud-run-source-deploy Artifact Registry রিপোজিটরি তৈরি করা হলে, কন্টেনার ইমেজ স্টোরেজ চার্জ এড়াতে এটি মুছে দিন:
    gcloud artifacts repositories delete cloud-run-source-deploy \
        --location=us-west1 \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --quiet
    
  5. বিকল্প হিসেবে, Cloud Shell-এ তৈরি করা লোকাল প্রোজেক্ট ডিরেক্টরি সরিয়ে দিন:
    cd ~ && rm -rf adk-dynamic-discovery
    

৮. অভিনন্দন

এই কোডল্যাবে, আপনি শিখেছেন কীভাবে Google Cloud Agent Registry এবং Agent Development Kit (ADK) ব্যবহার করে ডায়নামিকভাবে MCP সার্ভার খুঁজে পেতে এবং ব্যবহার করতে হয়:

  1. MCP সার্ভার রেজিস্টার করা: Cloud Run-এ সুরক্ষিত MCP সার্ভার ডিপ্লয় করা এবং এজেন্ট রেজিস্ট্রিতে এটি রেজিস্টার করা।
  2. পরিচয় দ্বারা MCP সার্ভার খুঁজে পাওয়া গেছে: URL হার্ডকোড করার পরিবর্তে এজেন্ট রেজিস্ট্রি থেকে MCP সার্ভার এন্ডপয়েন্ট সমাধান করা হয়েছে।
  3. সিম্যান্টিক্যালি MCP সার্ভার খুঁজে পাওয়া: এজেন্টকে রানটাইমে ন্যাচারাল ল্যাঙ্গুয়েজ সার্চ ব্যবহার করে MCP টুল খুঁজে পেতে এবং মাউন্ট করতে দিন, সাথে রিটেনশন এবং রিফ্রেশ করুন।

পরবর্তী ধাপ