Gemini Enterprise با Agent Gateway به سرور MCP سفارشی خصوصی با استفاده از Agent Registry خروجی می‌دهد

۱. مقدمه

این آزمایشگاه کد، اتصال خروجی خصوصی و مدیریت‌شده برای Gemini Enterprise را با استفاده از Agent Gateway در حالت agent-to-anywhere (خروجی) بررسی می‌کند. شما یک برنامه Gemini Enterprise را پیکربندی خواهید کرد تا با مسیریابی ترافیک از طریق Agent Gateway با استفاده از رابط‌های Private Service Connect (PSC) به طور ایمن یک سرور سفارشی Model Context Protocol (MCP) که در Cloud Run میزبانی می‌شود را فراخوانی کند تا به یک نقطه پایانی PSC برای APIهای گوگل در یک شبکه VPC متصل شود.

در محیط‌های سازمانی، اعطای دسترسی مستقیم به شبکه به عامل‌های خودمختار، خطر استخراج داده‌ها و اجرای ابزار بدون بررسی را به همراه دارد. Agent Gateway یک نقطه اجرای متمرکز و در سطح پلتفرم با قابلیت اعتماد صفر فراهم می‌کند که به صورت پویا، بارهای ابزار HTTP MCP قابل پخش را بررسی می‌کند. درخواست‌های خروجی با یک هویت عامل قابل تأیید رمزنگاری‌شده تأیید می‌شوند و از طریق پروکسی آگاه از هویت (IAP) با استفاده از سیاست‌های دسترسی یکپارچه IAM (UAP) با قوانین زبان بیان مشترک (CEL) مجاز می‌شوند. این امر امکان کنترل دسترسی جزئی بر ابزارها و روش‌های خاص MCP را بدون افشای حجم کار backend به اینترنت عمومی فراهم می‌کند.

آنچه می‌سازید

  • Agent Gateway که در حالت خروجی ( agent-to-anywhere ) با تأیید نقطه پایانی Agent Registry کار می‌کند
  • سرویس Cloud Run که میزبان یک سرور HTTP MCP خصوصی قابل پخش ( --ingress=internal ) ثبت شده با مشخصات ابزار آن در Agent Registry است.
  • افزونه‌ی مجوز پروکسی آگاه از هویت (IAP) برای Agent Gateway
  • سیاست‌های دسترسی یکپارچه IAM (UAP) با شرایط CEL برای مجوزدهی ابزار MCP
  • برنامه Gemini Enterprise به Agent Gateway متصل شده و به یک فروشگاه داده سرور MCP سفارشی که از Agent Registry وارد شده است، متصل است.
  • منابع شبکه VPC، منطقه Cloud DNS و نقطه پایانی PSC برای API های Google
  • اتصال شبکه PSC برای خروجی خصوصی VPC از Agent Gateway
  • قوانین سیاست فایروال نسل بعدی ابر (NGFW) برای ایمن‌سازی ترافیک VPC

شکل1

شکل 1. معماری Codelab

آنچه یاد می‌گیرید

  • نحوه استقرار یک سرور HTTP MCP خصوصی قابل پخش از منبع در Cloud Run و ثبت نقطه پایانی و طرحواره ابزار آن در Agent Registry
  • نحوه پیکربندی Agent Gateway با ورودی‌های رجیستری سازگار و مسیریابی فراخوانی‌های ابزار برنامه Gemini Enterprise از طریق Gateway
  • نحوه ایجاد خروجی خصوصی VPC با استفاده از اتصالات و رابط‌های شبکه PSC
  • نحوه واگذاری مجوز Agent Gateway به Identity-Aware Proxy (IAP)
  • نحوه‌ی ایجاد و اتصال سیاست‌های دسترسی یکپارچه‌ی IAM (UAP) با استفاده از destination.agent_registry.* و destination.is_registered CEL برای محدود کردن اجرای ابزار MCP
  • نحوه اعتبارسنجی اجرای سیاست‌ها و خروجی شبکه با استفاده از Cloud Logging

آنچه شما نیاز دارید

  • یک پروژه گوگل کلود با قابلیت پرداخت صورتحساب
  • یک لایسنس فعال Gemini Enterprise یا نسخه آزمایشی 30 روزه
  • مجوزهای IAM برای ارائه خدمات شبکه، Gemini Enterprise و منابع پلتفرم Agent
  • یک پوسته سازگار با POSIX ( bash یا zsh ) که رابط خط فرمان گوگل کلود ( gcloud )، curl و jq روی آن نصب شده باشد.

این بخش مقدمه را به پایان می‌رساند... و سپس به بخش مفاهیم می‌پردازیم.

۲. مفاهیم

توالی استقرار

این آزمایشگاه کد ابتدا زیرساخت را مستقر می‌کند تا مسیرهای شبکه خصوصی و کنترل‌های مدیریتی قبل از ثبت و اتصال ابزارهای MCP با Gemini Enterprise عملیاتی شوند:

  1. زیرساخت شبکه: تأمین زیرشبکه‌های VPC، یک نقطه پایانی PSC، یک اتصال شبکه PSC، قوانین سیاست Cloud NGFW و مناطق DNS ابری خصوصی.
  2. Agent Gateway: Agent Gateway را در حالت خروجی با ادغام Agent Registry ( registries ) و خروجی خصوصی VPC ( networkAttachment ) مستقر کنید.
  3. سیاست‌های مجوزدهی: افزونه مجوزدهی IAP، سیاست احراز هویت دروازه و سیاست دسترسی یکپارچه IAM (UAP) را با استفاده از شرایط destination.is_registered و destination.agent_registry.* CEL پیکربندی کنید.
  4. استقرار و ثبت سرور MCP: سرور ریاضی MCP را از منبع به Cloud Run ( --ingress=internal ) مستقر کنید و مشخصات سرویس و ابزار ( add و subtract ) را در Agent Registry ثبت کنید.
  5. برنامه Gemini Enterprise: برنامه Gemini Enterprise ( Engine ) را ایجاد کنید، تنظیمات هویت و قابلیت مشاهده را پیکربندی کنید و خروجی خروجی را به Agent Gateway ( agentGatewaySetting ) متصل کنید.
  6. وارد کردن رابط داده سفارشی MCP: رابط داده REGISTRY_MCP ( :setUpDataConnector ) را ایجاد و فعال کنید تا مخزن داده پشتیبان سرور MCP ثبت شده را به برنامه Gemini Enterprise متصل کنید.
  7. اعتبارسنجی: اجرای ابزارهای مجاز و غیرمجاز را در چت آزمایش کنید و اجرای سیاست‌ها را در لاگ‌های Agent Gateway، DNS، Firewall و Cloud Run تأیید کنید.

خروجی Gemini Enterprise

Gemini Enterprise درخواست‌های ابزار سرور MCP سفارشی را زمانی به Agent Gateway هدایت می‌کند که هم agentGatewaySetting در Engine و هم use_agent_gateway_egress: true در DataConnector پیکربندی شده باشند.

شکل ۲

شکل ۲. معماری خروجی Gemini Enterprise

اپلیکیشن Gemini Enterprise مسیریابی ابزارها را در چهار حوزه کلیدی سازماندهی می‌کند:

  1. ویجت ( default_search_widget_config ) :
    • رابط کاربری وب کلاینت را ارائه می‌دهد. ویجت از کاربر درخواست‌ها را دریافت می‌کند و جلسات چت را با موتور اصلی آغاز می‌کند.
  2. دستیار اصلی ( assistants/default_assistant/agents/default/core_assistant ) :
    • عامل استدلال مکالمه‌ای ریشه‌ای درون موتور. هنگام ارزیابی یک پرس‌وجوی کاربر، دستیار اصلی تعیین می‌کند که آیا محاسبه حسابی مورد نیاز است، ابزارهای موجود را بررسی می‌کند و اجرا را به زیرعامل سنتز شده Agent Gateway واگذار می‌کند.
  3. محل ذخیره داده و اتصال دهنده داده :
    • DataStore : هنگام اجرای :setUpDataConnector ، درون یک Collection اختصاصی ارائه می‌شود و طرحواره‌های ابزار Agent Registry وارد شده ( add ، subtract )، انواع آرگومان‌ها و دستورالعمل‌های agent را به Gemini Enterprise Engine (موتور سازمانی جمینی) پیوند می‌دهد ( dataStoreIds ).
    • DataConnector : اتصال اکشن REGISTRY_MCP ( createBapConnection: true ) را به سرور MCP راه دور ( instance_uri ) مدیریت می‌کند، منبع سرور Agent Registry MCP ( registry_mcp_server_name ) را شناسایی می‌کند و Agent Gateway egress ( use_agent_gateway_egress: true ) را فعال می‌کند.
  4. هویت عامل ، رجیستری عامل و دروازه عامل :
    • وقتی رابط داده، فراخوانی ابزار خروجی را ارسال می‌کند، ترافیک را به دروازه‌ای که در agentGatewaySetting مشخص شده است، هدایت می‌کند. دستیار اصلی یک توکن هویت SPIFFE ایجاد می‌کند که هویت آن را تأیید می‌کند: principal://agents.global.org-.../agents/default/core_assistant .
    • Agent Gateway با استفاده از فیلد registries با Agent Registry ادغام می‌شود تا به صورت پویا نقاط انتهایی مقصد و طرحواره‌های ابزار ثبت‌شده را شناسایی کند. این ابزار ویژگی‌های destination.is_registered و destination.agent_registry.* را پر می‌کند و آنها را قبل از اجازه دادن به انتقال به شبکه VPC، برای ارزیابی در برابر قوانین CEL سیاست دسترسی یکپارچه IAM (UAP) به IAP v2 ارسال می‌کند.

اتصال VPC دروازه

Agent Gateway اتصال شبکه خصوصی VPC را با استفاده از دو فیلد YAML فعال می‌کند:

  • networkConfig.egress.networkAttachment : ترافیک IP خصوصی را از طریق اتصال شبکه PSC به شبکه VPC هدایت می‌کند.
  • dnsPeeringConfig.domains : DNS را با شبکه VPC Cloud DNS zone تطبیق می‌دهد، بنابراین نام‌های میزبان هدف ( *.run.app ) به آدرس IP نقطه پایانی PSC خصوصی تعریف شده در شبکه VPC تبدیل می‌شوند.

محدودیت‌ها و الزامات

  • فقط StreamableHTTP: انتقال قدیمی Server-Sent Events (SSE) پشتیبانی نمی‌شود. سرورهای MCP باید از StreamableHTTP استفاده کنند.
  • الزامات TLS برای CA عمومی: نقاط پایانی MCP باید از گواهی‌های TLS امضا شده توسط یک CA مورد اعتماد عمومی استفاده کنند، حتی زمانی که به صورت خصوصی از طریق PSC به آنها دسترسی پیدا می‌شود.
  • لغو سیاست سازمانی: شما باید قبل از ثبت فروشگاه داده، صریحاً سیاست سازمانی را برای فروشگاه‌های داده سفارشی MCP لغو کنید .

این بخش مفاهیم را به پایان می‌رساند... و در ادامه به بخش تنظیمات می‌پردازیم.

۳. راه‌اندازی

نقش‌های مورد نیاز IAM

برای تکمیل Codelab، نقش‌های زیر مورد نیاز است:

دامنه

نقش‌های مورد نیاز IAM

پروژه و IAM

roles/orgpolicy.policyAdmin
roles/resourcemanager.projectIamAdmin
roles/iam.accessPolicyAdmin
roles/serviceusage.serviceUsageAdmin
roles/iam.serviceAccountUser

شبکه و درگاه

roles/networkservices.admin
roles/networksecurity.admin
roles/serviceextensions.admin
roles/compute.networkAdmin
roles/dns.admin

شرکت و ثبت شرکت جمینی

roles/discoveryengine.admin
roles/agentregistry.admin (یا roles/apphub.admin )

حجم کار و ساخت

roles/run.admin
roles/cloudbuild.builds.editor
roles/artifactregistry.writer
roles/storage.admin

مشاهده‌پذیری

roles/logging.viewer
roles/logging.logWriter

یا از یک نقش اساسی گسترده مانند roles/owner به همراه roles/orgpolicy.policyAdmin استفاده کنید (زیرا roles/owner به تنهایی نمی‌تواند سیاست‌های سازمان را تغییر دهد).

به پروژه خود دسترسی پیدا کنید

این Codelab از یک پروژه Google Cloud واحد استفاده می‌کند. مراحل پیکربندی از gcloud CLI و دستورات پوسته لینوکس استفاده می‌کنند.

با دسترسی به خط فرمان پروژه Google Cloud خود شروع کنید:

شناسه پروژه خود را تنظیم کنید

gcloud config set project SET_YOUR_PROJECT_ID_HERE

احراز هویت جلسه

# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login

تنظیم متغیرهای محیطی پوسته

# set custom var for slug (eg, "foo") and region preference
export SLUG="foo"
export REGION="us-central1"

echo ${SLUG}
echo ${REGION}
# create project vars (automatic)
export PROJ_ID=$(gcloud config list --format="value(core.project)")
export PROJ_NO=$(gcloud projects describe ${PROJ_ID} --format="value(projectNumber)")
export ORG_ID=$(gcloud projects get-ancestors ${PROJ_ID} --format="value(id)" | tail -n 1)
export USER_IDENTITY=$(gcloud config get-value account)

echo ${PROJ_ID}
echo ${PROJ_NO}
echo ${ORG_ID}
echo ${USER_IDENTITY}
# create resource vars for agent platform (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-ata"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export UAP_POLICY_NAME="uap-policy-${SLUG}"
export UAP_BINDING_NAME="uap-binding-${SLUG}"
export MCP_NAME="math-wizard"
export MCP_URL="https://${MCP_NAME}-${PROJ_NO}.${REGION}.run.app/mcp"

echo ${AGW_NAME}
echo ${AGW_URI}
echo ${UAP_POLICY_NAME}
echo ${UAP_BINDING_NAME}
echo ${MCP_NAME}
echo ${MCP_URL}
# create resource vars for gemini enterprise (automatic)
export GE_APP_DISPLAY_NAME="Codelab app"
export GE_APP_ORG_NAME="${SLUG}, Inc."
export GE_LOCATION="global"
export GE_APP_NAME="app-${SLUG}-${GE_LOCATION}"
export GE_APP_INIT="${GE_APP_NAME}_$(date +%s)"

echo ${GE_APP_DISPLAY_NAME}
echo ${GE_APP_ORG_NAME}
echo ${GE_LOCATION}
echo ${GE_APP_NAME}
echo ${GE_APP_INIT}

دامنه‌های اعتماد هویت عامل را تنظیم کنید

عبارت if-then-else بررسی می‌کند که آیا پروژه متعلق به یک سازمان است یا خیر تا دامنه اعتماد صحیح را برای هویت‌های عامل اصلی تنظیم کند.

# set var for trust domain
if [[ -n "${ORG_ID}" ]]; then
  export TRUST_DOMAIN="agents.global.org-${ORG_ID}.system.id.goog"
else
  export TRUST_DOMAIN="agents.global.proj-${PROJ_NO}.system.id.goog"
fi

echo "trust domain: ${TRUST_DOMAIN}"

تنظیم صورتحساب و پروژه سهمیه‌بندی

# set cli quota project
gcloud config set billing/quota_project ${PROJ_ID}
# set api quota project
gcloud auth application-default set-quota-project ${PROJ_ID}

ایجاد دایرکتوری محلی برای فایل‌های پیکربندی

# create config folder
mkdir -p cfg

اگر نصب خودمدیریت‌شده‌ی Google Cloud SDK (یعنی خارج از Cloud Shell) را اجرا می‌کنید، اجزا را به آخرین نسخه به‌روزرسانی کنید.

# update gcloud cli
gcloud components update

فعال کردن سرویس‌های API

# enable google apis (part 1)
gcloud services enable \
  agentregistry.googleapis.com \
  agentidentity.googleapis.com \
  aiplatform.googleapis.com \
  apphub.googleapis.com \
  apptopology.googleapis.com \
  cloudapiregistry.googleapis.com \
  cloudtrace.googleapis.com \
  compute.googleapis.com \
  dataform.googleapis.com \
  iam.googleapis.com \
  iap.googleapis.com \
  logging.googleapis.com \
  modelarmor.googleapis.com \
  monitoring.googleapis.com \
  networksecurity.googleapis.com \
  networkservices.googleapis.com \
  notebooks.googleapis.com \
  observability.googleapis.com
# enable google apis (part 2)
gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  discoveryengine.googleapis.com \
  dns.googleapis.com \
  orgpolicy.googleapis.com \
  run.googleapis.com \
  saasservicemgmt.googleapis.com \
  securitycenter.googleapis.com \
  storage.googleapis.com \
  telemetry.googleapis.com \
  texttospeech.googleapis.com

سیاست‌های سازمان

محدودیت‌های پیش‌فرض سیاست‌های سازمانی مدیریت‌شده توسط گوگل کلود، ویژگی‌های مورد استفاده در این Codelab را محدود می‌کنند:

  • discoveryengine.managed.disableCustomMcpServerConnector :
    • ایجاد رابط‌های داده‌ای که از یک سرور MCP سفارشی ( custom_mcp ) به عنوان منبع داده استفاده می‌کنند را محدود می‌کند (به طور پیش‌فرض اعمال می‌شود).
  • iam.managed.disableAccessPolicyBinding :
    • محدودیت‌های مربوط به سیاست‌های دسترسی IAM نسخه ۳ به منابع (به طور پیش‌فرض اعمال می‌شود).
  • discoveryengine.managed.allowedEgressFqdns :
    • دامنه‌های خروجی خروجی ( instance_uri FQDNs ) را برای رابط‌های داده محدود می‌کند، زمانی که کنترل‌های سرویس VPC (VPC-SC) فعال باشد یا پروژه در پارامتر enforcedProjects سازمان فهرست شده باشد.
  • discoveryengine.managed.allowedDataSources :
    • انواع کانکتور داده مجاز ( dataSource ) را زمانی که VPC-SC فعال است یا پروژه در پارامتر enforcedProjects سازمان فهرست شده است، محدود می‌کند.

با تنظیم صریح enforce: false ، هرگونه محدودیت سیاست سازمانی ارثی را در سطح پروژه لغو کنید.

غیرفعال کردن محدودیت سفارشی MCP

# disable data connector constraint (allow custom mcp servers)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.disableCustomMcpServerConnector
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe discoveryengine.managed.disableCustomMcpServerConnector \
  --project=${PROJ_ID} --effective

غیرفعال کردن محدودیت دسترسی در سیاست

# disable iam v3 constraint (allow v3 access policies)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/iam.managed.disableAccessPolicyBinding
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
  --project=${PROJ_ID} --effective

بررسی و غیرفعال کردن محدودیت‌های شرطی کانکتور داده

به طور پیش‌فرض، discoveryengine.managed.allowedEgressFqdns و discoveryengine.managed.allowedDataSources فقط در صورتی ایجاد کانکتور را مسدود می‌کنند که پروژه شما درون یک محیط VPC Service Controls (VPC SC) باشد یا اگر مدیر سازمان پروژه شما را به enforcedProjects اضافه کرده باشد.

ابتدا، سیاست‌های مؤثر در پروژه خود را بررسی کنید:

# check effective egress fqdn constraint on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective
# check effective data source constraint on project
gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

~~اگر~~ این محدودیت‌ها اعمال می‌شوند، برای اطمینان از اینکه راه‌اندازی کانکتور custom_mcp را در یک VPC SC یا سازمانی که سیاست‌ها در آن محدود شده است، مسدود نمی‌کنند ، مقدار enforce: false را روی هر دو سیاست پروژه خود تنظیم کنید:

# disable egress fqdn constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedEgressFqdns
spec:
  rules:
  - enforce: false
EOF
# disable allowed data sources constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedDataSources
spec:
  rules:
  - enforce: false
EOF
# verify both constraints are disabled on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective

gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

مجوزهای IAM

نقش‌های IAM مورد نیاز را به حساب کاربری خود و حساب سرویس پیش‌فرض Compute Engine که توسط Cloud Build استفاده می‌شود، اعطا کنید:

  • حساب کاربری ( ${USER_IDENTITY} ):
    • برای استقرار و فراخوانی سرویس‌های Cloud Run ( roles/run.admin ، roles/run.invoker ، roles/iam.serviceAccountUser )، ساخت تصاویر کانتینر ( roles/cloudbuild.builds.editor )، مدیریت Gemini Enterprise ( roles/discoveryengine.admin ) و ایجاد Unified Access Policies ( roles/iam.accessPolicyAdmin ) به مجوز نیاز دارد.
  • حساب سرویس پیش‌فرض موتور محاسبه ( ${PROJ_NO}-compute@developer.gserviceaccount.com ):
    • توسط Cloud Build برای استیج کردن کد منبع در Cloud Storage ( roles/storage.admin )، ارسال تصاویر به Artifact Registry ( roles/artifactregistry.writer ) و نوشتن گزارش‌های ساخت ( roles/logging.logWriter ) استفاده می‌شود.

برای اختصاص دادن اتصالات نقش، دستورات زیر را اجرا کنید:

# grant roles to user account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.invoker"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/discoveryengine.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.accessPolicyAdmin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/cloudbuild.builds.editor"
# grant roles to default compute (cloud build) service account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/storage.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/artifactregistry.writer"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/logging.logWriter"

مجوزهای IAM را تأیید کنید

شش ( 6 ) اتصال نقش را در حساب کاربری بررسی کنید.

# show iam policy on project for user account
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${USER_IDENTITY}" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

سه ( 3 ) اتصال نقش را در حساب سرویس محاسباتی پیش‌فرض بررسی کنید.

# show iam policy on project for default compute service account
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

تأیید اتصالات عامل سرویس (اقدام احتیاطی)

در یک پروژه جدید، Google Cloud به طور خودکار عامل سرویس Agent Gateway را آماده می‌کند و هنگام فعال شدن networkservices.googleapis.com برای اولین بار، roles/agentgateway.serviceAgent را به آن اعطا می‌کند. اگر در حال استفاده مجدد از یک پروژه موجود هستید که ممکن است پاکسازی قبلی، اتصالات پیش‌فرض عامل سرویس را حذف کرده باشد، دستورات زیر را به عنوان یک روش ایمن برای جلوگیری از خرابی اجرا کنید تا از سالم بودن اتصال هویت و نقش اطمینان حاصل شود:

# ensure network services service account has been created
gcloud beta services identity create \
  --service=networkservices.googleapis.com \
  --project="${PROJ_ID}"

# ensure network services service account has service agent roles applied
gcloud projects add-iam-policy-binding "${PROJ_ID}" \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-agentgateway.iam.gserviceaccount.com" \
  --role="roles/agentgateway.serviceAgent"

این بخش تنظیمات را به پایان می‌رساند... و در ادامه به بخش شبکه می‌پردازیم.

۴. شبکه

در این بخش، شما یک شبکه VPC را با استفاده از حالت سفارشی با یک زیرشبکه اختصاصی /28 ( 192.168.10.0/28 ) که از اتصال شبکه PSC برای خروجی شبکه Agent Gateway به شبکه VPC پشتیبانی می‌کند، مستقر خواهید کرد.

نقطه پایانی PSC برای APIهای گوگل با استفاده از یک آدرس IPv4 داخلی جهانی /32 ( 172.16.20.20 ) برای پشتیبانی از دسترسی داخلی خصوصی به APIها و سرویس‌های گوگل مستقر می‌شود. در این Codelab، Agent Gateway با استفاده از نقطه پایانی PSC و با حل دامنه run.app. توسط Cloud DNS peering، Cloud Run را هدف قرار می‌دهد.

ایجاد شبکه‌ها

یک شبکه جهانی VPC ایجاد کنید.

# create vpc network
gcloud compute networks create vnet-${SLUG} --subnet-mode=custom

زیرشبکه‌هایی برای اتصال شبکه‌ی PSC مربوط به Agent Gateway ایجاد کنید:

# create subnet for agent gateway psc na
gcloud compute networks subnets create subnet-${REGION}-agw \
  --network=vnet-${SLUG} \
  --range=192.168.10.0/28 \
  --region=${REGION} \
  --enable-private-ip-google-access

ایجاد قوانین فایروال

یک سیاست فایروال ایجاد کنید تا به همه ترافیک خروجی با قابلیت ثبت وقایع (logging) اجازه ورود دهد. این برای نظارت بر ترافیک خروجی از Agent Gateway به شبکه VPC استفاده خواهد شد. Cloud NGFW از هر دو لایه Essentials و Standard برای امنیت شبکه و نظارت بر ترافیک پشتیبانی می‌کند.

# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG} --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow all out and log" \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --action=allow \
  --direction=EGRESS \
  --layer4-configs=all \
  --dest-ip-ranges=0.0.0.0/0 \
  --enable-logging
# bind fw policy to network
gcloud compute network-firewall-policies associations create \
  --name=fw-policy-bind-${SLUG} \
  --firewall-policy=fw-policy-${SLUG} \
  --network=vnet-${SLUG} \
  --global-firewall-policy

ایجاد پیوست شبکه PSC

یک اتصال شبکه Private Service Connect (PSC) ایجاد کنید که به گونه‌ای پیکربندی شده باشد که به طور خودکار اتصالات از Agent Gateway را بپذیرد . این اتصال شبکه، سمت شبکه مصرف‌کننده VPC اتصال را برای اتصال ایمن با سمت تولیدکننده Agent Gateway برای ترافیک خروجی، برقرار می‌کند. برای اطلاعات بیشتر در مورد الزامات زیرشبکه و مشخصات محدوده IP، به پیکربندی اتصال VPC مراجعه کنید.

# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
  --region=${REGION} \
  --subnets=subnet-${REGION}-agw \
  --connection-preference=ACCEPT_AUTOMATIC

تأیید اتصال شبکه PSC

# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}

URI منبع پیوست شبکه PSC را بازیابی کرده و آن را در متغیر محیطی PSC_NA_URI ذخیره کنید. این URI در پیکربندی Agent Gateway ( networkConfig.egress.networkAttachment ) برای تأمین رابط PSC برای خروجی شبکه به شبکه VPC ارجاع داده خواهد شد:

# fetch psc network attachment uri
export PSC_NA_URI=$(gcloud compute network-attachments describe psc-na-${REGION}-agw \
  --region=${REGION} \
  --format="value(selfLink.scope(v1))")
echo ${PSC_NA_URI}

ایجاد نقطه پایانی PSC

یک نقطه پایانی سرویس خصوصی (PSC) برای APIهای گوگل برای Agent Gateway استفاده می‌شود تا اتصال خصوصی به سرور Cloud Run MCP را از طریق یک مسیر شبکه داخلی بدون افشای ترافیک به اینترنت عمومی برقرار کند. تماس‌های ابزار خروجی که از Agent Gateway به شبکه VPC خارج می‌شوند، URL سرویس Cloud Run هدف ( *.run.app ) را به این آدرس IP نقطه پایانی خصوصی تبدیل می‌کنند.

یک آدرس IPv4 داخلی جهانی برای نقطه پایانی PSC رزرو کنید. آدرس IP انتخاب شده باید یک آدرس /32 باشد که با هیچ زیرشبکه موجود در شبکه VPC شما همپوشانی نداشته باشد:

# set env var for psc ep ip address
export PSC_EP_IP="172.16.20.20"
echo ${PSC_EP_IP}
# reserve internal global ipv4 address
gcloud compute addresses create ip-psc2gapis \
  --global \
  --purpose=PRIVATE_SERVICE_CONNECT \
  --addresses=${PSC_EP_IP} \
  --network=vnet-${SLUG}

با استفاده از بسته all-apis که شامل Cloud Run ( run.app ) است، یک نقطه پایانی PSC برای API های گوگل ایجاد کنید.

# create psc endpoint for google apis
gcloud compute forwarding-rules create psc2gapis \
  --global \
  --network=vnet-${SLUG} \
  --address=ip-psc2gapis \
  --target-google-apis-bundle=all-apis

تأیید نقطه پایانی PSC

# show psc endpoint details
gcloud compute forwarding-rules describe psc2gapis --global

ایجاد منطقه و رکوردهای DNS

Cloud DNS برای فعال کردن Agent Gateway جهت برقراری ارتباط خصوصی با سرور MCP میزبانی شده توسط Cloud Run استفاده می‌شود. هنگامی که Agent Gateway درخواست‌های ابزار خروجی را که Cloud Run را هدف قرار می‌دهند ارزیابی می‌کند، از DNS peering ( dnsPeeringConfig.domains ) برای حل درخواست‌های DNS برای *.run.app با استفاده از منطقه Cloud DNS خصوصی مرتبط با شبکه VPC شما استفاده می‌کند. رکورد DNS خصوصی، درخواست را با آدرس IP نقطه پایانی PSC داخلی ( 172.16.20.20 ) برمی‌گرداند و به درخواست‌های ابزار MCP اجازه می‌دهد تا از طریق یک مسیر شبکه خصوصی مسیریابی شوند.

یک منطقه مدیریت‌شده خصوصی Cloud DNS برای دامنه run.app. ایجاد کنید:

# create private dns zone
gcloud dns managed-zones create priv-zone-run \
  --description="private zone for run.app" \
  --dns-name="run.app." \
  --visibility=private \
  --networks=vnet-${SLUG}

یک رکورد DNS A با پسوند *.run.app. ایجاد کنید که به آدرس IP نقطه پایانی PSC اشاره کند:

# create dns record
gcloud dns record-sets create "*.run.app." \
  --zone=priv-zone-run \
  --type=A \
  --ttl=300 \
  --rrdatas=${PSC_EP_IP}

یک سیاست Cloud DNS ایجاد کنید تا ثبت وقایع DNS را فعال کنید. ثبت وقایع DNS درخواست‌های تفکیک دامنه را که از Agent Gateway در شبکه VPC شما سرچشمه می‌گیرند، ثبت می‌کند و قابلیت حسابرسی را فراهم می‌کند و به شما امکان می‌دهد تأیید کنید که درخواست‌های ابزار *.run.app به درستی به نقطه پایانی PSC داخلی ارجاع داده می‌شوند:

# create dns policy (logging)
gcloud dns policies create dns-policy-${SLUG} \
  --description="dns logging for vnet-${SLUG}" \
  --networks=vnet-${SLUG} \
  --enable-logging

این بخش شبکه را به پایان می‌رساند... و در ادامه به بخش دروازه عامل (Agent Gateway) می‌پردازیم.

۵. دروازه عامل

Agent Gateway در کنار فیلدهای networkConfig که تنظیمات اتصال شبکه PSC و DNS peering را برای اتصال خصوصی VPC پیکربندی می‌کنند، registries برای نمونه‌های Agent Registry مشخص می‌کند:

  • registries : دروازه را با حداکثر دو نمونه از رجیستری عامل مرتبط می‌کند: یکی منطقه‌ای ( ../locations/${REGION} ) و دیگری سراسری ( ../locations/global ). این امر، دروازه عامل را با رجیستری عامل ادغام می‌کند تا هم استقرارهای منطقه‌ای (مانند سرورهای Cloud Run MCP در ${REGION} ) و هم منابع سراسری (مانند عوامل Gemini Enterprise و نقاط پایانی سراسری) را برای اجرای دقیق سیاست IAP v2 حل و فصل کند. ورودی‌های منطقه‌ای هنگام حل و فصل URLهای مقصد، بر ورودی‌های سراسری اولویت دارند.
  • networkAttachment : به پیوست شبکه PSC ( psc-na-${REGION}-agw ) اشاره می‌کند که Agent Gateway را برای خروج خصوصی به شبکه VPC شما متصل می‌کند.
  • dnsPeeringConfig.domains : run.app. طوری پیکربندی می‌کند که کوئری‌های DNS که از Agent Gateway برای سرویس‌های Cloud Run سرچشمه می‌گیرند، از DNS peering برای حل نام‌های میزبان به آدرس IP خصوصی Google APIs PSC endpoint ( 172.16.20.20 ) که در منطقه خصوصی Cloud DNS شما پیکربندی شده است، استفاده کنند.

استقرار دروازه عامل

فایل پیکربندی Agent Gateway را ایجاد و وارد کنید.

# create agent gateway config file
cat > cfg/${AGW_NAME}-networkConfig.yaml << EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
registries:
  - "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
networkConfig:
  egress:
    networkAttachment: ${PSC_NA_URI}
  dnsPeeringConfig:
    domains:
      - run.app.
    targetProject: ${PROJ_ID}
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}-networkConfig.yaml" \
  --location=${REGION}

تأیید استقرار Agent Gateway

رجیستری عامل و پیکربندی شبکه را تأیید کنید:

# show agent gateway registries and network config
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION} \
  --format="yaml(registries,networkConfig)"

خروجی مورد انتظار:

networkConfig:
  dnsPeeringConfig:
    domains:
    - run.app.
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
    targetProject: ${PROJ_ID}
  egress:
    networkAttachment: projects/${PROJ_ID}/regions/${REGION}/networkAttachments/psc-na-${REGION}-agw
registries:
- //agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}

تأیید کنید که خروجی، جزئیات پیکربندی مورد نیاز را نمایش می‌دهد:

  • registries ‎: آدرس رجیستری عامل منطقه‌ای ( ${REGION} ) مرتبط با دروازه را فهرست می‌کند.
  • egress.networkAttachment : آدرس اینترنتی (URI) اتصال شبکه PSC را برای VPC egress مشخص می‌کند.
  • dnsPeeringConfig.domains : شامل run.app. است که به targetNetwork برای تفکیک دامنه خصوصی اشاره می‌کند.

برای تأیید اتصال دروازه، پیوست شبکه PSC را بررسی کنید:

# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
  --region=${REGION} \
  --format="yaml(connectionEndpoints)"

بررسی کنید که یک نقطه پایانی اتصال پذیرفته شده وجود دارد:

connectionEndpoints:
- ipAddress: 192.168.10.2
  projectIdOrNum: '<AGW_TENANT_PROJ_NO>'
  status: ACCEPTED
  subnetwork: https://www.googleapis.com/compute/v1/projects/${PROJ_ID}/regions/${REGION}/subnetworks/subnet-${REGION}-agw

مجوز نمایندگی

Agent Gateway با استفاده از سیاست‌های مجوزدهی ( networksecurity.authzPolicies ) که با سیاست‌های دسترسی یکپارچه (UAP) و پروکسی آگاه از هویت (IAP) یکپارچه شده‌اند، ترافیک خروجی ابزار را ایمن و مدیریت می‌کند.

در حالی که Agent Gateway از قوانین پایه درون‌خطی ALLOW و DENY پشتیبانی می‌کند، محیط‌های سازمانی نیاز به مدیریت متمرکز و هویت‌محور دارند. با سیاست‌های دسترسی یکپارچه IAM (یا سیاست‌های دسترسی )، شما قوانین دسترسی خروجی را با استفاده از سیاست‌های دسترسی استاندارد IAM v3 مدیریت می‌کنید.

شکل ۳

شکل ۳. معماری مجوزدهی

جریان مجوز سه جزء را به هم متصل می‌کند:

  1. سیاست احراز هویت دروازه ( authzPolicy ) :
    • یک منبع منطقه‌ای که Agent Gateway را هدف قرار می‌دهد.
    • با policyProfile: REQUEST_AUTHZ و action: CUSTOM پیکربندی شده است تا تمام بررسی‌های مجوز خروجی به افزونه IAP Authz هدایت شود.
  2. افزونه سرویس IAP ( authzExtension ) :
    • یک منبع منطقه‌ای که نمایندگان آن درخواست مجوز برای Identity-Aware Proxy ( iap.googleapis.com ) را دارند.
    • سیاست‌ها را در حالت ENFORCE با استفاده از نسخه سیاست V2 ارزیابی می‌کند.
  3. سیاست دسترسی یکپارچه و اتصال IAM ( accessPolicy & policyBinding ) :
    • منابع سراسری IAM نسخه ۳ شامل قوانین دسترسی دقیق.
    • هویت اصلی SPIFFE عامل فراخوانی را احراز هویت می‌کند، مجوز جهانی iap.googleapis.com/resources.egressViaIAP را تأیید می‌کند و شرایط زبان عبارات مشترک (CEL) را در برابر ویژگی‌های مقصد ارزیابی می‌کند.

گسترش افزونه مجوز

یک پیکربندی افزونه‌ی مجوزدهی service-extensions ایجاد کنید که تصمیمات مجوزدهی را به سرویس IAP واگذار کند:

# create authz extension config file
cat > cfg/${AGW_NAME}-svc-ext-authz-iap.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap
service: iap.googleapis.com
failOpen: false
timeout: 1s
metadata:
  iapPolicyVersion: "V2"
EOF
# import iap authz extension (create authz extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap.yaml \
  --location=${REGION}

تأیید تمدید مجوز

بررسی کنید که افزونه‌ی مجوز فعال باشد:

# list authz extensions
gcloud service-extensions authz-extensions list \
  --location=${REGION} \
  --format="table(
    name.basename():label=NAME,
    createTime.date(tz=LOCAL):label=CREATED,
    updateTime.date(tz=LOCAL):label=MODIFIED,
    service:label=SERVICE,
    metadata:label=METADATA,
    timeout:label=TIMEOUT
  )"

سیاست مجوز استقرار

یک پیکربندی سیاست مجوزدهی network-security ایجاد کنید که Agent Gateway را هدف قرار دهد و درخواست تأیید را به افزونه مجوزدهی برای IAP واگذار کند:

# create authz policy config file
cat > cfg/${AGW_NAME}-authz-policy-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-iap
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF
# import authz policy config file (create authz policy)
gcloud network-security authz-policies import ${AGW_NAME}-authz-policy-iap \
  --source=cfg/${AGW_NAME}-authz-policy-iap.yaml \
  --location=${REGION}

سیاست مجوز را تأیید کنید

بررسی کنید که سیاست مجوز فعال باشد:

# list authz policies
gcloud network-security authz-policies list \
  --location=${REGION} \
  --format="table(
    name.basename():label=NAME,
    action:label=ACTION,
    customProvider.list().sub('\W.*', ''):label=CUSTOM_PROVIDER_TYPE,
    policyProfile:label=POLICY_PROFILE,
    customProvider.authzExtension.resources[0].basename():label=CUSTOM_PROVIDER_RESOURCE
  )"

ایجاد سیاست‌های دسترسی IAM

اکنون Agent Gateway بررسی‌های مجوز را به IAP واگذار می‌کند و فراداده‌های مقصد را از Agent Registry حل می‌کند. در مرحله بعد، یک قانون IAM Unified Access Policy برای مدیریت اجرای ابزار خروجی تعریف کنید.

IAP عبارات ویژگی CEL را در برابر ویژگی‌های مقصد رجیستری عامل زیر ارزیابی می‌کند:

  • وضعیت ثبت‌شده ( destination.is_registered ) :
    • مقدار بولی ( true / false ) که نشان می‌دهد آیا مقصد در Agent Registry فهرست‌بندی شده است یا خیر.
  • نام سرور MCP ( destination.agent_registry.mcp_server.name ) :
    • نام منبع سرور Canonical MCP در رجیستری نمایندگان ثبت شده است.
  • متد MCP ( destination.agent_registry.mcp_server.method ) :
    • متد MCP که فراخوانی می‌شود (مثلاً tools/call ، tools/list ، initialize ).
  • نام ابزار ( destination.agent_registry.mcp_server.tool.name ) :
    • نام ابزار خاص فراخوانی شده (مثلاً subtract یا add )، که امکان احراز هویت دقیق در سطح ابزار را در سرورهای ثبت شده MCP فراهم می‌کند.

تعریف قانون سیاست دسترسی IAM

مانیفست قانون سیاست IAM موارد زیر را مشخص می‌کند:

  • مدیران: هویت اصلی SPIFFE که نماینده‌ی دستیار اصلی Gemini Enterprise است.
  • مجوزها: مجوز جهانی iap.googleapis.com/resources.egressViaIAP برای همه ترافیک خروجی تحت مدیریت IAP الزامی است.
  • شرایط: یک عبارت CEL ( destination.is_registered == true ) که تضمین می‌کند عامل فقط می‌تواند نقاط پایانی فهرست‌شده در رجیستری عامل را فراخوانی کند.

فایل مانیفست قانون سیاست را ایجاد کنید:

# create access policy rule file
cat > cfg/${UAP_POLICY_NAME}-rules.json << EOF
[
  {
    "description": "allow ge assistant to any registered service",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true"
      }
    }
  }
]
EOF

سیاست دسترسی IAM را مستقر کنید

با استفاده از قوانین تعریف شده در فایل مانیفست، سیاست دسترسی سراسری IAM را ایجاد کنید:

# create iam access policy
gcloud iam access-policies create ${UAP_POLICY_NAME} \
  --details-rules=cfg/${UAP_POLICY_NAME}-rules.json \
  --project=${PROJ_ID} \
  --location=global

سیاست دسترسی IAM را تأیید کنید

بررسی کنید که سیاست دسترسی IAM با موفقیت ایجاد شده باشد و جزئیات قانون را بررسی کنید:

# show iam access policy details
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
  --project=${PROJ_ID} \
  --location=global

خروجی مورد انتظار:

details:
  rules:
  - conditions:
      iap.googleapis.com:
        expression: destination.is_registered == true
    description: allow ge assistant to any registered service
    effect: ALLOW
    operation:
      permissions:
      - iap.googleapis.com/resources.egressViaIAP
    principals:
    - principal://agents.global.org-${ORG_ID}.system.id.goog/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant
name: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}

سیاست دسترسی IAM را به پروژه متصل کنید

برای فعال کردن اعمال قانون در تمام دروازه‌های عامل (Agent Gateway) در پروژه خود، یک اتصال سیاست ایجاد کنید که سیاست دسترسی IAM را به منبع پروژه متصل کند:

# bind iam access policy to project resource
gcloud iam policy-bindings create ${UAP_BINDING_NAME} \
  --policy="projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}" \
  --target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJ_ID}" \
  --project=${PROJ_ID} \
  --location=global

تأیید الزام‌آور بودن سیاست دسترسی IAM

نقاط اتصال فعال سیاست را به سیاست و هدف صحیح بررسی کنید:

# show policy binding details
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
  --project=${PROJ_ID} \
  --location=global

خروجی مورد انتظار:

name: projects/${PROJ_ID}/locations/global/policyBindings/${UAP_BINDING_NAME}
policy: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}
policyKind: ACCESS
target:
  resource: //cloudresourcemanager.googleapis.com/projects/${PROJ_ID}

این بخش مربوط به دروازه عامل (Agent Gateway) است... و در ادامه بخش سرور MCP قرار دارد.

۶. سرور MCP

در این بخش، شما یک سرور FastMCP سفارشی ایجاد خواهید کرد که ابزارهای add و subtract را در اختیار شما قرار می‌دهد و آن را مستقیماً از منبع در Cloud Run مستقر خواهید کرد. در طول استقرار منبع ( --source )، Cloud Build تصویر کانتینر را با استفاده از Dockerfile و uv موجود (که وابستگی‌های تعریف شده در pyproject.toml نصب کرده و server.py را اجرا می‌کند) بسته‌بندی می‌کند.

پس از استقرار سرویس Cloud Run، سرور MCP را به همراه مشخصات ابزار آن ( toolspec.json ) در Agent Registry ثبت می‌کنید تا Gemini Enterprise بتواند ابزارهای آن را کشف و فراخوانی کند.

ایجاد برنامه سرور MCP

یک دایرکتوری پروژه math-wizard برای کد برنامه ایجاد کنید:

# create directory for code
mkdir -p math-wizard

فایل مانیفست پروژه پایتون را بنویسید:

# create python project manifest file
cat > math-wizard/pyproject.toml << 'EOF'
[project]
name = "math-wizard"
version = "0.1.0"
description = "math wizard mcp server"
requires-python = ">=3.12"
dependencies = [
    "fastmcp==2.13.1",
]
EOF

برخی توابع ابزار دقیق اضافی در کد گنجانده شده‌اند تا هدرهای HTTP ورودی ( mcp-session-id ، x-forwarded-for ، user-agent و x-cloud-trace-context ) را برای اعتبارسنجی Cloud Logging و Cloud Trace ثبت کنند.

فایل کد برنامه را بنویسید:

# create mcp server application code
cat > math-wizard/server.py << 'EOF'
import asyncio
import json
import logging
import os
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_headers
from mcp.types import ToolAnnotations

logger = logging.getLogger(__name__)
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)

mcp = FastMCP("math wizard mcp server")

def log_network_context(tool_name: str, a: int, b: int) -> None:
    headers = get_http_headers()
    print(json.dumps({
        "severity": "INFO",
        "message": f">>> 🛠️ Tool: '{tool_name}' called with numbers '{a}' and '{b}'",
        "tool": tool_name,
        "mcp_session_id": headers.get("mcp-session-id"),
        "x_forwarded_for": headers.get("x-forwarded-for"),
        "user_agent": headers.get("user-agent"),
        "trace_header": headers.get("x-cloud-trace-context"),
    }), flush=True)

@mcp.tool(
    annotations=ToolAnnotations(
        readOnlyHint=True,
    )
)
def add(a: int, b: int) -> int:
    """Use this to add two numbers together.

    Args:
        a: The first number.
        b: The second number.

    Returns:
        The sum of the two numbers.
    """
    logger.info(f">>> 🛠️ Tool: 'add' called with numbers '{a}' and '{b}'")
    log_network_context("add", a, b)
    return a + b

@mcp.tool(
    annotations=ToolAnnotations(
        readOnlyHint=True,
    )
)
def subtract(a: int, b: int) -> int:
    """Use this to subtract two numbers.

    Args:
        a: The first number.
        b: The second number.

    Returns:
        The difference of the two numbers.
    """
    logger.info(f">>> 🛠️ Tool: 'subtract' called with numbers '{a}' and '{b}'")
    log_network_context("subtract", a, b)
    return a - b

if __name__ == "__main__":
    logger.info(f"🚀 MCP server started on port {os.getenv('PORT', 8080)}")
    asyncio.run(
        mcp.run_async(
            transport="streamable-http",
            host="0.0.0.0",
            port=int(os.getenv("PORT", 8080)),
        )
    )
EOF

برای تعریف دستورالعمل‌های ساخت تصویر کانتینر و دستورات راه‌اندازی Dockerfile بنویسید:

# create dockerfile
cat > math-wizard/Dockerfile << 'EOF'
# use official python 3.12 image
FROM python:3.12-slim

# install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# install the project into /app
COPY . /app
WORKDIR /app

# allow statements and log messages to immediately appear in the logs
ENV PYTHONUNBUFFERED=1

# install dependencies
RUN uv sync

EXPOSE 8080

# run the mcp server
CMD ["uv", "run", "server.py"]
EOF

استقرار سرویس در Cloud Run

سرور MCP را از منبع با استفاده از Cloud Build (که از حساب سرویس محاسباتی پیش‌فرض پروژه ${PROJ_NO}-compute@developer.gserviceaccount.com استفاده می‌کند) مستقر کنید:

# deploy cloud run service
gcloud run deploy ${MCP_NAME} \
  --source math-wizard \
  --region=${REGION} \
  --no-invoker-iam-check \
  --ingress=internal \
  --quiet

تأیید استقرار Cloud Run

برای تأیید پیکربندی فعال، جزئیات سرویس Cloud Run را بررسی کنید:

# show cloud run service details
gcloud run services describe ${MCP_NAME} --region=${REGION}

خروجی مورد انتظار:

<snip>
✔ Service math-wizard in region ${REGION}

URL:     https://math-wizard-${PROJ_NO}.${REGION}.run.app
Ingress: internal
Traffic:
  100% LATEST (currently math-wizard-00001-<id>)
</snip>

سرور MCP را در رجیستری نمایندگان ثبت کنید

برای اینکه Gemini Enterprise بتواند ابزارهای دقیق موجود در سرور MCP را کشف کند، باید هنگام ثبت نام در Agent Registry، یک فایل مشخصات ابزار ( toolspec.json ) ارائه شود.

مشخصات ابزار MCP را ایجاد کنید

# create tool spec file
cat > cfg/toolspec.json << 'EOF'
{
  "tools": [
    {
      "name": "add",
      "description": "Use this to add two numbers together.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "a": { "type": "integer", "description": "The first number." },
          "b": { "type": "integer", "description": "The second number." }
        },
        "required": ["a", "b"]
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    },
    {
      "name": "subtract",
      "description": "Use this to subtract two numbers.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "a": { "type": "integer", "description": "The first number." },
          "b": { "type": "integer", "description": "The second number." }
        },
        "required": ["a", "b"]
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    }
  ]
}
EOF

سرور MCP را در رجیستری نمایندگان ثبت کنید

# register mcp server in agent registry
gcloud agent-registry services create ${MCP_NAME} \
  --project=${PROJ_ID} \
  --location=${REGION} \
  --display-name="${MCP_NAME}-${PROJ_NO}.${REGION}.run.app" \
  --description="MANDATORY MATH & ARITHMETIC AGENT: You MUST ALWAYS invoke \
this tool for ANY mathematical calculation, addition (+), subtraction (-), \
sum, difference, or arithmetic question (including simple questions like \
'what is 67 + 345?'). NEVER compute arithmetic yourself and NEVER transfer \
math queries to file_and_coding_agent / code interpreter. Always delegate \
every math question to this tool." \
  --mcp-server-spec-type=tool-spec \
  --mcp-server-spec-content=cfg/toolspec.json \
  --interfaces=protocolBinding=JSONRPC,url="${MCP_URL}"

سرور MCP را در رجیستری Agent تأیید کنید

تأیید کنید که سرویس Cloud Run مستقر شده به عنوان یک سرور MCP ثبت شده در منطقه به همراه URL نقطه پایانی و ابزارهای موجود آن فهرست شده است:

# list registered mcp servers in agent registry
gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --format="table(
    name.basename():label=REGISTRY_ID,
    displayName:label=DISPLAY_NAME,
    interfaces[0].url:label=ENDPOINT_URL,
    tools[].name.list():label=TOOLS
  )"

خروجی مورد انتظار:

REGISTRY_ID                                         DISPLAY_NAME                                  ENDPOINT_URL                                              TOOLS
agentregistry-00000000-0000-0000-0012-3456789abcde  math-wizard-${PROJ_NO}.${REGION}.run.app      https://math-wizard-${PROJ_NO}.${REGION}.run.app/mcp      add,subtract

مشخصات پیکربندی سرویس را مشاهده کنید تا ببینید که تعاریف دقیق ابزار، طرح‌های ورودی و حاشیه‌نویسی‌های رفتاری را برای هر ابزار ثبت می‌کند:

# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --format="yaml(mcpServerSpec.content.tools)"

این بخش سرور MCP را به پایان می‌رساند... و در ادامه به بخش Gemini Enterprise می‌رسیم.

۷. شرکت جمینی

در این بخش، یک برنامه Gemini Enterprise و یک منبع ذخیره داده سرور MCP سفارشی مرتبط ایجاد و پیکربندی خواهید کرد.

مدل منبع موتور اکتشاف

یک برنامه Gemini Enterprise (که به عنوان یک منبع Engine در رابط برنامه‌نویسی کاربردی Discovery Engine نمایش داده می‌شود) لایه مرکزی تنظیم و رابط مکالمه‌ای برای کاربران نهایی است. این برنامه جلسات چت کاربر را مدیریت می‌کند، مدل‌های مولد را بر اساس داده‌های سازمانی بنا می‌کند و اجرای پویای ابزار را هماهنگ می‌کند.

برنامه‌های Gemini Enterprise از طریق فروشگاه‌های داده با داده‌ها و سیستم‌ها تعامل دارند:

  • انبارهای داده دانش: محتوای استاتیک (مانند فضای ذخیره‌سازی ابری، گوگل درایو، بیگ‌کوئری) را برای بازیابی افزوده (RAG) دریافت و فهرست‌بندی می‌کنند.
  • رابط‌های داده (ارائه‌دهندگان عمل): به APIهای پویای شخص ثالث یا سفارشی متصل می‌شوند. یک مخزن داده سرور MCP سفارشی، ابزارهای تعریف‌شده توسط پروتکل زمینه مدل (MCP) را در معرض نمایش قرار می‌دهد و مدل را قادر می‌سازد تا در طول مکالمه، توابع خارجی را به‌صورت پویا فراخوانی کند.

مسیریابی خروجی از طریق Agent Gateway

به طور پیش‌فرض، Gemini Enterprise ترافیک اجرای کانکتور و ابزار را از طریق شبکه‌های عمومی هدایت می‌کند. با این حال، برای بارهای کاری خصوصی VPC و مدیریت Zero-trust، موتور را می‌توان طوری پیکربندی کرد که مسیر خروجی را از طریق Agent Gateway هدایت کند:

  • هنگام ایجاد مخزن داده سفارشی سرور MCP در ادامه این تمرین، می‌توانید گزینه Route egress through Agent Gateway را در تنظیمات مخزن داده فعال کنید.
  • این امر فراخوانی‌های ابزار خروجی موتور را به دروازه عامل منطقه‌ای شما متصل می‌کند، تضمین می‌کند که همه درخواست‌های MCP Agent Identity برنامه را دارند، با استفاده از سیاست‌های دسترسی یکپارچه IAP و IAM (UAP) مجوز زمان اجرا را دریافت می‌کنند و اتصال شبکه PSC را به VPC خصوصی شما منتقل می‌کنند.

ایجاد برنامه Gemini Enterprise

روش زیر از API مربوط به discoveryengine.googleapis.com برای ایجاد منابع و پیکربندی برنامه Gemini Enterprise استفاده می‌کند. برای پیکربندی با استفاده از رابط کاربری کنسول ابری گوگل، برای دستورالعمل‌ها به بخش «ایجاد یک برنامه» مراجعه کنید.

# create engine (ge app)
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines?engineId=${GE_APP_INIT}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "displayName": "${GE_APP_DISPLAY_NAME}",
  "dataStoreIds": [],
  "solutionType": "SOLUTION_TYPE_SEARCH",
  "industryVertical": "GENERIC",
  "appType": "APP_TYPE_INTRANET",
  "searchEngineConfig": {
    "searchTier": "SEARCH_TIER_ENTERPRISE",
    "searchAddOns": [
      "SEARCH_ADD_ON_LLM"
    ]
  },
  "commonConfig": {
    "companyName": "${GE_APP_ORG_NAME}"
  }
}
EOF

تأیید ایجاد برنامه

# fetch engine (ge app) id
export GE_APP_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq -r --arg name "${GE_APP_DISPLAY_NAME}" '.engines[] | select(.displayName==$name) | .name | split("/") | last')

echo "engine (ge app) id: ${GE_APP_ID}"

برای مشاهده پیکربندی ایجاد شده، جزئیات موتور را مشاهده کنید:

# get engine (ge app) details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

به ویژگی‌های زیر که توسط سرور در پاسخ JSON پر شده‌اند، توجه کنید:

  • name : مسیر منبع متعارف ( projects/${PROJ_NO}/locations/global/collections/default_collection/engines/${GE_APP_ID} ).
  • sessionConfig.sessionManagementPolicy : مقدار پیش‌فرض آن "VERTEX_AI_MANAGED" است که چت چند نوبتی و حالت فراخوانی ابزار را در Agent Platform (که قبلاً با نام Vertex AI شناخته می‌شد) حفظ می‌کند.
  • observabilityConfig.observabilityEnabled : برای معیارهای پایه به صورت پیش‌فرض روی true تنظیم شده است (ثبت جزئیات اعلان و ثبت اطلاعات ابزار در مرحله بعد فعال می‌شود).

ارائه دهنده هویت را فعال کنید

Google Identity را به عنوان ارائه دهنده هویت برای احراز هویت کاربر نهایی در برنامه Gemini Enterprise خود فعال کنید.

روش زیر از API مربوط به discoveryengine.googleapis.com برای پیکربندی ارائه‌دهنده هویت برنامه Gemini Enterprise استفاده می‌کند. برای پیکربندی با استفاده از رابط کاربری کنسول Google Cloud، برای دستورالعمل‌ها به پیکربندی ارائه‌دهنده هویت مراجعه کنید.

# set identity provider
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "idpConfig": {
    "idpType": "GSUITE"
  }
}
EOF

تأیید ارائه دهنده هویت

# show identity provider
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

خروجی "idpType": "GSUITE" مربوط به ارائه دهنده هویت گوگل است.

(اختیاری) فعال کردن لایسنس آزمایشی Gemini Enterprise

اگر از پروژه‌ای استفاده می‌کنید که مجوزهای Gemini Enterprise به آن اختصاص داده شده است، می‌توانید از این مرحله صرف نظر کنید. اگر از پروژه جدیدی بدون مجوز استفاده می‌کنید، ادامه دهید و این مراحل را دنبال کنید.

یک منبع پیکربندی مجوز ایجاد کنید تا به کاربران Gemini Enterprise به مدت 30 روز جایگاه اعطا کند. این کار مجوز پیش‌فرض را برای نسخه آزمایشی جدید تنظیم می‌کند، بنابراین هر کاربری که وارد سیستم شود، به طور خودکار یک جایگاه دریافت می‌کند:

# configure free trial subscription
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/licenseConfigs?licenseConfigId=free_trial_gemini" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "subscriptionTier": "SUBSCRIPTION_TIER_SEARCH_AND_ASSISTANT",
  "freeTrial": true
}
EOF

تأیید کنید که مجوز اعمال شده است

# show license config
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/licenseConfigs/free_trial_gemini" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

عبارت‌های "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" و "freeTrial": true را بررسی کنید.

# verify auto-registration enabled on default user store
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/userStores/default_user_store" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

عبارت‌های ../free_trial_gemini" و "enableLicenseAutoRegister": true .

تنظیمات مشاهده‌پذیری را فعال کنید

فعال کردن قابلیت مشاهده در سطح برنامه (موتور) Gemini Enterprise به شما امکان می‌دهد تعاملات دستیار اصلی را با داده‌های معیارها در Metrics Explorer مشاهده کنید و ردیابی‌های سرتاسری را در Cloud Trace مرتبط سازید.

# set observability on engine (ge app)
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}?updateMask=observabilityConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "observabilityConfig": {
    "observabilityEnabled": true,
    "sensitiveLoggingEnabled": true
  }
}
EOF

تنظیمات مشاهده‌پذیری را تأیید کنید

# verify observability is enabled on engine (ge app)
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{observabilityConfig: .observabilityConfig}'

بررسی کنید که آیا عبارت "sensitiveLoggingEnabled": true .

اتصال به دروازه عامل

مسیریابی ترافیک خروجی از Gemini Enterprise از طریق Agent Gateway یک مرز متمرکز برای مدیریت و اجرای امنیت Zero-Trust برای همه فراخوانی‌های ابزار عامل هوش مصنوعی ایجاد می‌کند:

  • اجرای متمرکز سیاست‌ها: Agent Gateway به عنوان یک پروکسی درون‌خطی عمل می‌کند که درخواست‌های ابزار خروجی را قبل از خروج ترافیک از محیط Agent، با سیاست‌های مجوزدهی و کنترل‌های مدیریتی مقایسه می‌کند.
  • خروجی شبکه خصوصی: اتصال Gemini Enterprise به Agent Gateway تضمین می‌کند که فراخوانی‌های ابزار، سرورهای خصوصی MCP را در Cloud Run به طور ایمن از طریق Private Service Connect (PSC) هدف قرار می‌دهند و اینترنت عمومی را دور می‌زنند.
  • قابلیت حسابرسی یکپارچه: ثبت درخواست‌ها، تله‌متری و ردیابی حسابرسی متمرکز را در تمام سرورهای MCP متصل و ابزارهای خارجی فراهم می‌کند.

با پیکربندی agentGatewaySetting در برنامه Gemini Enterprise خود، تماس‌های خروجی ابزار و اپراتور که توسط درخواست‌های کاربر نهایی (مانند تماس‌ها به سرورهای MCP سفارشی وارد شده از Agent Registry و اپراتورهای A2A) آغاز می‌شوند، به طور خودکار از طریق Agent Gateway هدایت می‌شوند.

Patch the engine agentGatewaySetting to enable:

# bind engine (ge app) to agent gateway
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}?updateMask=agentGatewaySetting.defaultEgressAgentGateway.name" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "agentGatewaySetting": {
    "defaultEgressAgentGateway": {
      "name": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
    }
  }
}
EOF

Verify Agent Gateway binding

Retrieve the app configuration to confirm the agentGatewaySetting binding:

# verify engine (ge app) agent gateway configuration
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name: .name, displayName: .displayName, agentGatewaySetting: .agentGatewaySetting}'

Expected output:

{
  "name": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}",
  "displayName": "${GE_APP_DISPLAY_NAME}",
  "agentGatewaySetting": {
    "defaultEgressAgentGateway": {
      "name": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
    }
  }
}

Create custom MCP server data store

In this section you will connect the MCP server to Gemini Enterprise by creating a custom MCP data store.

Using the Discovery Engine API, this is a two-step process:

  1. Create ( :setUpDataConnector ): Creates a dedicated Collection resource ( ${MCP_NAME}-%timestamp-collection ), attaches the DataConnector ( custom_mcp ), and provisions its backing DataStore ( ..._mcp_data ).
  2. Activate ( PATCH .../dataConnector?updateMask=actionConfig ): Activates the connector's action runtime ( actionState: "ACTIVE" ) using the Agent Registry tool spec and binds the DataStore ( dataStoreIds ) to your Gemini Enterprise Engine .
# fetch mcp server agent registry resource name
export MCP_REGISTRY_URI=$(gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --filter="displayName:${MCP_NAME}" \
  --format="value(name)")

echo "mcp registry name: ${MCP_REGISTRY_URI}"
echo "mcp url: ${MCP_URL}"

Create data connector

# create custom mcp data connector from agent registry and link to engine
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}:setUpDataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "collectionId": "${MCP_NAME}-$(date +%s)-collection",
  "collectionDisplayName": "${MCP_NAME}-collection",
  "dataConnector": {
    "dataSource": "custom_mcp",
    "dataSourceVersion": 1,
    "params": {
      "oauth_access_token": "unused"
    },
    "refreshInterval": "86400s",
    "entities": [
      {
        "entityName": "mcp_data"
      }
    ],
    "connectorModes": [
      "FEDERATED"
    ],
    "actionConfig": {
      "isActionConfigured": true,
      "createBapConnection": true,
      "actionParams": {
        "auth_type": "NO_AUTH",
        "instance_uri": "${MCP_URL}",
        "mcp_server_source": "REGISTRY_MCP",
        "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
        "mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
        "use_agent_gateway_egress": true,
        "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
      }
    }
  }
}
EOF

Verify data connector creation

# fetch collection id
export GE_COLLECTION_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq -r --arg dname "${MCP_NAME}-collection" '.collections[] | select(.displayName == $dname) | .name | split("/") | last' | head -n 1)

echo "ge collection id: ${GE_COLLECTION_ID}"

Check the "registry_mcp_server_name" field populates with the Agent Registry UUID for the MCP server:

# show data connector details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/dataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name, state, actionState, connectorModes, bapConfig, registry_mcp_server_name: .actionConfig.actionParams.registry_mcp_server_name}'

View the MCP server registry entry in the Google Cloud Console UI:

echo "mcp server registry page url: https://console.cloud.google.com/agent-platform/agent-registry/mcp-servers/${REGION}/${MCP_REGISTRY_URI##*/}/overview?project=${PROJ_ID}"

Activate data connector

# activate and bind data connector
curl -s -X PATCH "https://discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector?updateMask=actionConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "name": "projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector",
  "actionConfig": {
    "isActionConfigured": true,
    "createBapConnection": true,
    "actionParams": {
      "auth_type": "NO_AUTH",
      "instance_uri": "${MCP_URL}",
      "mcp_server_source": "REGISTRY_MCP",
      "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
      "mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
      "use_agent_gateway_egress": true,
      "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
    }
  }
}
EOF

Verify custom MCP server linkages

# show engine (ge app) details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name: .name, dataStoreIds: .dataStoreIds, agentGatewaySetting: .agentGatewaySetting}'

Check for the linked data store "dataStoreIds": "collection-math-wizard- _mcp_data" .

# show collection details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq --arg app "${GE_APP_ID}" '.collections[] | select(.dataConnector.actionConfig.actionParams.agent_gateway_engine // "" | endswith($app)) | .dataConnector | {name: .name, state: .state, actionState: .actionState, connectorModes: .connectorModes, actionParams: .actionConfig.actionParams}'

Check for "state": "ACTIVE" with all the parameters populated.

Tool actions

When you inspect the math-wizard-collection data store in the Gemini Enterprise dashboard, you will notice that the Actions tab is not used and the ↻ Reload custom actions button is disabled. This is expected behavior.

View the data store details page in the Google Cloud Console UI:

echo "data store details page url: https://console.cloud.google.com/gemini-enterprise/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/connector/details?project=${PROJ_ID}"

Depending on how you connect a custom MCP server to Gemini Enterprise, tool discovery and governance are handled in one of two ways:

  • Direct Custom MCP ( BYO_MCP workflow): When you configure a custom MCP server directly inside Gemini Enterprise without Agent Registry, the data store itself manages the tool catalog ( connectorModes: ["FEDERATED", "ACTIONS"] ). You must open the Actions tab, click ↻ Reload custom actions to fetch the tools/list schema, and manually toggle individual tools ( add and subtract ) on or off in the UI.
  • Agent Registry Import ( REGISTRY_MCP workflow used in this codelab): When you import an MCP server from Agent Registry , Agent Registry serves as the authoritative source of truth for the MCP endpoint, its interface metadata, and its tool catalog ( connectorModes: ["FEDERATED"] ). Gemini Enterprise automatically enables the registered MCP tools at runtime through the engine's Agent Gateway without requiring you to manually reload or toggle actions in the data store UI.

This concludes the Gemini Enterprise app portion... next on to the Validate section.

8. Validate

In this section you will trigger live MCP tool calls from the Gemini Enterprise web app and trace the request flow across Agent Gateway, Cloud DNS, VPC firewall, and Cloud Run logs. You will then tighten the IAM Unified Access Policy to allow subtract while blocking add , verifying zero-trust enforcement at the gateway.

User access

Construct the URL for the Gemini Enterprise web app:

# fetch app user url
export GE_WIDGET_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/widgetConfigs/default_search_widget_config" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  | jq -r '.configId')

export GE_APP_USER_URL="https://vertexaisearch.cloud.google.com/home/cid/${GE_WIDGET_ID}"

echo "app user url: ${GE_APP_USER_URL}"

Follow the link to open the Gemini Enterprise web app chat interface in your browser and click Get started .

Test agent queries in chat

In the chat UI, confirm the math-wizard-collection data connector is enabled by clicking on the puzzle piece icon for Connectors at the bottom of the chat box. You should see a toggle button that appears on (is colored in).

Try out the following test queries:

what is 2342345 - 98234798324?
what is 72347234 + 234234?

Verify that the assistant returns the correct answers and displays an interactive action citation badge (like Math Calculation (8s) 🤖 Agentgateway Agent ) beneath each response, confirming the tool was executed.

Inspect logs in Cloud Logging

Verify that Gemini Enterprise routed the tool calls through Agent Gateway and the private VPC network by inspecting the logs in Cloud Logging.

1. Verify Agent Gateway & IAP authorization

Confirm that Agent Gateway intercepted the request, resolved the target in Agent Registry, delegated authorization to IAP, and permitted the tool call:

# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    httpRequest.status:label=STATUS, \
    httpRequest.serverIp:label=SERVER_IP, \
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD, \
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL, \
    jsonPayload.authzPolicyInfo.result:label=AUTHZ, \
    jsonPayload.agentGatewayInfo.agentRegistryResource.basename():label=REGISTRY_MCP
  )"

Verify that the output contains:

  • STATUS : 200 (successful execution) and 202 ( notifications/initialized handshake).
  • SERVER_IP : Google APIs PSC endpoint IP ( 172.16.20.20:443 ).
  • MCP_METHOD & TOOL : The MCP protocol sequence ( notifications/initialized , tools/list , and tools/call with add or subtract ).
  • AUTHZ : ALLOWED (IAP authorization permitted egress).
  • REGISTRY_MCP : Resolved Agent Registry resource ID ( agentregistry-... ).

2. Verify DNS and firewall transit

Confirm that Cloud DNS resolved the hostname to the PSC endpoint and that the firewall permitted traffic from the Agent Gateway interface:

# show dns logs
gcloud logging read 'resource.type="dns_query"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    jsonPayload.queryName:label=QUERY_NAME, \
    jsonPayload.queryType:label=TYPE, \
    jsonPayload.responseCode:label=RCODE, \
    jsonPayload.rdata:label=RDATA
  )"
# show firewall logs
gcloud logging read 'logName:"compute.googleapis.com%2Ffirewall"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    jsonPayload.connection.src_ip:label=SRC_IP, \
    jsonPayload.connection.dest_ip:label=DEST_IP, \
    jsonPayload.connection.dest_port:label=PORT, \
    jsonPayload.rule_details.reference.basename():label=RULE, \
    jsonPayload.disposition:label=DISPOSITION
  )"

Verify the following values:

  • DNS QUERY_NAME & RDATA : Resolves math-wizard-...run.app. ( A record, NOERROR ) to 172.16.20.20 .
  • Firewall SRC_IP & DEST_IP : 192.168.10.2 (Agent Gateway PSC interface IP) to 172.16.20.20:443 .
  • Firewall RULE & DISPOSITION : Matched firewallPolicy:fw-policy-... with ALLOWED .

3. Verify Cloud Run tool execution

Confirm that the Cloud Run container received and processed the tool call:

# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
  AND textPayload:"Tool:"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="value(timestamp.date(tz=LOCAL), textPayload)"

Verify that textPayload displays tool execution entries (eg, >>> 🛠️ Tool: 'subtract' called with numbers '[x]' and '[y]' ).

Test least-privilege policy enforcement

In the initial IAM access policy, any method or tool was permitted as long as the destination was registered ( destination.is_registered == true ). In this step, update the policy to enforce least-privilege by allowing only the subtract tool while blocking add .

Update IAM access policy

When restricting MCP tool execution, use a two-rule pattern :

  1. Rule 1 (MCP discovery and handshake): Permits non-tool-call MCP lifecycle methods ( destination.is_registered == true and destination.agent_registry.mcp_server.method != 'tools/call' ). Because Gemini Enterprise negotiates stream setup and discovery ( initialize , notifications/initialized , tools/list ) before invoking a tool—and destination.agent_registry.mcp_server.tool.name is only populated during tools/call —Rule 1 is necessary to keep session initialization and catalog discovery working.
  2. Rule 2 (Tool-level restriction): Restricts tools/call execution so only the subtract tool is permitted ( destination.is_registered == true , destination.agent_registry.mcp_server.method == 'tools/call' , and destination.agent_registry.mcp_server.tool.name == 'subtract' ).

Update the access policy rule manifest file with both rules:

# create access policy rule file (update: allow subtract only)
cat > cfg/${UAP_POLICY_NAME}-rule-update.json << EOF
[
  {
    "description": "allow ge assistant to any registered endpoint to perform mcp discovery and handshake",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.mcp_server.method != 'tools/call'"
      }
    }
  },
  {
    "description": "allow ge assistant to any registered mcp server with tool call subtract",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.mcp_server.method == 'tools/call' && \
         destination.agent_registry.mcp_server.tool.name == 'subtract'"
      }
    }
  }
]
EOF

Apply the updated rules to the IAM access policy:

# update iam access policy
gcloud iam access-policies update ${UAP_POLICY_NAME} \
  --details-rules=cfg/${UAP_POLICY_NAME}-rule-update.json \
  --project=${PROJ_ID} \
  --location=global

Verify IAM access policy

Check the new IAM access policy is applied and only the subtract tool is allowed:

# show iam access policy details
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
  --project=${PROJ_ID} \
  --location=global \
  --flatten="details.rules[]" \
  --format="table( \
    details.rules.principals[0].scope(engines).sub('assistants/default_assistant/agents/default', '...'):label=PRINCIPAL, \
    details.rules.effect:label=EFFECT, \
    details.rules.conditions.'iap.googleapis.com'.expression.sub('\s*&&\s*', '\n&& ').sub('\s*\|\|\s*', '\n|| '):label=EXPRESSION
  )"

Test a prohibited tool call

Return to the Gemini Enterprise web app chat UI and try another test query:

what is 100 plus 20?

The assistant attempts to invoke add , but Agent Gateway and IAP evaluate the IAM policy condition as false and deny the egress request with HTTP 403 Forbidden . In the chat UI, you will notice the assistant display Calculate Sum and spin on 🤖 Agentgateway Agent ... Working on it. as it retries the blocked tool call. This is expected behavior . It confirms that Agent Gateway and IAP are actively intercepting and denying disallowed tool execution at the network level.

Re-inspect logs in Cloud Logging

View the Agent Gateway log entries and notice the new 403 entries corresponding to the disallowed add tool call:

# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    httpRequest.status:label=STATUS, \
    httpRequest.serverIp:label=SERVER_IP, \
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD, \
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL, \
    jsonPayload.authzPolicyInfo.result:label=AUTHZ, \
    jsonPayload.agentGatewayInfo.agentRegistryResource.basename():label=REGISTRY_MCP
  )"

Expected output:

TIMESTAMP            STATUS  SERVER_IP         MCP_METHOD                 TOOL  AUTHZ    REGISTRY_MCP
YYYY-MM-DDTHH:MM:SS  403                       tools/call                 add   DENIED   agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS  403
YYYY-MM-DDTHH:MM:SS  202     172.16.20.20:443  notifications/initialized        ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS          172.16.20.20:443                                   ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS  200     172.16.20.20:443  initialize                       ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde

Check that the additional request never reached the Cloud Run backend:

# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
  AND textPayload:"Tool:"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="value(timestamp.date(tz=LOCAL), textPayload)"

The command returns no new entries, confirming that Agent Gateway successfully enforced the IAM access policy.

This concludes the validate portion... next on to the Cleanup section.

9. Cleanup

Follow these steps to delete the resources and configurations created in this lab.

Remove Gemini Enterprise components

# delete gemini enterprise engine (app)
curl -s -X DELETE "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

# delete custom mcp collection, data connector, and backing data store
curl -s -X DELETE "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

# reset identity provider configuration
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d '{"idpConfig":{"idpType":"IDP_TYPE_UNSPECIFIED"}}'

Remove MCP server components

# delete agent registry service
gcloud -q agent-registry services delete ${MCP_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID}

# delete cloud run service, source-deploy artifact registry repo, and staging bucket
gcloud -q run services delete ${MCP_NAME} \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q artifacts repositories delete cloud-run-source-deploy \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q storage rm --recursive gs://run-sources-${PROJ_ID}-${REGION} \
  --project=${PROJ_ID}

Remove Agent Gateway and IAM access policies

# delete gateway authorization policy, iap extension, and agent gateway
gcloud -q network-security authz-policies delete ${AGW_NAME}-authz-policy-iap \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q network-services agent-gateways delete ${AGW_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID}
# delete iam policy binding and access policy
gcloud -q iam policy-bindings delete ${UAP_BINDING_NAME} \
  --location=global \
  --project=${PROJ_ID}

gcloud -q iam access-policies delete ${UAP_POLICY_NAME} \
  --location=global \
  --project=${PROJ_ID}

Remove DNS and firewall components

# delete dns record set, managed zone, and policy
gcloud -q dns record-sets delete "*.run.app." \
  --type=A \
  --zone=priv-zone-run \
  --project=${PROJ_ID}

gcloud -q dns managed-zones delete priv-zone-run \
  --project=${PROJ_ID}

gcloud -q dns policies update dns-policy-${SLUG} \
  --networks="" \
  --project=${PROJ_ID}

gcloud -q dns policies delete dns-policy-${SLUG} \
  --project=${PROJ_ID}
# delete firewall policy association, rule, and policy
gcloud -q compute network-firewall-policies associations delete \
  --name=fw-policy-bind-${SLUG} \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --project=${PROJ_ID}

gcloud -q compute network-firewall-policies rules delete 1001 \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --project=${PROJ_ID}

gcloud -q compute network-firewall-policies delete fw-policy-${SLUG} \
  --global \
  --project=${PROJ_ID}

Remove PSC and VPC network components

# delete psc forwarding rule and internal ip address
gcloud -q compute forwarding-rules delete psc2gapis \
  --global \
  --project=${PROJ_ID}

gcloud -q compute addresses delete ip-psc2gapis \
  --global \
  --project=${PROJ_ID}
# delete psc network attachment, subnet, and vpc network
gcloud -q compute network-attachments delete psc-na-${REGION}-agw \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q compute networks subnets delete subnet-${REGION}-agw \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q compute networks delete vnet-${SLUG} \
  --project=${PROJ_ID}

حذف لغو سیاست‌های سازمانی و فایل‌های محلی

# delete project-level organization policy overrides
gcloud -q org-policies delete discoveryengine.managed.disableCustomMcpServerConnector --project=${PROJ_ID}
gcloud -q org-policies delete iam.managed.disableAccessPolicyBinding --project=${PROJ_ID}
# remove local project files
rm -rf cfg math-wizard

This concludes the cleanup work... next on to the Conclusion !

10. Conclusion

Congratulations! You built an end-to-end architecture enabling a Gemini Enterprise app to securely discover and invoke tools on a private custom MCP server :

  • Custom MCP server & Agent Registry: Deployed a private FastMCP service on Cloud Run ( --ingress=internal ) and registered its endpoint and tool schema ( add and subtract ) in Agent Registry.
  • Gemini Enterprise integration: Provisioned a Gemini Enterprise app, bound outbound tool traffic to Agent Gateway , and attached the registered MCP server as a REGISTRY_MCP data connector.
  • Private VPC egress & zero-trust governance: Routed tool execution privately over PSC ( 172.16.20.20 ) and enforced tool-level least privilege using IAP and IAM Unified Access Policies ( destination.agent_registry.* ).

cosmopup

Cosmpup thinks Codelabs are absolutely goated!

قدم بعدی چیست؟

Feel free to offer comments, questions, or corrections by using this feedback form .

متشکرم!