GCP Cloud Run Deployment¶
This guide walks you through deploying the Zscaler Integrations MCP Server to Google Cloud Run with optional GCP Secret Manager integration for secure credential storage.
Video walkthrough¶
▶ Walkthrough: Zscaler MCP Server and Google Cloud Run (Wistia)
Prerequisites¶
gcloud CLI installed and authenticated
A GCP project with billing enabled
Zscaler OneAPI credentials (
ZSCALER_CLIENT_ID,ZSCALER_CLIENT_SECRET,ZSCALER_VANITY_DOMAIN,ZSCALER_CUSTOMER_ID)
Automated Deployment (Recommended)¶
The integrations/google/gcp/gcp_mcp_operations.py script provides an interactive deployment experience with support for Cloud Run, GKE, and Compute Engine VM targets:
cd integrations/google/gcp
python gcp_mcp_operations.py deploy
The script:
Reads credentials from your
.envfile (or prompts interactively)Optionally stores credentials in GCP Secret Manager
Deploys the container to Cloud Run with
zscalerauthentication modeGenerates
Authorization: Basicheaders from your Zscaler OneAPI credentialsAuto-configures Claude Desktop and Cursor client configs
Supports
--teardownfor easy service deletion
Options:
cd integrations/google/gcp
python gcp_mcp_operations.py deploy # Interactive guided deployment
python gcp_mcp_operations.py status # Check deployment
python gcp_mcp_operations.py logs # Stream logs
python gcp_mcp_operations.py destroy # Tear down
Authentication¶
The script defaults to Zscaler auth mode — clients authenticate with the same Zscaler OneAPI credentials (client_id:client_secret) via HTTP Basic auth. No external Identity Provider, JWT setup, or API keys are required.
The script automatically:
Sets
ZSCALER_MCP_AUTH_ENABLED=trueandZSCALER_MCP_AUTH_MODE=zscaleron the containerGenerates
base64(client_id:client_secret)for theAuthorization: BasicheaderConfigures Claude Desktop (via
mcp-remote --header) and Cursor (via nativeheaders) with the auth credentials
Manual Deployment¶
Deploy directly with gcloud:
gcloud run deploy zscaler-mcp-server \
--image=zscaler/zscaler-mcp-server:latest \
--region=us-central1 \
--platform=managed \
--port=8000 \
--args="--transport,streamable-http,--host,0.0.0.0,--port,8000" \
--set-env-vars="\
ZSCALER_CLIENT_ID=your-client-id,\
ZSCALER_CLIENT_SECRET=your-client-secret,\
ZSCALER_VANITY_DOMAIN=your-domain,\
ZSCALER_CUSTOMER_ID=your-customer-id,\
ZSCALER_CLOUD=production,\
ZSCALER_MCP_ALLOW_HTTP=true,\
ZSCALER_MCP_DISABLE_HOST_VALIDATION=true,\
ZSCALER_MCP_AUTH_ENABLED=true,\
ZSCALER_MCP_AUTH_MODE=zscaler" \
--memory=512Mi \
--allow-unauthenticated
Warning
Credentials passed as --set-env-vars are visible in the Cloud Console. Use GCP Secret Manager for production deployments.
GCP Secret Manager Integration¶
The Docker image includes a built-in credential loader for GCP Secret Manager. When enabled, the server fetches Zscaler API credentials at startup — no wrapper scripts or container modifications required.
How It Works:
Container starts and checks
ZSCALER_MCP_GCP_SECRET_MANAGERIf
true, fetches each credential from Secret Manager using Application Default CredentialsSets values as environment variables before the MCP server initializes
Naming Convention:
Environment variable names are converted to Secret Manager IDs by lowercasing and replacing underscores with hyphens:
Environment Variable |
Secret Manager ID |
|---|---|
|
|
|
|
|
|
|
|
|
|
Step 1: Create Secrets¶
PROJECT_ID="your-gcp-project"
echo -n "your-client-id" | \
gcloud secrets create zscaler-client-id \
--data-file=- --replication-policy=automatic --project=$PROJECT_ID
echo -n "your-client-secret" | \
gcloud secrets create zscaler-client-secret \
--data-file=- --replication-policy=automatic --project=$PROJECT_ID
# Repeat for zscaler-vanity-domain, zscaler-customer-id, zscaler-cloud
Step 2: Grant IAM Access¶
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
SA_EMAIL="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
for SECRET in zscaler-client-id zscaler-client-secret zscaler-vanity-domain \
zscaler-customer-id zscaler-cloud; do
gcloud secrets add-iam-policy-binding $SECRET \
--member="serviceAccount:$SA_EMAIL" \
--role="roles/secretmanager.secretAccessor" \
--project=$PROJECT_ID --quiet
done
Step 3: Deploy with Secret Manager¶
gcloud run deploy zscaler-mcp-server \
--image=zscaler/zscaler-mcp-server:latest \
--region=us-central1 \
--set-env-vars="\
ZSCALER_MCP_GCP_SECRET_MANAGER=true,\
GCP_PROJECT_ID=$PROJECT_ID,\
ZSCALER_MCP_ALLOW_HTTP=true,\
ZSCALER_MCP_DISABLE_HOST_VALIDATION=true,\
ZSCALER_MCP_AUTH_ENABLED=true,\
ZSCALER_MCP_AUTH_MODE=zscaler" \
--args="--transport,streamable-http,--host,0.0.0.0,--port,8000" \
--port=8000 --memory=512Mi --allow-unauthenticated
GKE Deployment¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: zscaler-mcp-server
spec:
replicas: 1
selector:
matchLabels:
app: zscaler-mcp-server
template:
metadata:
labels:
app: zscaler-mcp-server
spec:
serviceAccountName: zscaler-mcp-sa
containers:
- name: zscaler-mcp
image: zscaler/zscaler-mcp-server:latest
args: ["--transport", "streamable-http", "--host", "0.0.0.0", "--port", "8000"]
ports:
- containerPort: 8000
env:
- name: ZSCALER_MCP_GCP_SECRET_MANAGER
value: "true"
- name: GCP_PROJECT_ID
value: "your-gcp-project"
Connecting Clients¶
Claude Desktop¶
{
"mcpServers": {
"zscaler-mcp-server": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://your-service.run.app/mcp",
"--header",
"Authorization: Basic <base64(client_id:client_secret)>"
]
}
}
}
Generate the Base64 value:
echo -n "your-client-id:your-client-secret" | base64
Cursor¶
{
"mcpServers": {
"zscaler-mcp-server": {
"url": "https://your-service.run.app/mcp",
"headers": {
"Authorization": "Basic <base64(client_id:client_secret)>"
}
}
}
}
Credential Rotation¶
# Update the secret value
echo -n "new-client-secret" | \
gcloud secrets versions add zscaler-client-secret --data-file=-
# Restart the service to pick up the new version
gcloud run services update zscaler-mcp-server --region=us-central1
Troubleshooting¶
401 Unauthorized:
Verify the
Authorization: Basicheader contains validbase64(client_id:client_secret)Confirm
ZSCALER_MCP_AUTH_ENABLED=trueandZSCALER_MCP_AUTH_MODE=zscalerare set on the container
Permission denied accessing secret:
gcloud secrets add-iam-policy-binding zscaler-client-secret \
--member="serviceAccount:YOUR_SA_EMAIL" \
--role="roles/secretmanager.secretAccessor"
Viewing logs:
gcloud run services logs read zscaler-mcp-server --region=us-central1 --limit=50