{
  "markdown": "![Zscaler MCP](https://raw.githubusercontent.com/zscaler/zscaler-mcp-server/master/docs/media/zscaler.svg)\n\n[![PyPI version](https://badge.fury.io/py/zscaler-mcp.svg)](https://badge.fury.io/py/zscaler-mcp)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/zscaler-mcp)](https://pypi.org/project/zscaler-mcp/)\n[![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](hhttps://zscaler-mcp-server.readthedocs.io/en/latest/integrations/index.html)\n[![codecov](https://codecov.io/gh/zscaler/zscaler-mcp-server/graph/badge.svg?token=9HwNcw4Q4h)](https://codecov.io/gh/zscaler/zscaler-mcp-server)\n[![GitHub commit activity](https://img.shields.io/badge/commit-activity-blue)](https://github.com/zscaler/zscaler-mcp-server/graphs/commit-activity)\n[![License](https://img.shields.io/github/license/zscaler/zscaler-mcp-server.svg)](https://github.com/zscaler/zscaler-mcp-server)\n[![Automation Hub](https://img.shields.io/badge/automation-hub-blue)](https://automate.zscaler.com/docs/tools/sdk-documentation/sdk-getting-started)\n[![Zscaler Community](https://img.shields.io/badge/zscaler-community-blue)](https://community.zscaler.com/)\n\n**zscaler-mcp-server** is a Model Context Protocol (MCP) server that connects AI agents with the Zscaler Zero Trust Exchange platform. **By default, the server operates in read-only mode** for security, requiring explicit opt-in to enable write operations.\n\n## Support Disclaimer\n\n-> **Disclaimer:** Please refer to our [General Support Statement](https://github.com/zscaler/zscaler-mcp-server/blob/master/docs/guides/support.md) before proceeding with the use of this provider. You can also refer to our [troubleshooting guide](https://github.com/zscaler/zscaler-mcp-server/blob/master/docs/guides/TROUBLESHOOTING.md) for guidance on typical problems.\n\n> [!IMPORTANT]\n> **🚧 Public Preview**: This project is currently in public preview and under active development. Features and functionality may change before the stable 1.0 release. While we encourage exploration and testing, please avoid production deployments. We welcome your feedback through [GitHub Issues](https://github.com/zscaler/zscaler-mcp-server/issues) to help shape the final release.\n\n## 📄 Table of contents\n\n- [📺 Overview](#overview)\n- [🔒 Security & Permissions](#security-permissions)\n- [🔐 MCP Client Authentication](#mcp-client-authentication)\n- [Supported Tools](#supported-tools)\n- [Installation & Setup](#installation--setup)\n  - [Prerequisites](#prerequisites)\n  - [Environment Configuration](#environment-configuration)\n  - [Installation](#installation)\n- [Usage](#usage)\n  - [Command Line](#command-line)\n  - [Service Configuration](#service-configuration)\n  - [Additional Command Line Options](#additional-command-line-options)\n- [Zscaler API Credentials & Authentication](#zscaler-api-credentials-authentication)\n  - [OneAPI Authentication](#oneapi-authentication)\n  - [Authentication Troubleshooting](#authentication-troubleshooting)\n  - [MCP Server Configuration](#mcp-server-configuration)\n- [As a Library](#as-a-library)\n- [Container Usage](#container-usage)\n  - [Using Pre-built Image (Recommended)](#using-pre-built-image-recommended)\n  - [Building Locally (Development)](#building-locally-development)\n- [Editor/Assistant Integration](#editor-assistant-integration)\n  - [Using `uvx` (recommended)](#using-uvx-recommended)\n  - [With Service Selection](#with-service-selection)\n  - [Using Individual Environment Variables](#using-individual-environment-variables)\n  - [Docker Version](#docker-version)\n- [Additional Deployment Options](#additional-deployment-options)\n  - [Remote MCP Deployment (EC2, VM, etc.)](#remote-mcp-deployment-ec2-vm-etc)\n  - [Azure Container Apps / Virtual Machine / AKS (Preview)](#azure-container-apps--virtual-machine--aks-preview)\n  - [Google Cloud (Cloud Run / GKE / VM / ADK Agent)](#google-cloud-cloud-run--gke--vm--adk-agent)\n  - [Kubernetes (Helm Chart)](#kubernetes-helm-chart)\n  - [Amazon Bedrock AgentCore](#amazon-bedrock-agentcore)\n- [Using the MCP Server with Agents](#using-the-mcp-server-with-agents)\n  - [Claude Desktop](#claude-desktop)\n  - [Cursor](#cursor)\n  - [Visual Studio Code + GitHub Copilot](#visual-studio-code-github-copilot)\n- [Platform Integrations](#platform-integrations)\n- [Troubleshooting](#troubleshooting)\n- [License](#license)\n\n## 📺 Overview\n\nThe Zscaler Integrations MCP Server brings context to your agents. Try prompts like:\n\n- \"List my ZPA Application segments\"\n- \"List my ZPA Segment Groups\"\n- \"List my ZIA Rule Labels\"\n\n> [!WARNING]\n> **🔒 READ-ONLY BY DEFAULT**: For security, this MCP server operates in **read-only mode** by default. Only `list_*` and `get_*` operations are available. To enable tools that can **CREATE, UPDATE, or DELETE** Zscaler resources, you must explicitly enable write mode using the `--enable-write-tools` flag or by setting `ZSCALER_MCP_WRITE_ENABLED=true`. See the [Security & Permissions](#-security--permissions) section for details.\n\n<!-- markdownlint-disable MD028 -->\n\n> [!TIP]\n> **Writing effective prompts**: This server exposes **402 tools** across multiple Zscaler services. Most MCP clients (Claude Desktop, Cursor, etc.) use deferred tool loading and will search for relevant tools based on your prompt. For best results, **be specific about the service and action** in your prompts:\n>\n> - **Good**: *\"List my ZPA application segments\"* — targets the right service and tool directly\n> - **Good**: *\"Show ZIA firewall rules\"* — clear service (`zia`) and action (`list`)\n> - **Less effective**: *\"Show me my devices\"* — ambiguous; multiple services expose device-related tools\n>\n> When a service is [disabled](#additional-command-line-options), its tools are fully removed from the server. However, the AI agent may still attempt to find related tools in other services. If you get unexpected results, refine your prompt with the specific service name (e.g. `zpa`, `zia`, `zdx`, `zcc`, `zcell`, `zms`).\n\n## 🔒 Security & Permissions\n\nThe Zscaler MCP Server implements a **security-first design** with granular permission controls and safe defaults:\n\n### Read-Only Mode (Default - Always Available)\n\nBy default, the server operates in **read-only mode**, exposing only tools that list or retrieve information:\n\n- ✅ **ALWAYS AVAILABLE** - Read-only tools are registered by the server\n- ✅ Safe to use with AI agents autonomously\n- ✅ No risk of accidental resource modification or deletion\n- ✅ All `list_*` and `get_*` operations are available (110+ read-only tools)\n- ❌ All `create_*`, `update_*`, and `delete_*` operations are disabled by default\n- 💡 Note: You may need to enable read-only tools in your AI agent's UI settings\n\n```bash\n# Read-only mode (default - safe)\nzscaler-mcp\n```\n\nWhen the server starts in read-only mode, you'll see:\n\n```text\n🔒 Server running in READ-ONLY mode (safe default)\n   Only list and get operations are available\n   To enable write operations, use --enable-write-tools AND --write-tools flags\n```\n\n> **💡 Read-only tools are ALWAYS registered** by the server regardless of any flags. You never need to enable them server-side. Note: Your AI agent UI (like Claude Desktop) may require you to enable individual tools before use.\n\n### Write Mode (Explicit Opt-In - Allowlist REQUIRED)\n\nTo enable tools that can create, modify, or delete Zscaler resources, you must provide **BOTH** flags:\n\n1. ✅ `--enable-write-tools` - Global unlock for write operations\n2. ✅ `--write-tools \"pattern\"` - **MANDATORY** explicit allowlist\n\n> **🔐 SECURITY: Allowlist is MANDATORY** - If you set `--enable-write-tools` without `--write-tools`, **0 write tools will be registered**. This ensures you consciously choose which write operations to enable.\n\n```bash\n# ❌ WRONG: This will NOT enable any write tools (allowlist missing)\nzscaler-mcp --enable-write-tools\n\n# ✅ CORRECT: Explicit allowlist required\nzscaler-mcp --enable-write-tools --write-tools \"zpa_create_*,zpa_delete_*\"\n```\n\nWhen you try to enable write mode without an allowlist:\n\n```text\n⚠️  WRITE TOOLS MODE ENABLED\n⚠️  NO allowlist provided - 0 write tools will be registered\n⚠️  Read-only tools will still be available\n⚠️  To enable write operations, add: --write-tools 'pattern'\n```\n\n#### Write Tools Allowlist (MANDATORY)\n\nThe allowlist provides **two-tier security**:\n\n1. ✅ **First Gate**: `--enable-write-tools` must be set (global unlock)\n2. ✅ **Second Gate**: Explicit allowlist determines which write tools are registered (MANDATORY)\n\n**Allowlist Examples:**\n\n```bash\n# Enable ONLY specific write tools with wildcards\nzscaler-mcp --enable-write-tools --write-tools \"zpa_create_*,zpa_delete_*\"\n\n# Enable specific tools without wildcards\nzscaler-mcp --enable-write-tools --write-tools \"zpa_create_application_segment,zia_create_rule_label\"\n\n# Enable all ZPA write operations (but no ZIA/ZDX/ZTW)\nzscaler-mcp --enable-write-tools --write-tools \"zpa_*\"\n```\n\nOr via environment variable:\n\n```bash\nexport ZSCALER_MCP_WRITE_ENABLED=true\nexport ZSCALER_MCP_WRITE_TOOLS=\"zpa_create_*,zpa_delete_*\"\nzscaler-mcp\n```\n\n**Wildcard patterns supported:**\n\n- `zpa_create_*` - Allow all ZPA creation tools\n- `zpa_delete_*` - Allow all ZPA deletion tools\n- `zpa_*` - Allow all ZPA write tools\n- `*_application_segment` - Allow all operations on application segments\n- `zpa_create_application_segment` - Exact match (no wildcard)\n\nWhen using a valid allowlist, you'll see:\n\n```text\n⚠️  WRITE TOOLS MODE ENABLED\n⚠️  Explicit allowlist provided - only listed write tools will be registered\n⚠️  Allowed patterns: zpa_create_*, zpa_delete_*\n⚠️  Server can CREATE, MODIFY, and DELETE Zscaler resources\n🔒 Security: 85 write tools blocked by allowlist, 8 allowed\n```\n\n### Tool Design Philosophy\n\nEach operation is a **separate, single-purpose tool** with explicit naming that makes its intent clear:\n\n#### ✅ Good (Verb-Based - Current Design)\n\n```text\nzpa_list_application_segments    ← Read-only, safe to allow-list\nzpa_get_application_segment      ← Read-only, safe to allow-list\nzpa_create_application_segment   ← Write operation, requires --enable-write-tools\nzpa_update_application_segment   ← Write operation, requires --enable-write-tools\nzpa_delete_application_segment   ← Destructive, requires --enable-write-tools\n```\n\nThis design allows AI assistants (Claude, Cursor, GitHub Copilot) to:\n\n- Allow-list read-only tools for autonomous exploration\n- Require explicit user confirmation for write operations\n- Clearly understand the intent of each tool from its name\n\n#### Responses: the API record, verbatim\n\nA read tool returns the Zscaler API record **unchanged**. The server does not\ntrim, rename, or re-declare a resource's attributes — that attribute set belongs\nto the API, so a field Zscaler adds in future reaches you with no server upgrade.\n\nTo keep responses small, you control what comes back rather than the server\nguessing. Two levers:\n\n- **`--toolsets`** — load only the slice of tools you need, so the tool catalog\n  stays small (see [Toolsets](#toolsets)).\n- **`query`** — every list tool accepts an optional [JMESPath](https://jmespath.org/)\n  expression applied to the results, so the agent projects exactly what it wants:\n\n  ```text\n  zcc_list_devices(query=\"[*].{user: user, policy: policyName}\")   # just those two fields\n  zcc_list_devices(query=\"[?registrationState=='Quarantined']\")    # just quarantined devices\n  zcc_list_devices(query=\"length(@)\")                              # just the count\n  ```\n\n  Field names are exactly what the Zscaler API returns. Omit `query` to get the\n  full records.\n\n### Security Layers\n\nThe server implements multiple layers of security (defense-in-depth). The first nine **apply on every transport, including stdio** — they govern which tools are exposed and how dangerous calls are confirmed. The remaining HTTP-only layers (TLS, host-header validation, source-IP ACL, MCP client authentication) are described in the [Network-Level Controls](#network-level-controls-http-only) section further down.\n\n1. **Read-Only Tools Always Enabled**: Safe `list_*` and `get_*` operations are always available (254 tools).\n2. **Default Write Mode Disabled**: Write tools are disabled unless explicitly enabled via `--enable-write-tools`.\n3. **Mandatory Allowlist**: Write operations require explicit `--write-tools` allowlist (wildcard support).\n4. **OneAPI Entitlement Filter**: At startup, toolsets for products the OneAPI credentials cannot call are silently dropped (see [OneAPI Entitlement Filter](#oneapi-entitlement-filter) below).\n5. **Toolset Selection**: Optionally narrow the registered tool surface to a specific slice (e.g. `--toolsets zia_url_filtering,zpa_app_segments`). See the [Toolsets](#toolsets) section below.\n6. **Verb-Based Tool Naming**: Each tool clearly indicates its purpose (`list`, `get`, `create`, `update`, `delete`).\n7. **Tool Metadata Annotations**: All tools are annotated with `readOnlyHint` or `destructiveHint` for AI agent frameworks.\n8. **AI Agent Confirmation**: All write tools marked with `destructiveHint=True` trigger permission dialogs in AI assistants.\n9. **Human Confirmation for DELETE**: Delete operations are gated by a server-initiated confirmation. On clients that support MCP elicitation (Claude Desktop, Cursor), the server asks the **client** to prompt a human and the answer arrives as a protocol field — so a hijacked agent cannot author the approval, and a failed round trip fails closed. Clients without that capability fall back to a cryptographic confirmation token (HMAC-SHA256, single-use, 5-minute TTL, bound to the exact tool and parameters), which stops an approval being spent on another resource, replayed or reused — but is **not** by itself an anti-prompt-injection control, since a hijacked agent receives and can redeem it. The fallback is also **single-process**; elicitation-capable clients are unaffected. See [MCP protocol posture — confirmation threat model](docs/guides/mcp-protocol.md#destructive-operation-confirmation-threat-model) for the full analysis.\n10. **Environment Variable Control**: `ZSCALER_MCP_WRITE_ENABLED`, `ZSCALER_MCP_WRITE_TOOLS`, `ZSCALER_MCP_TOOLSETS`, `ZSCALER_MCP_DISABLE_ENTITLEMENT_FILTER`, and the disable lists can all be managed centrally without code changes.\n11. **Output Sanitization**: Every string in every tool result is run through a three-stage sanitizer before reaching the agent — invisible/control characters (BiDi overrides, zero-width chars, BOM, soft hyphen) are stripped, raw HTML and HTML comments are removed (via `bleach`), Markdown link/image syntax is neutralised so embedded URLs cannot be smuggled to the agent, and Markdown code-fence info-strings containing role-impersonation tokens (`system`, `assistant`, `tool`, `ignore`, …) are collapsed to a neutral `text` tag. This defends against prompt-injection payloads that an attacker — or a careless admin — might embed in editable Zscaler resources (rule descriptions, location names, label descriptions, etc.). On by default. Opt-out with `ZSCALER_MCP_DISABLE_OUTPUT_SANITIZATION=true` (use only for diagnostics).\n12. **Audit Logging**: When `--log-tool-calls` / `ZSCALER_MCP_LOG_TOOL_CALLS=true` is set, every tool invocation is logged with its arguments (sensitive values redacted), duration, and a result summary.\n\nThis multi-layered approach ensures that even if one security control is bypassed, others remain in place to prevent unauthorized operations. Layers 1-12 above apply equally to `stdio`, `sse`, and `streamable-http`.\n\n### Toolsets\n\nTools are grouped into 63 named **toolsets** so you can load only the slice an agent actually needs (e.g. `zia_url_filtering` (5 tools) instead of every tool from every service (402)). Toolsets reduce the agent's context cost and improve tool-selection accuracy.\n\n```bash\n# Load just two slices\nzscaler-mcp --toolsets zia_url_filtering,zpa_app_segments\n\n# Or use the curated default-on subset\nzscaler-mcp --toolsets default\n\n# Or load every registered toolset explicitly\nzscaler-mcp --toolsets all\n\n# Equivalent via environment variable\nexport ZSCALER_MCP_TOOLSETS=\"zia_url_filtering,zpa_app_segments\"\n```\n\nWhen `--toolsets` is unspecified, every toolset whose service is enabled is loaded (preserves the historical default).\n\nThe agent can also enable additional toolsets at runtime through the always-on `zscaler_list_toolsets`, `zscaler_get_toolset_tools`, and `zscaler_enable_toolset` tools.\n\nFor the full catalog (29 toolsets across all services), filter precedence rules, per-toolset agent guidance, and the complete reference, see [docs/guides/toolsets.md](docs/guides/toolsets.md).\n\n### OneAPI Entitlement Filter\n\nAfter your toolset selection resolves, the server reads the product entitlements from the OneAPI bearer token issued for your `ZSCALER_CLIENT_ID` and silently drops toolsets for products the credentials cannot call. If your OneAPI client is only entitled to ZIA and ZPA, every `zdx_*` / `zcc_*` / `ztw_*` / `zid_*` / `zeasm_*` / `zins_*` / `zms_*` toolset is filtered out at startup — even with `--toolsets all`.\n\nThis prevents an agent from discovering tools whose first call would only ever return `401 Unauthorized`. The filter applies on every transport, including `stdio`.\n\nWhen the filter runs you'll see one log line at startup, for example:\n\n```text\nentitlement filter applied: entitled services=['zia', 'zpa'], kept 12 toolset(s), removed 17 toolset(s)\n```\n\nThe filter is **non-fatal**. If credentials are missing, the token endpoint is unreachable, the token doesn't decode, or the token has no recognizable product entitlements, the server logs a single WARN line and starts normally with the user-selected toolsets unchanged.\n\nTo bypass the filter (for example, while diagnosing an unusual token shape):\n\n```bash\nzscaler-mcp --no-entitlement-filter\n# or\nexport ZSCALER_MCP_DISABLE_ENTITLEMENT_FILTER=true\n```\n\nOnly **product entitlement** is honoured — not role names. The server defers per-action permission enforcement to the live API; the entitlement filter only ensures we don't *advertise* tools for products the client has zero access to.\n\n### Cryptographic Confirmation for Destructive Actions\n\nDelete operations are never executed on the first call. What happens instead depends on the client:\n\n- **Clients that support MCP elicitation** get an interactive prompt naming the resource, answered by a **human**. The AI agent never handles the approval.\n- **Every other client** gets a **cryptographic confirmation token** (HMAC-SHA256) it must pass back to proceed. The token is bound to the specific operation and its parameters, is single-use, and expires after 5 minutes — so it can't be forged, replayed, or reused for a different resource.\n\n**There is no way to turn this off.** Deletes are irreversible against a live tenant, so the server ships no flag or environment variable that skips the gate. If you don't want an agent deleting anything, don't allowlist the delete tools: write tools are off by default and `--write-tools` takes explicit patterns (see [Write Mode](#write-mode-explicit-opt-in---allowlist-required)).\n\n### Network-Level Controls (HTTP only)\n\nThe next four subsections — TLS, source-IP allowlist, host-header validation, and the `.env` plaintext-secret scanner — apply only to the HTTP transports (`sse`, `streamable-http`). They control **who can reach the server over the network**. They are independent of the tool-level controls listed in [Security Layers](#security-layers) above (read-only mode, write allowlist, toolsets, entitlement filter, HMAC confirmations), which apply on every transport including `stdio`.\n\nThe corresponding *MCP client authentication* (Bearer / Basic / OAuth 2.1) is a fifth network-level layer covered in detail in the [MCP Client Authentication](#-mcp-client-authentication) section further below.\n\n#### HTTPS/TLS Support\n\n**HTTPS is required by default** for non-localhost deployments. The server will refuse to start on a non-localhost interface without TLS certificates unless you explicitly set `ZSCALER_MCP_ALLOW_HTTP=true`.\n\nWhen running with HTTP transports (`sse` or `streamable-http`), provide TLS certificates:\n\n```env\nZSCALER_MCP_TLS_CERTFILE=/path/to/cert.pem\nZSCALER_MCP_TLS_KEYFILE=/path/to/key.pem\n\n# Optional: private key password and CA bundle\nZSCALER_MCP_TLS_KEYFILE_PASSWORD=your-key-password\nZSCALER_MCP_TLS_CA_CERTS=/path/to/ca-bundle.pem\n```\n\nWhen TLS is configured, the server automatically starts with HTTPS. This works with both public (CA-signed) and private (self-signed) certificates. Generate a self-signed certificate for testing:\n\n```bash\nopenssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes \\\n  -subj \"/CN=localhost\"\n```\n\n#### Source IP Access Control\n\nYou can restrict which client IPs are allowed to connect using `ZSCALER_MCP_ALLOWED_SOURCE_IPS`. When unset (the default), source IP filtering is disabled and deferred to upstream controls (firewall rules, AWS Security Groups, etc.).\n\n```env\n# Allow only specific IPs/subnets\nZSCALER_MCP_ALLOWED_SOURCE_IPS=10.0.0.0/8,172.16.0.5\n\n# Allow all (effectively disable — same as not setting the variable)\nZSCALER_MCP_ALLOWED_SOURCE_IPS=0.0.0.0/0\n```\n\nSupports individual IPv4/IPv6 addresses, CIDR notation, and the wildcard `0.0.0.0/0`. Health-check endpoints (`/health`, `/healthz`, `/ready`) are exempt so load-balancer probes continue to work. Requests from disallowed IPs receive `403 Forbidden`.\n\n#### .env File Security Warning\n\nWhen starting with HTTP transports, the server automatically scans any `.env` file in the working directory for plaintext secrets (values containing `SECRET`, `PASSWORD`, `KEY`, or `TOKEN`). If detected, a security warning is logged recommending the use of a secrets manager or environment variables instead.\n\n### Security Posture Banner\n\nOn startup, the server logs a consolidated **Security Posture Banner** summarizing the active security configuration — transport mode, host validation status, authentication mode, TLS status, and any active warnings. This makes it easy to verify the security state at a glance.\n\n**Key Security Principles**:\n\n- No \"enable all write tools\" backdoor exists - allowlist is **mandatory**\n- AI agents must request permission before executing any write operation (`destructiveHint`)\n- Every destructive action requires explicit user approval through the AI agent's permission framework\n- Destructive confirmations are cryptographically bound to prevent prompt injection bypass\n\n### Best Practices\n\n- **Read-Only by Default**: No configuration needed for safe operations - read-only tools are always available\n- **Mandatory Allowlist**: Always provide explicit `--write-tools` allowlist when enabling write mode\n- **Development/Testing**: Use narrow allowlists (e.g., `--write-tools \"zpa_create_application_segment\"`)\n- **Production/Agents**: Keep server in read-only mode (default) for AI agents performing autonomous operations\n- **CI/CD**: Never set `ZSCALER_MCP_WRITE_ENABLED=true` without a corresponding `ZSCALER_MCP_WRITE_TOOLS` allowlist\n- **Least Privilege**: Use narrowest possible allowlist patterns for your use case\n- **Wildcard Usage**: Use wildcards for service-level control (e.g., `zpa_create_*`) or operation-level control (e.g., `*_create_*`)\n- **Audit Review**: Regularly review which write tools are allowlisted and remove unnecessary ones\n- **Specific Prompts**: With 402 tools and deferred loading, AI agents match prompts to tools by relevance. Use service-specific prompts (e.g., *\"List ZPA segments\"* instead of *\"Show my segments\"*) for accurate tool selection\n\n## 🔐 MCP Client Authentication\n\n> **📖 Full Documentation: [Authentication & Deployment Guide](docs/deployment/authentication-and-deployment.md)**\n\nWhen running the MCP server over HTTP (`sse` or `streamable-http` transports), you can enable authentication to control **who is allowed to connect** to the server. This is independent from the [Zscaler API credentials](#zscaler-api-credentials-authentication), which control how the server authenticates to Zscaler APIs.\n\nFor HTTP transports, the server **auto-detects and enables authentication** when auth-related environment variables are present. For `stdio` transport, authentication is not applicable (the operating system's process isolation provides security).\n\n### Authentication Modes\n\nThe server supports four authentication modes, configured via environment variables:\n\n| Mode | Description | Best For |\n|------|-------------|----------|\n| **`api-key`** | Simple shared secret — client sends `Authorization: Bearer <key>` | Quick setup, internal environments, development |\n| **`jwt`** | External Identity Provider via JWKS — tokens validated locally using public keys | Enterprise SSO, multi-tenant deployments (Auth0, Okta, Azure AD, Keycloak, AWS Cognito, PingOne, Google) |\n| **`zscaler`** | Zscaler OneAPI credential validation — client sends Basic Auth with `client_id:client_secret` | Environments already using Zscaler API credentials |\n| **`oidc`** | OAuth 2.1 against your own IdP — the server is an OAuth 2.0 protected resource (RFC 9728) and clients authenticate with the IdP directly | Browser-based login for human operators, any OIDC provider |\n\n### Quick Start\n\nEnable authentication by setting these environment variables in your `.env` file:\n\n```env\n# Enable authentication\nZSCALER_MCP_AUTH_ENABLED=true\nZSCALER_MCP_AUTH_MODE=api-key\n\n# For api-key mode: set a shared secret\nZSCALER_MCP_AUTH_API_KEY=sk-your-secret-key-here\n```\n\nThen start the server with an HTTP transport:\n\n```bash\nzscaler-mcp --transport streamable-http\n```\n\nClients must include the key in the `Authorization` header:\n\n```text\nAuthorization: Bearer sk-your-secret-key-here\n```\n\n### How It Works\n\nAuthentication is implemented as ASGI middleware that wraps the HTTP transport layer:\n\n```text\nMCP Client Request\n      │\n      ▼\n┌──────────────┐     ┌──────────────┐     ┌──────────────┐\n│  Auth         │────▶│  MCP          │────▶│  Zscaler     │\n│  Middleware   │     │  Server       │     │  APIs        │\n└──────────────┘     └──────────────┘     └──────────────┘\n Layer 1: WHO          MCP Protocol        Layer 2: HOW\n can connect?          Processing          server talks\n                                           to Zscaler\n```\n\n- **Layer 1 (MCP Client Auth)**: Controlled by `ZSCALER_MCP_AUTH_*` variables — validates the incoming request\n- **Layer 2 (Zscaler API Auth)**: Controlled by `ZSCALER_CLIENT_ID`, `ZSCALER_CLIENT_SECRET`, etc. — authenticates the server to Zscaler APIs\n\nThese two layers are completely independent. You can enable one, both, or neither.\n\n### Configuration by Mode\n\n#### API Key\n\n```env\nZSCALER_MCP_AUTH_ENABLED=true\nZSCALER_MCP_AUTH_MODE=api-key\nZSCALER_MCP_AUTH_API_KEY=sk-your-secret-key-here\n```\n\n#### JWT (External IdP via JWKS)\n\n```env\nZSCALER_MCP_AUTH_ENABLED=true\nZSCALER_MCP_AUTH_MODE=jwt\nZSCALER_MCP_AUTH_JWKS_URI=https://your-idp.com/.well-known/jwks.json\nZSCALER_MCP_AUTH_ISSUER=https://your-idp.com\nZSCALER_MCP_AUTH_AUDIENCE=zscaler-mcp-server\nZSCALER_MCP_AUTH_ALGORITHMS=RS256,ES256   # Optional (default: RS256,ES256)\n```\n\n#### Zscaler OneAPI Credentials\n\n```env\nZSCALER_MCP_AUTH_ENABLED=true\nZSCALER_MCP_AUTH_MODE=zscaler\n# Uses ZSCALER_VANITY_DOMAIN and ZSCALER_CLOUD from your existing config\n```\n\nClients authenticate with Basic Auth (`client_id:client_secret`) or custom headers (`X-Zscaler-Client-ID` / `X-Zscaler-Client-Secret`).\n\n### Authentication Defaults\n\nFor HTTP transports (`sse`, `streamable-http`), the server **auto-detects and enables authentication** if auth-related environment variables are present (e.g., `ZSCALER_MCP_AUTH_JWKS_URI`, `ZSCALER_MCP_AUTH_API_KEY`, or `ZSCALER_VANITY_DOMAIN`). If no auth configuration is detected and `ZSCALER_MCP_AUTH_ENABLED` is not explicitly set, the server logs a security warning but continues without authentication.\n\nTo explicitly disable authentication, set:\n\n```env\nZSCALER_MCP_AUTH_ENABLED=false\n```\n\nAuthentication does not apply to `stdio` transport (process isolation provides security).\n\n### OAuth 2.1 (`oidc` mode)\n\n`oidc` mode makes the server an **OAuth 2.0 protected resource** ([RFC 9728](https://www.rfc-editor.org/rfc/rfc9728.html)). The server publishes `/.well-known/oauth-protected-resource` naming your Identity Provider; the client reads that, runs the OAuth flow **against the IdP directly**, and presents the resulting token. The server's only job is verifying the token signature against the IdP's published public keys.\n\nIt is configured entirely through environment variables — no code, no extra packages:\n\n```env\nZSCALER_MCP_AUTH_ENABLED=true\nZSCALER_MCP_AUTH_MODE=oidc\n\nOIDCPROXY_CONFIG_URL=https://your-tenant.auth0.com/.well-known/openid-configuration\nOIDCPROXY_CLIENT_ID=<your app registration's client id>\nOIDCPROXY_BASE_URL=http://localhost:8000\nOIDCPROXY_AUDIENCE=zscaler-mcp-server\n# Optional: scopes a token must carry, comma-separated\n# OIDCPROXY_REQUIRED_SCOPES=zscaler.read\n```\n\nNotes:\n\n- **No client secret.** Verifying a signature needs the IdP's public keys, not a credential of ours. `OIDCPROXY_CLIENT_SECRET` is ignored if set.\n- `OIDCPROXY_BASE_URL` is **this server's** public URL, which clients use as the resource identifier — not the IdP's.\n- `OIDCPROXY_AUDIENCE` defaults to `OIDCPROXY_CLIENT_ID`. Entra ID puts the client ID in `aud`; Auth0 uses the API identifier.\n- The issuer and JWKS URI are read from the IdP's discovery document at startup, so they always match what the IdP actually signs with.\n- The server serves no `/authorize`, `/token` or `/register` — clients need a client ID issued by the IdP and cannot self-register.\n- Works with any OIDC-compliant provider (Auth0, Okta, Microsoft Entra ID, Keycloak, Google, AWS Cognito, PingOne).\n- All other security layers (TLS, source-IP ACL, host validation) remain active.\n\n**IdP requirements:** an application with the callback URL your client uses (`http://localhost:3334/oauth/callback` for `mcp-remote`, with the port pinned) registered, and an API/resource identifier matching `OIDCPROXY_AUDIENCE`.\n\n> **📖 For detailed setup instructions — including [Microsoft Entra ID step-by-step guide](docs/deployment/entra-id-oidcproxy.md), IdP-specific JWKS configuration, Docker deployment examples, client configuration for Claude/Cursor/VS Code, and troubleshooting — see the [Authentication & Deployment Guide](docs/deployment/authentication-and-deployment.md).**\n\n## Supported Tools\n\n<!-- The table below is auto-generated by `zscaler-mcp --generate-docs`. Edit\n     descriptions in `zscaler_mcp/services.py` and re-run the generator. -->\n\n<!-- generated:start service-summary -->\n\nThe Zscaler Integrations MCP Server provides **402 tools** for all major Zscaler services:\n\n| Service | Description | Tools |\n|---------|-------------|-------|\n| **ZIA** | Zscaler Internet Access — Security policies | 166 read/write |\n| **ZPA** | Zscaler Private Access — Application access | 109 read/write |\n| **ZDX** | Zscaler Digital Experience — Monitoring & analytics | 31 read/write |\n| **ZCell** | Zscaler Cellular — SIM inventory, usage analytics & anomaly policies | 20 read-only |\n| **ZMS** | Zscaler Microsegmentation — Agents, resources, policies | 20 read-only |\n| **ZTW** | Zscaler Workload Segmentation | 19 read/write |\n| **Z-Insights** | Z-Insights analytics — Web traffic, cyber incidents, shadow IT | 16 read-only |\n| **ZIdentity** | ZIdentity — Identity & access management | 10 read-only |\n| **EASM** | External Attack Surface Management | 7 read-only |\n| **ZCC** | Zscaler Client Connector — Device management | 4 read-only |\n\n<!-- generated:end service-summary -->\n\n📖 **[View Complete Tools Reference →](docs/guides/supported-tools.md)**\n\n> **Note:** All write operations require the `--enable-write-tools` flag and an explicit `--write-tools` allowlist. See the [Security & Permissions](#-security--permissions) section for details.\n\n## Installation & Setup\n\n### Prerequisites\n\n- Python 3.11 or higher\n- [`uv`](https://docs.astral.sh/uv/) or pip\n- Zscaler API credentials (see below)\n\n### Environment Configuration\n\nCopy the example environment file and configure your credentials:\n\n```bash\ncp .env.example .env\n```\n\nThen edit `.env` with your Zscaler API credentials:\n\n**Required Configuration (OneAPI):**\n\n- `ZSCALER_CLIENT_ID`: Your Zscaler OAuth client ID\n- `ZSCALER_CLIENT_SECRET`: Your Zscaler OAuth client secret\n- `ZSCALER_CUSTOMER_ID`: Your Zscaler customer ID\n- `ZSCALER_VANITY_DOMAIN`: Your Zscaler vanity domain\n\n**Optional Configuration:**\n\n- `ZSCALER_CLOUD`: (Optional) Zscaler cloud environment (e.g., `beta`) - Required when interacting with Beta Tenant ONLY.\n- `ZSCALER_PRIVATE_KEY`: (Optional) PEM-encoded private key for JWT-based OneAPI auth, used in place of `ZSCALER_CLIENT_SECRET`.\n- `ZSCALER_MCP_SERVICES`: Comma-separated list of services to enable (default: all services)\n- `ZSCALER_MCP_TRANSPORT`: Transport method - `stdio`, `sse`, or `streamable-http` (default: `stdio`)\n- `ZSCALER_MCP_DEBUG`: Enable debug logging - `true` or `false` (default: `false`)\n- `ZSCALER_MCP_HOST`: Host for HTTP transports (default: `127.0.0.1`)\n- `ZSCALER_MCP_PORT`: Port for HTTP transports (default: `8000`)\n\n*Alternatively, you can set these as environment variables instead of using a `.env` file.*\n\n> **Important**: Ensure your API client has the necessary permissions for the services you plan to use. You can always update permissions later in the Zscaler console.\n\n### Installation\n\n#### Install with VS Code (Quick Setup)\n\n[![VS Code Install](https://img.shields.io/badge/VS%20Code-Install-blue?logo=visual-studio-code&logoColor=white&style=for-the-badge)](https://vscode.dev/redirect?url=vscode:mcp/install?%7B%22name%22%3A%22zscaler-mcp-server%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22zscaler-mcp%22%5D%2C%22env%22%3A%7B%22ZSCALER_CLIENT_ID%22%3A%22%3CYOUR_CLIENT_ID%3E%22%2C%22ZSCALER_CLIENT_SECRET%22%3A%22%3CYOUR_CLIENT_SECRET%3E%22%2C%22ZSCALER_CUSTOMER_ID%22%3A%22%3CYOUR_CUSTOMER_ID%3E%22%2C%22ZSCALER_VANITY_DOMAIN%22%3A%22%3CYOUR_VANITY_DOMAIN%3E%22%7D%7D)\n\n> **Note**: This will open VS Code and prompt you to configure the MCP server. You'll need to replace the placeholder values (`<YOUR_CLIENT_ID>`, etc.) with your actual Zscaler credentials.\n\n#### Install using uv (recommended)\n\n```bash\nuv tool install zscaler-mcp\n```\n\n#### Install from source using uv (development)\n\n```bash\nuv pip install -e .\n```\n\n> **Remote deployment:** When running on EC2/VM, activate the project venv before starting: `source .venv/bin/activate`. See [Remote MCP Deployment](#remote-mcp-deployment-ec2-vm-etc).\n\n#### Install from source using pip\n\n```bash\npip install -e .\n```\n\n#### Install using make (convenience)\n\n```bash\nmake install-dev\n```\n\n> [!TIP]\n> If `zscaler-mcp-server` isn't found, update your shell PATH.\n\nFor installation via code editors/assistants, see the [Using the MCP Server with Agents](#using-the-mcp-server-with-agents) section below.\n\n## Usage\n\n> [!NOTE]\n> **Default Security Mode**: All examples below run in **read-only mode** by default (only `list_*` and `get_*` operations). To enable write operations (`create_*`, `update_*`, `delete_*`), add the `--enable-write-tools` flag to any command, or set `ZSCALER_MCP_WRITE_ENABLED=true` in your environment.\n\n### Command Line\n\nRun the server with default settings (stdio transport, read-only mode):\n\n```bash\nzscaler-mcp\n```\n\nRun the server with write operations enabled:\n\n```bash\nzscaler-mcp --enable-write-tools\n```\n\nRun with SSE transport:\n\n```bash\nzscaler-mcp --transport sse\n```\n\nRun with streamable-http transport:\n\n```bash\nzscaler-mcp --transport streamable-http\n```\n\nRun with streamable-http transport on custom port:\n\n```bash\nzscaler-mcp --transport streamable-http --host 0.0.0.0 --port 8080\n```\n\n### Service Configuration\n\nThe Zscaler Integrations MCP Server supports multiple ways to specify which services to enable:\n\n#### 1. Command Line Arguments (highest priority)\n\nSpecify services using comma-separated lists:\n\n```bash\n# Enable specific services\nzscaler-mcp --services zia,zpa,zdx\n\n# Enable only one service\nzscaler-mcp --services zia\n```\n\n#### 2. Environment Variable (fallback)\n\nSet the `ZSCALER_MCP_SERVICES` environment variable:\n\n```bash\n# Export environment variable\nexport ZSCALER_MCP_SERVICES=zia,zpa,zdx\nzscaler-mcp\n\n# Or set inline\nZSCALER_MCP_SERVICES=zia,zpa,zdx zscaler-mcp\n```\n\n#### 3. Default Behavior (all services)\n\nIf no services are specified via command line or environment variable, all available services are enabled by default.\n\n**Service Priority Order:**\n\n1. Command line `--services` argument (overrides all)\n2. `ZSCALER_MCP_SERVICES` environment variable (fallback)\n3. All services (default when none specified)\n\n### Excluding Services and Tools\n\nWhen you want to keep most tools available but exclude a few, use `--disabled-tools` or `--disabled-services` instead of listing every tool you want to include.\n\nBoth flags support **wildcards** via [fnmatch](https://docs.python.org/3/library/fnmatch.html) patterns.\n\n```bash\n# Exclude a single tool\nzscaler-mcp --disabled-tools zia_list_devices\n\n# Exclude all tools from a service prefix\nzscaler-mcp --disabled-tools \"zcc_*\"\n\n# Exclude multiple patterns\nzscaler-mcp --disabled-tools \"zcc_*,zdx_list_devices\"\n\n# Exclude entire services\nzscaler-mcp --disabled-services zcc,zdx\n\n# Combine: keep all services but exclude specific tools\nzscaler-mcp --disabled-tools \"zia_list_devices,zdx_*_analysis\"\n```\n\nEnvironment variables:\n\n```bash\nexport ZSCALER_MCP_DISABLED_TOOLS=\"zia_list_devices,zdx_*\"\nexport ZSCALER_MCP_DISABLED_SERVICES=\"zcc\"\n```\n\n**Precedence:** `--disabled-tools` takes precedence over `--tools` (include list). A tool that matches both the include list and the exclude list will be excluded.\n\n### Additional Command Line Options\n\n```bash\n# Enable write operations (create, update, delete)\nzscaler-mcp --enable-write-tools\n\n# Enable debug logging\nzscaler-mcp --debug\n\n# Combine multiple options\nzscaler-mcp --services zia,zpa --enable-write-tools --debug\n```\n\nFor all available options:\n\n```bash\nzscaler-mcp --help\n```\n\nAvailable command-line flags:\n\n- `--transport`: Transport protocol (`stdio`, `sse`, `streamable-http`)\n- `--services`: Comma-separated list of services to enable\n- `--disabled-services`: Comma-separated list of services to exclude (e.g., `zcc,zdx`)\n- `--tools`: Comma-separated list of specific tools to enable\n- `--disabled-tools`: Comma-separated list of tools to exclude, supports wildcards (e.g., `zcc_*,zdx_list_devices`)\n- `--toolsets`: Comma-separated toolset ids to enable (e.g. `zia_url_filtering,zpa_app_segments`). Special values: `default` (curated default-on subset), `all` (every toolset). When unspecified, every toolset whose service is enabled is loaded. See [docs/guides/toolsets.md](docs/guides/toolsets.md).\n- `--no-entitlement-filter`: Skip the OneAPI entitlement filter that trims toolsets to the products the configured `ZSCALER_CLIENT_ID` is entitled to. Emergency override only — the filter is non-fatal by default.\n- `--enable-write-tools`: Enable write operations (disabled by default for safety)\n- `--write-tools`: Mandatory allowlist of write tool patterns (e.g., `\"zpa_create_*,zpa_delete_*\"`)\n- `--log-tool-calls`: Enable per-tool-call audit logging (tool name, redacted arguments, duration, result summary)\n- `--debug`: Enable debug logging\n- `--host`: Host for HTTP transports (default: `127.0.0.1`)\n- `--port`: Port for HTTP transports (default: `8000`)\n- `--user-agent-comment`: Additional text appended to User-Agent header\n- `--generate-auth-token`: Generate a client auth token snippet and exit\n- `--list-tools`: List all available tools and exit\n- `--version`: Show server version and exit\n\n### Supported Agents\n\n- [Claude](https://claude.ai/)\n- [Cursor](https://cursor.so/)\n- [VS Code](https://code.visualstudio.com/download) or [VS Code Insiders](https://code.visualstudio.com/insiders)\n\n## Zscaler API Credentials & Authentication\n\nThe Zscaler Integrations MCP Server uses **OneAPI** authentication exclusively. A single set of credentials authenticates the server to every Zscaler product (ZIA, ZPA, ZCC, ZDX, Zscaler Cellular, ZTW, ZIdentity, ZMS, Z-Insights, EASM).\n\n> **Zscaler Cellular (ZCell)** needs one extra credential — your Zscaler Cellular customer ID via `ZCELL_CUSTOMER_ID` — which is separate from `ZSCALER_CUSTOMER_ID` (used by ZPA). See the environment-variable table below.\n\n### OneAPI Authentication\n\n#### Prerequisites\n\n1. Create an API Client in the [ZIdentity platform](https://help.zscaler.com/zidentity/about-api-clients).\n2. Obtain your `clientId`, `clientSecret` (or `privateKey` for JWT), `customerId`, and `vanityDomain`.\n3. Learn more: [Understanding OneAPI](https://help.zscaler.com/oneapi/understanding-oneapi).\n\n#### Quick Setup\n\nCreate a `.env` file in your project root (or wherever you start the MCP server):\n\n```env\n# OneAPI credentials (required)\nZSCALER_CLIENT_ID=your_client_id\nZSCALER_CLIENT_SECRET=your_client_secret\nZSCALER_CUSTOMER_ID=your_customer_id\nZSCALER_VANITY_DOMAIN=your_vanity_domain\n\n# Required only for Zscaler Cellular (ZCell) tools\nZCELL_CUSTOMER_ID=your_zscaler_cellular_customer_id\n\n# Optional: only required when targeting the Beta tenant\nZSCALER_CLOUD=beta\n```\n\n⚠️ **Security**: Do not commit `.env` to source control. Add it to your `.gitignore`.\n\n#### OneAPI Environment Variables\n\n| Environment Variable | Required | Description |\n|---------------------|----------|-------------|\n| `ZSCALER_CLIENT_ID` | Yes | OneAPI client ID from the ZIdentity console |\n| `ZSCALER_CLIENT_SECRET` | Yes (or `ZSCALER_PRIVATE_KEY`) | OneAPI client secret |\n| `ZSCALER_CUSTOMER_ID` | Yes (for ZPA tools) | Zscaler customer/tenant ID |\n| `ZCELL_CUSTOMER_ID` | Yes (for Zscaler Cellular tools) | Zscaler Cellular customer ID (distinct from `ZSCALER_CUSTOMER_ID`; also accepted as the `zcellCustomerId` config key) |\n| `ZSCALER_VANITY_DOMAIN` | Yes | Your organization's vanity domain (e.g., `acme`) |\n| `ZSCALER_CLOUD` | No | Cloud override (e.g., `beta`, `zscalertwo`); omit for production |\n| `ZSCALER_PRIVATE_KEY` | No | PEM-encoded private key for JWT auth (used in place of `ZSCALER_CLIENT_SECRET`) |\n\n#### Verification\n\nAfter populating `.env`, start the server:\n\n```bash\nzscaler-mcp\n```\n\nIf credentials are valid, the server starts cleanly. The Zscaler SDK client is created lazily on the first tool call, so missing or rotating credentials surface as a clear error message at call time rather than blocking server startup.\n\n---\n\n### Authentication Troubleshooting\n\n| Symptom | Likely cause | Fix |\n|---|---|---|\n| `Zscaler SDK failed to initialize due to missing OneAPI credentials: [...]` | One or more of `ZSCALER_CLIENT_ID`, `ZSCALER_VANITY_DOMAIN`, or (for ZPA) `ZSCALER_CUSTOMER_ID` is unset or empty. | Set the listed env vars in `.env` or your shell. |\n| `You must provide either ZSCALER_CLIENT_SECRET or ZSCALER_PRIVATE_KEY for the OneAPI client.` | Both auth materials are absent. | Set one of `ZSCALER_CLIENT_SECRET` or `ZSCALER_PRIVATE_KEY`. |\n| 401/403 from a Zscaler API at tool-call time | API client lacks the scope for that product, or credentials are revoked. | Verify the OneAPI client's permissions in the ZIdentity console; rotate credentials if necessary. |\n\n### MCP Server Configuration\n\nThe following environment variables control MCP server behavior (not authentication):\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `ZSCALER_MCP_TRANSPORT` | `stdio` | Transport protocol to use (`stdio`, `sse`, or `streamable-http`) |\n| `ZSCALER_MCP_SERVICES` | `\"\"` | Comma-separated list of services to enable (empty = all services). Supported values: `zcc`, `zdx`, `zia`, `zid`, `zpa`, `ztw` |\n| `ZSCALER_MCP_TOOLS` | `\"\"` | Comma-separated list of specific tools to enable (empty = all tools) |\n| `ZSCALER_MCP_DISABLED_SERVICES` | `\"\"` | Comma-separated list of services to exclude (e.g., `zcc,zdx`). Takes precedence over `ZSCALER_MCP_SERVICES`. |\n| `ZSCALER_MCP_DISABLED_TOOLS` | `\"\"` | Comma-separated list of tools to exclude. Supports wildcards (e.g., `zcc_*,zia_list_devices`). Takes precedence over `ZSCALER_MCP_TOOLS`. |\n| `ZSCALER_MCP_WRITE_ENABLED` | `false` | Enable write operations (`true`/`false`). When `false`, only read-only tools are available. Set to `true` or use `--enable-write-tools` flag to unlock write mode. |\n| `ZSCALER_MCP_WRITE_TOOLS` | `\"\"` | **MANDATORY** comma-separated allowlist of write tools (supports wildcards like `zpa_*`). Requires `ZSCALER_MCP_WRITE_ENABLED=true`. If empty when write mode enabled, 0 write tools registered. |\n| `ZSCALER_MCP_DEBUG` | `false` | Enable debug logging (`true`/`false`) |\n| `ZSCALER_MCP_HOST` | `127.0.0.1` | Host to bind to for HTTP transports |\n| `ZSCALER_MCP_PORT` | `8000` | Port to listen on for HTTP transports |\n| `ZSCALER_MCP_DISABLE_HOST_VALIDATION` | `false` | Disable Host header validation when exposing on EC2/public IP (`true`/`false`). Alternatively, use `--host 0.0.0.0` which auto-disables. |\n| `ZSCALER_MCP_ALLOWED_HOSTS` | `\"\"` | Comma-separated allowed Host values for remote deployment (e.g. `34.201.19.115:*,localhost:*`). Preferred over disable for production. |\n| `ZSCALER_MCP_TLS_CERTFILE` | `\"\"` | Path to TLS certificate file (PEM format) for HTTPS. |\n| `ZSCALER_MCP_TLS_KEYFILE` | `\"\"` | Path to TLS private key file (PEM format) for HTTPS. |\n| `ZSCALER_MCP_TLS_KEYFILE_PASSWORD` | `\"\"` | Password for encrypted TLS private key (if applicable). |\n| `ZSCALER_MCP_TLS_CA_CERTS` | `\"\"` | Path to CA certificate bundle for mutual TLS or custom CA chains. |\n| `ZSCALER_MCP_ALLOW_HTTP` | `false` | Allow plaintext HTTP on non-localhost interfaces. HTTPS is required by default for remote deployments. Set to `true` only when TLS is terminated upstream (reverse proxy, ZPA, VPN). |\n| `ZSCALER_MCP_ALLOWED_SOURCE_IPS` | `\"\"` | Comma-separated list of allowed client IPs/CIDRs (e.g. `10.0.0.0/8,172.16.0.5`). When unset, source IP filtering is disabled (defer to firewall/security groups). Set to `0.0.0.0/0` to allow all. |\n| `ZSCALER_MCP_CONFIRMATION_TTL` | `300` | HMAC **fallback** token lifetime in seconds. Does not apply to the sealed `requestState` used by elicitation-capable clients (SDK envelope TTL, default 600s). There is no variable that skips the confirmation itself. |\n| `ZSCALER_MCP_REQUEST_STATE_KEYS` | *(unset)* | Shared key ring for the SEP-2322 `requestState`. JSON array or comma-separated; each key ≥32 bytes (`python -c \"import secrets; print(secrets.token_hex(32))\"`). **Required for multi-replica HTTP deployments with write tools enabled** — unset uses a per-process key, so a confirmation issued by one replica cannot be validated by another. First key seals, all unseal (rotate `[old,new]` → `[new,old]` → `[new]`). |\n| `ZSCALER_MCP_DISABLE_OUTPUT_SANITIZATION` | `false` | Disable defense-in-depth output sanitization (BiDi / zero-width / HTML / Markdown / code-fence stripping). Sanitization is on by default; only set this for diagnostics — disabling it removes a prompt-injection defense layer. |\n| `ZSCALER_MCP_USER_AGENT_COMMENT` | `\"\"` | Additional information to include in User-Agent comment section |\n\n#### User-Agent Header\n\nThe MCP server automatically includes a custom User-Agent header in all API requests to Zscaler services. The format is:\n\n```sh\nUser-Agent: zscaler-mcp-server/<version> python/<python_version> <os>/<architecture>\n```\n\n**Example:**\n\n```sh\nUser-Agent: zscaler-mcp-server/0.3.1 python/3.11.8 darwin/arm64\n```\n\n**With Custom Comment:**\n\nYou can append additional information (such as the AI agent details) using the `ZSCALER_MCP_USER_AGENT_COMMENT` environment variable or the `--user-agent-comment` CLI flag:\n\n```bash\n# Via environment variable\nexport ZSCALER_MCP_USER_AGENT_COMMENT=\"Claude Desktop 1.2024.10.23\"\n\n# Via CLI flag\nzscaler-mcp --user-agent-comment \"Claude Desktop 1.2024.10.23\"\n```\n\nThis results in:\n\n```sh\nUser-Agent: zscaler-mcp-server/0.3.1 python/3.11.8 darwin/arm64 Claude Desktop 1.2024.10.23\n```\n\nThe User-Agent helps Zscaler identify API traffic from the MCP server and can be useful for support, analytics, and debugging purposes.\n\n### As a Library\n\nYou can use the Zscaler Integrations MCP Server as a Python library in your own applications:\n\n```python\nfrom zscaler_mcp.server import ZscalerMCPServer\n\n# Create server with read-only mode (default - safe)\nserver = ZscalerMCPServer(\n    debug=True,  # Optional, enable debug logging\n    enabled_services={\"zia\", \"zpa\", \"zdx\"},  # Optional, defaults to all services\n    enabled_tools={\"zia_list_rule_labels\", \"zpa_list_application_segments\"},  # Optional, defaults to all tools\n    disabled_services={\"zcc\"},  # Optional, exclude entire services\n    disabled_tools={\"zcc_*\", \"zdx_list_devices\"},  # Optional, exclude tools by name or wildcard\n    user_agent_comment=\"My Custom App\",  # Optional, additional User-Agent info\n    enable_write_tools=False  # Optional, defaults to False (read-only mode)\n)\n\n# Run with stdio transport (default)\nserver.run()\n\n# Or run with SSE transport\nserver.run(\"sse\")\n\n# Or run with streamable-http transport\nserver.run(\"streamable-http\")\n\n# Or run with streamable-http transport on custom host/port\nserver.run(\"streamable-http\", host=\"0.0.0.0\", port=8080)\n```\n\n**Example with write operations enabled:**\n\n```python\nfrom zscaler_mcp.server import ZscalerMCPServer\n\n# Create server with write operations enabled\nserver = ZscalerMCPServer(\n    debug=True,\n    enabled_services={\"zia\", \"zpa\"},\n    enable_write_tools=True  # Enable create/update/delete operations\n)\n\n# Run the server\nserver.run(\"stdio\")\n```\n\n**Available Services**: `zcc`, `zdx`, `zcell`, `zia`, `zid`, `zeasm`, `zins`, `zms`, `zpa`, `ztw`\n\n**Example with Environment Variables**:\n\n```python\nfrom zscaler_mcp.server import ZscalerMCPServer\nimport os\n\n# Load from environment variables\nserver = ZscalerMCPServer(\n    debug=True,\n    enabled_services={\"zia\", \"zpa\"}\n)\n\n# Run the server\nserver.run(\"stdio\")\n```\n\n### Running Examples\n\n```bash\n# Run with stdio transport\npython examples/basic_usage.py\n\n# Run with SSE transport\npython examples/sse_usage.py\n\n# Run with streamable-http transport\npython examples/streamable_http_usage.py\n```\n\n## Container Usage\n\nThe Zscaler Integrations MCP Server is available as a pre-built container image for easy deployment:\n\n### Using Pre-built Image (Recommended)\n\n```bash\n# Pull the latest pre-built image\ndocker pull zscaler/zscaler-mcp-server:latest\n\n# Run with .env file (recommended)\ndocker run --rm --env-file /path/to/.env zscaler/zscaler-mcp-server:latest\n\n# Run with .env file and SSE transport\ndocker run --rm -p 8000:8000 --env-file /path/to/.env \\\n  zscaler/zscaler-mcp-server:latest --transport sse --host 0.0.0.0\n\n# Run with .env file and streamable-http transport\ndocker run --rm -p 8000:8000 --env-file /path/to/.env \\\n  zscaler/zscaler-mcp-server:latest --transport streamable-http --host 0.0.0.0\n\n# Run with .env file and custom port\ndocker run --rm -p 8080:8080 --env-file /path/to/.env \\\n  zscaler/zscaler-mcp-server:latest --transport streamable-http --host 0.0.0.0 --port 8080\n\n# Run with .env file and specific services\ndocker run --rm --env-file /path/to/.env \\\n  zscaler/zscaler-mcp-server:latest --services zia,zpa,zdx\n\n# Use a specific version instead of latest\ndocker run --rm --env-file /path/to/.env \\\n  zscaler/zscaler-mcp-server:1.2.3\n\n# Alternative: Individual environment variables\ndocker run --rm -e ZSCALER_CLIENT_ID=your_client_id -e ZSCALER_CLIENT_SECRET=your_secret \\\n  -e ZSCALER_CUSTOMER_ID=your_customer_id -e ZSCALER_VANITY_DOMAIN=your_vanity_domain \\\n  zscaler/zscaler-mcp-server:latest\n```\n\n### Building Locally (Development)\n\nFor development or customization purposes, you can build the image locally:\n\n```bash\n# Build the Docker image\ndocker build -t zscaler-mcp-server .\n\n# Run the locally built image\ndocker run --rm -e ZSCALER_CLIENT_ID=your_client_id -e ZSCALER_CLIENT_SECRET=your_secret \\\n  -e ZSCALER_CUSTOMER_ID=your_customer_id -e ZSCALER_VANITY_DOMAIN=your_vanity_domain zscaler-mcp-server\n```\n\n**Note**: When using HTTP transports in Docker, always set `--host 0.0.0.0` to allow external connections to the container.\n\n## Editor/Assistant Integration\n\nYou can integrate the Zscaler Integrations MCP server with your editor or AI assistant. Here are configuration examples for popular MCP clients:\n\n### Using `uvx` (recommended)\n\n```json\n{\n  \"mcpServers\": {\n    \"zscaler-mcp-server\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--env-file\", \"/absolute/path/to/.env\", \"zscaler-mcp\"]\n    }\n  }\n}\n```\n\n> **Note:** The published PyPI package is `zscaler-mcp` (not `zscaler-mcp-server`). When integrating as a Claude Code plugin, use `${CLAUDE_PLUGIN_ROOT}/.env` instead of an absolute path; for Gemini extensions, use `${extensionPath}${pathSeparator}.env`.\n\n## Additional Deployment Options\n\n### Remote MCP Deployment (EC2, VM, etc.)\n\nWhen deploying the MCP server on a **remote host** (EC2, VM, internal server) so clients connect over HTTP from another machine:\n\n**Server setup:**\n\n1. Install and configure credentials (see [Installation](#installation) and [Environment Configuration](#environment-configuration)).\n2. If using an **editable install** (`uv pip install -e .`), you **must activate the project venv** before running—otherwise an older or different installation may run:\n\n   ```bash\n   cd /path/to/zscaler-mcp-server\n   source .venv/bin/activate\n   zscaler-mcp --transport streamable-http --host 0.0.0.0 --port 8000\n   ```\n\n3. Use `--host 0.0.0.0` to bind on all interfaces. This **automatically disables Host header validation** (required when clients send the server's public IP in the Host header). For production, consider `ZSCALER_MCP_ALLOWED_HOSTS` in `.env` to restrict to known hostnames.\n4. Ensure the firewall allows inbound traffic on the chosen port (e.g. 8000).\n\n**Client configuration (Claude Desktop):**\n\nClaude Desktop expects a `command` that spawns a process. For remote HTTP, use `mcp-remote` which supports custom authentication headers.\n\n**macOS / Linux:**\n\n```json\n{\n  \"mcpServers\": {\n    \"zscaler-mcp-server\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"mcp-remote\",\n        \"http://YOUR_SERVER_IP:8000/mcp\",\n        \"--allow-http\",\n        \"--header\",\n        \"Authorization: Bearer sk-your-api-key\"\n      ]\n    }\n  }\n}\n```\n\n**Windows:**\n\nOn Windows, paths with spaces (e.g., `C:\\Program Files\\...`) cause `npx` to fail when invoked directly. Wrap the call through `cmd /c`:\n\n```json\n{\n  \"mcpServers\": {\n    \"zscaler-mcp-server\": {\n      \"command\": \"cmd\",\n      \"args\": [\n        \"/c\",\n        \"npx\",\n        \"-y\",\n        \"mcp-remote\",\n        \"http://YOUR_SERVER_IP:8000/mcp\",\n        \"--allow-http\",\n        \"--header\",\n        \"Authorization: Bearer sk-your-api-key\"\n      ]\n    }\n  }\n}\n```\n\n> **`--allow-http`**: Required when connecting to a non-localhost HTTP endpoint. `mcp-remote` enforces HTTPS by default for non-localhost URLs. Omit this flag when connecting over HTTPS or to `localhost`.\n\n**Using Zscaler auth mode (Basic Auth):**\n\nReplace the `Authorization` header with Basic Auth credentials. The value is the Base64 encoding of `client_id:client_secret`:\n\n```bash\n# Generate the Base64 value\necho -n \"your-client-id:your-client-secret\" | base64\n```\n\nThen use `\"Authorization: Basic <base64_value>\"` in place of the Bearer header above.\n\n**Prerequisites on the client:** Node.js (for `npx`) must be installed.\n\n> **📖 Full remote deployment details** (venv usage, 421 troubleshooting, security, TLS): [Remote Deployment](docs/deployment/authentication-and-deployment.md#remote-deployment-ec2-vm-etc) · [421 Misdirected Request](docs/deployment/authentication-and-deployment.md#421-misdirected-request-invalid-host-header) · [Troubleshooting](docs/guides/TROUBLESHOOTING.md#remote-mcp-421-misdirected-request)\n\n### Azure Container Apps / Virtual Machine / AKS (Preview)\n\nDeploy the Zscaler MCP Server to Azure with your choice of deployment target:\n\n| Target | Description | Runtime | Status |\n|--------|-------------|---------|--------|\n| **Container Apps** | Managed, serverless | Docker Hub image | GA |\n| **Virtual Machine** | Ubuntu 22.04, self-managed | Python library (PyPI) | GA |\n| **Azure Kubernetes Service (AKS)** | Kubernetes Deployment + LoadBalancer | Docker Hub image | **Preview** |\n\n```bash\n# Interactive guided deployment — no .env file required\ncd integrations/azure\npython azure_mcp_operations.py deploy\n\n# MCP Server management\npython azure_mcp_operations.py status     # check health\npython azure_mcp_operations.py logs       # stream logs\npython azure_mcp_operations.py ssh        # SSH into VM (VM only)\npython azure_mcp_operations.py destroy    # tear down all resources\n\n# Azure AI Foundry Agent (optional — wraps MCP server as an AI agent)\npip install azure-ai-projects azure-identity\npython azure_mcp_operations.py agent_create    # create Foundry agent\npython azure_mcp_operations.py agent_chat      # interactive CLI chat\npython azure_mcp_operations.py agent_status    # show agent info\npython azure_mcp_operations.py agent_destroy   # delete agent\n```\n\nThe script will prompt you for:\n\n- **Deployment target**: Container Apps, Virtual Machine, or Azure Kubernetes Service (Preview)\n- **Credential source**: `.env` file path or manual entry\n- **Auth mode**: OIDC (OAuth 2.1), JWT, API Key, Zscaler, or None (OIDC not yet supported on AKS)\n- **Azure options**: resource group, region, Key Vault (new or existing); for AKS: cluster lifecycle (create new or use existing), node count/size, namespace\n\nContainer Apps and VM store all secrets in Azure Key Vault (mandatory) and auto-configure Claude Desktop / Cursor. **AKS Preview** injects credentials as Kubernetes environment variables on the Deployment — Workload Identity Federation + Key Vault CSI driver integration is planned.\n\n**Foundry Agent**: Optionally create an Azure-hosted AI agent that wraps the MCP server. The agent is accessible via CLI chat (with spinner, token tracking, and timing), the [Azure AI Foundry portal](https://ai.azure.com) playground, REST APIs, or Microsoft 365 Copilot integrations.\n\n> **📖 Full Azure deployment guide**: [integrations/azure/README.md](integrations/azure/README.md)\n\n### Google Cloud (Cloud Run / GKE / VM / ADK Agent)\n\nGoogle Cloud deployments cover both the standalone MCP Server and the Gemini-powered ADK Agent. A complete video walkthrough is available here:\n\n**[Zscaler Integration MCP Server in GCP — Video Demo](https://zscaler.wistia.com/medias/13jxjizk3r)**\n\nTwo interactive Python scripts manage all five Google Cloud deployment targets:\n\n| Script | Deployment Targets |\n|--------|-------------------|\n| `integrations/google/gcp/gcp_mcp_operations.py` | Cloud Run, GKE, Compute Engine VM (standalone MCP server) |\n| `integrations/google/adk/adk_agent_operations.py` | Local, Cloud Run, Vertex AI Agent Engine, Agentspace (ADK agent) |\n\n**Standalone MCP Server — Automated Deployment:**\n\n```bash\ncd integrations/google/gcp\npython gcp_mcp_operations.py deploy      # guided deployment (prompts for target)\npython gcp_mcp_operations.py status      # check health\npython gcp_mcp_operations.py logs        # stream logs\npython gcp_mcp_operations.py ssh         # SSH into VM (VM target only)\npython gcp_mcp_operations.py destroy     # tear down\n```\n\nThe script prompts for deployment target, credentials, and auth mode. It:\n\n- Prompts for GCP project/region (or reads from `.env`)\n- Optionally stores credentials in GCP Secret Manager\n- Deploys the container to Cloud Run with `zscaler` authentication mode\n- Generates `Authorization: Basic` headers from your Zscaler OneAPI credentials\n- Auto-configures Claude Desktop (`claude_desktop_config.json`) and Cursor (`~/.cursor/mcp.json`)\n- Writes a deployment state file (`.gcp-deploy-state.json`) for subsequent `status` / `logs` / `destroy` operations\n\n**ADK Agent — Interactive Deployment:**\n\n```bash\ncd integrations/google/adk\npython adk_agent_operations.py deploy      # gui",
  "bytes": 60000,
  "sha": "3aa40144e4ba5a733d8d1120d0534839d55f61bffd3e0ac0c5bcee18d51072d6",
  "repo_slug": "zscaler/zscaler-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_zscaler_zscaler_mcp_server_zscaler_624ec88f/readme"
}