Summary
With only UNIFI_NETWORK_API_KEY configured, most Network tools fail. The API-key path exists — AuthProvider.get_api_key_session() in unifi_core/auth.py — but is used by exactly two managers, dpi_manager.py and firewall_manager.py. Every other manager reaches the controller through aiounifi, which performs a session login with username and password.
On a Ubiquiti SSO account with MFA enabled, that login cannot succeed:
Failed to list networks: Not connected to controller:
last connection attempt failed: SSO MFA required but no totp_secret configured
The sample config already labels the key as "experimental — read-only, subset of tools", so the limitation is known. This issue documents the concrete gap and proposes a direction.
Environment
|
|
| unifi-network-mcp |
0.27.3 |
| unifi-core / unifi-mcp-shared / aiounifi |
0.4.30 / 0.6.9 / 93 |
| Controller |
self-hosted, UniFi Network API 10.5.67 |
| Auth |
Ubiquiti SSO account with MFA; API key from Control Plane → Integrations |
What I verified
1. The API key works against the official Integration API.
curl -sk -H "X-API-KEY: $KEY" -H "Accept: application/json" \
https://<host>/proxy/network/integration/v1/sites
# HTTP 200 → {"offset":0,"limit":25,"count":2,"totalCount":2,"data":[…]}
Same for /sites/{siteId}/networks, which returns vlanId and name per network.
2. In the installed package, the API-key path is referenced in only four files.
AuthProvider, AuthMethod and get_api_key_session appear in:
unifi_core/auth.py
unifi_core/network/managers/dpi_manager.py
unifi_core/network/managers/firewall_manager.py
unifi_network_mcp/runtime.py (wiring)
Meanwhile 25 modules import aiounifi — device_manager, client_manager, acl_manager, dns_manager, client_group_manager, event_manager, and so on.
3. There is no global switch.
def from_string(cls, value: str | None) -> "AuthMethod":
if value is None:
return cls.LOCAL_ONLY
AuthMethod is selected per call site, and no environment variable maps onto it. An operator who supplies only an API key gets an MFA error from deep inside aiounifi rather than a clear statement that the tool needs local auth.
Why it matters
Ubiquiti pushes cloud SSO, and MFA is often enforced. The workarounds today are both unattractive:
- Store the account's TOTP seed next to the password — which removes the benefit of the second factor entirely.
- Create a local-only admin account — works, but is another credential to manage, and in some deployments it is not desirable or permitted.
An API key is the natural fit: scoped, revocable on its own, and unaffected by MFA.
What the Integration API already covers
From the controller's own reference (Control Plane → Integrations, API 10.5.67):
Application Info · Sites · Devices (list, details, statistics, adopt/unadopt, device actions, port actions) · Clients (list, details, actions) · Networks (CRUD and references) · WiFi Broadcasts · Hotspot vouchers · Firewall zones and policies · ACL rules · Switching (stacks, MC-LAG, LAGs) · DNS policies · Traffic Matching Lists · Supporting resources (WAN interfaces, site-to-site VPN, VPN servers, RADIUS profiles, device tags, DPI, countries)
That appears to cover the majority of the read-oriented tools, and a good share of the write operations too.
Proposal
- Extend the existing pattern to the inventory managers first —
device_manager, client_manager, and the network/WLAN listing paths — using await self._auth.get_api_key_session() exactly as dpi_manager and firewall_manager already do.
- Expose the selection as configuration, e.g.
UNIFI_NETWORK_AUTH_METHOD=api_key_only|either|local_only, so a key-only setup fails fast with a clear message instead of an MFA error from aiounifi.
- Mark tools that genuinely require a legacy endpoint in the tool index, so a key-only deployment can see up front what is unavailable rather than discovering it at call time.
I am happy to work on step 1 if that direction is welcome — I have a fork at the78mole/unifi-mcp and a controller to test against.
Summary
With only
UNIFI_NETWORK_API_KEYconfigured, most Network tools fail. The API-key path exists —AuthProvider.get_api_key_session()inunifi_core/auth.py— but is used by exactly two managers,dpi_manager.pyandfirewall_manager.py. Every other manager reaches the controller throughaiounifi, which performs a session login with username and password.On a Ubiquiti SSO account with MFA enabled, that login cannot succeed:
The sample config already labels the key as "experimental — read-only, subset of tools", so the limitation is known. This issue documents the concrete gap and proposes a direction.
Environment
What I verified
1. The API key works against the official Integration API.
Same for
/sites/{siteId}/networks, which returnsvlanIdandnameper network.2. In the installed package, the API-key path is referenced in only four files.
AuthProvider,AuthMethodandget_api_key_sessionappear in:unifi_core/auth.pyunifi_core/network/managers/dpi_manager.pyunifi_core/network/managers/firewall_manager.pyunifi_network_mcp/runtime.py(wiring)Meanwhile 25 modules import
aiounifi—device_manager,client_manager,acl_manager,dns_manager,client_group_manager,event_manager, and so on.3. There is no global switch.
AuthMethodis selected per call site, and no environment variable maps onto it. An operator who supplies only an API key gets an MFA error from deep insideaiounifirather than a clear statement that the tool needs local auth.Why it matters
Ubiquiti pushes cloud SSO, and MFA is often enforced. The workarounds today are both unattractive:
An API key is the natural fit: scoped, revocable on its own, and unaffected by MFA.
What the Integration API already covers
From the controller's own reference (Control Plane → Integrations, API 10.5.67):
Application Info · Sites · Devices (list, details, statistics, adopt/unadopt, device actions, port actions) · Clients (list, details, actions) · Networks (CRUD and references) · WiFi Broadcasts · Hotspot vouchers · Firewall zones and policies · ACL rules · Switching (stacks, MC-LAG, LAGs) · DNS policies · Traffic Matching Lists · Supporting resources (WAN interfaces, site-to-site VPN, VPN servers, RADIUS profiles, device tags, DPI, countries)
That appears to cover the majority of the read-oriented tools, and a good share of the write operations too.
Proposal
device_manager,client_manager, and the network/WLAN listing paths — usingawait self._auth.get_api_key_session()exactly asdpi_managerandfirewall_manageralready do.UNIFI_NETWORK_AUTH_METHOD=api_key_only|either|local_only, so a key-only setup fails fast with a clear message instead of an MFA error fromaiounifi.I am happy to work on step 1 if that direction is welcome — I have a fork at
the78mole/unifi-mcpand a controller to test against.