Skip to main content
plugin

zscaler — Claude Code plugin: what it does, how to install

Connects AI agents to the Zscaler Zero Trust Exchange platform to inspect policies, audit configurations, and monitor ZPA, ZIA, or ZDX services.

Install into Claude Code · Plugin marketplace All methods and platforms ↓
/plugin install zscaler@claude-plugins-official
/plugin marketplace add anthropics/claude-plugins-community
/plugin install zscaler@claude-community
/plugin marketplace add anthropics/claude-plugins-official
Open on GitHub

What zscaler does

This integration exposes Zscaler cloud security services to Claude Code using MCP. It packages 402 tools covering ZPA, ZIA, ZDX, ZCC, EASM, and Z-Insights. The agent can retrieve application segments, inspect firewall rules, and review connectivity settings directly inside the workspace.

Safety controls are active from the start: the server defaults to a read-only state with over 110 retrieval actions. Any operation that creates, updates, or deletes configuration entries is blocked until you explicitly supply the --enable-write-tools flag or set ZSCALER_MCP_WRITE_ENABLED=true.

The repository is currently in public preview, meaning features can shift before a stable 1.0 release. Naming the exact target service in your request (such as zpa or zia) keeps the agent from triggering the wrong retrieval tool.

What it helps with

  • retrieve ZPA application segments and segment groups
  • inspect ZIA firewall rules and rule labels
  • audit security configurations across Zscaler services
  • investigate connectivity issues within the Zero Trust ecosystem

Example prompts for the agent

  • List my ZPA application segments
  • Show ZIA firewall rules
  • Check ZPA segment groups

How to install zscaler

Plugin marketplace

/plugin install zscaler@claude-plugins-official
/plugin marketplace add anthropics/claude-plugins-community
/plugin install zscaler@claude-community
/plugin marketplace add anthropics/claude-plugins-official

Step by step, with commands for each platform: Claude Code plugins: marketplaces, installing, and building your own

Questions about zscaler

How do I install zscaler in Claude Code?

Register the marketplace first using /plugin marketplace add anthropics/claude-plugins-official. After that, install the package by running /plugin install zscaler@claude-plugins-official.

What does the zscaler plugin do?

It interfaces Claude Code with the Zscaler Zero Trust Exchange platform. It provides tools to query and manage components like ZPA, ZIA, and ZDX.

Can the plugin modify Zscaler resources?

Not in its default setup. The server restricts execution to read-only tools unless you pass --enable-write-tools or set ZSCALER_MCP_WRITE_ENABLED=true.

Source text

SKILL.md · MIT
![Zscaler MCP](https://raw.githubusercontent.com/zscaler/zscaler-mcp-server/master/docs/media/zscaler.svg)

[![PyPI version](https://badge.fury.io/py/zscaler-mcp.svg)](https://badge.fury.io/py/zscaler-mcp)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/zscaler-mcp)](https://pypi.org/project/zscaler-mcp/)
[![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](hhttps://zscaler-mcp-server.readthedocs.io/en/latest/integrations/index.html)
[![codecov](https://codecov.io/gh/zscaler/zscaler-mcp-server/graph/badge.svg?token=9HwNcw4Q4h)](https://codecov.io/gh/zscaler/zscaler-mcp-server)
[![GitHub commit activity](https://img.shields.io/badge/commit-activity-blue)](https://github.com/zscaler/zscaler-mcp-server/graphs/commit-activity)
[![License](https://img.shields.io/github/license/zscaler/zscaler-mcp-server.svg)](https://github.com/zscaler/zscaler-mcp-server)
[![Automation Hub](https://img.shields.io/badge/automation-hub-blue)](https://automate.zscaler.com/docs/tools/sdk-documentation/sdk-getting-started)
[![Zscaler Community](https://img.shields.io/badge/zscaler-community-blue)](https://community.zscaler.com/)

**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.

## Support Disclaimer

-> **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.

> [!IMPORTANT]
> **🚧 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.

## 📄 Table of contents

- [📺 Overview](#overview)
- [🔒 Security & Permissions](#security-permissions)
- [🔐 MCP Client Authentication](#mcp-client-authentication)
- [Supported Tools](#supported-tools)
- [Installation & Setup](#installation--setup)
  - [Prerequisites](#prerequisites)
  - [Environment Configuration](#environment-configuration)
  - [Installation](#installation)
- [Usage](#usage)
  - [Command Line](#command-line)
  - [Service Configuration](#service-configuration)
  - [Additional Command Line Options](#additional-command-line-options)
- [Zscaler API Credentials & Authentication](#zscaler-api-credentials-authentication)
  - [OneAPI Authentication](#oneapi-authentication)
  - [Authentication Troubleshooting](#authentication-troubleshooting)
  - [MCP Server Configuration](#mcp-server-configuration)
- [As a Library](#as-a-library)
- [Container Usage](#container-usage)
  - [Using Pre-built Image (Recommended)](#using-pre-built-image-recommended)
  - [Building Locally (Development)](#building-locally-development)
- [Editor/Assistant Integration](#editor-assistant-integration)
  - [Using `uvx` (recommended)](#using-uvx-recommended)
  - [With Service Selection](#with-service-selection)
  - [Using Individual Environment Variables](#using-individual-environment-variables)
  - [Docker Version](#docker-version)
- [Additional Deployment Options](#additional-deployment-options)
  - [Remote MCP Deployment (EC2, VM, etc.)](#remote-mcp-deployment-ec2-vm-etc)
  - [Azure Container Apps / Virtual Machine / AKS (Preview)](#azure-container-apps--virtual-machine--aks-preview)
  - [Google Cloud (Cloud Run / GKE / VM / ADK Agent)](#google-cloud-cloud-run--gke--vm--adk-agent)
  - [Kubernetes (Helm Chart)](#kubernetes-helm-chart)
  - [Amazon Bedrock AgentCore](#amazon-bedrock-agentcore)
- [Using the MCP Server with Agents](#using-the-mcp-server-with-agents)
  - [Claude Desktop](#claude-desktop)
  - [Cursor](#cursor)
  - [Visual Studio Code + GitHub Copilot](#visual-studio-code-github-copilot)
- [Platform Integrations](#platform-integrations)
- [Troubleshooting](#troubleshooting)
- [License](#license)

## 📺 Overview

The Zscaler Integrations MCP Server brings context to your agents. Try prompts like:

- "List my ZPA Application segments"
- "List my ZPA Segment Groups"
- "List my ZIA Rule Labels"

> [!WARNING]
> **🔒 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.

<!-- markdownlint-disable MD028 -->

> [!TIP]
> **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:
>
> - **Good**: *"List my ZPA application segments"* — targets the right service and tool directly
> - **Good**: *"Show ZIA firewall rules"* — clear service (`zia`) and action (`list`)
> - **Less effective**: *"Show me my devices"* — ambiguous; multiple services expose device-related tools
>
> 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`).

## 🔒 Security & Permissions

The Zscaler MCP Server implements a **security-first design** with granular permission controls and safe defaults:

### Read-Only Mode (Default - Always Available)

By default, the server operates in **read-only mode**, exposing only tools that list or retrieve information:

- ✅ **ALWAYS AVAILABLE** - Read-only tools are registered by the server
- ✅ Safe to use with AI agents autonomously
- ✅ No risk of accidental resource modification or deletion
- ✅ All `list_*` and `get_*` operations are available (110+ read-only tools)
- ❌ All `create_*`, `update_*`, and `delete_*` operations are disabled by default
- 💡 Note: You may need to enable read-only tools in your AI agent's UI settings

```bash
# Read-only mode (default - safe)
zscaler-mcp
```

When the server starts in read-only mode, you'll see:

```text
🔒 Server running in READ-ONLY mode (safe default)
   Only list and get operations are available
   To enable write operations, use --enable-write-tools AND --write-tools flags
```

> **💡 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.

### Write Mode (Explicit Opt-In - Allowlist REQUIRED)

To enable tools that can create, modify, or delete Zscaler resources, you must provide **BOTH** flags:

1. ✅ `--enable-write-tools` - Global unlock for write operations
2. ✅ `--write-tools "pattern"` - **MANDATORY** explicit allowlist

> **🔐 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.

```bash
# ❌ WRONG: This will NOT enable any write tools (allowlist missing)
zscaler-mcp --enable-write-tools

# ✅ CORRECT: Explicit allowlist required
zscaler-mcp --enable-write-tools --write-tools "zpa_create_*,zpa_delete_*"
```

When you try to enable write mode without an allowlist:

```text
⚠️  WRITE TOOLS MODE ENABLED
⚠️  NO allowlist provided - 0 write tools will be registered
⚠️  Read-only tools will still be available
⚠️  To enable write operations, add: --write-tools 'pattern'
```

#### Write Tools Allowlist (MANDATORY)

The allowlist provides **two-tier security**:

1. ✅ **First Gate**: `--enable-write-tools` must be set (global unlock)
2. ✅ **Second Gate**: Explicit allowlist determines which write tools are registered (MANDATORY)

**Allowlist Examples:**

```bash
# Enable ONLY specific write tools with wildcards
zscaler-mcp --enable-write-tools --write-tools "zpa_create_*,zpa_delete_*"

# Enable specific tools without wildcards
zscaler-mcp --enable-write-tools --write-tools "zpa_create_application_segment,zia_create_rule_label"

# Enable all ZPA write operations (but no ZIA/ZDX/ZTW)
zscaler-mcp --enable-write-tools --write-tools "zpa_*"
```

Or via environment variable:

```bash
export ZSCALER_MCP_WRITE_ENABLED=true
export ZSCALER_MCP_WRITE_TOOLS="zpa_create_*,zpa_delete_*"
zscaler-mcp
```

**Wildcard patterns supported:**

- `zpa_create_*` - Allow all ZPA creation tools
- `zpa_delete_*` - Allow all ZPA deletion tools
- `zpa_*` - Allow all ZPA write tools
- `*_application_segment` - Allow all operations on application segments
- `zpa_create_application_segment` - Exact match (no wildcard)

When using a valid allowlist, you'll see:

```text
⚠️  WRITE TOOLS MODE ENABLED
⚠️  Explicit allowlist provided - only listed write tools will be registered
⚠️  Allowed patterns: zpa_create_*, zpa_delete_*
⚠️  Server can CREATE, MODIFY, and DELETE Zscaler resources
🔒 Security: 85 write tools blocked by allowlist, 8 allowed
```

### Tool Design Philosophy

Each operation is a **separate, single-purpose tool** with explicit naming that makes its intent clear:

#### ✅ Good (Verb-Based - Current Design)

```text
zpa_list_application_segments    ← Read-only, safe to allow-list
zpa_get_application_segment      ← Read-only, safe to allow-list
zpa_create_application_segment   ← Write operation, requires --enable-write-tools
zpa_update_application_segment   ← Write operation, requires --enable-write-tools
zpa_delete_application_segment   ← Destructive, requires --enable-write-tools
```

This design allows AI assistants (Claude, Cursor, GitHub Copilot) to:

- Allow-list read-only tools for autonomous exploration
- Require explicit user confirmation for write operations
- Clearly understand the intent of each tool from its name

#### Responses: the API record, verbatim

A read tool returns the Zscaler API record **unchanged**. The server does not
trim, rename, or re-declare a resource's attributes — that attribute set belongs
to the API, so a field Zscaler adds in future reaches you with no server upgrade.

To keep responses small, you control what comes back rather than the server
guessing. Two levers:

- **`--toolsets`** — load only the slice of tools you need, so the tool catalog
  stays small (see [Toolsets](#toolsets)).
- **`query`** — every list tool accepts an optional [JMESPath](https://jmespath.org/)
  expression applied to the results, so the agent projects exactly what it wants:

  ```text
  zcc_list_devices(query="[*].{user: user, policy: policyName}")   # just those two fields
  zcc_list_devices(query="[?registrationState=='Quarantined']")    # just quarantined devices
  zcc_list_devices(query="length(@)")                              # just the count
  ```

  Field names are exactly what the Zscaler API returns. Omit `query` to get the
  full records.

### Security Layers

The 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.

1. **Read-Only Tools Always Enabled**: Safe `list_*` and `get_*` operations are always available (254 tools).
2. **Default Write Mode Disabled**: Write tools are disabled unless explicitly enabled via `--enable-write-tools`.
3. **Mandatory Allowlist**: Write operations require explicit `--write-tools` allowlist (wildcard support).
4. **OneAPI Entitlement Filter**: At startup, toolsets for products the OneAPI credentials cannot call are silently dropped (see [OneAPI Entitlement Filter](#oneapi-entitlement-filter) below).
5. **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.
6. **Verb-Based Tool Naming**: Each tool clearly indicates its purpose (`list`, `get`, `create`, `update`, `delete`).
7. **Tool Metadata Annotations**: All tools are annotated with `readOnlyHint` or `destructiveHint` for AI agent frameworks.
8. **AI Agent Confirmation**: All write tools marked with `destructiveHint=True` trigger permission dialogs in AI assistants.
9. **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.
10. **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.
11. **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).
12. **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.

This 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`.

### Toolsets

Tools 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.

```bash
# Load just two slices
zscaler-mcp --toolsets zia_url_filtering,zpa_app_segments

# Or use the curated default-on subset
zscaler-mcp --toolsets default

# Or load every registered toolset explicitly
zscaler-mcp --toolsets all

# Equivalent via environment variable
export ZSCALER_MCP_TOOLSETS="zia_url_filtering,zpa_app_segments"
```

When `--toolsets` is unspecified, every toolset whose service is enabled is loaded (preserves the historical default).

The agent can also enable additional toolsets at runtime through the always-on `zscaler_list_toolsets`, `zscaler_get_toolset_tools`, and `zscaler_enable_toolset` tools.

For 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).

### OneAPI Entitlement Filter

After 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`.

This prevents an agent from discovering tools whose first call would only ever return `401 Unauthorized`. The filter applies on every transport, including `stdio`.

When the filter runs you'll see one log line at startup, for example:

```text
entitlement filter applied: entitled services=['zia', 'zpa'], kept 12 toolset(s), removed 17 toolset(s)
```

The 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.

To bypass the filter (for example, while diagnosing an unusual token shape):

```bash
zscaler-mcp --no-entitlement-filter
# or
export ZSCALER_MCP_DISABLE_ENTITLEMENT_FILTER=true
```

Only **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.

### Cryptographic Confirmation for Destructive Actions

Delete operations are never executed on the first call. What happens instead depends on the client:

- **Clients that support MCP elicitation** get an interactive prompt naming the resource, answered by a **human**. The AI agent never handles the approval.
- **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.

**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)).

### Network-Level Controls (HTTP only)

The 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`.

The 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.

#### HTTPS/TLS Support

**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`.

When running with HTTP transports (`sse` or `streamable-http`), provide TLS certificates:

```env
ZSCALER_MCP_TLS_CERTFILE=/path/to/cert.pem
ZSCALER_MCP_TLS_KEYFILE=/path/to/key.pem

# Optional: private key password and CA bundle
ZSCALER_MCP_TLS_KEYFILE_PASSWORD=your-key-password
ZSCALER_MCP_TLS_CA_CERTS=/path/to/ca-bundle.pem
```

When 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:

```bash
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes \
  -subj "/CN=localhost"
```

#### Source IP Access Control

You 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.).

```env
# Allow only specific IPs/subnets
ZSCALER_MCP_ALLOWED_SOURCE_IPS=10.0.0.0/8,172.16.0.5

# Allow all (effectively disable — same as not setting the variable)
ZSCALER_MCP_ALLOWED_SOURCE_IPS=0.0.0.0/0
```

Supports 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`.

#### .env File Security Warning

When 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.

### Security Posture Banner

On 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.

**Key Security Principles**:

- No "enable all write tools" backdoor exists - allowlist is **mandatory**
- AI agents must request permission before executing any write operation (`destructiveHint`)
- Every destructive action requires explicit user approval through the AI agent's permission framework
- Destructive confirmations are cryptographically bound to prevent prompt injection bypass

### Best Practices

- **Read-Only by Default**: No configuration needed for safe operations - read-only tools are always available
- **Mandatory Allowlist**: Always provide explicit `--write-tools` allowlist when enabling write mode
- **Development/Testing**: Use narrow allowlists (e.g., `--write-tools "zpa_create_application_segment"`)
- **Production/Agents**: Keep server in read-only mode (default) for AI agents performing autonomous operations
- **CI/CD**: Never set `ZSCALER_MCP_WRITE_ENABLED=true` without a corresponding `ZSCALER_MCP_WRITE_TOOLS` allowlist
- **Least Privilege**: Use narrowest possible allowlist patterns for your use case
- **Wildcard Usage**: Use wildcards for service-level control (e.g., `zpa_create_*`) or operation-level control (e.g., `*_create_*`)
- **Audit Review**: Regularly review which write tools are allowlisted and remove unnecessary ones
- **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

## 🔐 MCP Client Authentication

> **📖 Full Documentation: [Authentication & Deployment Guide](docs/deployment/authentication-and-deployment.md)**

When 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.

For 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).

### Authentication Modes

The server supports four authentication modes, configured via environment variables:

| Mode | Description | Best For |
|------|-------------|----------|
| **`api-key`** | Simple shared secret — client sends `Authorization: Bearer <key>` | Quick setup, internal environments, development |
| **`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) |
| **`zscaler`** | Zscaler OneAPI credential validation — client sends Basic Auth with `client_id:client_secret` | Environments already using Zscaler API credentials |
| **`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 |

### Quick Start

Enable authentication by setting these environment variables in your `.env` file:

```env
# Enable authentication
ZSCALER_MCP_AUTH_ENABLED=true
ZSCALER_MCP_AUTH_MODE=api-key

# For api-key mode: set a shared secret
ZSCALER_MCP_AUTH_API_KEY=sk-your-secret-key-here
```

Then start the server with an HTTP transport:

```bash
zscaler-mcp --transport streamable-http
```

Clients must include the key in the `Authorization` header:

```text
Authorization: Bearer sk-your-secret-key-here
```

### How It Works

Authentication is implemented as ASGI middleware that wraps the HTTP transport layer:

```text
MCP Client Request
      │
      ▼
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  Auth         │────▶│  MCP          │────▶│  Zscaler     │
│  Middleware   │     │  Server       │     │  APIs        │
└──────────────┘     └──────────────┘     └──────────────┘
 Layer 1: WHO          MCP Protocol        Layer 2: HOW
 can connect?          Processing          server talks
                                           to Zscaler
```

- **Layer 1 (MCP Client Auth)**: Controlled by `ZSCALER_MCP_AUTH_*` variables — validates the incoming request
- **Layer 2 (Zscaler API Auth)**: Controlled by `ZSCALER_CLIENT_ID`, `ZSCALER_CLIENT_SECRET`, etc. — authenticates the server to Zscaler APIs

These two layers are completely independent. You can enable one, both, or neither.

### Configuration by Mode

#### API Key

```env
ZSCALER_MCP_AUTH_ENABLED=true
ZSCALER_MCP_AUTH_MODE=api-key
ZSCALER_MCP_AUTH_API_KEY=sk-your-secret-key-here
```

#### JWT (External IdP via JWKS)

```env
ZSCALER_MCP_AUTH_ENABLED=true
ZSCALER_MCP_AUTH_MODE=jwt
ZSCALER_MCP_AUTH_JWKS_URI=https://your-idp.com/.well-known/jwks.json
ZSCALER_MCP_AUTH_ISSUER=https://your-idp.com
ZSCALER_MCP_AUTH_AUDIENCE=zscaler-mcp-server
ZSCALER_MCP_AUTH_ALGORITHMS=RS256,ES256   # Optional (default: RS256,ES256)
```

#### Zscaler OneAPI Credentials

```env
ZSCALER_MCP_AUTH_ENABLED=true
ZSCALER_MCP_AUTH_MODE=zscaler
# Uses ZSCALER_VANITY_DOMAIN and ZSCALER_CLOUD from your existing config
```

Clients authenticate with Basic Auth (`client_id:client_secret`) or custom headers (`X-Zscaler-Client-ID` / `X-Zscaler-Client-Secret`).

### Authentication Defaults

For 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.

To explicitly disable authentication, set:

```env
ZSCALER_MCP_AUTH_ENABLED=false
```

Authentication does not apply to `stdio` transport (process isolation provides security).

### OAuth 2.1 (`oidc` mode)

`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.

It is configured entirely through environment variables — no code, no extra packages:

```env
ZSCALER_MCP_AUTH_ENABLED=true
ZSCALER_MCP_AUTH_MODE=oidc

OIDCPROXY_CONFIG_URL=https://your-tenant.auth0.com/.well-known/openid-configuration
OIDCPROXY_CLIENT_ID=<your app registration's client id>
OIDCPROXY_BASE_URL=http://localhost:8000
OIDCPROXY_AUDIENCE=zscaler-mcp-server
# Optional: scopes a token must carry, comma-separated
# OIDCPROXY_REQUIRED_SCOPES=zscaler.read
```

Notes:

- **No client secret.** Verifying a signature needs the IdP's public keys, not a credential of ours. `OIDCPROXY_CLIENT_SECRET` is ignored if set.
- `OIDCPROXY_BASE_URL` is **this server's** public URL, which clients use as the resource identifier — not the IdP's.
- `OIDCPROXY_AUDIENCE` defaults to `OIDCPROXY_CLIENT_ID`. Entra ID puts the client ID in `aud`; Auth0 uses the API identifier.
- 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.
- The server serves no `/authorize`, `/token` or `/register` — clients need a client ID issued by the IdP and cannot self-register.
- Works with any OIDC-compliant provider (Auth0, Okta, Microsoft Entra ID, Keycloak, Google, AWS Cognito, PingOne).
- All other security layers (TLS, source-IP ACL, host validation) remain active.

**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...

© Zscaler · MIT · zscaler/zscaler-mcp-server

Similar plugins

All plugins for Security →

From the same set2

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor