Skip to main content
Glama
README.md
# lancontrol

lancontrol reads UniFi Network controller state through a single
action-router tool: connected clients, network devices, WLAN
configurations, site health, active alarms, recent events,
controller sysinfo, and the authenticated identity. One binary
serves a command-line interface and a stdio MCP server.

This is a labelled core subset. The upstream surface defines 267
actions in total; lancontrol builds only the 8 preserved
convenience actions plus `help` (9 action values). The generated
families are omitted, on purpose and by name: `official_*`
(78 actions), `unifi_*` (175 actions), and the 5 hybrid aliases
(`list_clients`, `list_devices`, `list_networks`, `list_wifi`,
`get_system_info`).

## Configuration

Both variables are required for every action except `help`; a
missing value errors before any request is made:

| Variable | Required | Purpose |
| --- | --- | --- |
| `UNIFI_URL` | yes | Controller base URL, e.g. `https://unifi.local`. |
| `UNIFI_API_KEY` | yes | API key, sent as the `X-API-KEY` header. |
| `UNIFI_SITE` | no | UniFi site name. Defaults to `default`. |

Never pass the API key as a tool argument; it is read from the
environment only.

## Install

```bash
npx @reneturcios/lancontrol help
```

Or run the container image:

```bash
docker run -i ghcr.io/cloudcorprecords/lancontrol
```

The container defaults to the MCP server (see below). Pass CLI
arguments to use it as a CLI instead.

## CLI

```bash
lancontrol clients
lancontrol devices
lancontrol wlans
lancontrol health
lancontrol alarms
lancontrol events --limit 25
lancontrol sysinfo
lancontrol me
lancontrol help

lancontrol --version
```

Action commands print the upstream JSON payload. `help` prints
the local action documentation and needs no configuration and no
network. Exit codes: `0` on success, `1` when a call fails
(including a missing-config or upstream API error), `2` for usage
errors.

## MCP server

One bin serves both faces. The `mcp` subcommand starts a stdio
MCP server:

```bash
npx -y @reneturcios/lancontrol mcp
```

MCP client configuration:

```json
{
  "mcpServers": {
    "lancontrol": {
      "command": "npx",
      "args": ["-y", "@reneturcios/lancontrol", "mcp"],
      "env": {
        "UNIFI_URL": "https://unifi.local",
        "UNIFI_API_KEY": "...",
        "UNIFI_SITE": "default"
      }
    }
  }
}
```

### Tool

One tool is exposed:

| Tool | Input | What it returns |
| --- | --- | --- |
| `unifi` | `action` (required, one of the 9 subset values), `limit` (optional integer, `events` only) | The upstream payload for the chosen action, or local documentation for `help`. |

| Action | Description |
| --- | --- |
| `clients` | Connected wireless and wired clients. |
| `devices` | Network devices: APs, switches, gateways. |
| `wlans` | WiFi network configurations. |
| `health` | Site health summary. |
| `alarms` | Active alarms and alerts. |
| `events` | Recent controller events. |
| `sysinfo` | Controller system information. |
| `me` | Authenticated UniFi identity. |
| `help` | Built-in action documentation. |

## Upstream mapping (documented reconstruction)

The public spec names the actions but does not publish, in its
convenience-action table, the exact controller path for each one.
Each action is therefore implemented as a GET to a plausible
documented UniFi internal endpoint under `UNIFI_URL`, with the
`X-API-KEY` header:

| Action | Endpoint |
| --- | --- |
| `clients` | `GET /proxy/network/api/s/{site}/stat/sta` |
| `devices` | `GET /proxy/network/api/s/{site}/stat/device` |
| `wlans` | `GET /proxy/network/api/s/{site}/rest/wlanconf` |
| `health` | `GET /proxy/network/api/s/{site}/stat/health` |
| `alarms` | `GET /proxy/network/api/s/{site}/stat/alarm` |
| `events` | `GET /proxy/network/api/s/{site}/stat/event` (plus `?_limit={limit}` when a limit is supplied) |
| `sysinfo` | `GET /proxy/network/api/s/{site}/stat/sysinfo` |
| `me` | `GET /proxy/network/api/self` |
| `help` | no request — answered locally |

HTTP failures surface the status plus the upstream message
(`meta.msg`, `message`, or `error`) when present.

## Development

```bash
npm install
npm run build   # tsc -> dist/
npm test        # node test runner over test/*.test.ts, no network (fake fetch fixtures)
npm run dev     # run the CLI from source via tsx
```

## License

MIT — see `LICENSE`.