# What Is ziti-mcp-server? OpenZiti's Full Management API for AI Agents

AI agents are getting tool access to infrastructure faster than most security teams have thought through what that means. If you run OpenZiti, you now have a specific, well-scoped answer to "how should an AI agent interact with my network": **ziti-mcp-server** wraps the full Ziti Management API, 209 tools, and exposes it to any MCP-compatible client. Claude Desktop, Cursor, Windsurf, or anything else that speaks Model Context Protocol.

> **What is OpenZiti?** OpenZiti is an open-source, zero-trust networking platform that embeds security directly into application connectivity. It replaces traditional VPNs and network perimeters with identity-aware, policy-driven service access — no open ports, no implicit trust. ziti-mcp-server is built on top of it, which means the agent's access to your management plane is governed by the same primitives you use for everything else in your network. It's developed by [**NetFoundry**](https://netfoundry.io/),

**TL;DR**

*   ziti-mcp-server is an MCP server exposing 201 Ziti Management API tools plus 8 session meta-tools, full coverage of identities, services, routers, policies, configs, and fabric operations

*   Runs as a local process between your MCP client and your Ziti controller; credentials never leave your machine

*   For quick evaluation, UPDB (username/password) is the fastest path; for production, create a Ziti identity, enroll it, and authenticate using the identity file, the agent becomes a real Ziti identity subject to your access policies

*   Tested with OpenZiti v1.6+; requires Go 1.24+ if building from source

*   One gotcha: after any configuration change, restart your MCP client, ziti-mcp-server does not hot-reload


## What Is ziti-mcp-server?

ziti-mcp-server is a [Model Context Protocol](https://modelcontextprotocol.io) server that gives AI agents direct access to the Ziti Management API. It runs as a local process between your MCP client (Claude Desktop, Cursor, Windsurf) and your Ziti controller, exposing 209 tools: 201 wrapping the full REST management API and 8 for session lifecycle. Nothing is stubbed out or simplified — the tool surface is generated directly from the Ziti OpenAPI spec.

That 209-tool surface covers identities, services, edge routers, service policies, edge router policies, configurations, config types, authenticators, CAs, posture checks, and the fabric layer including terminators, circuits, and cluster operations.

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#1e293b', 'primaryTextColor': '#e2e8f0', 'primaryBorderColor': '#3b82f6', 'lineColor': '#64748b', 'background': '#0f172a', 'mainBkg': '#1e293b', 'edgeLabelBackground': '#1e293b'}}}%%
flowchart LR
  classDef client fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd,stroke-width:2px
  classDef server fill:#1e293b,stroke:#0ea5e9,color:#7dd3fc,stroke-width:2px
  classDef ctrl fill:#1a1f2e,stroke:#6366f1,color:#a5b4fc,stroke-width:2px

  MCP["🤖 MCP Client\n(Claude Desktop · Cursor · Windsurf)"]:::client
  ZMS["⚙️ ziti-mcp-server\n(local process)"]:::server
  Ctrl[("🔑 Ziti Controller\nManagement API")]:::ctrl

  MCP -->|"tool calls via stdio"| ZMS
  ZMS -->|"REST + mTLS"| Ctrl
```

*ziti-mcp-server runs locally and proxies MCP tool calls to the Ziti controller's management API. Credentials stay on your machine.*

## What Can You Actually Ask It?

Once connected, your MCP client can answer operational questions and execute management operations through natural language. The agent translates your request into one or more Ziti API calls and returns the result. Multi-step operations happen in a single conversational request, with no scripting required.

Some examples that work well:

*   *"Which identities have access to the payments-api service?"*, runs `listServiceIdentities` and formats the result

*   *"Show me a network summary: total identities, services, and edge routers"*, combines `listIdentities`, `listServices`, and `listEdgeRouters` with count aggregation

*   *"Create a new identity called ci-runner and return the enrollment JWT"*, runs `createIdentity` then `createEnrollment`

*   *"List all edge routers and flag any that haven't connected in the last 24 hours"*, uses `listEdgeRouters` with status filtering

*   *"What version is the controller running?"*, calls `getVersion`


The agent handles multi-step operations naturally. Asking "create an identity, generate an enrollment JWT, and give me the one-time token" produces three sequential API calls without you scripting any of it.

## How Do You Get Running in 5 Minutes?

Pre-built binaries are available for macOS (Intel and ARM), Linux (amd64/arm64), and Windows. On macOS Apple Silicon:

```bash
curl -sL https://github.com/openziti/ziti-mcp-server/releases/latest/download/ziti-mcp-server_darwin_arm64.tar.gz | tar xz
sudo mv ziti-mcp-server /usr/local/bin/
```

Or build from source with Go 1.24+:

```bash
go install github.com/openziti/ziti-mcp-server/cmd/ziti-mcp-server@latest
```

Register with Claude Desktop, this writes the server entry into Claude's config file, nothing more:

```bash
ziti-mcp-server install
```

For Cursor or Windsurf:

```bash
ziti-mcp-server install --client cursor
ziti-mcp-server install --client windsurf
```

**Now restart your MCP client.** This is the step people miss. Config changes don't hot-reload, the client needs a full restart before it picks up the new server registration.

Once Claude Desktop is back up, you'll see the Ziti tools available. Authenticate at runtime using the `loginUpdb` tool, pass your controller host, username, and password when Claude asks. That's enough to start exploring.

## What Authentication Mode Should You Use?

The right answer depends on your use case. ziti-mcp-server supports four modes:

| Mode | How it works | Use it when |
| --- | --- | --- |
| **UPDB** | Username + password at runtime | Evaluating, dev environments |
| **Device auth** | Browser-based OAuth2 flow | Interactive sessions with SSO |
| **Client credentials** | OAuth2 client ID + secret | Automated pipelines, CI |
| **Identity file** | Enrolled Ziti identity JSON | Production, recommended |

For anything beyond kicking the tires, the identity file approach is the right model. Create a Ziti identity for the agent, enroll it, and configure ziti-mcp-server to authenticate using the resulting `identity.json`. Pre-configure it so no credentials are passed at runtime:

```bash
# Create the identity in your Ziti network
ziti edge create identity mcp-agent --role-attributes mcp-agents -o mcp-agent.jwt

# Enroll it to produce the identity file
ziti edge enroll mcp-agent.jwt -o mcp-agent.json

# Pre-configure ziti-mcp-server to use it
ziti-mcp-server init \
  --auth-mode identity \
  --ziti-controller-host your-controller.example.com \
  --identity-file ./mcp-agent.json \
  --profile prod
```

The reason this matters: the agent now has a real Ziti identity. You can scope its access using role attributes and service policies exactly as you would for any other identity in your network. Want the agent to be read-only against production but fully operational against staging? That's a policy decision, not a server configuration. The [no listening ports model](https://blog.openziti.io/no-listening-ports) OpenZiti applies to application traffic applies equally well to management plane access, and as of OpenZiti v1.8, the [controller APIs can themselves be OpenZiti services](https://blog.openziti.io/openziti-drinks-its-own-champagne), making this pattern even tighter.

## How Do You Restrict What the Agent Can Do?

Two mechanisms: the `--read-only` flag and `--tools` glob filtering.

`--read-only` strips all mutating tools at startup. The agent can query and inspect but cannot create, update, delete, or enroll anything:

```bash
ziti-mcp-server run --read-only
```

`--tools` lets you filter by tool name patterns:

```bash
# Identity operations only
ziti-mcp-server run --tools '*Identity*'

# All list and get operations
ziti-mcp-server run --tools 'list*,get*'

# Combine: read-only identity tools only
ziti-mcp-server run --tools '*Identity*' --read-only
```

Multi-profile support lets you configure separate credentials and restrictions per network. A `--profile prod` can run read-only while `--profile staging` has full access. Switch between them at runtime using the `selectNetwork` tool without restarting the server.

## Frequently Asked Questions About ziti-mcp-server

### Does the LLM see my credentials?

No. Credentials are stored in `~/.config/ziti-mcp-server/config.json` with `0600` permissions, readable only by your user. The LLM sees tool names and results, not the underlying auth tokens or identity file contents. When using UPDB at runtime, you pass credentials through the tool call, but they're handled by the local process and never included in the response the model receives.

### Which MCP clients does it support?

Claude Desktop, Cursor, and Windsurf have first-class `install` support. For any other MCP-compatible client, add the server manually to the client's config:

```json
{
  "mcpServers": {
    "ziti": {
      "command": "/usr/local/bin/ziti-mcp-server",
      "args": ["run"]
    }
  }
}
```

Then restart the client.

### What OpenZiti version does it require?

ziti-mcp-server has been tested with OpenZiti v1.6 and later. The tool surface is generated from the Ziti OpenAPI spec, so older controllers may not support all 201 API tools, earlier API versions will return errors on unsupported operations rather than silently failing.

### Is it production-ready?

The server is stable and the tool coverage is complete, but treat it as you would any agent with management plane access: scope its identity tightly, run `--read-only` against production where possible, and use role-attribute-based service policies to limit what the identity can reach. The security model is sound precisely because it uses OpenZiti's own access control primitives rather than inventing new ones.

### Can I manage multiple Ziti networks from one session?

Yes. Configure separate profiles with `ziti-mcp-server init --profile <name>` for each network. Use the `listNetworks` tool to see all configured profiles and their connection status, and `selectNetwork` to switch the active profile at runtime.

* * *

ziti-mcp-server is available now at [github.com/openziti/ziti-mcp-server](https://github.com/openziti/ziti-mcp-server) under Apache 2.0.

File issues, contribute tooling improvements, or drop into the [OpenZiti community Discourse](https://openziti.discourse.group) if you run into anything unexpected.

If you like OpenZiti, it's always very much appreciated if you take a moment to [drop us a star](https://github.com/openziti/ziti). We see and appreciate every repository star.

