Skip to main content
Glama

UniFi MCP Server

MCP server providing Claude Code with full UniFi network management capabilities -- devices, clients, ports, bandwidth auditing, firewall policies, and traffic rules -- all through natural language.

License: MIT GitHub release MCP Tools TypeScript Node.js UniFi


Overview

The UniFi MCP Server connects Claude Code to one or more UniFi network controllers via the UDM REST API. It exposes 19 tools that let you query, audit, and configure your network infrastructure conversationally.

Key capabilities:

  • Self-healing authentication -- automatic re-auth on expiry or 401, with proactive refresh and mutex protection against concurrent auth storms

  • Automated TOTP -- generates MFA codes from a stored seed, no manual authenticator app interaction

  • 19 management tools covering devices, clients, ports, port profiles, networks, bandwidth auditing, traffic routes, and firewall policies

  • Encrypted session persistence using AES-256-GCM

  • Resilient API client with 429 throttle handling, 5xx exponential backoff, and 401 transparent re-auth

  • Dual-controller support -- cloud-hosted controllers (two-step MFA) and UDM Pro Max (single-step MFA)

Architecture

graph LR
    CC[Claude Code] <-->|stdio| MCP[MCP Server<br/>StdioServerTransport]
    MCP --> Tools[19 Tools<br/>Zod-validated inputs]
    Tools --> UC[UniFi Client<br/>Axios + retry interceptors]
    UC --> SM[Session Manager<br/>Self-healing auth]
    SM --> SC[Session Cache<br/>AES-256-GCM]
    SM --> TOTP[TOTP Generator<br/>RFC 6238]
    UC -->|HTTPS| API[UniFi Controller<br/>REST API]

    style CC fill:#4A90D9,color:#fff
    style MCP fill:#6C5CE7,color:#fff
    style Tools fill:#00B894,color:#fff
    style UC fill:#FDCB6E,color:#000
    style SM fill:#E17055,color:#fff
    style API fill:#2D3436,color:#fff

Features

Self-Healing Authentication

The server never requires manual re-authentication during operation. The session manager implements a multi-layered strategy:

Layer

Trigger

Behavior

Proactive refresh

Session < 15 min remaining

Fire-and-forget re-auth in the background; current request uses existing session

Expired session

Session TTL = 0

Blocking re-auth before the request proceeds

401 retry

Controller returns HTTP 401

Interceptor triggers re-auth, then transparently retries the original request

Mutex protection

Concurrent requests during auth

All callers await the same in-flight auth promise (no auth storms)

Failure circuit breaker

3 consecutive auth failures

Auth disabled until server restart (prevents credential lockout)

Two-Step MFA with Automated TOTP

Cloud-hosted UniFi controllers require two-step MFA:

sequenceDiagram
    participant S as MCP Server
    participant C as UniFi Controller
    participant T as TOTP Generator

    S->>C: POST /api/auth/login {username, password}
    C-->>S: 200 MFA_AUTH_REQUIRED + UBIC_2FA cookie
    S->>T: Generate TOTP from base32 seed
    T-->>S: 6-digit code
    S->>C: POST /api/auth/login {username, password, token}<br/>Cookie: UBIC_2FA=...
    C-->>S: 200 + Set-Cookie: TOKEN=jwt...
    S->>S: Parse JWT for CSRF token + expiry
    S->>S: Encrypt and persist session to disk

For UDM Pro Max controllers, authentication completes in a single step (username + password + TOTP in one request).

Resilient API Client

Every API call passes through axios interceptors that handle transient failures:

  • 429 Too Many Requests -- waits for Retry-After header (or 5s default), then retries

  • 5xx Server Error -- exponential backoff (1s, 2s, 4s) up to 3 retries

  • 401 Unauthorized -- triggers self-healing re-auth, refreshes headers, retries the request once


Tools Reference

Device Tools (3)

Tool

Description

Key Parameters

unifi-device-list

List all devices (switches, APs, gateways) with name, model, IP, state, firmware

type: filter by usw, uap, ugw, udm, or all

unifi-device-detail

Full detail for a single device by MAC address, including port count and uptime

mac: device MAC address

unifi-device-ports

All ports on a switch with status, speed, PoE, connected MACs, and assigned port profile

mac: switch MAC address

Client Tools (3)

Tool

Description

Key Parameters

unifi-client-list

List active clients connected to the network

filter: all, wired, or wireless; limit: max results (1-500)

unifi-client-detail

Detailed info for a specific client by MAC

mac: client MAC address

unifi-client-history

All known clients including offline (historical database)

limit: max results (1-500)

Port Profile Tools (6 -- 2 read, 4 write)

Tool

Description

Key Parameters

unifi-port-profiles

List all port profiles (bandwidth/VLAN configs)

--

unifi-port-profile-detail

Full raw detail for a port profile by ID

profileId

unifi-port-profile-create

Create a new port profile with bandwidth limits

name, forward, nativeNetworkId, egressRateKbps, ingressRateKbps, confirm

unifi-port-profile-update

Update an existing profile (fetch-then-merge)

profileId, + any field to change, confirm

unifi-port-profile-delete

Delete a port profile (fails if ports still assigned)

profileId, confirm

unifi-port-set-profile

Assign a port profile to a specific switch port

deviceMac, portIdx, profileId, portName, confirm

All write tools require confirm: true to execute. Set confirm: false for a dry-run preview of what would change.

Network Tools (2)

Tool

Description

Key Parameters

unifi-network-list

List all configured networks (VLANs, corporate, guest)

--

unifi-network-detail

Full configuration for a specific network

networkId

Audit Tools (1)

Tool

Description

Key Parameters

unifi-bandwidth-audit

Per-room bandwidth audit across all switches. Shows port name, bandwidth limits, active status, connected device count. Designed for cross-referencing with billing systems.

switchMac (optional), includeUnnamed

Route & Firewall Tools (2)

Tool

Description

Key Parameters

unifi-traffic-routes

List traffic routes/rules with bandwidth shaping data (raw response)

--

unifi-firewall-policies

List firewall policies from v2 API including traffic rules (raw response)

--

Utility Tools (2)

Tool

Description

Key Parameters

unifi-auth-status

Check authentication status, session expiry, and controller connectivity

--

unifi-api

Generic API escape hatch -- make any UniFi API call not covered by other tools

method, path, useAbsolutePath, params, body


Setup

Prerequisites

  • Node.js >= 20.0.0

  • Access to a UniFi controller (cloud-hosted or UDM Pro / UDM Pro Max)

  • TOTP seed from your authenticator app setup (for automated MFA)

  • WireGuard VPN (if targeting a UDM Pro / UDM Pro Max on a private LAN)

VPN Setup (WireGuard)

If your UniFi controller is a UDM Pro / UDM Pro Max on a private network, you need a WireGuard VPN tunnel to reach it. Cloud-hosted controllers are publicly accessible and do not require VPN.

Required routed subnets:

Your WireGuard AllowedIPs must include every subnet the MCP server and your tools need to reach:

Subnet

Purpose

UDM management subnet

Controller API access (required)

Switch management subnet

SSH access for device operations (if switches are on a separate subnet)

Tenant/client subnets

Client data and VLAN networks (if querying client tools)

Example WireGuard peer config:

[Peer]
PublicKey = <udm-public-key>
AllowedIPs = <udm-subnet>/24, <switch-subnet>/24, <tenant-supernet>/8
Endpoint = <udm-wan-ip>:51820

Verifying connectivity:

# Check the tunnel routes all required subnets
wg show <tunnel-name> allowed-ips

# Verify controller reachable
ping <your-udm-ip>

# Verify switches reachable (if on a separate management subnet)
ping <switch-ip>

Troubleshooting: devices unreachable but controller responds

The WireGuard Windows app stores tunnel configs internally. Editing the .conf file on disk does not update the running tunnel. If your config file has the correct AllowedIPs but wg show is missing a subnet:

  1. Open the WireGuard app

  2. Remove the tunnel

  3. Import tunnel from file (re-import the updated .conf)

  4. Activate the tunnel

Verify with wg show <tunnel-name> allowed-ips.

Installation

# Clone the repository
git clone <repo-url>
cd mcp-servers/unifi-mcp-server

# Install dependencies
npm install

# Configure environment
cp .env.example .env
# Edit .env with your controller details (see Configuration section)

# Build
npm run build

# Authenticate (first time)
npm run auth           # Interactive mode
npm run auth -- --auto # Non-interactive (requires UNIFI_USERNAME, UNIFI_PASSWORD, UNIFI_TOTP_SEED)

# Start the server
npm run start

Claude Code Configuration

Add the server to your Claude Code MCP settings (~/.claude/settings.json or project-level .mcp.json):

{
  "mcpServers": {
    "unifi": {
      "command": "node",
      "args": ["/path/to/unifi-mcp-server/dist/index.js"],
      "env": {
        "UNIFI_HOST": "your-controller-ip",
        "UNIFI_SITE": "default"
      }
    }
  }
}

The server communicates over stdin/stdout using the MCP StdioServerTransport.


Configuration

All configuration is loaded from .env at the project root via Zod-validated schemas.

Core Settings

Variable

Required

Default

Description

UNIFI_HOST

Yes

--

Hostname or IP of the UniFi controller

UNIFI_PORT

No

443

HTTPS port

UNIFI_SITE

No

default

UniFi site ID (visible in the controller URL)

UNIFI_VERIFY_SSL

No

false

Set true only if the controller has a valid TLS certificate

Authentication

Variable

Required

Default

Description

UNIFI_USERNAME

For self-healing

--

UniFi SSO or local admin username

UNIFI_PASSWORD

For self-healing

--

UniFi SSO or local admin password

UNIFI_TOTP_SEED

For self-healing

--

Base32-encoded TOTP secret from authenticator setup

Session Storage

Variable

Required

Default

Description

TOKEN_CACHE_PATH

No

./data/unifi-session.encrypted.json

Path to the encrypted session cache file

TOKEN_ENCRYPTION_KEY

No

--

64-character hex key for AES-256-GCM encryption. Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))". Falls back to base64 encoding if unset.

Logging

Variable

Required

Default

Description

LOG_LEVEL

No

info

Log verbosity: debug, info, warn, error

Webhook Push (scripts/webhook-push.ts only)

Variable

Required

Default

Description

WEBHOOK_URL

For webhook

--

Make.com or other webhook URL for monthly bandwidth audit

VPN_TUNNEL_NAME

No

--

WireGuard tunnel name for automatic VPN connect/disconnect

VPN_GATEWAY

No

--

IP to ping for VPN health check (e.g., your gateway behind the tunnel)

MAX_RETRIES

No

3

Number of retry attempts for webhook push

RETRY_DELAY_MS

No

60000

Initial delay between retries in ms (linear backoff: 1x, 2x, 3x)


Authentication

How It Works

UniFi controllers use cookie-based authentication with JWT tokens. The server supports two authentication flows depending on the controller type:

Cloud-hosted controller (two-step MFA):

  1. POST username + password to /api/auth/login -- returns UBIC_2FA cookie

  2. Generate TOTP code from the stored base32 seed (RFC 6238, HMAC-SHA1, 30-second period, 6 digits)

  3. POST username + password + TOTP code with the UBIC_2FA cookie -- returns TOKEN in Set-Cookie

  4. Parse the JWT payload for the csrfToken and exp (expiry) claims

  5. Encrypt and persist the session to disk

UDM Pro / UDM Pro Max (single-step):

  1. POST username + password + TOTP code in a single request -- returns TOKEN in Set-Cookie

  2. Parse and persist as above

Initial Authentication

Run the auth script to establish the first session:

# Interactive -- prompts for username and password
npm run auth

# Non-interactive -- reads credentials from environment
npm run auth -- --auto

The --auto flag is used for scheduled tasks and CI environments. It requires UNIFI_USERNAME, UNIFI_PASSWORD, and UNIFI_TOTP_SEED to be set in .env.

Self-Healing Auth

When UNIFI_USERNAME, UNIFI_PASSWORD, and UNIFI_TOTP_SEED are all present in the environment, the server re-authenticates automatically without any manual intervention:

  • Proactive refresh: When the session has fewer than 15 minutes remaining, a background refresh is triggered (fire-and-forget; the current request continues with the existing session)

  • Expired re-auth: When the session has fully expired, re-auth blocks until complete before the request proceeds

  • 401 retry: If the controller returns 401, the axios interceptor triggers re-auth, refreshes the Cookie and X-CSRF-Token headers, and retries the original request

  • Mutex: A promise-based mutex ensures concurrent requests share a single auth attempt

  • Circuit breaker: After 3 consecutive authentication failures, auth is disabled until the server is restarted (prevents credential lockout loops)


Scripts

webhook-push.ts

Automated monthly bandwidth audit push to a Make.com webhook. Designed to run as a scheduled task on the 1st of each month.

npx tsx scripts/webhook-push.ts

What it does:

  1. Connects WireGuard VPN (if VPN_TUNNEL_NAME is set)

  2. Authenticates to the UniFi controller with automated TOTP

  3. Pulls all switch device data and builds a per-room bandwidth payload

  4. POSTs the payload to the configured WEBHOOK_URL

  5. Disconnects VPN

  6. Retries up to MAX_RETRIES times with linear backoff on failure

initial-auth.ts

Interactive or automated initial login to establish a session cache.

npm run auth           # Interactive
npm run auth -- --auto # Non-interactive

auto-reauth.ts

Non-interactive re-authentication for use in scheduled tasks and CI. Generates TOTP automatically, saves the session to the encrypted cache.

npx tsx scripts/auto-reauth.ts            # re-auth + save session
npx tsx scripts/auto-reauth.ts --quiet    # suppress progress logs
npx tsx scripts/auto-reauth.ts --json     # output token JSON to stdout for script chaining

Development

Commands

Command

Description

npm run build

Compile TypeScript to dist/

npm run dev

Watch mode (tsc --watch)

npm run start

Run the compiled server (node dist/index.js)

npm run auth

Run the initial auth script (npx tsx scripts/initial-auth.ts)

Project Structure

unifi-mcp-server/
├── src/
│   ├── index.ts                 # Server bootstrap (McpServer + StdioServerTransport)
│   ├── config/
│   │   └── index.ts             # Zod-validated env config from .env
│   ├── auth/
│   │   ├── sessionManager.ts    # Self-healing auth with proactive refresh + mutex
│   │   ├── sessionCache.ts      # AES-256-GCM encrypted session persistence
│   │   └── totp.ts              # RFC 6238 TOTP generator (zero external dependencies)
│   ├── unifi/
│   │   ├── unifiClient.ts       # Axios client with 401/429/5xx retry interceptors
│   │   └── types.ts             # TypeScript interfaces for UniFi API entities
│   ├── tools/
│   │   ├── index.ts             # registerTools() — wires all tool modules
│   │   ├── devices.ts           # 3 tools: device-list, device-detail, device-ports
│   │   ├── clients.ts           # 3 tools: client-list, client-detail, client-history
│   │   ├── ports.ts             # 6 tools: profiles CRUD + port-set-profile
│   │   ├── networks.ts          # 2 tools: network-list, network-detail
│   │   ├── audit.ts             # 1 tool: bandwidth-audit
│   │   ├── routes.ts            # 2 tools: traffic-routes, firewall-policies
│   │   └── utility.ts           # 2 tools: auth-status, generic api escape hatch
│   └── utils/
│       ├── errors.ts            # Error hierarchy: UniFiError → Auth / Api / Config
│       ├── logger.ts            # stderr logger with sensitive key redaction
│       └── formatters.ts        # Entity formatters for clean LLM output
├── scripts/
│   ├── initial-auth.ts          # Interactive/auto auth script
│   ├── auto-reauth.ts           # Non-interactive re-auth for scheduled tasks
│   └── webhook-push.ts          # Monthly bandwidth audit → webhook
├── data/                        # Session cache (gitignored)
├── dist/                        # Compiled output (gitignored)
├── .env                         # Environment variables (gitignored)
├── .env.example                 # Template with all variables documented
├── .gitignore
├── package.json
└── tsconfig.json

Adding a New Tool

  1. Create or edit a file in src/tools/ (group by entity type).

  2. Export a register*Tools(server: McpServer) function:

    import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
    import { z } from 'zod';
    import { unifiClient } from '../unifi/unifiClient.js';
    import { formatErrorForMcp } from '../utils/errors.js';
    
    export function registerMyTools(server: McpServer): void {
      server.tool(
        'unifi-my-tool',
        'Description of what this tool does.',
        {
          param: z.string().describe('What this parameter controls'),
        },
        async ({ param }) => {
          try {
            const data = await unifiClient.get('/rest/endpoint');
            return {
              content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
            };
          } catch (error) {
            return {
              content: [{ type: 'text', text: formatErrorForMcp(error) }],
              isError: true,
            };
          }
        }
      );
    }
  3. Wire it into src/tools/index.ts:

    import { registerMyTools } from './mytools.js';
    // ...
    export function registerTools(server: McpServer): void {
      // ... existing registrations
      registerMyTools(server);
    }
  4. Build and test: npm run build && npm run start

TypeScript Conventions

  • Target: ES2022 with NodeNext module resolution

  • ESM: "type": "module" in package.json -- all imports must use .js extensions

  • Strict mode: enabled ("strict": true in tsconfig)

  • Output: dist/ with declaration files and source maps


Security

Token Encryption

Session tokens are persisted to disk for survival across server restarts. When TOKEN_ENCRYPTION_KEY is set (64-character hex string = 32 bytes), the session cache is encrypted using AES-256-GCM with:

  • Random 16-byte IV per write

  • GCM authentication tag for tamper detection

  • Format: iv_hex:auth_tag_hex:ciphertext_hex

If the encryption key is not set, sessions fall back to base64 encoding (a warning is logged on every save).

Generate a key:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Credential Handling

  • Credentials (UNIFI_USERNAME, UNIFI_PASSWORD, UNIFI_TOTP_SEED) are read from environment variables only -- never stored in code or committed to version control.

  • The logger automatically redacts any log context key containing token, secret, password, credential, authorization, bearer, apikey, api_key, or cookie.

  • All logs are written to stderr (stdout is reserved for MCP protocol communication).

Self-Signed SSL

UniFi controllers typically use self-signed certificates. By default, UNIFI_VERIFY_SSL=false disables certificate verification via https.Agent({ rejectUnauthorized: false }). Set to true only if your controller has a valid certificate from a trusted CA.


Dependencies

Package

Version

Purpose

@modelcontextprotocol/sdk

^1.12.0

MCP server framework (McpServer, StdioServerTransport)

axios

^1.7.9

HTTP client with interceptor support for retry logic

dotenv

^16.4.7

Load .env files into process.env

zod

^3.24.1

Runtime schema validation for config and tool inputs

Dev dependencies: typescript ^5.7.2, tsx ^4.19.2, @types/node ^22.10.2


Built by Element Zero

This project is built and maintained by Element Zero -- an AI-driven network automation company specializing in multi-tenant building infrastructure.

We use this MCP server daily to manage commercial building networks with 60+ tenant VLANs, automated bandwidth auditing, and billing integration. It's battle-tested in production.

If you manage UniFi networks for multi-tenant buildings, hotels, or coworking spaces -- we'd love to hear from you. Reach out at phil@ezero.ai.


License

MIT

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/philipvanlewis/unifi-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server