omada-mcp
Provides tools for interacting with TP-Link Omada SDN controllers, enabling read-only access by default and optional allowlisted write operations across sites, devices, clients, switches, WLANs, routing, security, diagnostics, and rollback workflows.
Click on "Deploy 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., "@omada-mcp which access points are overloaded on my Omada controller?"
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.
omada-mcp
A Model Context Protocol server for TP-Link Omada SDN controllers — zero dependencies, read-only by default, and honest about every failure.
Your Omada controller already knows which AP is overloaded, which client is
sitting on the guest VLAN, and which switch dropped a port. omada-mcp hands
that to Claude, Cursor, Hermes or any other MCP host — as 35 read-only tools
that return clean JSON (plus 47 optional write tools behind an explicit allowlist,
plus --watch and --export-metrics monitoring modes),
with a self-test that tells you exactly what to fix when something is wrong.
uvx omada-mcp --doctoromada-mcp doctor v1.2.1 on Linux-6.8 (Python 3.12.7)
------------------------------------------------------------------
PASS env /home/you/.config/omada-mcp/.env | url=https://192.0.2.10:8043 user=omada-readonly password=set (24 chars)
PASS tls verified against /home/you/.config/omada-mcp/controller-ca.pem (serverName=Omada) | reachable, omadacId=0123456789abcdef01234567, controllerVer=6.2.10.17, family=software-6.x
PASS login token accepted for omada-readonly (role=Viewer, scope=all sites, cookie=TPOMADA_SESSIONID), Csrf-Token round-trip OK
PASS site Home (89abcdef0123456789abcdef) site 1 of 1; matched OMADA_SITE_NAME=Home
PASS tools list_devices -> 7 device(s); 35 read-only tools registered (0 write tool(s) enabled), 23 client(s)
PASS write disabled (OMADA_WRITE_TOOLS is empty; read-only tools only)
------------------------------------------------------------------
6/6 checks passed
Ready: `omada-mcp` will serve 35 read-only tools on stdio.Add --json (omada-mcp --doctor --json) for machine-readable output validated against schemas/doctor.schema.json. JSON output redacts local .env and OMADA_CA_BUNDLE filesystem paths to origin labels (OMADA_ENV_FILE, cwd, appdata, xdg, environment) so reports are safe to paste into issues.
Why this exists
Omada exposes two unrelated APIs and the documentation blurs them:
Web API v2 ( | Open API ( | |
Auth | username + password ( | OAuth2 client-credentials |
Setup on controller | none — it is the API the web UI calls | "Platform Integration" must be configured |
Account roles | Viewer is enough | Client ID/secret per integration |
Works on OC200/OC300 | yes | firmware dependent |
omada-mcp speaks the Web API. That means: create a local Viewer account,
put three values in a dotenv file, and you are done. No OAuth app, no client
secret rotation, no per-firmware integration screen.
Three properties make it safe to hand to an LLM:
Read-only tools only. Every tool is annotated
readOnlyHint: true, andOMADA_READ_ONLY=truefails closed: a call to anything not declared read-only is refused with-32003before lookup, so a future write tool cannot leak past the switch.No secret echo. The password never appears in output (only
set (N chars)), the session token is never logged, and WLAN pre-shared keys are redacted —list_wlansreportshasPresharedKey: trueinstead.Errors that carry the fix. Controller error codes are translated (
-1505,-1600,-33726,-41011,-44116, …) and every message ends with the action to take.
Related MCP server: mcp-omada
Install
# from git (works today)
uvx --from git+https://github.com/falehsub/omada-mcp omada-mcp --doctor
# from PyPI
uvx omada-mcp --doctor
# or install the command
uv tool install omada-mcp # or: pipx install omada-mcp
pip install omada-mcp # plain pip
# from a local checkout:
git clone https://github.com/falehsub/omada-mcp && cd omada-mcp
uv tool install . # installs the `omada-mcp` command from the checkoutRequires Python 3.10+ and nothing else. There are no runtime dependencies —
urllib, ssl, json and argparse are the whole stack, which keeps the
supply chain at zero.
Configure
mkdir -p ~/.config/omada-mcp
cp .env.example ~/.config/omada-mcp/.env
chmod 600 ~/.config/omada-mcp/.env
$EDITOR ~/.config/omada-mcp/.envThe minimum is three lines:
OMADA_BASE_URL=https://192.0.2.10:8043
OMADA_USERNAME=omada-readonly
OMADA_PASSWORD=...Where configuration is read from
Highest priority first — the first hit wins per variable, and the process environment always overrides a file:
process environment (
export OMADA_BASE_URL=...)$OMADA_ENV_FILE— an explicit path (missing file = hard error, so a typo cannot silently fall through)./.env— relative to the working directory (handy for per-project setups)%APPDATA%\omada-mcp\.env— Windows only, where a Windows user expects a per-user config~/.config/omada-mcp/.env(or$XDG_CONFIG_HOME/omada-mcp/.env)
Windows
Everything is supported natively — no WSL, no MSYS. The console script installs as
omada-mcp.exe, and uvx / uv tool install behave exactly as on POSIX.
New-Item -ItemType Directory -Force "$env:APPDATA\omada-mcp" | Out-Null
Copy-Item .env.example "$env:APPDATA\omada-mcp\.env"
notepad "$env:APPDATA\omada-mcp\.env"Windows-specific behaviour, handled for you:
Config location.
%APPDATA%\omada-mcp\.envis picked up before~/.config/omada-mcp/.env, so the usual Windows location just works.Encoding. Stdio is forced to UTF-8. The console code page (cp1252, cp1256, cp437 …) cannot encode an Arabic or CJK SSID, and the failure mode is a
UnicodeEncodeErrorin the middle of a session — this never reaches you.Line endings. Frames are written with a single
\n; text mode would otherwise emit\r\nand strict clients can mis-frame. Incoming\r\nframes are accepted too.Proxies. System/WinINET proxies are ignored by default (
OMADA_USE_SYSTEM_PROXY=trueto opt in).File permissions. API keys live in your user profile;
--doctorskips the POSIXchmodadvice on Windows rather than handing you a command that does nothing. To restrict the file to your account:icacls "%APPDATA%\omada-mcp\.env" /inheritance:r /grant:r "%USERNAME%:F".
get_device/get_client accept a MAC in any format (AA-BB-CC-DD-EE-FF,
aabbccddeeff, aa:bb:cc:dd:ee:ff) as well as a hostname or IP, so PowerShell
output pastes straight in.
All variables
Variable | Default | Notes |
| — required |
|
| — required | Local controller account. |
| — required | Never printed, never logged. |
| first site | Display name, e.g. |
| first site | Hex id or name — names are resolved, because the controller only accepts the hex id in URLs (that mismatch is exactly what |
| system store | PEM bundle with the controller's CA. |
|
|
|
|
|
|
| — | Optional TLS |
|
| Default |
| empty | Comma-separated exact write tool names to enable (wildcards and |
| platform state dir | Override directory for pre-write JSON snapshots and |
| empty | Comma-separated IPv4 hosts/CIDRs (in addition to controller host IP) protected from lockouts during VLAN isolation, DHCP pool, or deny-ACL writes. |
|
| System/registry proxies are ignored by default. On Windows, |
|
| Per-request timeout. |
|
| Minimum spacing between controller calls; raise to |
|
| Minimum serialized spacing between write requests (writes never auto-retry |
|
|
|
| all | Optional comma-separated tool categories ( |
|
| Emit single-line compact JSON in |
omada-mcp --show-config prints the resolved values with the password masked;
omada-mcp --doctor validates them.
Connect an MCP host
The server is plain stdio: a host runs uvx omada-mcp, then speaks JSON-RPC on
stdin/stdout. The OMADA_ENV_FILE environment variable lets several hosts share
one configuration file.
Hermes Agent
hermes mcp add omada --command uvx --args omada-mcp \
--env OMADA_ENV_FILE=$HOME/.config/omada-mcp/.envOr in ~/.hermes/config.yaml:
mcp_servers:
omada:
command: uvx
args: ["omada-mcp"]
env:
OMADA_ENV_FILE: /home/you/.config/omada-mcp/.envClaude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or
%APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"omada": {
"command": "uvx",
"args": ["omada-mcp"],
"env": {
"OMADA_ENV_FILE": "/home/you/.config/omada-mcp/.env"
}
}
}
}A copy lives at examples/claude_desktop_config.json.
Claude Code
claude mcp add omada --env OMADA_ENV_FILE=$HOME/.config/omada-mcp/.env -- uvx omada-mcp
claude mcp listCursor
.cursor/mcp.json in the project, or the global ~/.cursor/mcp.json:
{
"mcpServers": {
"omada": {
"command": "uvx",
"args": ["omada-mcp"],
"env": { "OMADA_ENV_FILE": "/home/you/.config/omada-mcp/.env" }
}
}
}Anything else
Any host that can spawn a process and speak newline-delimited JSON-RPC 2.0 works:
{
"mcpServers": {
"omada": {
"command": "uvx",
"args": ["omada-mcp"],
"env": { "OMADA_ENV_FILE": "/home/you/.config/omada-mcp/.env" }
}
}
}From a git checkout instead of PyPI:
uvx --from git+https://github.com/falehsub/omada-mcp omada-mcp --doctorTools
Thirty-five read-only tools are always registered;
47 optional write tools stay hidden and disabled until both OMADA_READ_ONLY=false
and OMADA_WRITE_TOOLS allowlist them explicitly. All site-scoped tools also accept
an optional per-call site name or ID (strictly pinned when OMADA_SITE_NAME/
OMADA_SITE_ID is set unless OMADA_ALLOW_CROSS_SITE=true). list_clients windowing
is bounded by limit (default 500, max 5000) and de-duplicated by MAC.
Read-only tools (always available)
Full generated parameter & safety reference across all 82 tools: docs/tools-reference.md.
Tool | Arguments | Returns |
| — | Sites visible to the account ( |
|
| Site name/id, WAN/LAN/WLAN state, device and client counts, controller version |
| — | MAC, name, type, model, firmware, IP, uptime, client count, status, |
|
| MAC, name, hostname, IP, wireless, guest, SSID, AP, network, VLAN, rx/tx, duration, last seen (UTC ISO-8601) |
|
| Same projection, wireless only |
|
| Same projection, wired only |
|
| Filtered client search ( |
|
| One device |
|
| One client |
| — | SSID, band, VLAN, security, guest, |
| — | Wireless WLAN group IDs/names and member SSID summaries (secrets stripped) |
| — | Merged |
| — | Switch port profiles ( |
|
| Offline/static DHCP reservations from |
|
| Gateway ( |
|
| IP/port/profile groups ( |
| — | Port-forwarding NAT rules ( |
| — | Static/interface routes ( |
| — | Policy routing rules ( |
| — | Local LAN DNS records ( |
| — | UPnP, DNS proxy, mDNS rules & built-in profiles, DDNS, and WAN port state |
|
| Controller |
|
| Per-switch port link/speed/duplex, PoE budget/power, LAG membership, uplink & controller-port flags, RX/TX errors, and cable tests |
|
| Per-AP |
|
| Latest RF scan status and per-band interference summary for an AP |
|
| Live WAN link/internet state, failover/load-balance mode, gateway/DNS, latency/loss, and latest speedtest |
| — | WireGuard, OpenVPN, IPsec, and L2TP tunnel & peer state (all private keys, PSKs, and PEM blocks redacted) |
| — | Compact uplink tree (Gateway -> Switch[port] -> AP/Switch) using |
| — | IPS/IDS status and recent threat/WIDS alerts with graceful missing-hardware warnings |
|
| Composite client troubleshooter correlating client RSSI/SNR, |
|
| Composite WAN troubleshooter correlating link/failover, latency/loss, VPN state, and WAN log events |
| — | Composite one-call health audit: pending firmware, offline devices, PoE budget >= 85%, uplink speed mismatches, AP retry spikes, WAN loss/failover, unexpected VLAN clients, unisolated VLANs, DHCP pool utilization, and stable finding codes |
|
| Structured decoder for Omada |
|
| Read-only snapshot merging |
|
| Deterministic drift diff between two |
Opt-in write tools (OMADA_READ_ONLY=false + OMADA_WRITE_TOOLS)
Every write tool defaults dryRun=true, captures a pre-mutation JSON snapshot under OMADA_SNAPSHOT_DIR, requires confirm="<tool>:<target>" when dryRun=false, verifies state on read-back, and never auto-retries on -1600.
Category | Tools | Behaviour & Safety |
Snapshot rollback |
| Loads snapshot strictly inside |
Switch ports & profiles |
| Port enable/PoE mode/profile updates, custom port profile CRUD, and PoE power cycling; refuses built-in profile deletion or stranding uplink, controller-hosting, or LAG member ports unless |
AP radios, RF scan & WLAN groups |
| Preserves sibling band configs during |
Live client controls & fixed IP |
| Full-object stripped client PATCH ( |
Offline DHCP reservations |
| Create/update/delete reservations in |
LAN & VLAN management |
| Two-endpoint LAN RMW, normalizes |
IP groups & ACLs |
| Aligned CIDR packing ( |
Wireless SSIDs |
| Manage SSIDs under |
Routing, DNS, NAT & services |
| NAT port forwards, static & policy routing, local LAN DNS records, mDNS repeater rules, and UPnP toggle |
Device operations |
| Rename / LED / locate / reboot EAPs, switches, and gateways ( |
omada-mcp --list-tools prints active descriptors without touching the network
(add --all to inspect all 82 tools including non-allowlisted writes).
Every descriptor in tools/list declares MCP annotations and an MCP 2025-06-18
outputSchema, so hosts can auto-approve reads and validate structured results:
{
"name": "list_devices",
"title": "List Omada devices",
"outputSchema": {
"type": "object",
"properties": {
"items": { "type": "array" },
"count": { "type": "integer", "minimum": 0 }
},
"required": ["items", "count"]
},
"annotations": {
"title": "List Omada devices",
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": true
}
}Output shape (content vs structuredContent)
List tools (
list_devices,list_clients,list_wifi_clients,list_wired_clients,search_clients,list_wlans,list_wlan_groups,list_lan_networks,list_port_profiles,list_dhcp_reservations,list_acls,list_ip_groups,list_port_forwards,list_static_routes,list_policy_routes,list_lan_dns_rules,list_vpn_tunnels,list_logs):content[0].textis serialized as a bare JSON array ([{...}, ...]), whilestructuredContentis an object matchingoutputSchema:{"items": [...], "count": <int>}. Callers parsingcontent[0].text(for example migrating from wrapper objects like{"devices": [...]}) receive a JSON list directly, whereas MCP2025-06-18hosts readstructuredContent.itemsandstructuredContent.count.Object tools (
get_device,get_client,get_site_info,get_network_services,get_switch_ports,get_ap_radios,get_rf_scan,get_wan_status,get_topology,get_security_status,diagnose_client,diagnose_wan,network_audit,explain_error,get_config_snapshot, and write envelopes): bothcontent[0].textandstructuredContentcontain the same JSON object matchingoutputSchema.
omada-mcp --list-tools prints active descriptors without touching the network;
omada-mcp --list-tools --all prints all 82 descriptors (add --compact for single-line JSON).
Direct controller connections reuse persistent HTTP/1.1 keep-alive TLS sockets (UrllibTransport),
and composite troubleshooters (network_audit, diagnose_client, diagnose_wan,
get_config_snapshot, --watch / --export-metrics) deduplicate repeated site-wide GETs within
a single invocation via an ephemeral per-call cache (OmadaClient.scoped_cache()).
Watch mode, Prometheus metrics & Docker
Both monitoring modes reuse one persistent authenticated OmadaClient session
and enforce >= 0.8 s pacing so they never evict shared sessions:
# Stream JSON telemetry snapshot + event diffs (wan_failover, ap_retry_spike, weak_client_rssi, dhcp_pool_utilization)
omada-mcp --watch --interval 30
# One-shot Prometheus text exposition
omada-mcp --export-metrics
# Persistent /metrics HTTP endpoint (cached with >= 5 s scrape TTL + /healthz)
omada-mcp --export-metrics --metrics-port 9108 --metrics-host 127.0.0.1Build and run the non-root container (OMADA_READ_ONLY=true by default):
docker build -t omada-mcp .
docker run --rm -i --env-file ~/.config/omada-mcp/.env omada-mcp --doctor
docker run --rm -p 9108:9108 --env-file ~/.config/omada-mcp/.env omada-mcp --export-metrics --metrics-port 9108 --metrics-host 0.0.0.0Safety model
Control | Behaviour |
| Refuses any tool not declared read-only ( |
| Defaults empty. Wildcards and |
Two-phase apply ( | Every write defaults |
Snapshot before & verify after | Saves pre-write JSON snapshot + |
Anti-stranding guards | Refuses VLAN isolation, DHCP pool overlaps, or deny ACL rules that isolate/conflict with controller IP, gateway, device IPs, or |
Credential handling | Password only ever rendered as |
Secret redaction |
|
Session recovery | A 200 response containing the web UI shell triggers one re-login: reads replay once, writes re-read live state first and never auto-retry |
Pacing | Reads spaced by |
Dotenv hygiene |
|
Troubleshooting
Run omada-mcp --doctor first — it names the failing phase and the fix. The
table below maps the symptoms it cannot see.
Symptom | Cause | Fix |
| Site name used where the hex site id is required | Set |
| Wrong path shape ( | Reads retry once after 0.8 s; writes never auto-retry |
| Group is referenced by one or more ACL rules | Use |
| The group holds at most 16 entries | Store ranges as network-aligned CIDRs (packed automatically by |
| A mandatory field missing from a PATCH body — for LAN networks it is | Send the whole object (handled automatically by LAN write tools) |
| Current user role lacks write permission (e.g. Viewer account on Omada 6.2.x) | Use a dedicated Admin account for writes; keep Viewer for read-only mode |
| No adopted gateway/switch on the site supports Network Isolation | Adopt an isolation-capable gateway/switch or use gateway ACLs instead |
|
| Use an IP group (e.g. |
| Client does not exist, MAC belongs to a managed device, or Viewer role on | Use |
| You are on the Open API without Platform Integration | Use this server (Web API) instead |
HTTP 200 with HTML in response | The controller's server-side session died (cookie is still valid for 15 days) — another login for the same account, or a restart | Automatic: the client re-authenticates once and replays |
| Self-signed controller cert, IP/SAN mismatch, or Python 3.13+ strict X509 | Set |
| Wrong port or unroutable network | Controller web UI is |
Host starts but every call fails | No credentials at server start | Expected: |
Windows: timeouts although the controller pings | WinINET proxy inherited by | Proxies are off by default; if you need one, |
Windows: |
| Use |
Compatibility
See docs/compatibility.md for the full compatibility table.
Software controller v6.x — read-only path (
--doctor --jsonand all 35 read-only tools) verified live on v6.2.10.17 (TPOMADA_SESSIONID), and 20 baseline read-only tools plus controller-native write CRUD (create/update/delete_lan_networkwith explicitipaddrStart/ipaddrEndpools,set_vlan_dhcp_pools,upsert/delete_dhcp_reservation,create/replace/delete_ip_group,create/update/set_acl_rule_status/delete_gateway_aclincluding the 6-step swap,create_switch_acl/create_eap_aclwith typed toggle/update/delete lifecycle,create/update/delete_ssidwith PSK redaction,upsert/delete_port_forward,upsert/delete_static_route,upsert/delete_mdns_rule,set_upnpdry-run + live disable +-33001gateway check,-33598on hardwareless isolation, Viewer-1007 -> insight/clientsfallback, and-41011/not-found probes) verified live against an isolated Docker Omada Controller v6.2.14.11; client fixed-IP lease-delayed behavior (set_client_fixed_ip/release_client_fixed_ip), client actions, and device controls (update_device,reboot_device) are covered by the stateful mock controller.Software controller v5.x — expected (v5.13.30.8 core auth/list shapes supported; awaiting a
--doctor --jsoncapture via the issue template).OC200 / OC300 hardware &
TPEAP_SESSIONIDbuilds — expected (--doctordetects bothTPOMADA_SESSIONIDandTPEAP_SESSIONID, handles legacyresult.omadacIdlogin shapes, and reportshardware-5.x/hardware-6.x). Runomada-mcp --doctor --jsonand submit a Controller Compatibility Report.
Development
git clone https://github.com/falehsub/omada-mcp && cd omada-mcp
python -m unittest discover -s tests -v # stdlib tests; loopback HTTP only
python -m omada_mcp.cli --help # after: pip install -e .
uvx --from . omada-mcp --doctor # what an external user does
# uv caches the build of a local *path* and does not rebuild when the source
# changes (`--refresh` does not help). Force a fresh environment while iterating:
UV_CACHE_DIR=$(mktemp -d) uvx --from . omada-mcp --doctorFor a repeatable live read-only sweep, use an explicit isolated lab configuration:
python scripts/read_selftest.py --env-file /path/to/isolated/viewer.envThe sweep forces read-only mode, blocks mutations at the transport boundary, and reports pass/fail/skip, elapsed time and request counts without controller payloads. Hardware-dependent checks are skipped when the site has no matching devices or clients. Configuration, service and routing exports expose known fields only; diagnostic snapshots are not full controller backups.
See the local review and prioritized improvements for measured results, limitations and the next development priorities.
Layout:
src/omada_mcp/config.py dotenv discovery, validation, base-URL normalisation, write allowlist
src/omada_mcp/errors.py OmadaError taxonomy, ERROR_CATALOG, explain_error_code, redaction
src/omada_mcp/transport.py pooled keep-alive HTTP/1.1 transport, TLS context, SiteInfo/AuthInfo
src/omada_mcp/client.py Web API v2 client: auth, pagination, write gate, snapshots/audit
src/omada_mcp/domains/ cohesive read, write, diagnostic, rollback & schema modules
src/omada_mcp/tools.py tool registry facade (35 read-only + 47 write = 82 tools)
src/omada_mcp/write_tools.py backward-compatible write handler & validator facade
src/omada_mcp/_helpers.py backward-compatible shared diagnostic helper facade
src/omada_mcp/monitor.py single-session --watch JSON diff streamer & --export-metrics Prometheus exporter
src/omada_mcp/server.py JSON-RPC stdio server, fail-closed gates, strict arg/bool checks
src/omada_mcp/doctor.py 6-phase self-test (env, tls, login, site, tools, write) with --json
Dockerfile minimal non-root container (stdio default, --watch, --export-metrics)
schemas/doctor.schema.json JSON Schema for --doctor --json
docs/tools-reference.md auto-generated 82-tool parameter & safety reference
docs/compatibility.md controller family and cookie compatibility matrix
docs/write-support.md write-support contract, verified endpoints, and controller traps
server.json MCP Registry manifest (PyPI + GHCR OCI metadata)
SECURITY.md vulnerability disclosure policy & credential safety model
CONTRIBUTING.md contributor setup, mock/Docker lab rules & zero-drift checks
tests/mock_controller.py stateful Web API v2 mock controller with fault injection
tests/fake_controller.py lightweight FakeController & offline unit fixtures
tests/test_*.py domain-split read, protocol, monitor, write & regression tests
skills/omada-controller/ agent skill: field notes for the Omada API itselfThe API notes in skills/omada-controller/SKILL.md
document the parts of the controller that are not in any public reference:
session expiry semantics, CIDR packing limits, dual-pool DHCP bodies, and the
endpoints that are Admin-only.
Contributing & releasing
See CONTRIBUTING.md and SECURITY.md for local setup, mock/Docker lab testing rules, and vulnerability reporting.
Pull requests only: Develop changes on a branch and open a Pull Request targeting
mainrather than pushing directly tomain. Every PR runs the CI matrix across Ubuntu, Windows, and macOS (Python3.10–3.14), zero-drift doc checks (python scripts/generate_docs.py --check), and Docker container smoke tests via.github/workflows/ci.yml.PyPI, GHCR & Attestations: Releases publish to PyPI via
.github/workflows/publish.ymlusing GitHub Actions OIDC Trusted Publishing (pypienvironment, no stored tokens), push multi-arch (linux/amd64,linux/arm64) containers toghcr.io/falehsub/omada-mcp, and attach SLSA build provenance attestations plusSHA256SUMS.txt.
Write support
Read-only mode remains the default (OMADA_WRITE_TOOLS defaults empty and write
tools are hidden). Opt-in writes follow the contract in
docs/write-support.md — explicit OMADA_WRITE_TOOLS
allowlist, dryRun=true default, confirm="<tool>:<target-id>", pre-write snapshots +
audit.jsonl, whole-object verification, and anti-stranding checks. Use a dedicated
Admin local account separate from your read bridge and web UI to avoid session
eviction. Firmware upgrades remain unshipped pending a maintenance-window policy.
Roadmap
Read-only inspection, composite diagnostics (get_switch_ports, get_ap_radios,
get_wan_status, get_topology, diagnose_client, diagnose_wan), --doctor --json,
network_audit, the 82-tool control surface (rollback_from_snapshot + anti-stranding
switch/AP/routing/DNS/ACL/client controls), multi-site workflows (list_sites + per-call
site), diff_config_snapshots, --watch/--export-metrics, non-root multi-arch Docker
packaging, and MCP Registry metadata (server.json) are implemented. See
ROADMAP.md for historical milestones and future ideas. PyPI installation is available.
License
MIT — see LICENSE.
Not affiliated with TP-Link. Omada is a trademark of TP-Link Technologies.
This server calls an undocumented internal API; a controller firmware update can
change it, which is exactly why --doctor exists.
Available Tools
35 toolsdiagnose_clientDiagnose a WiFi or wired clientCRead-onlyIdempotent
Correlate client signal/link state, connection history, parent AP radio or switch port telemetry, and recent…
Inputs: mac (required), site, hours. Returns: client, findings, warnings, nextSteps, +4 more
diagnose_wanDiagnose gateway WAN & VPN healthCRead-onlyIdempotent
Correlate live WAN link state, latency/packet loss, speedtest, VPN tunnel health, and gateway alerts/events…
Inputs: site, hours, includeSpeedtest. Returns: wan, findings, warnings, nextSteps, +2 more
diff_config_snapshotsDiff site configuration snapshotsCRead-onlyIdempotent
Deterministically compare two get_config_snapshot payloads…
Inputs: baseline (required), site, current, objects. Returns: summary, sections, crossSite, hasChanges, +2 more
explain_errorExplain Omada errorCodeCRead-onlyIdempotent
Decode an Omada Web API errorCode (e.g. -1600, -33717, -33726, -1505, -1001, -30109, -41011, -44116) into its…
Inputs: code (required), endpoint. Returns: fix, code, known, title, +5 more
get_ap_radiosGet AP radio & channel stateCRead-onlyIdempotent
Inspect an AP's 2.4G/5G/5G2/6G radios: channel, width, TX power, channel utilization, interference…
Inputs: mac (required), site, includeRfScan, includeAvailableChannels. Returns: mac, name, radios, warnings
get_clientGet clientBRead-onlyIdempotent
Get one client by MAC address, hostname or IP address.
Inputs: mac (required), site. Returns: ip, mac, name, ssid, +12 more
get_config_snapshotGet site configuration snapshotCRead-onlyIdempotent
Read-only snapshot of LAN networks (both collection and /interface endpoints), gateway ACLs, IP/port groups…
Inputs: site, objects. Returns: site, objects, warnings
get_deviceGet deviceCRead-onlyIdempotent
Get one device by MAC address or device name.
Inputs: mac (required), site. Returns: ip, mac, name, type, +6 more
get_network_servicesGet network servicesCRead-onlyIdempotent
Summarize UPnP, DNS proxy, mDNS reflector rules and profiles, secret-redacted DDNS configuration, and…
Inputs: site. Returns: wan, ddns, mdns, upnp, +2 more
get_rf_scanGet AP RF scan resultsCRead-onlyIdempotent
Read the latest cached RF scan status/neighbor results (empty channels list if no scan was triggered) and…
Inputs: mac (required), site. Returns: mac, name, channels, warnings, +2 more
get_security_statusGet IPS/IDS, WIDS & rogue AP statusCRead-onlyIdempotent
Summarize IPS/IDS enablement, recent threat events, attack defense limits, WIDS/WIPS, and rogue AP detections…
Inputs: site, hours, limit. Returns: ips, counts, rogueAps, warnings, +1 more
get_site_infoGet site summaryBRead-onlyIdempotent
Site summary: name, id, WAN/LAN/WLAN state, device and client counts, controller version.
Inputs: site. Returns: id, name, siteUrl, clientCount, +8 more
get_switch_portsGet switch ports, PoE & diagnosticsCRead-onlyIdempotent
Inspect per-port link status, speed/duplex, PoE delivery & switch budget, active port profile/VLANs…
Inputs: mac (required), site, compact, includeCounters, +2 more. Returns: mac, poe, name, ports, +2 more
get_topologyGet site uplink topology treeBRead-onlyIdempotent
Build the site's Gateway -> Switch(port) -> AP/Switch uplink tree with device counts.
Inputs: site, includeClients. Returns: roots, counts, warnings, unattachedDevices
get_wan_statusGet live WAN link & health statusBRead-onlyIdempotent
Inspect gateway WAN link state, gateway/DNS/WAN IP, failover/load-balance mode, latency/packet loss health…
Inputs: site, maskWanIp, includeSpeedtest. Returns: ports, wanMode, warnings, hasGateway, +3 more
list_aclsList firewall ACL rulesCRead-onlyIdempotent
List gateway, switch, or EAP ACL rules (setting/firewall/acls?type=0|1|2) with policy, source/destination…
Inputs: site, aclType. Returns: count, items
list_clientsList clientsCRead-onlyIdempotent
List connected clients (WiFi and wired) with MAC, IP, SSID, AP, VLAN, traffic counters, session duration and…
Inputs: site, limit. Returns: count, items
list_devicesList Omada devicesCRead-onlyIdempotent
List all managed network devices (APs, switches, gateways) on the site with MAC, model, firmware, IP, uptime…
Inputs: site. Returns: count, items
list_dhcp_reservationsList static DHCP reservationsBRead-onlyIdempotent
List static DHCP reservations configured on the site (works for offline clients too).
Inputs: site, vlan. Returns: count, items
list_ip_groupsList IP/port/MAC profile groupsBRead-onlyIdempotent
List profile groups (IP groups type=0, port groups type=1, MAC groups type=2) with entry counts and ACL…
Inputs: site, groupType. Returns: count, items
list_lan_dns_rulesList local LAN DNS rulesBRead-onlyIdempotent
List local LAN DNS records (gracefully warns on controller versions without LAN DNS).
Inputs: site. Returns: count, items, warnings, supported
list_lan_networksList LAN and VLAN networksCRead-onlyIdempotent
List configured LAN/VLAN networks merging setting/lan/networks and /interface…
Inputs: site. Returns: count, items
list_logsList controller alerts, events, or audit logsBRead-onlyIdempotent
Query controller site logs ('alerts', 'events', or 'audit') with time window, optional level filter, and row…
Inputs: site, hours, level, limit, +1 more. Returns: count, items
list_policy_routesList gateway policy routing rulesBRead-onlyIdempotent
List policy routing rules (gracefully reports unavailability if no gateway exists).
Inputs: site. Returns: count, items, warnings, supported
list_port_forwardsList port forwarding rulesBRead-onlyIdempotent
List gateway NAT port forwarding and DMZ-mapped rules.
Inputs: site. Returns: count, items
list_port_profilesList switch LAN port profilesBRead-onlyIdempotent
List switch port profiles (All, Disable, custom VLAN/PoE profiles).
Inputs: site. Returns: count, items
list_sitesList visible controller sitesBRead-onlyIdempotent
List sites visible to the authenticated Viewer or Admin account with site IDs, names, connectivity flags, and…
Inputs: no named parameters. Returns: count, items
list_static_routesList static routesBRead-onlyIdempotent
List configured gateway static routes (destinations, next hop, interface, metric).
Inputs: site. Returns: count, items
list_vpn_tunnelsList VPN tunnels & secret-redacted configsBRead-onlyIdempotent
List WireGuard, OpenVPN, IPsec, and SSL/L2TP VPN tunnel state and configured profiles…
Inputs: site. Returns: counts, tunnels, warnings, configuredVpns
list_wifi_clientsList WiFi clientsBRead-onlyIdempotent
List only wireless clients, same fields as list_clients.
Inputs: site, limit. Returns: count, items
list_wired_clientsList wired clientsBRead-onlyIdempotent
List only wired clients, same fields as list_clients.
Inputs: site, limit. Returns: count, items
list_wlan_groupsList WLAN groups & SSID bindingsCRead-onlyIdempotent
List configured WLAN groups and their SSIDs for assigning APs cleanly.
Inputs: site. Returns: count, items
list_wlansList WLANsBRead-onlyIdempotent
List configured WLANs/SSIDs with band, VLAN, security type and guest flag.
Inputs: site. Returns: count, items
network_auditAudit site network healthBRead-onlyIdempotent
One-call read-only health audit checking WAN state/packet loss, offline devices, pending firmware upgrades…
Inputs: site. Returns: site, counts, healthy, findings, +2 more
search_clientsSearch clientsBRead-onlyIdempotent
Search online and offline/historical clients by MAC, name, hostname, IP, SSID, or VLAN/network, with…
Inputs: site, ssid, vlan, guest, +4 more. Returns: count, items
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 35 tools
Most tools target clearly distinct resources (devices, clients, WLANs, ACLs, VPN tunnels, WAN status, logs), and the get_* vs list_* vs diagnose_* split is meaningful. Overlap exists between list_clients and the list_wifi_clients/list_wired_clients subsets, and between network_audit/get_config_snapshot/diagnose_wan which all report WAN health from different angles, but descriptions make the intended use reasonably clear.
Almost all names follow a consistent snake_case verb_noun pattern (list_*, get_*, diagnose_*, search_*, diff_*), with list_/get_ used predictably for collections vs single records. The one deviation is the noun-style 'network_audit', and 'explain_error'/'diff_config_snapshots' are slightly off-pattern but still readable.
35 tools is heavy and exceeds a comfortable range, though the breadth reflects a genuinely wide network-controller domain (sites, devices, clients, WiFi, ACLs, VPN, routing, DNS, RF, logs). Some tools are thin convenience wrappers (list_wifi_clients, list_wired_clients, get_rf_scan) that could be parameters of existing tools rather than separate entries.
The read-only observability surface is thorough: inventory, topology, health audits, config snapshots with diffing, diagnostics, and error decoding cover the monitoring lifecycle well. The main gap is that the server is entirely read-only—no mutations for DHCP reservations, ACLs, WLANs, or firmware upgrades—so flows like 'detected pending firmware' dead-end without an action tool.
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
One OAuth connector for your team's remote MCP servers, with Tool Packs, guardrails and logs.
Scans remote MCP servers for protocol, security, and TLS issues; exposes scan tools via MCP.
Host any HTTP API as MCP tools with a tamper-evident cross-agent settlement ledger.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes the UniFi Network Integration API as MCP tools, dynamically loaded from JSON manifests, with read-only mode by default.MIT
- AlicenseAqualityCmaintenanceRead-only MCP server for TP-Link Omada SDN controllers, enabling querying controller, site, device, and WiFi state.8Apache 2.0
- AlicenseCqualityBmaintenanceEnables managing TP-Link Omada SDN controllers through MCP, exposing 72 tools for sites, devices, clients, networks, switch ports, firewalls, schedules, and site settings, including reboot and PoE scheduling.721MIT
- AlicenseCqualityBmaintenanceMCP server that lets AI assistants monitor and manage TP-Link Omada controllers. It provides analytics and read-only queries plus write operations such as rebooting devices, blocking clients, and changing network or firewall settings.84MIT