Azure Deployment¶
This guide walks you through deploying the Zscaler Integrations MCP Server to Microsoft Azure with the interactive azure_mcp_operations.py script. Three deployment targets are supported:
Target |
Description |
Image / Package |
Status |
|---|---|---|---|
Azure Container Apps |
Managed, serverless containers (recommended) |
Docker Hub: |
GA |
Azure Virtual Machine |
Ubuntu 22.04, self-managed |
PyPI: |
GA |
Azure Kubernetes Service (AKS) |
Kubernetes Deployment + LoadBalancer Service |
Docker Hub: |
Preview |
All three targets use Azure Key Vault for secret storage by default (Container Apps + AKS via Workload Identity Federation, VM via direct injection at deploy time). The same script also creates and manages Azure AI Foundry agents that call the deployed MCP server as a tool.
Video walkthrough¶
End-to-end walkthrough of every deployment target covered below. Per-target videos are linked at the top of each section.
Target |
Walkthrough |
|---|---|
Azure Container Apps |
|
Azure Virtual Machine |
|
Azure Kubernetes Service (Preview) |
|
Azure AI Foundry Agent |
Prerequisites¶
Azure CLI (
az) — logged in viaaz loginNode.js — required by
npx mcp-remote(Claude Desktop bridge)Zscaler OneAPI credentials (
ZSCALER_CLIENT_ID,ZSCALER_CLIENT_SECRET,ZSCALER_VANITY_DOMAIN,ZSCALER_CUSTOMER_ID)For AKS:
kubectlinstalled (brew install kubernetes-clion macOS)For OIDCProxy auth: an OIDC provider app registration (Entra ID, Okta, Auth0, etc.)
For VM: SSH key pair (the script can generate one on demand)
Authentication Modes¶
The script supports five MCP client authentication modes. Container Apps and VM support all five; AKS Preview supports four (OIDCProxy is on the roadmap).
Mode |
Description |
Client Auth Header |
|---|---|---|
OIDCProxy |
OAuth 2.1 + Dynamic Client Registration via your OIDC provider (browser login) |
Handled automatically by |
JWT |
Validate JWTs against a JWKS endpoint |
|
API Key |
Shared secret, auto-generated if not provided |
|
Zscaler |
Validate via OneAPI client credentials |
|
None |
No authentication — development only |
No header |
Quick Start¶
cd integrations/azure
python azure_mcp_operations.py deploy
The script prompts for:
Deployment target — Container Apps, VM, or AKS Preview
Credential source — load from a
.envfile or enter manuallyAuth mode — OIDCProxy, JWT, API Key, Zscaler, or None
Azure options — resource group, region, Key Vault, deployment-specific options
When the deployment finishes, the script automatically updates your Claude Desktop and Cursor configurations with the new MCP server URL and the appropriate auth header.
MCP Server Operations¶
Command |
Description |
|---|---|
|
Interactive guided deployment (Container Apps, VM, or AKS Preview) |
|
Show deployment status and health |
|
Stream container / VM / pod logs |
|
SSH into the VM (VM deployments only) |
|
Tear down all Azure resources. For AKS with an existing cluster, removes only the K8s |
python azure_mcp_operations.py status # check health
python azure_mcp_operations.py logs # stream logs
python azure_mcp_operations.py destroy -y # non-interactive teardown
Container Apps Deployment¶
▶ Walkthrough: Zscaler MCP Server and Azure Container Apps (Wistia)
Container Apps is the recommended path for most deployments — Azure handles scaling, ingress, and TLS termination automatically.
Image — Docker Hub:
zscaler/zscaler-mcp-server:latest(no build required)TLS — Automatic HTTPS via Azure Container Apps ingress
Scaling — Azure manages 1–3 replicas by default
Secrets — Stored in Azure Key Vault and injected at startup via system-assigned managed identity
VM Deployment¶
▶ Walkthrough: Zscaler MCP Server and Azure VM (Wistia)
Ubuntu 22.04 VM with the MCP server installed from PyPI (zscaler-mcp-server) and managed by systemd.
Self-managed — full control over the VM (SSH, packages, updates)
systemd service — automatic startup and restart on failure
NSG configured — port 22 (SSH) and port 8000 (MCP) opened
Secrets — Key Vault is mandatory; values are pulled at deploy time and rendered into the systemd unit file
VM service management:
# SSH into the VM (or use the script wrapper)
python azure_mcp_operations.py ssh
# On the VM:
sudo systemctl status zscaler-mcp # check status
sudo journalctl -u zscaler-mcp -f # stream logs
sudo systemctl restart zscaler-mcp # restart service
# Environment file:
/opt/zscaler-mcp/env
AKS Deployment (Preview)¶
▶ Walkthrough: Zscaler MCP Server and Azure Kubernetes Service (Wistia)
Note
Status: Preview. AKS support is fully functional for jwt, api-key, zscaler, and none auth modes and has been validated end-to-end with cluster creation, LoadBalancer Service, and the Docker Hub image. Credentials are stored in Azure Key Vault by default and pulled at runtime via Workload Identity Federation + the Key Vault CSI driver. OIDCProxy auth, TLS Ingress, and HPA are still planned for AKS GA.
Deploys the MCP server to an Azure Kubernetes Service cluster as a Deployment exposed via a Service of type LoadBalancer.
Cluster lifecycle — create a brand-new AKS cluster (PoC / testing) or use an existing cluster (production)
Container image — same Docker Hub image as Container Apps (
zscaler/zscaler-mcp-server:latest)External access — Azure Standard Load Balancer with public IP
Resource defaults —
200m–1000mCPU and512Mi–1Gimemory per pod, single replicaNamespace — defaults to
default, configurableCredential storage:
Azure Key Vault (default, recommended). Workload Identity Federation + Key Vault CSI driver. The script provisions the vault, the User-Assigned Managed Identity (UAMI), the federated credential bound to the pod’s
ServiceAccount, and theSecretProviderClass. Pods consume secrets viavalueFrom.secretKeyRefagainst a synced KubernetesSecret.Plain env vars (PoC). Credentials are baked into the Deployment manifest at deploy time — fine for short demos, not for production.
Cleanup — if the script created the cluster,
destroydeletes the entire resource group; if you supplied an existing cluster,destroyremoves only the K8s resources we created plus the per-deployment UAMI and federated credential (the Key Vault is preserved).
Operations on AKS:
python azure_mcp_operations.py status # AKS provisioning state, pod, and service
python azure_mcp_operations.py logs # kubectl logs deployment/zscaler-mcp-server -f
python azure_mcp_operations.py destroy # full or partial teardown (see above)
Direct kubectl access works after deployment — the script sets your kubectl context to the cluster automatically:
kubectl get pods -n default -l app=zscaler-mcp-server
kubectl get svc zscaler-mcp-server -n default
kubectl describe deployment zscaler-mcp-server -n default
Known limitations (Preview):
OIDCProxy auth is not supported on AKS today — use
jwt,api-key,zscaler, ornone.No Ingress controller — the script provisions a
LoadBalancerService that exposes plain HTTP on port 80. For production, place this behind Application Gateway or NGINX Ingress withcert-managerfor TLS (requires a DNS A record pointing at the cluster’s ingress LoadBalancer).Single replica by default — for HA, scale via
kubectl scale deployment zscaler-mcp-server --replicas=3or edit the generated.aks-manifest.yaml.
Azure AI Foundry Agent Integration¶
▶ Walkthrough: Zscaler MCP Server and Azure AI Foundry Agent (Wistia)
For organizations using Azure AI Foundry, the same script can create a managed Foundry agent (powered by GPT-4o or GPT-4) that calls the deployed MCP server as a tool. End users interact with the agent in natural language and the agent decides which Zscaler tools to call.
Prerequisites:
Azure AI Foundry project at ai.azure.com
Azure OpenAI deployment of GPT-4o or GPT-4
A deployed MCP server (Container Apps, VM, or AKS — from the steps above)
Python packages:
pip install azure-ai-projects azure-ai-agents azure-identityAzure CLI authenticated:
az login
MCP Server Authentication from Foundry¶
Azure AI Foundry no longer accepts authentication headers passed inline through MCPTool.headers. Any header containing words like secret, key, token, or authorization is rejected with invalid_payload:
Headers that can include sensitive information are not allowed in the headers
property for MCP tools. Use project_connection_id instead.
The supported pattern is to register a Custom keys connection in the Foundry project that holds the headers, and reference it via MCPTool.project_connection_id. Foundry then injects the connection’s keys as request headers when calling the MCP server.
One-time portal setup (required before agent_create will succeed when an MCP auth mode that needs headers is selected):
Open your project at ai.azure.com.
Left navigation: Management center → Connected resources.
Click + New connection → Custom keys.
Connection name:
zscaler-mcp-headers(the script’s default; override viaAZURE_FOUNDRY_CONNECTION_NAME).Mark each row as a secret and add the keys for your MCP auth mode:
MCP Auth Mode |
Custom Keys to Add |
Source |
|---|---|---|
|
|
OneAPI credentials |
|
|
MCP API key |
|
(no connection needed) |
— |
Click Save, then run
agent_create.
The connection name is read from AZURE_FOUNDRY_CONNECTION_NAME (env var or .env), defaulting to zscaler-mcp-headers. The data-plane SDK (azure-ai-projects v2.0.x) cannot create connections — only read them — so the portal step is currently required. Connection CRUD via the management plane is on the follow-up roadmap.
The script’s agent_create command probes the connection at runtime: if it exists, it proceeds silently; if it’s missing, it prints copy-paste-ready portal instructions and exits before mutating anything in Foundry.
Foundry Agent Operations¶
Command |
Flags |
Description |
|---|---|---|
|
Create a Foundry agent with Zscaler MCP tools. Reads the project endpoint, model name, and connection name from |
|
|
Show agent name, version, model, MCP server URL, and project endpoint. |
|
|
|
Start an interactive multi-turn chat. Optionally pass an initial message. |
|
|
Delete the Foundry agent. Pass |
# 1. Deploy the MCP server (if you haven't already)
python azure_mcp_operations.py deploy
# 2. One-time: create the Custom keys connection in the portal (see above)
# 3. Create the Foundry agent
python azure_mcp_operations.py agent_create
# 4. Chat
python azure_mcp_operations.py agent_chat
python azure_mcp_operations.py agent_chat -m "list ZPA segment groups"
# 5. Manage
python azure_mcp_operations.py agent_status
python azure_mcp_operations.py agent_destroy -y
After agent_create succeeds, the script prints a deep link straight into the new Foundry experience for the agent. The chat command exposes:
Animated spinner with a live elapsed-time counter while the model thinks
Per-response token usage (input, output, total)
Wall-clock latency for each request/response
Tool approval flow —
require_approval="always"is set by default, so you confirm each Zscaler tool call before it runsMulti-turn context — proper response chaining preserves conversation history
Session summary — total duration and cumulative token count on exit
Finding the Agent in the Foundry Portal¶
Agents created by agent_create are Prompt Agents in the new Foundry experience (versioned, type prompt). To find them in the portal:
Open the project at ai.azure.com.
Make sure the “New Foundry” toggle (top-right) is ON — Prompt Agents only appear in the new experience.
Left nav: Build → Agents → Agents tab.
Select
zscaler-mcp-agent(Type:prompt, Version:1).Use the Playground to test interactively, or Publish to share with your tenant.
Note
Two agent surfaces in Foundry — heads-up. The “Agents” tab in the new Foundry experience lists Prompt Agents (created by this script). The classic experience also has an “Agents” tab that lists Assistant API agents (type asst_xxxx, no versioning). They are different platforms in the same project. If you previously opened the Playground or used another tool, you may see leftover Agent### rows in classic — they’re unrelated to zscaler-mcp-agent and safe to leave alone.
Connecting Clients¶
After deployment, the script automatically updates your Claude Desktop (claude_desktop_config.json) and Cursor (mcp.json) configurations with the new MCP server URL and the auth header for the selected mode. If you need to configure a client manually, see the integrations/azure README for full per-client examples.
For HTTP endpoints (VM, AKS without Ingress), Claude Desktop requires the --allow-http flag to mcp-remote. The script adds this automatically when the deployed URL is HTTP.
Credential Sources¶
From a ``.env`` file. Copy integrations/azure/env.properties to .env and fill in the values. During deployment, select “From a .env file” and provide the file path.
Interactive prompts. Select “Enter manually” and the script will prompt for each credential. Secrets are entered via getpass (hidden input).
Required environment variables for all auth modes:
Variable |
Description |
|---|---|
|
OneAPI client ID from ZIdentity |
|
OneAPI client secret |
|
Zscaler vanity domain |
|
Zscaler customer ID |
|
Zscaler cloud (e.g. |
Troubleshooting¶
“Non-HTTPS URLs are only allowed for localhost” in Claude Desktop:
Add
--allow-httpto yourmcp-remoteargs. The deployment script does this automatically for HTTP endpoints; only manual configurations need the flag.
Claude Desktop shows “Server disconnected”:
Run
python azure_mcp_operations.py statusto check the deployment health,... logsto inspect the server logs, andcurl http://<PUBLIC_IP>:8000/mcp(or the HTTPS Container Apps URL) to verify reachability. For VM deployments, also confirm the NSG allows inbound on the MCP port.
Foundry ``agent_create`` errors with “Headers that can include sensitive information are not allowed”:
You’re hitting the policy described in MCP Server Authentication from Foundry above. Create the Custom keys connection in the portal and re-run; the script will pick it up via
project_connection_id.
Foundry ``agent_create`` errors with “Foundry connection ‘zscaler-mcp-headers’ was not found”:
Same fix — the connection name in your
.env(AZURE_FOUNDRY_CONNECTION_NAME) must match a Custom keys connection that exists in the project’s Connected resources.
OIDCProxy callback URL issues:
For OIDCProxy mode, register the callback URL in your identity provider:
http://<PUBLIC_IP>:8000/auth/callbackSome providers also require explicitly allowing HTTP callback URLs for non-HTTPS deployments.
Security¶
Secrets in Key Vault. All credentials are stored in Azure Key Vault by default for Container Apps, mandatory for VM, and the recommended path on AKS via Workload Identity Federation.
Five auth modes. Choose the level appropriate for the environment — production deployments should use OIDCProxy, JWT, or Zscaler.
TLS. Container Apps provides automatic HTTPS. VM deployments default to HTTP (front with a load balancer + TLS for production). AKS Preview exposes plain HTTP today; place behind Application Gateway / NGINX +
cert-managerfor production.NSG. VM deployments configure Network Security Group rules for SSH and the MCP port.
HMAC confirmations. Destructive Zscaler operations require cryptographic confirmation tokens (controlled by
ZSCALER_MCP_SKIP_CONFIRMATIONSandZSCALER_MCP_CONFIRMATION_TTL).Read-only by default. Write tools are disabled unless explicitly enabled via
ZSCALER_MCP_WRITE_ENABLED=trueandZSCALER_MCP_WRITE_TOOLS.
References¶
integrations/azure/ — full integration source, env templates, and per-client configuration examples