mcp-unifi-network
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-unifi-networkShow me all clients currently connected on site Home"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@mgcrea/mcp-unifi-network
Model Context Protocol server for the UniFi Network API — sites, devices, clients, hotspot vouchers, networks, WiFi and firewall configuration, plus an optional tier for the parts the official API does not cover. Read-only by default: the mutating tools are not registered at all until you opt in, so an agent cannot call them.
Features
Wraps the official Network Integration API (
X-API-KEY, no cookie, no CSRF) as the primary transport, with server-side filtering pushed down to the console.Accepts a site as its UUID, its legacy 8-character name, or its display name and translates — so the obvious guess works on the first call instead of returning a 400.
Registers tools against the console's actual Network version. This API had 7 endpoints in 9.0 and 44 in 10.3, so an older console is offered only what it can serve.
Optional legacy controller tier for what the official API lacks: blocking, unblocking and reconnecting clients, events, alarms, health, port forwarding and adoption.
Native
fetch, no HTTP client. Two runtime dependencies plusundici— see Security.
Related MCP server: UniFi MCP Server
Security
Supply chain. Three runtime dependencies: the MCP SDK, Zod, and undici. The last is a
deviation from the rest of this fleet, taken deliberately: local UniFi consoles ship self-signed
certificates, Node's native fetch ignores a node:https agent, and the only scoped way to
relax verification is an undici dispatcher. The alternative,
NODE_TLS_REJECT_UNAUTHORIZED=0, is process-global and would silently disable verification for
every other request the process makes. undici is the same engine Node's own fetch already runs.
TLS. Verification is on by default, and UNIFI_INSECURE_TLS is refused in cloud mode where it
would be a pure downgrade. When it is on, the banner says tls=INSECURE on every start.
Verifying instead takes two things together, and either alone achieves nothing: the certificate is
self-signed, so NODE_EXTRA_CA_CERTS must point at it; and it is issued to unifi.local with
no IP SAN, so UNIFI_HOST must be a host name that resolves to the console rather than its IP.
See .env.example for both commands.
Your credentials. The API key and, if the legacy tier is enabled, the console password come
from the environment or from ~/.config/unifi/config.json, which is warned about if it is
group-readable. The legacy session cookie is a full console-admin credential and is held in
memory only — never written to disk. Nothing is sent anywhere but your console.
Configuration never kills the server. A contradictory setting is resolved to the safe option
and reported through the startup banner and unifi_auth_status, rather than throwing — a server
that exits at startup appears in the client as a bare Connection closed with stderr swallowed,
taking its own explanation with it.
Blast radius. With the defaults, this server can only read. Turning on UNIFI_ALLOW_WRITES
adds: restart a device, power-cycle a PoE port, authorize and unauthorize guest access, create
and delete vouchers, and — with the legacy tier — block, unblock and reconnect clients. Every
irreversible one requires an explicit confirm: true that the schema enforces before the handler
runs. Firewall and network configuration are read-only in every configuration: a wrong policy
locks you out of the console you are managing it through, with no undo.
Configure
Variable | Default | Meaning |
| — | The console. A pasted browser URL is accepted and split. |
| — | Settings → Control Plane → Integrations → Create API Key. |
| inferred |
|
| — | Cloud mode: the console id from unifi.ui.com. |
| — | Default site. UUID, legacy name or display name. |
|
| Register the mutating tools. |
|
| Disable certificate verification, this server only. |
|
| Register the |
| — | Legacy tier fallback only. A local admin, not SSO. |
| probed | Pin the version instead of probing at startup. |
| 50 / 20 / 3 | Tuning. |
|
| JSON alternative to all of the above. |
.env.example is the annotated version. Environment variables beat the config file per field,
so a one-off UNIFI_ALLOW_WRITES=0 overrides a file that says true without discarding the rest.
Quick start
npx -y @mgcrea/mcp-unifi-networkor from source:
pnpm install && pnpm build
UNIFI_HOST=192.168.1.1 UNIFI_API_KEY=… node dist/cli.jsThe banner on stderr reports what it resolved:
unifi-mcp connected (mode=unifios, host=192.168.1.1, version=10.6.101, tier=full (probe),
sites=1, integration=on, legacy=off, tls=verified, writes=disabled)Wire into Claude Code
Copy .mcp.json.example to .mcp.json (gitignored) and fill it in.
Inspect the tools
npx @modelcontextprotocol/inspector node dist/cli.jsTools
W = registered only with UNIFI_ALLOW_WRITES=1. ⚠️ = requires confirm: true.
Needs = the minimum UniFi Network version.
Tool | What it does | Needs | |
| Configuration, console version, and what to set | — | |
| Version, tier, and which capabilities are gated off here | 9.0 | |
| Every site with all three of its identifiers | 9.0 | |
| Currently connected clients | 9.0 | |
| One client in full | 9.3 | |
| Adopted devices, state, model, firmware | 9.0 | |
| One device in full | 9.0 | |
| CPU, memory, uptime, uplink throughput | 9.0 | |
| Hotspot guest vouchers | 9.3 | |
| Networks / VLANs (read-only) | 10.0 | |
| WiFi broadcasts / SSIDs (read-only) | 10.0 | |
| Firewall zones (read-only) | 10.0 | |
| Zone policies, and their ordering per zone pair | 10.0 | |
| Escape hatch for any unwrapped endpoint | W for non-GET | 9.0 |
| Reboot a device | W ⚠️ | 9.0 |
| Reboot whatever is on a PoE port | W ⚠️ | 9.3 |
| Let a client onto the guest network | W | 9.3 |
| Cut a guest's access immediately | W ⚠️ | 9.3 |
| Generate guest vouchers | W | 9.3 |
| Delete one voucher, or every match of a filter | W ⚠️ | 9.3 |
With UNIFI_ENABLE_LEGACY=1. On a UniFi OS console this needs no extra
credential — the console accepts UNIFI_API_KEY on the legacy paths too, so the
flag alone is enough:
Tool | What it does | |
| "Why will this device not connect?" — one call, with a verdict | |
| "Is my network OK?" — ranked findings across every subsystem | |
| Every client ever seen, which are blocked, and what is new | |
| Raw per-subsystem health | |
| Controller event log | |
| Open alarms | |
| Escape hatch: port forwarding, adoption, upgrades, DPI | W ⚠️ non-GET |
| Let a blocked client back on | W |
| Block a client by MAC | W ⚠️ |
| Kick a client so it reassociates | W ⚠️ |
Prompts
Clients surface these as slash commands. They carry the order to call things in and the wrong conclusions to avoid on the way — the part no single tool description can hold, because it spans several tools.
Prompt | Argument | For |
|
| "Why won't my lawnmower connect?" |
|
| "Did anything new join the network?" |
| — | "Is everything OK?" |
All three are registered unconditionally, so they work before anything is configured.
Resources
unifi://troubleshooting — field notes on the API behaviours that return a
successful, plausible, wrong answer. Registered unconditionally, including
with no credentials, because several of them describe failures that occur before
anything is configured. Read it before concluding that a device is absent, that
nothing is blocked, or that a client has been offline for months.
A worked example: a device that will not connect
unifi_diagnose_client { "device": "husqvarna" }
→ { found: false, verdict: "absent", explanation: "NOT KNOWN TO THIS CONSOLE AT ALL …" }absent is a diagnosis, not a dead end. A client record is written on
association, which happens before the password is checked — so a device refused
at the 802.11 authentication frame appears nowhere in the API: no record, no
event, nothing. The usual cause is an orphaned block: blocking a client
writes its MAC to /etc/persistent/cfg/blocked_sta on every AP, and deleting the
client from the controller afterwards leaves that file behind with no way to undo
it in the UI. It survives reboots and re-provisioning.
unifi_legacy_unblock_client is safe on a MAC the controller has never heard of
and clears exactly this. To confirm before or after, read the AP logs the gateway
already collects:
ssh <gateway> 'grep -a "<mac>" /srv/unifi/logs/remote/*.log | tail -20'auth: disallowed by ACL is a block. Silence means the device never reached the
AP at all.
A worked example: find and reboot a stuck access point
unifi_list_devices { "state": "OFFLINE" }
→ [{ id: "…", name: "Garage AP", model: "U6LR", state: "OFFLINE", … }]
unifi_get_device_stats { "deviceId": "…" }
→ { uptimeSec: 32, cpuUtilizationPct: 94, … }
unifi_restart_device { "deviceId": "…", "confirm": true }The first call filters on the console — state.eq('OFFLINE') goes down as a query parameter,
so nothing is fetched and discarded here.
Traps worth knowing
All of these are baked into the tool descriptions, but they explain the shape of this server.
unifi_list_clientsreturns only what is connected right now. It is not a device inventory. A blocked client, or one that has not been on the network for a week, is simply absent — so "is anything blocked?" and "why will this thing not connect?" cannot be answered from it, and an empty result reads like an all-clear when it is nothing of the kind. The Integration API has no historical view at all: there is no known-clients, blocked-clients or event endpoint anywhere in it.unifi_legacy_list_known_clientsis the answer, and it is the main reason to turn the legacy tier on.Worse, the obvious workaround does not work. A server-side filter for the blocked state returns an empty set rather than an error for a value that does not exist:
filter=access.type.eq('BLOCKED') → 0 results filter=access.type.eq('NOT_A_REAL_VALUE') → 0 resultsSo a zero from that query is not evidence of absence, and it is very easy to report a false all-clear from it. Whenever a filtered count is load-bearing, check it against a value you know is fake before you trust the zero.
There are two kinds of API key. A cloud key from
unifi.ui.comis not a local console key, and using one against a local console gives a 401 that looks like a typo. See Configure. A local key is accepted on the legacy paths too, which is why the legacy tier needs no console password on UniFi OS.Cloud mode cannot reach a console the Site Manager API does not list.
UNIFI_CONSOLE_IDhas to come fromGET https://api.ui.com/v1/hosts, and that listing is not the same as what unifi.ui.com shows you. A console grouped into a Fabric — several consoles (Network, Protect, NAS) presented under one name — appears in the web UI but not in/v1/hosts, even withcloudConnected: trueon the console itself. Observed on a UDM-Pro that the portal showed and the API did not, on both/v1/hostsand/ea/hosts, with no pagination involved. For such a console there is no host id, so cloud mode is unavailable and you need a local Integration key withUNIFI_MODE=unifios.siteIdis a UUID, notdefault. A site has three identifiers: the UUID this API's paths take, the legacy 8-characterinternalReferencethat appears in every controller URL and forum post, and a display name. Every tool accepts all three. The legacy tools need theinternalReference, and that translation happens for you too.The endpoint set depends on the console's version. 7 paths in 9.0, 12 in 9.3, 32 in 10.0, 44 in 10.3. The server probes
GET /v1/infoat startup and registers accordingly, so the tool list can differ between two runs against different consoles.unifi_get_console_infosays why. If the console cannot be reached at startup the server still comes up, assumes the newest version, and lets any gap surface as an error naming the version it needs — a visible failure beats a silently missing tool.Local consoles use self-signed certificates, and pinning one is not enough. The certificate is issued to
unifi.localwith no IP SAN, so a console addressed by IP fails verification however the certificate is trusted — you need a host name too. See Security.The classic self-hosted controller has no Integration API. API keys are UniFi OS only, so port 8443 means the legacy tier or nothing. The config refuses the contradictory combination rather than failing later at request time.
The legacy API reports errors with HTTP 200.
{"meta":{"rc":"error"}}is a failure however healthy the status line looks. That is unwrapped for you in one place.Legacy payloads are enormous — a
stat/deviceobject declares ~423 fields and one UDM-Pro is 50–150 KB. Legacy responses are projected down, andunifi_legacy_requestrefuses anything over 5 MB rather than parsing it. Passattrsand_limit.Login is rate-limited. The legacy session is established once per server start and reused; a 429 on login is never retried, because retrying deepens the lockout.
Troubleshooting
The server does not appear / Connection closed. Run node dist/cli.js by hand with the same
environment and read stderr — this server is built never to exit on missing configuration, so a
real crash is visible there.
A tool I expected is missing. Call unifi_auth_status, then unifi_get_console_info. It is
almost always the version gate or the write flag, both of which unregister rather than refuse.
401 on every call. The key is per-console and shown only once. Re-create it under one of two different kinds of key, which are not interchangeable and which produce a confusing 401 when mixed up:
Local Integration key — created on the console itself at
https://<console>/network/default/settings/control-plane/integrations. This is whatUNIFI_MODE=unifiosneeds. Use the URL rather than hunting the sidebar: on Network 10.6Control Planelives under a heading named after your console at the bottom of the settings sidebar, belowSystem, which is why it gets reported as missing.Cloud Site Manager key — created at
https://unifi.ui.com/settings/api-keys. A console's local API rejects this with a 401. It is used withUNIFI_MODE=cloudandUNIFI_CONSOLE_ID, which also works behind CGNAT and needs no TLS workaround at all.
Either kind is shown once and can afterwards only be renamed or deleted, any admin can create one, and creation sometimes errors on the first attempt, so retry before assuming it is broken.
fetch failed / certificate errors. Self-signed certificate; see Security.
Develop
pnpm dev # tsdown --watch
pnpm test # vitest, offline, no credentials needed
pnpm typecheck
pnpm lint && pnpm formatRelease:
pnpm dlx release-it # bump, commit, tag
git push --follow-tags # CI publishes to npm and cuts the GitHub releaseThe offline suite covers the registration matrix, the confirm gates, site resolution and both
error envelopes. The real-console check is the curl probe in .env.example plus the inspector.
License
MIT
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI assistants to manage and monitor UniFi Network Controllers through natural language. Provides 25 read-only tools for discovering devices and clients, viewing security configurations, analyzing network statistics, and exporting configuration data.41MIT
- AlicenseNot gradedqualityDmaintenanceEnables comprehensive management of UniFi Network infrastructure through 24 tools for monitoring and controlling devices, clients, wireless networks, security, and guest access. Supports network administration tasks like device restarts, client blocking, WLAN configuration, and backup creation.20MIT
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Ubiquiti UISP API for managing network devices, sites, and monitoring through dynamically generated read-only tools.1MIT
- AlicenseAqualityAmaintenanceExposes the UniFi Network Integration API as tools for managing sites, devices, clients, networks, WiFi, firewalls, ACLs, switching, DNS policies, hotspot vouchers, VPNs, and more.41260MIT
Related MCP Connectors
Read-only CVE intelligence, remediation playbooks, and agent setup guides. Not a scanner.
Read-only access to your VortexIQ store data: audits, KPIs, alerts, Brand DNA, reports, Ask VIQ.
XFA's remote MCP server — query device posture, compliance, policies & CVEs. Read-only.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/mgcrea/mcp-unifi-network'
If you have feedback or need assistance with the MCP directory API, please join our Discord server