1. לפני שמתחילים
Model Context Protocol (MCP) הוא תקן פתוח שמאפשר למודלים ולסוכני AI לגשת בצורה מאובטחת לכלים, למסדי נתונים ולנתוני הקשר של הארגון. מאז ההשקה שלו בשנת 2024, הפרוטוקול אומץ באופן נרחב על ידי ספקי ענן וספקי מודלים גדולים של שפה (LLM). המפרט החדש ביותר MCP Spec 2026-07-28 (MCP 2.0) מגדיר ארכיטקטורה בלי שמירת מצב, העברות פשוטות והקלדה קפדנית של תוצאות, תוך שמירה על תאימות לאחור עם גרסאות קודמות.
MCP Python SDK הרשמי (mcp>=2.0.0) מספק את MCPServer (mcp.server.mcpserver.MCPServer), שמחליף את FastMCP ב-MCP 2.0 כמסגרת בעלת ביצועים גבוהים וידידותית למפתחים ליצירת שרתי MCP מוכנים לייצור, בהתאם למפרט MCP המודרני (28 ביולי 2026) עם העברות HTTP ו-Server-Sent Events (SSE) שניתנות להזרמה באמצעות SSL/TLS.
בשיעור Codelab הזה תלמדו איך ליצור שרת MCP ברמת ייצור באמצעות MCPServer מ-MCP 2.0 Python SDK וניהול תלות uv. תציידו את שרת ה-MCP בארבעה כלים של Google Cloud (הפעלת Vertex AI Gemini, בדיקה של Google Cloud Storage, כתיבת ביקורת של Cloud Logging ובדיקת תקינות של משאבי Google Cloud). לאחר מכן, תכניסו את השרת לקונטיינר ותפרסו אותו בשני יעדי זמן ריצה ב-Google Cloud: Cloud Run ו-Google Kubernetes Engine (GKE) Autopilot. בנוסף, תרשמו את שרת ה-MCP ותשתמשו בו ב-Gemini Enterprise Agent Platform.
הפעולות שתבצעו:
- פיתוח
MCPServerבאמצעות 4 כלים של Google Cloud עם Python 3.12 ואילך, ו-uvבהתאם ל-MCP Spec 2026-07-28. - יצירת קונטיינר לשרת ה-MCP באמצעות Docker build רב-שלבי.
- מאבטחים ופורסים את שרת ה-MCP ב-Cloud Run עם אימות IAM ואבטחת SSL/TLS.
- מאבטחים ופורסים את שרת ה-MCP ב-GKE Autopilot באמצעות Workload Identity ו-Kubernetes Gateway API עם TLS.
- רושמים את נקודת הקצה של שרת ה-MCP המאובטח ב-Gemini Enterprise Agent Platform באמצעות כותרות של טוקן bearer של OIDC.
הדרישות
- פרויקט ב-Google Cloud שהחיוב בו מופעל.
- Google Cloud SDK (
gcloudCLI) מותקן ומוגדר. - Python 3.12 ואילך ומנהל החבילות
uvמותקנים. - האפליקציה
dockerהותקנה. - הכלי של
kubectlהותקן.
2. הגדרת סביבת Google Cloud
לפני שיוצרים משאבים, צריך לאמת את הסביבה ולהפעיל את ממשקי Google Cloud API הנדרשים.
אימות של ה-CLI של gcloud
מתחברים לחשבון Google Cloud:
gcloud auth login
מגדירים את מזהה הפרויקט הפעיל ב-Google Cloud:
export PROJECT_ID=$(gcloud config get-value project)
gcloud config set project ${PROJECT_ID}
הפעלת שירותי Google Cloud
מפעילים את כל ממשקי ה-API הנדרשים ל-Cloud Run, GKE, Vertex AI, Artifact Registry, Cloud Build, Cloud Logging, Storage ו-Compute Engine:
gcloud services enable \
agentregistry.googleapis.com \
run.googleapis.com \
container.googleapis.com \
artifactregistry.googleapis.com \
aiplatform.googleapis.com \
logging.googleapis.com \
storage.googleapis.com \
compute.googleapis.com \
iam.googleapis.com \
cloudbuild.googleapis.com \
--project="${PROJECT_ID}"
מוודאים שממשקי ה-API הופעלו בהצלחה:
Operation "operations/..." finished successfully.
אימות של Application Default Credentials
מאמתים את הסביבה כדי שספריות הלקוח של Python יוכלו לגשת ל-Vertex AI ול-Cloud Storage באופן מקומי במהלך הפיתוח:
gcloud auth application-default login
3. איך יוצרים שרת MCP באמצעות MCPServer ו-uv
בשלב הזה, תפעילו פרויקט Python באמצעות uv ותבנו MCPServer שתומך בארבע יכולות של Google Cloud.
הפעלת פרויקט באמצעות uv
יוצרים את ספריית השרת ומפעילים את uv:
mkdir -p mcp-server/src/mcp_server
cd mcp-server
uv init --lib
מעתיקים את הקוד לקובץ pyproject.toml:
[project]
name = "secure-mcp-gcp-server"
version = "0.1.0"
description = "MCP server with Google Cloud tools supporting MCP Spec 2026-07-28 over Streamable HTTP"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"mcp>=2.0.0",
"google-genai>=1.0.0",
"google-cloud-storage>=2.14.0",
"google-cloud-logging>=3.11.0",
"google-cloud-resource-manager>=1.12.0",
"uvicorn>=0.30.0",
"httpx2>=0.1.0",
"pydantic>=2.7.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/mcp_server"]
סנכרון יחסי תלות באמצעות uv:
uv sync
כתיבת הקוד של MCPServer
יוצרים את קובץ ההטמעה של השרת במיקום src/mcp_server/server.py:
import logging
import os
from typing import Any
from google import genai
from google.cloud import logging as cloud_logging
from google.cloud import storage
from mcp.server.mcpserver import MCPServer
from starlette.requests import Request
from starlette.responses import PlainTextResponse
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("mcp-gcp-server")
# Initialize MCPServer conforming to MCP Spec 2026-07-28
mcp = MCPServer(
"Google Cloud Production Tools",
instructions="MCP Server conforming to MCP Spec 2026-07-28 for Vertex AI, Cloud Storage, Audit Logging, and Health Inspection.",
)
@mcp.custom_route("/healthz", methods=["GET"])
async def health_check(request: Request) -> PlainTextResponse:
"""Kubernetes readiness and liveness probe health check endpoint."""
return PlainTextResponse("OK")
@mcp.tool(description="Generate content or answer questions using Vertex AI Gemini model.")
def vertex_ai_generate_content(
prompt: str,
model_name: str = "gemini-2.5-flash",
project_id: str | None = None,
location: str = "us-central1",
) -> str:
"""Invokes Vertex AI Gemini API using official google-genai SDK."""
target_project = project_id or os.getenv("GCP_PROJECT") or os.getenv("GOOGLE_CLOUD_PROJECT")
if not target_project:
return "Error: GCP project ID not configured."
try:
client = genai.Client(vertexai=True, project=target_project, location=location)
response = client.models.generate_content(
model=model_name,
contents=prompt,
)
return response.text or "No text returned from Gemini."
except Exception as e:
logger.error("Vertex AI Tool Error: %s", e)
return f"Error executing Vertex AI tool: {e!s}"
@mcp.tool(description="List objects and inspect metadata for a specified Google Cloud Storage bucket.")
def gcs_bucket_inspector(
bucket_name: str,
max_results: int = 10,
prefix: str | None = None,
) -> dict[str, Any]:
"""Inspects GCS bucket content and metadata conforming to MCP Spec 2026-07-28 resultType schema."""
try:
client = storage.Client()
bucket = client.bucket(bucket_name)
blobs = list(client.list_blobs(bucket, max_results=max_results, prefix=prefix))
items = [{"name": b.name, "size_bytes": b.size, "updated": str(b.updated)} for b in blobs]
return {
"resultType": "complete",
"bucket_name": bucket_name,
"object_count_sample": len(items),
"objects": items,
}
except Exception as e:
logger.error("GCS Inspector Error: %s", e)
return {"resultType": "complete", "error": f"Failed to inspect GCS bucket: {e!s}"}
@mcp.tool(description="Write structured operational or security audit log records to Google Cloud Logging.")
def cloud_logging_audit_writer(
log_name: str,
message: str,
severity: str = "INFO",
metadata: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""Sends structured audit entry to Cloud Logging."""
try:
client = cloud_logging.Client()
logger_instance = client.logger(log_name)
payload = {"message": message, "metadata": metadata or {}, "source": "mcp-server-gcp"}
logger_instance.log_struct(payload, severity=severity.upper())
return {
"resultType": "complete",
"status": "success",
"log_name": log_name,
"recorded_message": message,
}
except Exception as e:
logger.error("Cloud Logging Error: %s", e)
return {"resultType": "complete", "error": f"Failed to record audit log: {e!s}"}
@mcp.tool(description="Check health and operational state of Google Cloud project resources.")
def gcp_resource_health_checker(project_id: str | None = None) -> dict[str, Any]:
"""Returns project resource summary and status."""
target_project = project_id or os.getenv("GOOGLE_CLOUD_PROJECT") or "unknown-project"
return {
"resultType": "complete",
"status": "HEALTHY",
"project_id": target_project,
"mcp_spec_version": "2026-07-28",
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/serverInfo": {"name": "mcp-gcp-server", "version": "0.1.0"},
},
"transports_enabled": ["Streamable HTTP"],
"ssl_tls_enabled": True,
}
if __name__ == "__main__":
port = int(os.getenv("PORT", "8080"))
logger.info("Starting MCPServer on port %d (Streamable HTTP Transport, Spec 2026-07-28)...", port)
mcp.run(
transport="streamable-http",
host="0.0.0.0",
port=port,
stateless_http=True,
json_response=True,
)
בדיקת שרת ה-MCP באופן מקומי
שלב 1: הפעלת שרת ה-MCP
בטרמינל הראשי, מפעילים את השרת באמצעות uv:
uv run python -m src.mcp_server.server
יוצגו לכם יומני הפעלה שמאשרים ששרת ה-HTTP של Streamable מאזין ביציאה 8080:
INFO:mcp-gcp-server:Starting MCPServer on port 8080 (Streamable HTTP Transport, Spec 2026-07-28)... INFO: Started server process [12345] INFO: Waiting for application startup. INFO:mcp.server.streamable_http_manager:StreamableHTTP session manager started INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
משאירים את הטרמינל הזה פתוח ופעיל.
שלב 2: אימות של נקודת קצה (endpoint) של HTTP שאפשר להזרים ממנה נתונים באמצעות curl
ב-MCP 2.0 (MCP Spec 2026-07-28), לחיצת היד initialize עם שמירת מצב והכותרת Mcp-Session-Id מוחלפות בבקשות ללא שמירת מצב. אפשר להפעיל את tools/list ישירות על ידי העברת הכותרות MCP-Protocol-Version ו-Mcp-Method יחד עם מטא-נתונים של הלקוח ב-params._meta.
פותחים חלון טרמינל שני ושולחים בקשת HTTP POST של Streamable:
cd mcp-server
curl -i -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/list" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "curl-test",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'
MCPServer יגיב עם HTTP/1.1 200 OK ויחזיר את התוצאה של JSON-RPC tools/list ישירות:
HTTP/1.1 200 OK
date: Wed, 12 Aug 2026 14:55:00 GMT
server: uvicorn
content-type: application/json
{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"vertex_ai_generate_content",...},{"name":"gcs_bucket_inspector",...},{"name":"cloud_logging_audit_writer",...},{"name":"gcp_resource_health_checker",...}]}}
שלב 3: מריצים את לקוח הבדיקה של MCP
כדי לבדוק את האפשרות לאתר ולהפעיל כלים בשרת המקומי באמצעות HTTP ניתן להזרמה, יוצרים סקריפט של לקוח לבדיקה src/mcp_server/test_client.py:
import asyncio
from mcp import Client
from mcp.types import TextContent
async def test_mcp_server() -> None:
"""Connects to the local MCP v2.0 server, lists tools, and invokes health check."""
server_url = "http://localhost:8080/mcp"
print(f"[*] Connecting to local MCPServer at {server_url} (Streamable HTTP)...")
async with Client(server_url) as client:
print(
f"[+] Connected (protocol: {client.protocol_version}, "
f"server: {client.server_info.name if client.server_info else 'unknown'})."
)
# List available tools
tools_response = await client.list_tools()
print("\n[*] Discovered MCP Tools:")
for tool in tools_response.tools:
print(f" - {tool.name}: {tool.description}")
# Invoke gcp_resource_health_checker tool
print("\n[*] Invoking tool: gcp_resource_health_checker...")
health_result = await client.call_tool("gcp_resource_health_checker", {})
print("[+] Result:")
for content in health_result.content:
if isinstance(content, TextContent):
print(content.text)
if __name__ == "__main__":
asyncio.run(test_mcp_server())
מריצים את הסקריפט של לקוח הבדיקה באמצעות uv:
uv run python src/mcp_server/test_client.py
אמור להופיע פלט שמראה שהחיבור הצליח, שהכלי זוהה והכלי הופעל:
[*] Connecting to local MCPServer at http://localhost:8080/mcp (Streamable HTTP)...
[+] Connected (protocol: 2026-07-28, server: Google Cloud Production Tools).
[*] Discovered MCP Tools:
- vertex_ai_generate_content: Generate content or answer questions using Vertex AI Gemini model.
- gcs_bucket_inspector: List objects and inspect metadata for a specified Google Cloud Storage bucket.
- cloud_logging_audit_writer: Write structured operational or security audit log records to Google Cloud Logging.
- gcp_resource_health_checker: Check health and operational state of Google Cloud project resources.
[*] Invoking tool: gcp_resource_health_checker...
[+] Result:
{"resultType": "complete", "status": "HEALTHY", "project_id": "my-gcp-project", "mcp_spec_version": "2026-07-28", "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/serverInfo": {"name": "mcp-gcp-server", "version": "0.1.0"}}, "transports_enabled": ["Streamable HTTP"], "ssl_tls_enabled": true}
אחרי האימות, לוחצים על CTRL+C במסוף הראשי כדי לעצור את השרת המקומי.
4. העברת שרת ה-MCP לקונטיינר
כדי לפרוס את שרת ה-MCP ב-Cloud Run וב-GKE Autopilot, צריך לארוז את השרת בקובץ אימג' מינימלי של קונטיינר באמצעות קובץ Dockerfile רב-שלבי שמבוסס על uv.
יצירת Dockerfile
ב-mcp-server/Dockerfile:
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
WORKDIR /app
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
COPY pyproject.toml uv.lock* /app/
RUN uv sync --no-install-project --no-dev
COPY README.md /app/
COPY src /app/src
RUN uv sync --no-dev
FROM python:3.12-slim-bookworm
WORKDIR /app
COPY --from=builder /app /app
ENV PATH="/app/.venv/bin:$PATH"
ENV PORT=8080
ENV PYTHONUNBUFFERED=1
EXPOSE 8080
CMD ["python", "-m", "src.mcp_server.server"]
יצירה של קובץ אימג' והעברה שלו ל-Artifact Registry
יוצרים מאגר Artifact Registry:
gcloud artifacts repositories create mcp-servers \
--repository-format=docker \
--location=us-central1 \
--description="Docker repository for MCP Servers" \
--project="${PROJECT_ID}"
נותנים לחשבון המשתמש ולחשבון השירות שמשמש כברירת המחדל של Compute Engine את הרשאות ה-IAM הנדרשות, כדי ש-Cloud Build יוכל להכין מקורות, לכתוב יומנים ולדחוף תמונות ל-Artifact Registry:
export USER_EMAIL=$(gcloud config get-value account)
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="user:${USER_EMAIL}" \
--role="roles/cloudbuild.builds.editor"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="user:${USER_EMAIL}" \
--role="roles/storage.admin"
export DEFAULT_SA=$(gcloud iam service-accounts list \
--filter="email:compute@developer.gserviceaccount.com" \
--format="value(email)" \
--project="${PROJECT_ID}")
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${DEFAULT_SA}" \
--role="roles/storage.objectViewer"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${DEFAULT_SA}" \
--role="roles/artifactregistry.writer"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${DEFAULT_SA}" \
--role="roles/logging.logWriter"
שולחים את יצירת קובץ האימג' באמצעות Cloud Build:
export IMAGE_URI="us-central1-docker.pkg.dev/${PROJECT_ID}/mcp-servers/secure-mcp-server:latest"
gcloud builds submit . --tag="${IMAGE_URI}" --project="${PROJECT_ID}"
בסיום, קובץ האימג' של הקונטיינר מאוחסן באופן מאובטח ב-Artifact Registry:
SUCCESS: Image published to us-central1-docker.pkg.dev/.../secure-mcp-server:latest
5. פריסה ל-Cloud Run עם IAM ו-HTTPS
Cloud Run מספק סביבה מנוהלת ללא שרת (serverless) עם סיום אוטומטי של אישור HTTPS / SSL ובקרת גישה פרטנית של Cloud IAM.
יצירת חשבון שירות ייעודי
יוצרים חשבון שירות של Google עם הרשאות מינימליות ל-Cloud Run:
gcloud iam service-accounts create mcp-server-cr-sa \
--display-name="MCP Server Cloud Run SA" \
--project="${PROJECT_ID}"
export SA_EMAIL="mcp-server-cr-sa@${PROJECT_ID}.iam.gserviceaccount.com"
# Grant Vertex AI, Logging, and GCS permissions
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/aiplatform.user"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/logging.logWriter"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/storage.objectViewer"
פריסת שירות ב-Cloud Run
פורסים את הקונטיינר ב-Cloud Run עם אימות IAM (--no-allow-unauthenticated) ואבטחת SSL מנוהלת כברירת מחדל:
gcloud run deploy secure-mcp-server \
--image="${IMAGE_URI}" \
--platform=managed \
--region=us-central1 \
--service-account="${SA_EMAIL}" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--no-allow-unauthenticated \
--ingress=all \
--project="${PROJECT_ID}"
אחזור כתובת ה-URL מסוג HTTPS:
export CLOUD_RUN_URL=$(gcloud run services describe secure-mcp-server --platform=managed --region=us-central1 --format='value(status.url)' --project="${PROJECT_ID}")
echo "Cloud Run HTTPS Endpoint: ${CLOUD_RUN_URL}"
אימות של אבטחת נקודות קצה
ניסיון לשלוח בקשה לא מורשית לנקודת הקצה של Streamable HTTP יחזיר את השגיאה 403 Forbidden:
curl -i -X POST "${CLOUD_RUN_URL}/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/list" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "curl-test",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'
HTTP/2 403 content-type: text/html; charset=UTF-8 date: Mon, 11 Aug 2026 14:00:00 GMT
יוצרים אסימון מזהה OIDC באמצעות gcloud כדי לאמת תקשורת מורשית:
export ID_TOKEN=$(gcloud auth print-identity-token --audiences="${CLOUD_RUN_URL}")
curl -i -X POST "${CLOUD_RUN_URL}/mcp" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/list" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "curl-test",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'
HTTP/2 200
content-type: application/json
{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"vertex_ai_generate_content",...},{"name":"gcs_bucket_inspector",...},{"name":"cloud_logging_audit_writer",...},{"name":"gcp_resource_health_checker",...}]}}
בדיקת הפעלה של כלי בזמן אמת: Cloud Storage Inspector
עכשיו, אחרי ששרת ה-MCP המרוחק מאומת ומגיב, אפשר לבדוק את ההרצה של הכלי gcs_bucket_inspector מול תשתית הענן של Google Cloud.
שלב 1: יצירת קטגוריה של Cloud Storage לבדיקה
יוצרים קטגוריה לדוגמה ומעלים קובץ לדוגמה:
export BUCKET_NAME="${PROJECT_ID}-mcp-demo"
# Create Cloud Storage bucket
gcloud storage buckets create "gs://${BUCKET_NAME}" \
--location=us-central1 \
--project="${PROJECT_ID}"
# Upload sample file
echo "Hello from Secure MCP on Google Cloud!" > sample.txt
gcloud storage cp sample.txt "gs://${BUCKET_NAME}/sample.txt"
שלב 2: יצירת לקוח לבדיקה של כלי GCS מרחוק
יוצרים סקריפט לקוח לבדיקה בשם src/mcp_server/test_gcs_tool.py כדי לבצע אימות מול Cloud Run ולהפעיל את הכלי gcs_bucket_inspector:
import asyncio
import os
import subprocess
import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
from mcp.types import TextContent
async def test_gcs_tool() -> None:
"""Authenticates to Cloud Run via OIDC and invokes the gcs_bucket_inspector tool."""
cloud_run_url = os.getenv("CLOUD_RUN_URL")
bucket_name = os.getenv("BUCKET_NAME")
if not cloud_run_url or not bucket_name:
print("[!] Please set both CLOUD_RUN_URL and BUCKET_NAME environment variables.")
return
# Generate Google OIDC ID token for Cloud Run authentication
id_token = subprocess.check_output(
["gcloud", "auth", "print-identity-token", f"--audiences={cloud_run_url.rstrip('/')}"],
text=True,
).strip()
headers = {"Authorization": f"Bearer {id_token}"}
server_url = f"{cloud_run_url.rstrip('/')}/mcp"
print(f"[*] Connecting to remote Cloud Run MCP server at {server_url} (Streamable HTTP)...")
async with httpx2.AsyncClient(
headers=headers,
timeout=httpx2.Timeout(30.0, read=300.0),
) as http_client:
transport = streamable_http_client(server_url, http_client=http_client)
async with Client(transport) as client:
print(
f"[+] Authenticated and connected (protocol: {client.protocol_version})."
)
# List tools
tools_response = await client.list_tools()
print(f"[*] Verified {len(tools_response.tools)} available tools on Cloud Run.")
# Invoke gcs_bucket_inspector tool
print(f"\n[*] Invoking tool: gcs_bucket_inspector on '{bucket_name}'...")
result = await client.call_tool(
"gcs_bucket_inspector", {"bucket_name": bucket_name}
)
print("[+] Response from Cloud Run MCP Server:")
for content in result.content:
if isinstance(content, TextContent):
print(content.text)
if __name__ == "__main__":
asyncio.run(test_gcs_tool())
שלב 3: מריצים את לקוח הבדיקה של GCS מרחוק
מריצים את סקריפט הבדיקה באמצעות uv:
uv run python src/mcp_server/test_gcs_tool.py
אמורים לראות מטא-נתונים של אובייקט בזמן אמת שמוחזרים משרת ה-MCP של Cloud Run:
[*] Connecting to remote Cloud Run MCP server at https://secure-mcp-server-...-uc.a.run.app/mcp (Streamable HTTP)...
[+] Authenticated and connected (protocol: 2026-07-28).
[*] Verified 4 available tools on Cloud Run.
[*] Invoking tool: gcs_bucket_inspector on 'my-project-mcp-demo'...
[+] Response from Cloud Run MCP Server:
{"resultType":"complete","bucket_name":"my-project-mcp-demo","object_count_sample":1,"objects":[{"name":"sample.txt","size_bytes":39,"updated":"..."}]}
6. פריסה ל-GKE Autopilot עם Workload Identity ו-TLS
עבור עומסי עבודה של Kubernetes, GKE Autopilot מנהל את הקצאת הצמתים, ו-Workload Identity מבטל את השימוש במפתחות סטטיים של חשבונות שירות.
הקצאת אשכול GKE Autopilot
הקצאת אשכול GKE Autopilot:
gcloud container clusters create-auto mcp-gke-cluster \
--location=us-central1 \
--project="${PROJECT_ID}"
gcloud container clusters get-credentials mcp-gke-cluster \
--location=us-central1 \
--project="${PROJECT_ID}"
הגדרת Workload Identity
יוצרים חשבון שירות של Google (GSA) וחשבון שירות של Kubernetes (KSA), ואז מקשרים ביניהם באמצעות Workload Identity:
# 1. Create GSA
gcloud iam service-accounts create mcp-gke-sa \
--display-name="GKE MCP Service Account" \
--project="${PROJECT_ID}"
export GSA_EMAIL="mcp-gke-sa@${PROJECT_ID}.iam.gserviceaccount.com"
# 2. Grant IAM Roles to GSA
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${GSA_EMAIL}" --role="roles/aiplatform.user"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${GSA_EMAIL}" --role="roles/logging.logWriter"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${GSA_EMAIL}" --role="roles/storage.objectViewer"
# 3. Create KSA
kubectl create serviceaccount mcp-server-ksa --namespace default
# 4. Annotate KSA
kubectl annotate serviceaccount mcp-server-ksa \
--namespace default \
iam.gke.io/gcp-service-account="${GSA_EMAIL}"
# 5. Bind KSA to GSA
gcloud iam service-accounts add-iam-policy-binding "${GSA_EMAIL}" \
--role="roles/iam.workloadIdentityUser" \
--member="serviceAccount:${PROJECT_ID}.svc.id.goog[default/mcp-server-ksa]" \
--project="${PROJECT_ID}"
החלת פריסת Kubernetes ו-Gateway API עם TLS
שלב 1: הזמנת כתובת IP סטטית והקצאת אישור SSL בניהול Google באמצעות nip.io
לפני שמחילים את מניפסטים של Kubernetes, צריך לשריין כתובת IP חיצונית גלובלית ולהשתמש בשירות DNS עם תו כללי nip.io () כדי ליצור שם דומיין ציבורי תקין (MCP_DOMAIN):
# Reserve global static IP address for GKE Gateway Load Balancer
gcloud compute addresses create mcp-server-ip \
--global \
--project="${PROJECT_ID}"
export MCP_IP=$(gcloud compute addresses describe mcp-server-ip --global --format="value(address)" --project="${PROJECT_ID}")
export MCP_DOMAIN="mcp.${MCP_IP}.nip.io"
echo "Reserved Static IP: ${MCP_IP}"
echo "Configured nip.io Domain: ${MCP_DOMAIN}"
# Provision Google-managed SSL certificate
gcloud compute ssl-certificates create mcp-server-cert \
--domains="${MCP_DOMAIN}" \
--global \
--project="${PROJECT_ID}"
לא צריך לחכות עד שהקצאת אישור ה-SSL תסתיים כדי להמשיך – למעשה, אישורים שמנוהלים על ידי Google נשארים במצב PROVISIONING עד שהם מצורפים למאזן העומסים של שער הכניסה בשלב 3. ממשיכים מיד לשלבים הבאים.
שלב 2: יצירת מניפסט הפריסה והשירות
יוצרים קובץ deployment.yaml שמכיל את הפריסה ואת הגדרות השירות הפנימיות. מכיוון ש-MCP 2.0 (MCP Spec 2026-07-28) הוא חסר מצב (stateless), Kubernetes Service לא דורש זיקה לסשן (session affinity) לכתובת IP של הלקוח:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server-deployment
namespace: default
labels:
app: mcp-server
# GKE takes this label and registers the deployment as an MCP server to Agent Registry
registry.gke.io/functional-type: "MCP_SERVER"
annotations:
# Endpoint URL where the GKE controller can access this MCP server
modelcontextprotocol.info/urls: |
- https://MCP_DOMAIN/mcp
# Defines structural capabilities for the MCP server card
modelcontextprotocol.info/capabilities: |
card:
endpoint: "/mcp"
protocol: "HTTP"
spec:
replicas: 2
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
annotations:
# Workload Identity annotation for identity and access management
iam.gke.io/spiffe-identity-type: agent-identity
spec:
serviceAccountName: mcp-server-ksa
containers:
- name: mcp-server
image: us-central1-docker.pkg.dev/PROJECT_ID/mcp-servers/secure-mcp-server:latest
ports:
- containerPort: 8080
name: http
env:
- name: PORT
value: "8080"
- name: GOOGLE_CLOUD_PROJECT
value: "PROJECT_ID"
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
---
apiVersion: v1
kind: Service
metadata:
name: mcp-server-service
namespace: default
labels:
app: mcp-server
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
name: http
selector:
app: mcp-server
מחליפים את MCP_DOMAIN ו-PROJECT_ID ומחילים את הפריסה:
sed -e "s|MCP_DOMAIN|${MCP_DOMAIN}|g" \
-e "s|PROJECT_ID|${PROJECT_ID}|g" \
deployment.yaml | kubectl apply -f -
שלב 3: יוצרים את המניפסט של Gateway API, HealthCheckPolicy ו-GCPBackendPolicy
יוצרים gateway.yaml שמכיל את Gateway, HTTPRoute, HealthCheckPolicy ו-GCPBackendPolicy:
-
HealthCheckPolicy: הגדרת מאזן העומסים של Google Cloud לביצוע בדיקה של/healthzביציאה 8080. -
GCPBackendPolicy(Backend Timeout): הגדרתtimeoutSec: 300כך שיתאים לזמן הקצוב לתפוגה של קריאה באורך 300 שניות ב-MCP SDK v2 עבור זרמי HTTP / SSE שניתנים להזרמה (ערך ברירת המחדל של GKE Gateway הוא 30 שניות אם לא מציינים ערך).
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: mcp-gateway
namespace: default
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
options:
networking.gke.io/pre-shared-certs: mcp-server-cert
addresses:
- type: NamedAddress
value: mcp-server-ip
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: mcp-http-route
namespace: default
spec:
parentRefs:
- name: mcp-gateway
hostnames:
- "MCP_DOMAIN"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: mcp-server-service
port: 80
---
apiVersion: networking.gke.io/v1
kind: HealthCheckPolicy
metadata:
name: mcp-health-check-policy
namespace: default
spec:
default:
checkIntervalSec: 15
timeoutSec: 5
healthyThreshold: 1
unhealthyThreshold: 2
config:
type: HTTP
httpHealthCheck:
port: 8080
requestPath: /healthz
targetRef:
group: ""
kind: Service
name: mcp-server-service
---
apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: mcp-backend-policy
namespace: default
spec:
default:
# Aligns with MCP SDK v2's 300s read timeout for Streamable HTTP / SSE streams
# (GKE Gateway defaults to 30s if omitted)
timeoutSec: 300
targetRef:
group: ""
kind: Service
name: mcp-server-service
החלת Gateway, HTTPRoute, HealthCheckPolicy ו-GCPBackendPolicy:
sed "s/MCP_DOMAIN/${MCP_DOMAIN}/g" gateway.yaml | kubectl apply -f -
שלב 4: בדיקת הפריסה ושרת ה-MCP באמצעות העברת פורטים
כי לוקח 5 עד 15 דקות להקצות ולאמת אישורי SSL בניהול Google ולבסס ניתוב DNS במאזני עומסים חיצוניים של Google Cloud Application, ולכן אפשר לבדוק מיד את הפודים הפועלים של GKE באמצעות kubectl port-forward.
קודם צריך לבדוק שה-Pods וה-Gateway פועלים:
kubectl get pods -l app=mcp-server
kubectl get gateway mcp-gateway
NAME READY STATUS RESTARTS AGE mcp-server-deployment-7b8f9495c5-x2n8q 1/1 Running 0 45s mcp-server-deployment-7b8f9495c5-z4k9p 1/1 Running 0 45s NAME CLASS ADDRESS PROGRAMMED AGE mcp-gateway gke-l7-global-external-managed 34.120.x.x True 2m
בשלב הבא, בודקים את שירות GKE הפעיל באופן מקומי באמצעות העברת יציאות:
- במסוף, מעבירים את היציאה המקומית
8080לשירות GKE ClusterIP:
kubectl port-forward svc/mcp-server-service 8080:80
- בטרמינל השני, יוצרים סקריפט של לקוח לבדיקה בשם
src/mcp_server/test_vertex_tool.pyכדי להפעיל את הכליvertex_ai_generate_contentב-GKE באמצעות Workload Identity:
import argparse
import asyncio
import os
from mcp import Client
from mcp.types import TextContent
async def test_vertex_tool(server_url: str) -> None:
"""Connects to the MCP v2.0 server and invokes the vertex_ai_generate_content tool."""
print(f"[*] Connecting to MCPServer at {server_url} (Streamable HTTP)...")
async with Client(server_url) as client:
print(
f"[+] Connected (protocol: {client.protocol_version}, "
f"server: {client.server_info.name if client.server_info else 'unknown'})."
)
# List available tools
tools_response = await client.list_tools()
print(f"[*] Discovered {len(tools_response.tools)} MCP Tools:")
for tool in tools_response.tools:
print(f" - {tool.name}")
# Invoke vertex_ai_generate_content tool
prompt = "Explain in 2 sentences why Model Context Protocol (MCP) Streamable HTTP is great for cloud deployments."
print(f"\n[*] Invoking tool: vertex_ai_generate_content with prompt: '{prompt}'...")
result = await client.call_tool(
"vertex_ai_generate_content",
{
"prompt": prompt,
"model_name": "gemini-2.5-flash",
},
)
print("\n[+] Response from Vertex AI Gemini:")
for content in result.content:
if isinstance(content, TextContent):
print(content.text)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Test Vertex AI MCP Tool on MCPServer.")
parser.add_argument(
"--host",
default=os.getenv("MCP_URL", "http://localhost:8080/mcp"),
help="MCP Server host or URL (default: http://localhost:8080/mcp or $MCP_URL)",
)
args = parser.parse_args()
# Normalize URL format
url = args.host
if not url.startswith("http://") and not url.startswith("https://"):
url = f"https://{url}"
if not url.endswith("/mcp"):
url = f"{url.rstrip('/')}/mcp"
asyncio.run(test_vertex_tool(url))
- מריצים את סקריפט הבדיקה מול המופע המקומי של העברת הפורטים:
uv run python src/mcp_server/test_vertex_tool.py --host="http://localhost:8080/mcp"
[*] Connecting to MCPServer at http://localhost:8080/mcp (Streamable HTTP)... [+] Connected (protocol: 2026-07-28, server: Google Cloud Production Tools). [*] Discovered 4 MCP Tools: - vertex_ai_generate_content - gcs_bucket_inspector - cloud_logging_audit_writer - gcp_resource_health_checker [*] Invoking tool: vertex_ai_generate_content with prompt: 'Explain in 2 sentences why Model Context Protocol (MCP) Streamable HTTP is great for cloud deployments.'... [+] Response from Vertex AI Gemini: MCP Streamable HTTP enables lightweight, stateless HTTP interactions that scale effortlessly across cloud-native platforms like GKE and Cloud Run. It simplifies infrastructure management by using standard HTTP/HTTPS protocols while preserving rich bidirectional streaming for AI agents.
האישור הזה מעיד על כך שתרמילי ה-GKE תקינים, ש-Workload Identity מאמת בהצלחה מול Vertex AI ללא פרטי כניסה סטטיים, ושהעברת הנתונים ב-HTTP שניתנת להזרמה פועלת כמצופה.
שלב 5: אימות של נקודת הקצה (endpoint) של שער HTTPS ציבורי
בודקים את סטטוס הקצאת האישורים באמצעות הפקודה:
gcloud compute ssl-certificates describe mcp-server-cert --global --format="value(managed.status)"
אחרי שהאישור ACTIVE, בודקים את נקודת הקצה הציבורית של HTTPS באמצעות לקוח הבדיקה של Python עם הדגל --host:
uv run python src/mcp_server/test_vertex_tool.py --host="https://${MCP_DOMAIN}/mcp"
[*] Connecting to MCPServer at https://mcp.34.120.x.x.nip.io/mcp (Streamable HTTP)... [+] Connected (protocol: 2026-07-28, server: Google Cloud Production Tools). [*] Discovered 4 MCP Tools: - vertex_ai_generate_content - gcs_bucket_inspector - cloud_logging_audit_writer - gcp_resource_health_checker [*] Invoking tool: vertex_ai_generate_content with prompt: 'Explain in 2 sentences why Model Context Protocol (MCP) Streamable HTTP is great for cloud deployments.'... [+] Response from Vertex AI Gemini: MCP Streamable HTTP enables lightweight, stateless HTTP interactions that scale effortlessly across cloud-native platforms like GKE and Cloud Run. It simplifies infrastructure management by using standard HTTP/HTTPS protocols while preserving rich bidirectional streaming for AI agents.
7. שילוב של שרת MCP עם פלטפורמת הסוכנים של Google Cloud
עכשיו, אחרי שפרסתם את MCPServer באופן מאובטח לנקודות קצה של HTTPS ב-Cloud Run וב-GKE Autopilot, אתם יכולים לרשום את כלי ה-MCP ולגלות אותם באמצעות Google Cloud Agent Platform (Agent Registry), כדי שסוכנים ארגוניים ומודלים של AI יוכלו לגלות אותם ולהפעיל אותם באופן דינמי.
1. רישום של שרת MCP מותאם אישית ב-Cloud Run ב-Agent Platform ובדיקה באמצעות Service Discovery
שלב 1: חילוץ מפרטי הכלי (toolspec.json)
כדי לרשום שרת MCP חיצוני או מותאם אישית ב-Agent Registry, צריך לשלוח שאילתה ל-tools/list בשרת MCP 2.0 הפעיל חסר המצב, להסיר את השדות _meta ברמת הכלי ולשמור את התוצאה ב-toolspec.json בצינור יחיד:
# 1. Generate identity token
export ID_TOKEN=$(gcloud auth print-identity-token --audiences="${CLOUD_RUN_URL}")
# 2. Query, parse, sanitize and save in one single pipeline
curl -s -X POST "${CLOUD_RUN_URL}/mcp" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/list" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "cli",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}' \
| sed -n 's/^data: //p; /^{/p' \
| jq '.result | del(.tools[]._meta)' > toolspec.json
שלב 2: רישום השירות ב-Agent Registry
משתמשים ב-gcloud agent-registry services create כדי ליצור קטלוג של שרת ה-MCP:
export SERVER_NAME="secure-mcp-server"
export DISPLAY_NAME="Google Cloud MCPServer"
export REGION="global"
gcloud agent-registry services create "${SERVER_NAME}" \
--project="${PROJECT_ID}" \
--location="${REGION}" \
--display-name="${DISPLAY_NAME}" \
--mcp-server-spec-type="tool-spec" \
--mcp-server-spec-content=toolspec.json \
--interfaces="url=${CLOUD_RUN_URL}/mcp,protocolBinding=jsonrpc"
מוודאים שהשירות נרשם בהצלחה:
gcloud agent-registry services describe "${SERVER_NAME}" --location="${REGION}"
name: projects/PROJECT_ID/locations/global/services/secure-mcp-server displayName: Google Cloud MCPServer interfaces: - protocolBinding: JSONRPC url: https://secure-mcp-server-xxxx.a.run.app/mcp mcpServerSpec: type: TOOL_SPEC
שלב 3: יצירה והפעלה של לקוח לבדיקת גילוי שירותים
יוצרים סקריפט Python בשם src/mcp_server/test_agent_platform.py שמבצע באופן דינמי פעולת Resolve של נקודת הקצה מקטלוג mcp-servers של Agent Registry, מבצע אימות באמצעות Google Cloud IAM ומפעיל כלי באמצעות httpx2 ו-MCP 2.0 Client:
import asyncio
import os
import subprocess
import httpx2 # MCP SDK 2.x utilizes httpx2 instead of httpx
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
async def main() -> None:
server_name = os.getenv("SERVER_NAME", "secure-mcp-server")
location = os.getenv("REGION", "global")
# 1. Discover endpoint URL from Google Cloud Agent Registry (mcp-servers catalog)
print(f"[*] Discovering '{server_name}' in '{location}' from Agent Registry...")
url = subprocess.check_output(
[
"gcloud",
"agent-registry",
"mcp-servers",
"list",
f"--location={location}",
f"--filter=displayName='{server_name}' OR mcpServerId ~ ':{server_name}$'",
"--format=value(interfaces[0].url)",
"--limit=1",
],
text=True,
).strip()
if not url:
raise RuntimeError(
f"No endpoint URL found for '{server_name}' in location '{location}'. "
"Verify the server is registered and has an interface URL configured."
)
print(f"[+] Discovered Endpoint: {url}")
# 2. Generate IAM identity token if connecting to Cloud Run
headers: dict[str, str] = {}
if "run.app" in url:
audience = url.split("/mcp")[0]
token = subprocess.check_output(
["gcloud", "auth", "print-identity-token", f"--audiences={audience}"],
text=True,
).strip()
headers["Authorization"] = f"Bearer {token}"
# 3. Configure a custom httpx2 Client with MCP-safe timeouts
# We set read to 300s to ensure the long-lived SSE/GET stream stays open
async with httpx2.AsyncClient(
headers=headers,
timeout=httpx2.Timeout(30.0, read=300.0),
) as http_client:
# 4. Initialize Streamable HTTP Transport (yielding a 2-tuple in MCP v2.x)
transport = streamable_http_client(url, http_client=http_client)
# 5. Connect using the clean high-level Client interface
async with Client(transport) as client:
print("[+] Session active. Connected successfully.")
# Verify tools registered in the catalog (Attributes are snake_case in MCP v2)
tools_response = await client.list_tools()
print(f"[+] Discovered {len(tools_response.tools)} tools:")
for tool in tools_response.tools:
print(f" - {tool.name}")
# Test executing the health check tool
print("\n[*] Invoking tool: gcp_resource_health_checker...")
result = await client.call_tool("gcp_resource_health_checker", {})
print(f"[+] Tool Output from Agent Platform:\n{result.content[0].text}")
if __name__ == "__main__":
asyncio.run(main())
מריצים את סקריפט הבדיקה:
uv run python src/mcp_server/test_agent_platform.py
[*] Discovering 'secure-mcp-server' in 'global' from Agent Registry...
[+] Discovered Endpoint: https://secure-mcp-server-xxxx.a.run.app/mcp
[+] Session active. Connected successfully.
[+] Discovered 4 tools:
- vertex_ai_generate_content
- gcs_bucket_inspector
- cloud_logging_audit_writer
- gcp_resource_health_checker
[*] Invoking tool: gcp_resource_health_checker...
[+] Tool Output from Agent Platform:
{"resultType": "complete", "status": "HEALTHY", "mcp_spec_version": "2026-07-28"}
2. גילוי אוטומטי של שרת MCP והרשמה אליו באמצעות GKE
Google Kubernetes Engine (GKE) מספק שילוב אוטומטי עם Agent Registry. על ידי תיוג והוספת הערות למניפסט הפריסה של GKE, GKE מבצע באופן אוטומטי סריקת אינטרוספקציה מול שרת ה-MCP, רושם את הכלים בקטלוג ומקרין את השירות לצד הצרכן בלי שצריך ליצור או להעלות toolspec.json באופן ידני.
שלב 1: איך פועל גילוי אוטומטי ב-GKE
כשמחילים את deployment.yaml מהקטע הקודם, ההגדרות הבאות מפעילות גילוי אוטומטי:
-
registry.gke.io/functional-type: "MCP_SERVER": מודיע לבקר של אשכול GKE לרשום את הפריסה ב-Google Cloud Agent Registry. -
modelcontextprotocol.info/urls: מספק את נקודת הקצה של שער ה-HTTPS החיצוני (https://${MCP_DOMAIN}/mcp) לבדיקה של בקר וניתוב של צרכן. -
modelcontextprotocol.info/capabilities: הגדרה של נקודת הקצה (endpoint) של ה-HTTP transport (/mcp). -
iam.gke.io/spiffe-identity-type: agent-identity: הגדרת Workload Identity לתקשורת בין סוכנים.
שלב 2: אימות של רישום אוטומטי של GKE במאגר סוכנים
מוודאים ש-GKE גילה ורשם באופן אוטומטי את שרת ה-MCP בקטלוג האזורי mcp-servers:
# List the automatically registered GKE MCP server in us-central1
gcloud agent-registry mcp-servers list \
--location=us-central1 \
--format="table(displayName, tools.len():label=TOOLS)"
DISPLAY_NAME TOOLS mcp-server-deployment 4
שלב 3: בדיקת שרת GKE MCP באמצעות Service Discovery
כדי לבדוק את פריסת ה-MCP ב-GKE, משתמשים בסקריפט לזיהוי שירותים מול שם השרת שנרשם אוטומטית ב-us-central1:
SERVER_NAME="mcp-server-deployment" \
REGION=us-central1 \
uv run python src/mcp_server/test_agent_platform.py
[*] Discovering 'mcp-server-deployment' in 'us-central1' from Agent Registry...
[+] Discovered Endpoint: https://mcp.34.120.x.x.nip.io/mcp
[+] Session active. Connected successfully.
[+] Discovered 4 tools:
- vertex_ai_generate_content
- gcs_bucket_inspector
- cloud_logging_audit_writer
- gcp_resource_health_checker
[*] Invoking tool: gcp_resource_health_checker...
[+] Tool Output from Agent Platform:
{"resultType": "complete", "status": "HEALTHY", "mcp_spec_version": "2026-07-28"}
8. לפנות משאבים
כדי להימנע מחיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם ב-codelab הזה, מוחקים את שירות Cloud Run, את אשכול GKE, את חשבונות השירות ואת מאגר התמונות של הקונטיינרים.
מחיקת שירות Cloud Run
gcloud run services delete secure-mcp-server \
--platform=managed \
--region=us-central1 \
--quiet \
--project="${PROJECT_ID}"
מחיקת אשכול GKE Autopilot
gcloud container clusters delete mcp-gke-cluster \
--location=us-central1 \
--quiet \
--project="${PROJECT_ID}"
מחיקה של חשבונות שירות ושל IAM Bindings
gcloud iam service-accounts delete "mcp-server-cr-sa@${PROJECT_ID}.iam.gserviceaccount.com" --quiet --project="${PROJECT_ID}"
gcloud iam service-accounts delete "mcp-gke-sa@${PROJECT_ID}.iam.gserviceaccount.com" --quiet --project="${PROJECT_ID}"
מחיקת מאגר Artifact Registry
gcloud artifacts repositories delete mcp-servers \
--location=us-central1 \
--quiet \
--project="${PROJECT_ID}"
מחיקת שירות מותאם אישית של Agent Registry
gcloud agent-registry services delete secure-mcp-server \
--location=global \
--quiet \
--project="${PROJECT_ID}"
מחיקת קטגוריה של Cloud Storage
gcloud storage rm --recursive "gs://${BUCKET_NAME}" --quiet
מחיקת כתובת IP סטטית ואישור SSL
gcloud compute ssl-certificates delete mcp-server-cert --global --quiet --project="${PROJECT_ID}"
gcloud compute addresses delete mcp-server-ip --global --quiet --project="${PROJECT_ID}"
מוודאים שפעולת הניקוי של המחיקה הושלמה:
Deleted service [secure-mcp-server]. Deleted cluster [mcp-gke-cluster]. Deleted repository [mcp-servers].
9. מזל טוב
מזל טוב! יצרתם, אבטחתם ופרסתם בהצלחה שרת MCP 2.0 באמצעות MCPServer מ-MCP Python SDK ו-uv ב-Google Cloud.
מה שילמתם
- יצרנו
MCPServerשתומך במפרט MCP (28 ביולי 2026) באמצעות HTTP ניתן להזרמה בלי שמירת מצב. - יצרנו 4 כלים לשימוש בייצור ב-Google Cloud שמשלבים את Vertex AI Gemini, Cloud Storage, Cloud Logging ו-Resource Health.
- פריסות מאובטחות של קונטיינרים ב-Cloud Run עם אכיפה של אימות IAM ו-SSL/TLS.
- הגדרת אימות ללא סודות ב-GKE Autopilot באמצעות Workload Identity ו-Kubernetes Gateway API עם TLS.
- נקודות קצה של שרתי MCP שנרשמו וזוהו באמצעות Gemini Enterprise Agent Platform (Agent Registry) באמצעות כותרות הרשאות OIDC.
השלבים הבאים
- אפשר לעיין במפרט Model Context Protocol כדי לראות משאבים מתקדמים והגדרות של הנחיות.
- מידע נוסף על MCP Python SDK
- מידע מעמיק על אבטחה ב-Google Cloud Run ו-Workload Identity ב-GKE.