
Unifi Fabric Mcp Server
io.github.swkstudios由 GitHub 帳號 swkstudios 發布v0.7.0更新於 Nov 3, 2026
MCP server for UniFi Fabric: Network, Protect, Site Manager, InnerSpace, Carrier Fabric, Mobility.
發布方自己的服務:Fabric
概覽
Unifi Fabric 的本機 MCP 服務;無需登入;STDIO。
暫無 AI 概覽:以下資訊來自註冊中心條目和服務本身。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Unifi Fabric Mcp Server,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
UniFi Fabric MCP Server
[CI] [PyPI] [Python 3.12+] [License: MIT] [MCP Registry]
Manage your entire UniFi network remotely from any AI assistant, through the UniFi Fabric API in Ubiquiti's cloud. Nothing to install on your network, no controller login. 786 tools across Site Manager, Network, Protect, InnerSpace and more, read-only if you want.
Scripted replica of a Claude Code session: real MCP tool calls to this server against a mock UniFi API with synthetic data, writes in dry-run mode (how it's made and how to reproduce it).
By default the client sees 5 discovery meta-tools that reach every tool; see Discovery mode.
Why this server
- Remote management through the UniFi Fabric API in Ubiquiti's cloud.
- 786 tools across Site Manager, Network, Protect, InnerSpace, Mobility and Carrier Fabric.
- Discovery mode advertises 5 tools in about 5 KB while reaching the full catalog; full mode uses about 1454 KB.
- Pass-through tools preserve upstream fields by default; projections and summaries are documented. Configured server secrets are masked and data-secret redaction is optional.
- Choose read-only mode, dry-run previews, redaction and audit logging.
- Every tool runs in CI against a simulated upstream.
- Works with MCP clients and is MIT licensed. See MSP setup and demos.
Contents: Quick Start · Safety · Read-only mode · Examples · Clients · Tools · Configuration · Troubleshooting · Contributing
Disclaimer: This project is not affiliated with, endorsed by, or sponsored by Ubiquiti Inc. UniFi is a trademark of Ubiquiti Inc.
The canonical console command is unifi-fabric-mcp. The MCP Registry also launches the
equivalent unifi-fabric-mcp-server console alias, matching the PyPI package identifier.
Quick Start
- Get a UniFi API key. Enable Site Manager and Network scopes at minimum, plus Protect for cameras.
- In Claude Code, run
/plugin marketplace add swkstudios/unifi-fabric-mcp-serverand then/plugin install unifi-fabric@unifi-fabric. The plugin requires uv and prompts for the key. - Ask: "List my UniFi sites and the devices in each one."
Choose your client
Local stdio setups use uv; Docker deployments need Docker instead. Set UNIFI_API_KEY in your environment before using the CLI commands. Configuration files may store keys in plain text; keep them private.
Get Your API Key
- Sign in to UniFi Site Manager with your Ubiquiti account
- Select your organization from the dropdown (top-left)
- In the left sidebar, click API Keys
- Click Create New API Key and give it a descriptive name
- Select the API Scope — enable Site Manager and Network at minimum (add Protect if managing cameras)
- Under Sites, choose which sites the key can access (or select all)
- Copy the key immediately — it won't be shown again
Note: These are UniFi Site Manager API keys that authenticate against the UniFi Fabric API in Ubiquiti's cloud (
api.ui.com). Your consoles must be adopted to your UI.com account and connected to Ubiquiti's cloud for the key to discover them. See the API Docs for more details.
Safety controls you set
Always on: Every read tool is marked read-only and every write tool is marked destructive, derived from code and checked by tests. Supporting clients can use these hints to distinguish reads from writes. Use your client permission settings to ask before a write. The server masks its own UniFi API key when UniFi echoes it, and in errors and logs. A dry-run preview can echo a key that the caller supplied in the request body. The optional confirm argument is accepted and ignored; it is not an approval control. In discovery mode, all writes go through call_write_tool; choosing "do not ask again" for it may approve every later write.
Full access is the default because the server exists to manage your network. To start cautiously, turn on read-only mode first. These switches are opt-in and off by default; set them in the client server environment:
Read-only mode
Set UNIFI_READ_ONLY=1 to hide write and action tools and refuse calls before they reach UniFi. Reads remain available. Turn on the Claude Code plugin Read-only mode option, add the variable to a client configuration or pass -e UNIFI_READ_ONLY=1 to Docker. Remove it or turn the plugin option off and restart to enable writes again.
For example, with Claude Code:
The command stores the key in Claude Code's MCP configuration in plain text; keep it private. See read-only details for accepted values, selection order and per-area flags.
Example Prompts
Copy-paste these into Claude Code or any MCP client after connecting:
Sample Tool Output
When you ask the MCP server a question, it executes tools and returns structured data. Here is get_fleet_summary on a single console with one site and five devices (output from a sanitized recorded response; it returns counts only, no records):
With several API keys configured, the summary also carries _key_labels (the labels of the keys that answered), _keyTotals (each answering key's share of the counts, summing to the totals), and errors for a key that failed; incomplete / incompleteReason appear when a list stopped at the opt-in UNIFI_PAGINATE_MAX_PAGES cap.
Set up your client
The Quick Start table links here. Every option runs the server on your own machine with your own UniFi API key; nothing goes through a hosted service, and requests go from your machine to api.ui.com only.
Install as a Claude Code plugin
The plugins/claude/ folder is a Claude Code plugin. It runs this server locally through uvx with the API key you enter when you enable it (kept in Claude Code's secure credential storage), and it has optional Read-only mode and Tool mode settings. Nothing goes through a hosted service: requests go from your machine to api.ui.com only. It works in Claude Code (terminal, IDE extensions and the desktop Code tab). Claude Desktop chat runs local servers configured through claude_desktop_config.json; see Use with Claude Desktop. The claude.ai web and mobile chat clients do not run local MCP servers. See the plugin README for what it runs, where data goes, and example prompts, and PRIVACY.md for the privacy policy.
Install it from this repository's marketplace (Claude Code 2.1.275 or later installs in one step):
Claude Code asks for your API key, Read-only mode and Tool mode (discovery by default) when you enable it. Or try it for one session from a checkout:
Without the plugin, register the server directly with claude mcp add as shown in Safety defaults or Track A.
Use with Claude Desktop
Claude Desktop chat runs local MCP servers from its config file (macOS and Windows; not claude.ai on the web or mobile). Open it with Settings > Developer > Edit Config:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Replace /absolute/path/to/uvx with the output of which uvx (macOS) or where uvx (Windows): an app started from the Dock or Start menu may not see ~/.local/bin or other shell PATH entries. Add "UNIFI_READ_ONLY": "1" to env to hide and refuse every write and action tool. Then quit Claude Desktop completely and start it again. The key sits in this file in plain text, so keep the file private.
On macOS or Windows you can instead install the Claude Desktop extension bundle (.mcpb), built from plugins/claude-desktop/: Claude Desktop asks for the key at install time and keeps it in its secure storage. See the bundle README.
Use with OpenAI Codex
The Codex CLI, the Codex IDE extension and the ChatGPT desktop app share ~/.codex/config.toml, so one setup serves all three. ChatGPT on the web cannot start local servers; see Use with ChatGPT (self-hosted).
Recommended: forward the key from your environment (nothing stored). Add this to ~/.codex/config.toml:
Then start Codex from a shell that has the key (the read keeps it out of your shell history):
One-liner (stores the key in config.toml in plain text):
Add --env UNIFI_READ_ONLY=1 for read-only mode. codex mcp list shows the server.
ChatGPT desktop app: it reads the same config.toml, and its servers are listed under Settings > MCP servers (Add server for a new one, then Restart). An app started from the Dock or Finder does not see variables exported in a terminal, so env_vars forwarding only works when Codex starts from a shell; for the desktop app, give the key with the one-liner above (or an env = { UNIFI_API_KEY = "your-api-key-here" } line in the [mcp_servers.unifi-fabric] table).
Codex plugin: this repository is also a Codex plugin marketplace (plugins/codex/). The plugin stores no key; it forwards UNIFI_API_KEY, UNIFI_READ_ONLY and UNIFI_TOOL_MODE from the environment Codex starts in:
With no key in the environment the server exits at startup and Codex lists no unifi-fabric tools; a wrong key returns the upstream HTTP 401 on the first tool call.
Use with Google Antigravity
Antigravity starts local servers with the environment of the shell that started agy, and it does not expand ${VAR} in env values. Keep the key out of config files by exporting it before you start agy:
Or install the plugin from a checkout of this repository; it uses the same exported key:
Antigravity 2.0 and the Antigravity IDE read the same ~/.gemini/config, but when started from the Dock they do not see variables exported in a terminal. For them, store the key in the config instead (in plain text, in ~/.gemini/config/mcp_config.json):
Without a key the server exits at startup and Antigravity lists no unifi-fabric tools; a wrong key returns the upstream HTTP 401 on the first tool call. See the plugin README.
Use with Gemini CLI
Google replaced the consumer Gemini CLI with Antigravity; Gemini CLI remains available to Enterprise and API-key users. This repository's root gemini-extension.json makes it a Gemini CLI extension that prompts at install time for your API key (stored in the system keychain) and the optional Read-only mode and Tool mode settings:
We have checked the manifest against the extension reference but have not run it in Gemini CLI. Antigravity's agy plugin import also reads this manifest.
Use with ChatGPT (self-hosted)
ChatGPT on the web and in its apps only connects to remote MCP servers over HTTPS, signed in with OAuth 2.1; it cannot start a local server or send an API key. You can still use this server with ChatGPT by hosting your own instance in OAuth mode behind your own identity provider and adding it as a custom MCP server. Never put this write-capable server on a public URL without authentication. The self-hosted ChatGPT guide has the prerequisites, steps, a known limitation and a security checklist; that setup has not been tested end to end with ChatGPT.
A listing in the ChatGPT app directory would need a hosted service run by us. We do not run one, so there is no directory listing.
Track A — Local (stdio)
Install from PyPI and run the server locally. The MCP client launches it as a subprocess over stdio. Requires Python 3.12+ (or uv, which fetches a suitable Python for you).
Or install it once in an isolated environment:
Or use a virtual environment you manage:
For Claude Code, put this in .mcp.json at your project root (Claude Code asks you to approve it on first use). To register the server for all your projects, use claude mcp add --scope user unifi-fabric -e UNIFI_API_KEY=… -- uvx --from unifi-fabric-mcp-server==0.7.0 unifi-fabric-mcp; Claude Code stores that configuration in ~/.claude.json. Supported locations are documented by Claude Code.
If you installed with pipx or pip instead, use "command": "unifi-fabric-mcp" and omit args.
PATH note: A bare
"command": "unifi-fabric-mcp"only resolves if it is on the MCP client'sPATH. Many MCP clients do not inherit the shell's virtual environment. Useuvxas above, the absolute path to the installed binary (for example/path/to/.venv/bin/unifi-fabric-mcp), or install globally withpipx install unifi-fabric-mcp-server==0.7.0oruv tool install unifi-fabric-mcp-server==0.7.0.
Homebrew: a Homebrew formula is planned, but there is no tap yet; follow issue #24.
Verify it works: When launched by the client the server exits immediately if UNIFI_API_KEY is absent or empty; an incorrect key will not prevent startup but will cause tool calls to fail with an authentication error. A successful start produces no output on stdio (the client communicates over stdin/stdout).
Track B — Docker (HTTP)
See Docker HTTP setup and verification.
Track C — From source (development)
Agent skills
The skills/ folder holds six workflow skills: firewall zone and policy audit,
network or VLAN change, device and client troubleshooting, Protect camera and event review,
Wi-Fi radio change, and site health report. Each tells the agent which tools to call and in
which order: reads first, the exact change shown to you, the tool's own dry-run preview where it
has one, the write, then a read-back. The Claude Code plugin loads them; for Claude Desktop,
Codex, Gemini CLI and Antigravity see docs/AGENT-SKILLS.md.
About this server
What is UniFi Fabric? Ubiquiti spells it "UniFi Fabrics" and describes it as: "UniFi Fabrics transforms Site Manager into a single control plane built for unlimited scale of sites and users." (Ubiquiti, Introducing UniFi Fabrics, 2026-01-12). Watch Ubiquiti's own video, Introducing: UniFi Fabrics, or read The New Site Manager - Now Official.
This is an MCP (Model Context Protocol) server that exposes the UniFi Site Manager API as tools for AI assistants. Built with FastMCP, it works with Claude Code, Codex, Antigravity, Gemini CLI, Cline and other MCP clients.
Highlights:
- 786 tools across Fleet, Network, Firewall, Protect, VPN, InnerSpace, History, and more
- Faithful pass-through by default: tools return complete upstream payloads, including credential fields (WLAN passphrases, RADIUS secrets, API tokens), GPS coordinates, and Protect recognition data. The one change always made is that the server's own configured secrets (its API keys,
MCP_BEARER_TOKEN,MCP_TLS_KEY_PASSWORD) are replaced by***wherever an upstream response echoes them. Mask credential fields with the opt-inUNIFI_REDACT_SECRETS, or refuse all writes withUNIFI_READ_ONLY - Configurable authentication:
none(loopback/dev) /bearer(LAN/VPN) /oauth(resource-server, JWT-verified via JWKS) - Configurable TLS: plain HTTP / in-server HTTPS (
https) / mutual TLS (mtls) - Stdio transport for local use;
streamable-http/ssefor containerized deployments - Stateless, cloud-first design — connects to
api.ui.comvia the UniFi Site Manager API; no direct controller access required
Architecture
What is MCP?
Model Context Protocol (MCP) is an open standard that enables large language models (LLMs) and AI assistants to securely interact with external systems and tools. Instead of asking the AI to make manual API calls or describe steps, MCP allows the AI to:
- Execute commands and operations directly in external systems
- Query data and retrieve real-time information
- Automate complex workflows through natural conversation
This UniFi Fabric MCP server bridges UniFi's network management API with AI assistants, enabling you to control your network infrastructure through conversation.
Use Cases
- Network Operations: Monitor fleet health, manage sites, and troubleshoot devices using natural language
- Security Management: Create and update firewall policies, manage ACLs, and configure DNS policies without manual API calls
- MSP Operations: Manage multiple UniFi consoles and organizations with a single AI interface
- Device Management: Monitor and control cameras, sensors, and other Protect devices across your infrastructure
- Automation: Build AI-powered workflows for routine network tasks and compliance audits
- Placement snapshots: Read a structured snapshot of console, device and floor-plan placement for maps and dashboards; see Placement snapshots.
Compatibility and coverage
Verification status
The live run also recorded failures and untested tools. Later focused tests exercised fixes on different builds; they do not constitute a new full sweep. See coverage and limitations for evidence and scope.
Available Tools
The server exposes 786 tools organized by domain for managing UniFi infrastructure. The following counts are domain tools available in full mode or through discovery search; discovery mode advertises meta-tools in tools/list.
Show all domains
The domain groupings above are illustrative and each tool is counted once. For the full tool reference — including all 786 tool names, parameter tables, and descriptions — see docs/TOOLS.md. MCP clients can also query the server directly: tools/list lists every tool with UNIFI_TOOL_MODE=full; in the default discovery mode it lists the five meta-tools, and search_tools / describe_tool return the names and schemas (Discovery mode).
Every tool parameter carries a description (in tools/list in full mode, or from describe_tool in discovery mode) that says where its value comes from (for example, firewall zone ids from list_firewall_zones_proxy) and whether it is a Network or a Protect id; write tools also document their request body (a spec-derived shape, or an explicit free-form note). Worked examples for the longer workflows are in docs/TOOL-USAGE.md. Read tools are annotated readOnlyHint: true and destructiveHint: false; every write, action, delete and connector-relay tool (including fabric_connector_get, which can reach a state-changing GET route) is annotated readOnlyHint: false and destructiveHint: true (annotation semantics).
If a call is missing a required argument, passes an unknown one, or sends the wrong type, the error names each parameter, repeats its description, lists the valid parameters and shows the tool's example call (a tool whose description has none shows the shape of a call with its required arguments instead), for example:
Errors from the UniFi API itself are returned with their real request path and complete body. The server's own configured secrets are always replaced by *** in them; credential fields are masked only under the opt-in UNIFI_REDACT_SECRETS.
InnerSpace
InnerSpace is UniFi's spatial/floor-plan application. This server covers all six endpoints of the official, GET-only UniFi InnerSpace Integration API (v1.3.23), reached through the Site Manager cloud connector (…/proxy/innerspace/integration/v1/*):
Note: get_innerspace_asset returns the whole asset in one response (the base64 text is about 4/3 the image size). Use metadata_only=true to check size_bytes first if response size matters to your client.
The official Integration API is read-only: it exposes no create/update/save endpoint. Writes go through the internal /proxy/innerspace/api routes.
The typed InnerSpace read tools use the public Integration API; get_innerspace_project, get_innerspace_summary and list_innerspace_devices fall back to the internal /api/project route when the connector refuses the integration route, and get_innerspace_project uses it when user_email or site_id is given. The internal-route tools add five reads (doors, stats, uCore manifest and status, health) and 18 write tools (plans, plan assets and maps, project, wall and attenuation types, shape transforms and imports, backup export and import, support dump, storage clean-up); UNIFI_ENABLE_INNERSPACE_WRITE governs them (enabled by default; set it to a false value to refuse them).
Placement snapshots
Consume get_unifi_placement_snapshot for a bounded, 3D
placement/topology snapshot suited to floor-plan, map, and dashboard consumers. It returns a projection, not whole upstream bodies (as the summary tools such as get_fleet_summary and get_innerspace_summary return server-computed counts rather than records): a read-only, closed unifi.placement-snapshot/v1 field selection with provenance and a
120-second freshness contract. Its strings are the upstream values verbatim, including
device mac / ip and the floor-plan asset URLs. Withholding is opt-in: with
UNIFI_REDACT_SECRETS on, URLs, IP / MAC addresses and credential-marker text are left
out, counted under _withheld, and _withheld_how_to_obtain says where to read each
value (with it off, _withheld is never present). Records schema v1 cannot represent
are counted in either mode under _unprojected, with _unprojected_how_to_obtain
naming the verbatim read tool. It runs with any connector-write setting (it never writes); a
dedicated publisher deployment may still choose UNIFI_ENABLE_CONNECTOR_WRITE=0.
For a scheduled publisher, unifi-fabric-mcp placement-snapshot --host <console> writes one
snapshot as JSON to stdout. Before scheduling it, run
unifi-fabric-mcp placement-snapshot-preflight --host <console>: it checks the four
required logical capabilities through their existing GET-only collectors and reports
each source capability name and a coarse outcome, plus the complete error text for a
failed one; no successful response payload is included. Collector resolution or
pagination can issue more than four HTTP requests; the gate is intentionally about
complete source capability, not a fixed request count.
Generic Fabric Connector Relay (guarded)
Ubiquiti's official Network Cloud Connector (and the Site Manager v1.0.0 OpenAPI) document a generic method relay family — GET | POST | PUT | PATCH | DELETE /v1/connector/consoles/{id}/*path — that forwards a request through Fabric to a console's /proxy/<path> surface. The typed console tools (Network, Protect, InnerSpace) ride that connector. The Site Manager reads of hosts, sites, devices, ISP metrics and SD-WAN configs, and the Mobility and Carrier Fabric tools, call their api.ui.com cloud routes directly (/v1/hosts, /v1/sites, /v1/devices, /v1/isp-metrics/..., /v1/sd-wan-configs, /v1/mobility/..., /v1/carrier/...) without the connector. The fabric_connector_* family exposes the relay directly, as a guarded escape hatch for a controller-supported route that has no typed wrapper yet (a per-device Classic REST config route, a legacy InnerSpace save route, etc.). Verb references: Connector PUT, Connector PATCH (documented against Network app v10.6.106), and the Site Manager v1.0.0 OpenAPI.
path is the relay-relative application path after /proxy/ — e.g. network/integration/v1/sites, network/api/s/{site}/rest/device/{id}, or innerspace/api/shapes/{id}. Use the {site} (slug) or {site_id} (UUID) placeholder for the site segment; the server resolves the site through the Registry and substitutes its slug or UUID, and the result reports the path as sent, substituted site included, under resolvedPath. Like path, resolvedPath is relative to the console's /proxy/: the console id (resolved from host) and the API key are never part of either.
Guards (all enforced, none optional):
- Registry-only identity —
host(name/id) resolves to the owning API key + host id;{site}/{site_id}are substituted from the Registry. - Route classes (a route-to-area map, not a capability cap): Network
integration/v1, Network Classicapi/s/{site}/rest|cmd|stat(and every other Classic route), Networkv2/api, Protectintegration/v1andapi, InnerSpaceintegration/v1andapi, Accessintegration/v1andapieach map to arouteClass, so a per-area write opt-out binds the relay as it binds that area's typed tools. Any other valid path (for exampletalk/...,connect/...,drive/...) relays withrouteClass: "unclassified": a GET always, and a mutation unless a per-area write opt-out (UNIFI_ENABLE_NETWORK_WRITE,UNIFI_PROTECT_MUTATIONS_ENABLED,UNIFI_ENABLE_MOBILITY_WRITE,UNIFI_ENABLE_CARRIER_FABRIC_WRITE,UNIFI_ENABLE_INNERSPACE_WRITE) is active. Its area cannot be proven, so while one is set the mutation is refused, naming the active variable(s). - Positive-charset path validation —
..,%-encoding, backslash, whitespace, control characters,//empty segments, and a URL scheme (://) are rejected before any network call. - Mutation gating (read + write on by default) — an ordinary GET read is always available. A known state-changing GET route (Protect camera
enable-control/disable-control) is a write:UNIFI_ENABLE_CONNECTOR_WRITE, the Protect opt-out,UNIFI_READ_ONLYandUNIFI_DRY_RUNapply to it as to a mutation, and it is sent once. Connector writes are enabled by default; a deployment opts out by settingUNIFI_ENABLE_CONNECTOR_WRITE=0(see Enabling / disabling connector writes). When opted out, a mutation is refused before the console is touched. Theconfirmargument is accepted for compatibility but is ignored. - Area opt-outs apply to the relay — a relayed mutation on a
network/route is refused before the console is touched whenUNIFI_ENABLE_NETWORK_WRITEopts Network out, one on aprotect/route whenUNIFI_PROTECT_MUTATIONS_ENABLEDopts Protect out, and one on aninnerspace/route whenUNIFI_ENABLE_INNERSPACE_WRITEopts InnerSpace out, exactly as the typed write tools of those areas are; the Mobility and Carrier Fabric opt-outs are honoured the same way for any relay route of their area (both live on Site Manager cloud routes the console relay does not reach). The refusal names the variable. - No 429 auto-retry on a write — a relayed POST/PUT/PATCH/DELETE is sent once and an HTTP 429 is raised with the upstream body (the server-wide retry rule: only a read via GET is retried; a relayed GET of a state-changing route, the Protect camera enable-control or disable-control, is sent once too), because the relay cannot tell a physical action (a siren, a relay output, a Classic
cmd) from a settings write and a retry can repeat it. The read-before / read-after GETs keep the GET retry. - Read-before / write / read-after — for PUT/PATCH/DELETE the resource is read before and after the write (
readBefore/readAfter), and the no-op verdict compares only what the write requests (_no_op_verdictinsrc/unifi_fabric/tools/connector.py). A PUT/PATCH with a JSON object body isnoOp: truewhen the write and both reads answered 2xx and every leaf the body names holds the same value (type-strict) before and after; unrequested siblings never count, so an unchanged requestedenabledbeside a changedupdatedAtis stillnoOp: true. A requested leaf that differs, appears or disappears isnoOp: false; a requested leaf absent from both reads, or a read that is not one JSON object, isnoOp: nullwithnoOpReason. A body-less write, a non-object body, or an empty object ({}) falls back to comparing the two whole reads, so a change only toupdatedAtmakes an empty-object PATCHnoOp: false. A Classicrest/device/<_id>write reads the site'sstat/devicelist narrowed to that device and compares only the fields the body writes (noOpBasis). A DELETE isnoOp: false,changed: trueonly when the read-after answers 404; one still readable afterwards isnoOp: null("deletion not confirmed").noOpis null when it cannot be told (a rejected write, a failed or non-2xx read:readAfterError), andchangedis present only beside a non-nullnoOp. - Classic
meta.rcerrors — a Classic route (network/api/...) reports its outcome in the body: HTTP 200 withmeta.rcother than"ok"(e.g.{"meta": {"rc": "error", "msg": "api.err.Invalid"}, "data": []}) is a rejected request. The relay reports it the way it reports any upstream error status, without raising:statusandbodystay verbatim and the result gains_classicRcError(the reason,meta.msgincluded); the write then has nonoOp/changedverdict. AreadBefore/readAfteranswered that way carries the same marker and never counts as a successful read. - Scope guard — an optional
scope(device/site/global) is cross-checked against the path so a site-global setting route (e.g.global_switch.stp_version) cannot be driven by a device-scoped request. - Verbatim bodies + audit — the relayed upstream body is returned unchanged, except that the server's own configured secrets (its API keys,
MCP_BEARER_TOKEN,MCP_TLS_KEY_PASSWORD) are always replaced by***if the body echoes them (credential fields are masked only when the operator opts in withUNIFI_REDACT_SECRETS, which covers this relay like every tool); every relayed body carries the upstreamcontentType. JSON is returned decoded and any other text exactly as received (decoded in its declared charset, such as latin-1), underbody. A binary body (a non-text Content-Type such asimage/jpegorapplication/octet-stream, or bytes that do not decode in the declared charset, UTF-8 when none) is returned the way the typed binary tools return bytes: complete, with no size cap, base64-encoded underbodyBase64withsizeBytes, andbodynull. The same applies to the write responses and toreadBefore/readAfter. A 3xx is never followed: its response headers (Locationincluded; credentials and cookies excluded) come back underheaders, on the write and onreadBefore/readAfter. Bodies are never logged; every mutation attempt is written to a structured audit line (console, site, method, path, confirm, outcome, status) that never contains the API key. - Dry-run — under
UNIFI_DRY_RUNa relayed mutation is not sent: the result'sstatusis"dry_run"(never an HTTP status) andbodyis the preview, and the audit line saysoutcome=dry_runwith no status.
Read-only mode details
Show technical details
UNIFI_READ_ONLY is a single, global, opt-in switch that makes the whole server read-only. It is off by default — unset (or a false value) means read + write is on and behaviour is byte-identical to a build without the switch.
-
Default — writes ENABLED. With the variable unset, every tool works as usual.
-
To enable read-only — set the variable to a truthy value (
1/true/yes/on/t/y, case-insensitive) in the environment of the process that starts the server:- Claude Code plugin: turn on the plugin's Read-only mode option.
- Other local (stdio) clients: add
UNIFI_READ_ONLYto the server'senvblock in the client configuration, or pass-e UNIFI_READ_ONLY=1toclaude mcp addor--env UNIFI_READ_ONLY=1tocodex mcp add. Antigravity reads it from the shell that starts the client; Codex does so only when the variable is listed in the server'senv_vars(as in the Codex setup). - Docker Compose: set it in the service's
environment:block, then recreate the container (if a sidecar shares this server's network namespace, restart the whole compose group together, as for the connector-write flag below), as in this service fragment:
- To return to read + write — local install: unset
UNIFI_READ_ONLYin the client config'senv(or turn off the plugin's Read-only mode option) and restart the server; Docker: remove the variable or set it to a falsey value (0/false/no/off/f/n, case-insensitive), then recreate the container.
When enabled, write/action tools are hidden from tools/list and from discovery search, descriptions and family counts at startup; a client that calls a hidden write by name still receives the audited read-only refusal. This includes the discovery call_write_tool dispatcher; the read discovery meta-tools stay available. Filters compose in order: tool-family allowlist, tool-family opt-out list, API-source disable list, read-only selection, then the per-area write opt-outs, using the tools' derived annotations. Every write/action tool across all areas — Network create/update/delete, device and client actions, Protect, the generic connector relay, Carrier Fabric, Mobility, port-profiles, and vouchers — is refused before any upstream call, and the refusal names the variable and its value, says where to unset it, and points back to this section. Read tools are unaffected, including the allowlisted read-POST queries (the Network v2 traffic-flows query, Classic stat/session and stat/report, and the ISP-metrics query) and the four Classic read commands (cmd/firmware with list-available or list-cached, cmd/backup with list-backups, cmd/devmgr with speedtest-status). A fabric_connector_get call to a known state-changing GET route (Protect camera enable-control / disable-control) is a write and is refused.
This switch is independent of the per-area write flags (UNIFI_ENABLE_CONNECTOR_WRITE, UNIFI_ENABLE_NETWORK_WRITE, UNIFI_ENABLE_CARRIER_FABRIC_WRITE, UNIFI_ENABLE_MOBILITY_WRITE, UNIFI_ENABLE_INNERSPACE_WRITE, UNIFI_PROTECT_MUTATIONS_ENABLED): a write is refused if either read-only mode is on or the relevant area flag opts out. Read-only mode and an area opt-out both win over UNIFI_DRY_RUN: a refused write returns the refusal, never a dry-run preview.
Accepted values (case-insensitive): unset / 0 / false / no / off / f / n → read + write on; 1 / true / yes / on / t / y → read-only. Any other value fails startup, naming the variable.
Enabling / disabling connector writes
Connector writes and each area's writes are enabled by default.
The switches are UNIFI_ENABLE_NETWORK_WRITE, UNIFI_PROTECT_MUTATIONS_ENABLED, UNIFI_ENABLE_MOBILITY_WRITE, UNIFI_ENABLE_CARRIER_FABRIC_WRITE, UNIFI_ENABLE_INNERSPACE_WRITE, UNIFI_ENABLE_CONNECTOR_WRITE.
To make one read-only, set it to 0 in the server's environment: the service's environment: block of the docker-compose file that deploys this server (then recreate the container, restarting the whole compose group if a sidecar shares its network namespace), or for a local install the client's server env block or a shell export before the client starts (Codex forwards only the variables listed in the server’s env_vars; the Codex plugin forwards UNIFI_API_KEY, UNIFI_READ_ONLY and UNIFI_TOOL_MODE only). At startup an opted-out area's write tools are hidden from tools/list and from discovery search, descriptions and family counts, so a client sees only tools it can call. A client that calls a hidden write by name still gets the refusal, which names the variable and its current value, and the refusal is audited. confirm is accepted and ignored. What each switch governs (including a fabric_connector_get of a state-changing route), the accepted spellings and an example: docs/CONFIGURATION.md.
Each switch hides the write tools of its families: the Network switch covers network, firewall, devices, clients, vpn, hotspot and statistics, and the connector switch covers the relay's write tools and the typed tools it also governs (listed in docs/CONFIGURATION.md). Tool counts at 0.7.0 are the same in full mode and in discovery search:
A 4xx/5xx from the relay is returned as status (not raised), so an invalid-ID probe surfaces its own reachability status. Undocumented legacy routes remain experimental until persistence and rollback are proven against a live console.
Live decision-closing probe procedures (documented; each is deferred to a maintenance window and is covered only by hermetic tests in this repo, never run live here):
- InnerSpace save route.
PATCH innerspace/api/shapes/00000000-0000-0000-0000-000000000000with an empty/invalid body. Expect a 4xx (400/404/405/422= route/method reachability evidence). A 200/204 is an immediate stop condition — do not use a real shape ID and do not issue a collection create/delete. Only after the route + schema are confirmed: one low-stakes reversible shape update, read back, restore the exact original shape, verify persistence on a fresh read. A 401/403 on the legacy namespace is auth/namespace gating, not a write path. - Per-device STP/PoE config. Read the target switch via
network/api/s/{site}/rest/device/{id}(scopedevice), probe with the exact current value first (a same-value write →noOp: true), then change only that switch's STP priority (or a harmless empty-port field), read back via/stat/device(the controller has no GET on/rest/device; the relay's own read-before/read-after usestat/devicefor this route), then restore the original value and verify. Globalglobal_switch.stp_versionis site-wide — the scope guard refuses it for adevice-scoped request; keep it to a separately named site-wide path.
Mobility
The UniFi Mobility API (https://api.ui.com/v1/mobility/...) manages UMR mobile
routers through a workspace-based identity model that is deliberately kept separate
from the console host/site resolution used elsewhere — a Mobility workspace is not a
UniFi console, so these tools take a workspace_id (and device_id) directly and never
touch the host/site registry. They ride the same Fabric / Site Manager API key (with
optional key_label selection); a missing Mobility scope or an unavailable subscription
surfaces as the upstream error verbatim.
The three PUT writes are guarded: read-before, no-op detection against observable device state, an environment capability flag (UNIFI_ENABLE_MOBILITY_WRITE, enabled by default; set it to 0 for a read-only Mobility deployment), and a read-after verification. The confirm argument is accepted and ignored. The network endpoint is documented as a partial update and the tool sends only the fields you pass. The Mobility getting-started page describes PUT as full replacement, so if the console applies replacement, LAN/DHCP fields you did not send can be reset. The name and wireless writes send the full documented body.
Port profiles and VLAN auto-exclusion
Creating a network makes UniFi silently exclude it from every custom-tagged port profile, which
blackholes the new VLAN on those uplinks. create_network returns a D12_AUTO_EXCLUSION warning
naming each profile, and allow_network_on_port_profile / exclude_network_on_port_profile fix or
undo it. The full explanation and remediation are in
Tool usage details.
Optional opt-in features
These settings are optional. Each one except discovery mode is off by default, and unset it
changes nothing. Discovery mode is the default tool mode; set UNIFI_TOOL_MODE=full for the
full catalog. All are configured through the UNIFI_* environment family, set in the environment of the process that starts the server (the client's server env block, a shell export, or a Compose service's environment: block). The YAML snippets below show the Compose form; set the same variable in your client's env block when you run the server with uvx.
Tool-family allowlist (UNIFI_TOOL_FAMILIES)
Some MCP clients cap how many tools a server may advertise, and some operators only use
a subset of product areas. Set UNIFI_TOOL_FAMILIES to a list of families to advertise
only those families, or UNIFI_DISABLED_TOOL_FAMILIES to a list of families to leave
out; every other tool stays registered. The opt-out list is applied after the allowlist.
Tools outside the selection are de-registered at startup (never removed from the
implementation). Unset (the default) registers every family — no family is ever off
by default. Separate names with commas and/or whitespace, in any letter case
("network, protect", "network protect" and "Network,PROTECT" are the same).
Catalog size. With every family registered, full mode advertises 786 tools and its
tools/list response is roughly 1454 KB of JSON; default discovery mode advertises five meta-tools. In full mode every tool carries its full description
and parameter docs; the 40 pinned-spec request bodies add their top-level fields and a
compact outline of the nested ones (72,208 bytes of compact JSON in all). A client that loads
the whole catalog into a model's context pays that cost on every session. Trimming to the families you use shrinks it
proportionally, for example (0.7.0; the UTF-8 JSON-RPC response to tools/list, 1 KB = 1000 bytes):
See measured family catalog sizes.
There are 13 families; firewall is assigned by route. The families, what each covers and their tool counts are listed in docs/CONFIGURATION.md.
An unknown name, including a family name from an earlier release, fails fast at startup with the list of the 13 valid families rather than silently advertising nothing.
Discovery mode (default)
Discovery mode keeps the initial catalog small while retaining access to every selected domain tool. UNIFI_TOOL_MODE=discovery is the default. Set UNIFI_TOOL_MODE=full to advertise every domain tool with its complete description and input schema, preserving the previous tool surface. Discovery changes how clients find tools; no tool is removed or capped.
UNIFI_TOOL_FAMILIES and UNIFI_DISABLED_TOOL_FAMILIES select available families before
mode selection. Leave them unset to retain every family. With UNIFI_READ_ONLY=1 or an
area write opt-out, the hidden write tools are left out of search, descriptions and the
family counts as well. Calls use the same registered functions and middleware, preserving
validation, dry-run, per-area opt-outs, UNIFI_READ_ONLY, audit and secret scrubbing.
The advertised tools/list is stable across connections.
Claude Code and Codex already defer tool loading, so some users prefer full with their native discovery.
Behind an MCP gateway, discovery registers the five meta-tools under the gateway's prefix (for example <prefix>-search-tools);
the name inside each wrapper stays the raw tool name, such as list_hosts. Pin full when the gateway must register every
domain tool individually (for example per-tool allow-lists). Empty or whitespace-only UNIFI_TOOL_MODE uses the default; invalid values fail startup with an error naming UNIFI_TOOL_MODE and the valid choices (discovery, full).
To turn discovery off:
- Call
search_tools, for example{"query":"firewall policies","writes":false}, or{"query":"","limit":null}for everything. - Call
describe_toolfor the selected name and read its required arguments. - Call
call_read_toolwith that name and arguments, for example{"name":"list_firewall_policies","arguments":{"host":"console.example","site":"default"}}. Use host/site choices returned by your own server. Usecall_write_toolfor writes.
See measured discovery and full catalog sizes.
API-source selection (UNIFI_DISABLE_API_SOURCES)
Every tool is classified by the upstream API it calls, as <app>/<source>/<access>:
the app (network, protect, innerspace, site_manager, mobility,
carrier_fabric, console, relay for the generic connector relay, server for tools
that make no upstream request), the source (official for a published Ubiquiti API, or a
private surface of that app: network/private.classic, network/private.v2,
network/private.other, protect/private, innerspace/private, console/private), and
read or write. The class is derived from
each tool's routes, carried in its unifi/apiSource metadata, and listed in
docs/TOOLS.md.
Set UNIFI_DISABLE_API_SOURCES to comma-separated selectors to leave every covered tool
unregistered. A selector can name any level: an app (network), an app's private group
(network/private), one surface (network/private.classic), an access level within either
(network/private/write, protect/write), or every app (*/write, */private). A tool
that calls a disabled private surface is disabled even when its own class is official.
Unset (the default) enables every source. An unknown or repeated selector fails fast at
startup and lists the valid values. UNIFI_READ_ONLY is separate and works as before.
The generic fabric_connector_* tools are classified as relay/generic, can reach any
route (including private APIs), and are not disabled by */private. To disable these
relays, select relay or */generic. */read and relay/read also remove fabric_connector_get (class relay/generic/read, the only GET relay), and */write keeps it. A write selector (*/write, protect/write) therefore leaves the Protect camera enable-control and disable-control GET routes reachable through fabric_connector_get; to block them, use UNIFI_READ_ONLY, UNIFI_ENABLE_CONNECTOR_WRITE=0 or the relay selector. API-source selection does not restrict the routes
an enabled relay can reach. */local selects tools that make no upstream request.
Dry-run preview for all writes (UNIFI_DRY_RUN)
Set UNIFI_DRY_RUN to a truthy value to make every write/action tool — across all
product areas (network, Protect, hotspot, device management, clients, Carrier Fabric,
Mobility, port profiles, settings, the connector relay, ...) — return a clearly-labeled
preview (status: "dry_run", dryRun: true, sent: false, with preview: {method, path, params, body}, where params is
the query string the write would carry, or null) of the intended mutation and perform
no upstream write. This
is enforced at the shared HTTP chokepoint: a request is treated as a write when its method
is PUT/PATCH/DELETE, when it is a GET to a known state-changing route (the Protect camera
enable-control / disable-control routes), or when it is a POST other than the read-only
POSTs, which still execute normally. The read-only POSTs are the four query routes on the
read-POST allowlist (the Network v2 .../v2/api/site/<site>/traffic-flows query, the Network
Classic .../api/s/<site>/stat/session and .../stat/report/<interval>.<scope> queries, and Site Manager
/v1/isp-metrics/{interval}/query) and four Classic read commands, each a read only with
exactly its one-field body: .../cmd/firmware with {"cmd": "list-available"} or
{"cmd": "list-cached"}, .../cmd/backup with {"cmd": "list-backups"} and
.../cmd/devmgr with {"cmd": "speedtest-status"}. Any other POST, a relayed POST
included, is a write: previewed under dry-run and audited. Read-only mode and an area write opt-out win over dry-run: a refused write returns the refusal, not a preview. Default off: writes execute as usual and the request path is byte-identical.
Tools that verify their write (update_setting's silent-no-op check, the Protect, Mobility and Carrier Fabric read-before / write / read-after flows, and the connector relay's read-after) return the preview without verifying: nothing was written, so there is nothing to verify. update_setting returns the preview itself; the others return status: "dry_run" with the read-before (Protect before, Mobility device, Carrier Fabric subscriber) and the preview under response. The connector relay returns the preview under body and the read-before under readBefore. This holds when the change is already applied too: under dry-run the no-op short-circuit never stands in for the preview, so the result always shows what would be sent. A multipart upload (upload_protect_file) previews its parts under preview.multipart (field, filename, contentType, sizeBytes), never the file content.
Preview credential masking is opt-in under UNIFI_REDACT_SECRETS. When enabled,
credential-named fields in its body and params (password, passphrase,
x_passphrase, psk, x_psk, x_private_key, secret, token, ... — the list in
Credential redaction) are shown as ***REDACTED***.
With the default setting off, the preview contains the caller's values unchanged except
that configured server secrets are always replaced with ***, including in the preview's
path, body, query parameters and multipart metadata.
(A bare key field is not masked: in Classic settings bodies it is the setting group's name.) The connector relay's dry-run result says
status: "dry_run", never an HTTP status.
No dry-run result claims that a write happened. Delete tools return {status: "dry_run", deleted: false, message, response} (never deleted: true), Protect writes and actions
return status: "dry_run" (never created / triggered), a multi-MAC forget_device
returns {status: "dry_run", byMac, errors} with each MAC's preview (no forgotten), and
the port-profile writes (update_port_profile, allow_network_on_port_profile,
exclude_network_on_port_profile) return the bare preview with none of their additive
keys and no follow-up read.
Optional audit log (UNIFI_AUDIT_LOG)
Audit logging is best-effort: a file I/O failure warns and the call continues. Point UNIFI_AUDIT_LOG at a file path to append a structured record for every write attempt (all tools, via the same shared chokepoint): timestamp (UTC), HTTP method, resolved path, outcome and upstream status, plus tool, resolvedHost, resolvedSite and duration_ms when known. A write refused before it is sent is recorded as outcome=refused. Its reason names the gate (UNIFI_READ_ONLY, an area opt-out variable or UNIFI_ENABLE_CONNECTOR_WRITE, empty_update / required_body_fields), or for any other refusal (an argument check, an unknown id, relay validation) it is the refusal message. A refusal made before the request is resolved has no method or path (- in text, null in JSON). Other outcomes include dry_run, error and rate_limited. UNIFI_AUDIT_LOG_FORMAT selects text (default, key=value line) or json (one JSON object per line); any other value fails startup listing the two. Unset (the default) writes no audit file. The request body and the API key value are never recorded. Container deployments may use UNIFI_AUDIT_LOG=/dev/stderr; use a persistent writable directory when audit history must survive container replacement.
Future and unsupported tools
API surfaces that are deliberately absent from the current tool set, and why (single-site gateways, unavailable Classic routes, Access, the Protect WebSocket subscription) are listed in docs/COVERAGE.md.
Configuration
Everything is configured with environment variables, set in your client's server env block, a shell export, or a Docker or Compose environment: block. The full reference is docs/CONFIGURATION.md; the settings most people touch:
HTTP deployments add authentication and TLS: docs/AUTH-TLS.md covers bearer tokens and the auth by TLS matrix, docs/AUTH-OAUTH.md the OAuth resource-server mode and docs/TLS.md certificates and mTLS.
Pagination, filtering and retries
See pagination, filtering and retries, with full pagination and retry details.
Troubleshooting
Common Setup Issues
"ModuleNotFoundError: No module named 'unifi_fabric'"
- Ensure the package is installed in the active environment:
pip install unifi-fabric-mcp-server==0.7.0(orpip install -e .in a source checkout) - Verify your Python version is 3.12+:
python3 --version - Try
pip install --upgrade pipand reinstall if using an older pip version
"command not found: unifi-fabric-mcp"
- The entry point is only available after installation:
pipx install unifi-fabric-mcp-server==0.7.0(orpip install -e .in a source checkout), or run it on demand withuvx --from unifi-fabric-mcp-server==0.7.0 unifi-fabric-mcp - For local development, install the source checkout first:
python3 -m pip install -e ., then rununifi-fabric-mcp - Check that your virtual environment is activated:
source .venv/bin/activate
A detached docker compose up of a stdio server exits with code 0
- A stdio server needs a client on stdin/stdout. Configure your MCP client to spawn it instead: see Override Transport in Docker Compose
Docker fails to start with "exit code 1"
- Exit code 1 at startup means a configuration error: a missing key ("UNIFI_API_KEY is not set") or a malformed setting ("invalid configuration: "), printed on stderr. Read it with
docker logs <container-id> - Startup makes no upstream call, so an unreachable
api.ui.comor a rejected key does not stop the server; it shows up on the first tool call
Environment Variable Misconfiguration
"401 Unauthorized" or "Invalid API key"
- Verify your
UNIFI_API_KEYis correct — copy it directly from UniFi Site Manager API Keys (left sidebar) - API keys expire or may be regenerated; if recently created, use the new key
- Ensure no trailing whitespace in the env var:
export UNIFI_API_KEY="key-here"(not"key-here "). Startup rejects a key holding whitespace, naming the variable
"UNIFI_API_KEYS" JSON parse error
- Use proper JSON formatting:
[{"key": "...", "label": "..."}, ...] - Escape quotes correctly in shell:
export UNIFI_API_KEYS='[{"key":"your-key"}]'(single quotes) - In a Docker
--env-file, write the value without surrounding quotes: the Docker CLI keeps them literally and they break JSON parsing. Composeenv_file:removes surrounding quotes, but an unquoted line works with both (details) - Validate locally after setting the variable:
python3 -c 'import json, os; json.loads(os.environ["UNIFI_API_KEYS"]); print("Valid JSON")'. Keep API keys out of online validators and public issue reports
"Base URL is incorrect" or "api.ui.com not found"
- The default base URL is
https://api.ui.com— do not change this unless you have a private Ubiquiti API endpoint - If you must override, set
UNIFI_API_BASE_URL="https://your-custom-endpoint.com" - It must be an absolute
http(s)URL with a host and no credentials, query or fragment; startup rejects anything else, naming the variable. A trailing slash is ignored
Connection Errors
"Connection refused" or "Cannot connect to api.ui.com"
- Check your internet connection:
ping api.ui.com - Verify your firewall/proxy allows outbound HTTPS (port 443)
- Behind an outbound proxy, set
HTTPS_PROXYin the server's environment - The server makes requests to
https://api.ui.com/v1/— ensure this endpoint is reachable
"Certificate verification failed" or "SSL: CERTIFICATE_VERIFY_FAILED"
- This typically occurs behind corporate proxies with MITM certificate injection
- The UniFi API client trusts the certifi bundle, not the system trust store; keep it current with
pip install --upgrade certifi - For a corporate CA, set
SSL_CERT_FILEto a PEM bundle that contains it (orSSL_CERT_DIRto a directory of them); importing it into the system trust store has no effect - Certificate verification of the UniFi API cannot be turned off
"Request timeout" or "socket timeout"
- UniFi requests have no application elapsed-time deadline. The deprecated
UNIFI_REQUEST_TIMEOUT_SECONDSsetting has been removed; delete it from deployment configuration before upgrading. - A timeout reported by a proxy, peer, or transport remains a network failure; inspect that source and connection progress rather than increasing a local cap.
- Check if
api.ui.comis experiencing an outage: status.ui.com - If using Docker, ensure the container has network connectivity:
docker run --network host ...
"No hosts found" or "Site not found"
- Your API key must have access to the sites you're querying. Verify in UniFi Site Manager by opening API Keys, then the key, then Sites
- Which sites a key sees is set on the key in Site Manager (its Sites selection).
is_org_keyinUNIFI_API_KEYSis only a label the server reports back; it does not change access - If you just created the key or changed site permissions, wait 1-2 minutes for propagation and retry. The server also caches host and site lists for
UNIFI_CACHE_TTL_SECONDS(default 900 s), and a not-found lookup does not refresh them: restart the server, or wait up to 15 minutes
Errors you may see
"HTTP 403" from a tool call — The key lacks the scope for that product. Edit the key in UniFi Site Manager (API Keys) and enable Site Manager, Network, and Protect as needed. The error carries a hint naming the key and pointing at Get Your API Key.
"refused: the server is in read-only mode" — UNIFI_READ_ONLY is set. Unset it (or turn off the plugin's Read-only mode) in the configuration that starts the server, and restart the server to allow writes. See Read-only mode.
ambiguous site '<name>' / ambiguous host '<name>' — Several sites or consoles share that name. Pass the id from list_sites / list_hosts instead.
cannot resolve '<name>' unambiguously — The site or console list is incomplete, because a page cap (UNIFI_PAGINATE_MAX_PAGES) stopped it or the list drain stopped short, so another object with that name may exist. Use the exact id (unsetting the cap helps only in the first case).
Classic API error from <METHOD> <path>: HTTP 200 with meta.rc 'error' (meta.msg 'api.err.…') — The Network controller rejected the request in its Classic response body although the HTTP status was 200. Every typed tool treats that as an upstream error and quotes the complete body (meta and data); meta.msg names the controller's reason (an invalid value, an unknown object).
Server starts but no tools appear (Codex, Antigravity) — Usually the server did not start: the key was not in the environment of the process that launched the client, so it exited with "UNIFI_API_KEY is not set" on stderr. Export UNIFI_API_KEY and restart the client. Seeing only five tools is normal: that is discovery mode.
Getting Help
- Check developer.ui.com for API documentation and latest firmware compatibility
- Search existing GitHub issues for your problem
- Include the following in bug reports:
- Tool name and parameters you were using
- Full error message (redact your API key and sensitive IPs)
- Server version (
unifi-fabric-mcp --version) - Python version (
python3 --version) and OS - Docker image tag (if applicable)
- Relevant env vars (without secrets)
Development
Docker Deployment
See Docker deployment details for image pinning and stateless operation.
Verify the image
Release images are signed with Cosign and carry an SBOM and provenance attestation; see Verify the image.
Get involved
- Request an endpoint.
- Join GitHub Discussions.
- See the roadmap.
Contributing
We welcome contributions. See CONTRIBUTING.md for setup instructions, branch naming, commit conventions, CI gates, testing requirements, and the changelog rule. Everyone taking part follows the Code of Conduct. For security vulnerabilities, see SECURITY.md — do not open a public issue.
License
MIT. See LICENSE for details.
來源:README.md,提交 c19e268
工具
0版本歷史
1- v0.7.0最新Nov 3, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分
其他 Fabric 整合
Fabric
so.fabric官方發布者
Fabric 的託管 MCP 服務,由 fabric.so 發布;需要憑證;Streamable HTTP。

MCP Fabric (Minecraft)
由 GitHub 帳號 denfry 發布
通過mcpfabric模組(Fabric和NeoForge)檢視並遊玩Minecraft: Java Edition。AI 翻譯

Neblex Integration Fabric
由 GitHub 帳號 neblexhq 發布
Neblex Integration Fabric 遠端伺服器,讓助理在雲端或地端建置、測試並發佈 iPaaS 流程、應用程式、表單與 AI 代理。

Fabric Verify
ai.augmentev
把 AI 代理的動作簽章記錄到防竄改公開日誌,並產生可離線驗證的證明。

PacketFabric
由 GitHub 帳號 PacketFabric 發布
查詢和管理PacketFabric NaaS:埠、虛擬電路、雲路由器、定價、指標。AI 翻譯